Initial commit: Meshkee dashboards monorepo.

Includes business, customer, and super-admin apps with shared packages and production deploy scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-07-22 13:48:53 +03:30
co-authored by Cursor
commit f566387c61
509 changed files with 62690 additions and 0 deletions
@@ -0,0 +1,143 @@
export interface ApiClientConfig {
baseUrl: string
accessTokenKey: string
refreshTokenKey: string
}
export class ApiError extends Error {
status: number
constructor(message: string, status: number) {
super(message)
this.name = 'ApiError'
this.status = status
}
}
export function isAbortError(err: unknown): boolean {
return err instanceof DOMException && err.name === 'AbortError'
}
function parseErrorMessage(payload: unknown, fallback: string) {
if (!payload || typeof payload !== 'object') {
return fallback
}
const message = (payload as { message?: string | string[] }).message
if (Array.isArray(message)) {
return message.join(', ')
}
if (typeof message === 'string') {
return message
}
return fallback
}
export interface ApiClient {
getAccessToken: () => string | null
getRefreshToken: () => string | null
setTokens: (accessToken: string, refreshToken: string) => void
clearTokens: () => void
apiRequest: <T>(path: string, options?: ApiRequestOptions) => Promise<T>
}
interface ApiRequestOptions extends Omit<RequestInit, 'body'> {
body?: unknown
auth?: boolean
}
export function createApiClient(config: ApiClientConfig): ApiClient {
const { baseUrl, accessTokenKey, refreshTokenKey } = config
function getAccessToken() {
return localStorage.getItem(accessTokenKey)
}
function getRefreshToken() {
return localStorage.getItem(refreshTokenKey)
}
function setTokens(accessToken: string, refreshToken: string) {
localStorage.setItem(accessTokenKey, accessToken)
localStorage.setItem(refreshTokenKey, refreshToken)
}
function clearTokens() {
localStorage.removeItem(accessTokenKey)
localStorage.removeItem(refreshTokenKey)
}
async function refreshAccessToken() {
const refreshToken = getRefreshToken()
if (!refreshToken) {
return false
}
const response = await fetch(`${baseUrl}/auth/refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken }),
})
if (!response.ok) {
clearTokens()
return false
}
const data = await response.json()
setTokens(data.accessToken, data.refreshToken)
return true
}
async function apiRequest<T>(path: string, options: ApiRequestOptions = {}): Promise<T> {
const { body, auth = false, headers, ...rest } = options
const requestHeaders = new Headers(headers)
if (body !== undefined) {
requestHeaders.set('Content-Type', 'application/json')
}
if (auth) {
const accessToken = getAccessToken()
if (accessToken) {
requestHeaders.set('Authorization', `Bearer ${accessToken}`)
}
}
const response = await fetch(`${baseUrl}${path}`, {
...rest,
headers: requestHeaders,
body: body !== undefined ? JSON.stringify(body) : undefined,
})
if (response.status === 401 && auth) {
const refreshed = await refreshAccessToken()
if (refreshed) {
return apiRequest<T>(path, options)
}
}
const payload = await response.json().catch(() => null)
if (!response.ok) {
throw new ApiError(
parseErrorMessage(payload, `Request failed with status ${response.status}`),
response.status,
)
}
return payload as T
}
return {
getAccessToken,
getRefreshToken,
setTokens,
clearTokens,
apiRequest,
}
}