@spacelr/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +609 -0
- package/dist/index.d.ts +609 -0
- package/dist/index.js +1471 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1438 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../libs/sdk/src/core/errors.ts","../../../../libs/sdk/src/core/http-client.ts","../../../../libs/sdk/src/core/token-storage.ts","../../../../libs/sdk/src/core/token-manager.ts","../../../../libs/sdk/src/types/common.ts","../../../../libs/sdk/src/core/pkce.ts","../../../../libs/sdk/src/core/realtime.ts","../../../../libs/sdk/src/modules/auth.module.ts","../../../../libs/sdk/src/modules/storage.module.ts","../../../../libs/sdk/src/modules/database.module.ts","../../../../libs/sdk/src/modules/notifications.module.ts","../../../../libs/sdk/src/client.ts"],"sourcesContent":["export class SpacelrError extends Error {\n readonly code: string;\n readonly statusCode?: number;\n readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n statusCode?: number,\n details?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'SpacelrError';\n this.code = code;\n this.statusCode = statusCode;\n this.details = details;\n }\n}\n\nexport class SpacelrAuthError extends SpacelrError {\n constructor(\n message: string,\n statusCode = 401,\n details?: Record<string, unknown>\n ) {\n super(message, 'AUTH_ERROR', statusCode, details);\n this.name = 'SpacelrAuthError';\n }\n}\n\nexport class SpacelrNetworkError extends SpacelrError {\n constructor(message: string, details?: Record<string, unknown>) {\n super(message, 'NETWORK_ERROR', undefined, details);\n this.name = 'SpacelrNetworkError';\n }\n}\n\nexport class SpacelrTimeoutError extends SpacelrError {\n constructor(timeoutMs: number) {\n super(\n `Request timed out after ${timeoutMs}ms`,\n 'TIMEOUT_ERROR',\n undefined,\n { timeoutMs }\n );\n this.name = 'SpacelrTimeoutError';\n }\n}\n\nexport class SpacelrTwoFactorRequiredError extends SpacelrError {\n readonly twoFactorToken: string;\n\n constructor(twoFactorToken: string, details?: Record<string, unknown>) {\n super(\n 'Two-factor authentication required',\n 'TWO_FACTOR_REQUIRED',\n 200,\n details\n );\n this.name = 'SpacelrTwoFactorRequiredError';\n this.twoFactorToken = twoFactorToken;\n }\n}\n\nexport class SpacelrEmailVerificationRequiredError extends SpacelrError {\n readonly emailSent: boolean;\n\n constructor(emailSent: boolean, details?: Record<string, unknown>) {\n super(\n emailSent\n ? 'Email verification required. A new verification email has been sent.'\n : 'Email verification required. Please check your inbox for the verification email.',\n 'EMAIL_VERIFICATION_REQUIRED',\n 200,\n details\n );\n this.name = 'SpacelrEmailVerificationRequiredError';\n this.emailSent = emailSent;\n }\n}\n","import { SpacelrClientConfig, ApiResponse } from '../types';\nimport {\n SpacelrError,\n SpacelrAuthError,\n SpacelrNetworkError,\n SpacelrTimeoutError,\n SpacelrTwoFactorRequiredError,\n SpacelrEmailVerificationRequiredError,\n} from './errors';\nimport { TokenManager } from './token-manager';\n\nexport interface HttpRequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n path: string;\n body?: unknown;\n authenticated?: boolean;\n headers?: Record<string, string>;\n query?: Record<string, string | number | undefined>;\n /** Send cookies cross-origin (credentials: 'include'). Defaults to true for /auth/ paths. */\n withCredentials?: boolean;\n}\n\nexport class HttpClient {\n private config: SpacelrClientConfig;\n private tokenManager: TokenManager;\n\n constructor(config: SpacelrClientConfig, tokenManager: TokenManager) {\n this.config = config;\n this.tokenManager = tokenManager;\n }\n\n async request<T>(options: HttpRequestOptions): Promise<T> {\n const url = this.buildUrl(options.path, options.query);\n const headers = await this.buildHeaders(options);\n const timeout = this.config.timeout ?? 30000;\n const includeCredentials = options.withCredentials ?? options.path.startsWith('/auth/');\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n ...(includeCredentials && { credentials: 'include' as RequestCredentials }),\n });\n\n const responseBody = await this.parseResponse(response);\n\n if (!response.ok) {\n this.throwHttpError(response.status, responseBody);\n }\n\n return this.extractData<T>(responseBody);\n } catch (error) {\n if (error instanceof SpacelrError) throw error;\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw new SpacelrTimeoutError(timeout);\n }\n\n throw new SpacelrNetworkError(\n error instanceof Error ? error.message : 'Network request failed'\n );\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async uploadForm<T>(\n path: string,\n formData: FormData,\n onProgress?: (event: { loaded: number; total: number }) => void,\n ): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildFormHeaders();\n const timeoutMs = this.config.timeout ?? 30000;\n\n // Use XMLHttpRequest when progress tracking is needed\n if (onProgress) {\n return this.uploadFormWithProgress<T>(url, headers, formData, onProgress, timeoutMs);\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: formData,\n signal: controller.signal,\n });\n\n const responseBody = await this.parseResponse(response);\n\n if (!response.ok) {\n this.throwHttpError(response.status, responseBody);\n }\n\n return this.extractData<T>(responseBody);\n } catch (error) {\n if (error instanceof SpacelrError) throw error;\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw new SpacelrTimeoutError(timeoutMs);\n }\n\n throw new SpacelrNetworkError(\n error instanceof Error ? error.message : 'Network request failed'\n );\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private uploadFormWithProgress<T>(\n url: string,\n headers: Record<string, string>,\n formData: FormData,\n onProgress: (event: { loaded: number; total: number }) => void,\n timeoutMs: number,\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.open('POST', url);\n xhr.timeout = timeoutMs;\n\n for (const [key, value] of Object.entries(headers)) {\n xhr.setRequestHeader(key, value);\n }\n\n xhr.upload.addEventListener('progress', (e) => {\n if (e.lengthComputable) {\n onProgress({ loaded: e.loaded, total: e.total });\n }\n });\n\n xhr.addEventListener('load', () => {\n try {\n const contentType = xhr.getResponseHeader('content-type') ?? '';\n if (!contentType.includes('application/json')) {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve({ success: true, data: xhr.responseText } as unknown as T);\n } else {\n reject(new SpacelrNetworkError(`HTTP ${xhr.status}: ${xhr.responseText.slice(0, 200)}`));\n }\n return;\n }\n const body = JSON.parse(xhr.responseText);\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve(this.extractData<T>(body));\n } else {\n this.throwHttpError(xhr.status, body);\n }\n } catch (error) {\n if (error instanceof SpacelrError) {\n reject(error);\n } else {\n reject(new SpacelrNetworkError('Failed to parse response'));\n }\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new SpacelrNetworkError('Network request failed'));\n });\n\n xhr.addEventListener('timeout', () => {\n xhr.abort();\n reject(new SpacelrTimeoutError(timeoutMs));\n });\n\n xhr.send(formData);\n });\n }\n\n private buildUrl(\n path: string,\n query?: Record<string, string | number | undefined>\n ): string {\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n // .well-known endpoints are served at the origin without the API prefix\n const base = cleanPath.startsWith('/.well-known')\n ? new URL(this.config.apiUrl).origin\n : this.config.apiUrl.replace(/\\/+$/, '');\n const url = new URL(`${base}${cleanPath}`);\n\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private async buildHeaders(\n options: HttpRequestOptions\n ): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-client-id': this.config.clientId,\n 'x-project-id': this.config.projectId,\n ...options.headers,\n };\n\n if (options.authenticated) {\n const token = await this.tokenManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n }\n\n return headers;\n }\n\n private async buildFormHeaders(): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n 'x-client-id': this.config.clientId,\n 'x-project-id': this.config.projectId,\n };\n\n const token = await this.tokenManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n return headers;\n }\n\n private async parseResponse(\n response: Response\n ): Promise<ApiResponse | Record<string, unknown>> {\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n return response.json();\n }\n const text = await response.text();\n return { success: response.ok, data: text };\n }\n\n private throwHttpError(\n statusCode: number,\n body: ApiResponse | Record<string, unknown>\n ): never {\n const apiBody = body as ApiResponse;\n const message =\n apiBody.error?.message ?? `HTTP ${statusCode}`;\n const code = apiBody.error?.code ?? `HTTP_${statusCode}`;\n const details = apiBody.error?.details;\n\n if (statusCode === 401 || statusCode === 403) {\n throw new SpacelrAuthError(message, statusCode, details);\n }\n\n throw new SpacelrError(message, code, statusCode, details);\n }\n\n private extractData<T>(body: ApiResponse | Record<string, unknown>): T {\n const apiBody = body as ApiResponse;\n // If the response wraps data in a standard envelope, extract it\n if ('success' in apiBody && apiBody.data !== undefined) {\n const data = apiBody.data as Record<string, unknown>;\n // Check if the response indicates email verification is required\n if (data['emailVerificationRequired'] === true) {\n throw new SpacelrEmailVerificationRequiredError(data['emailSent'] === true);\n }\n // Check if the response indicates a 2FA challenge\n if (data['twoFactorRequired'] === true && typeof data['twoFactorToken'] === 'string') {\n throw new SpacelrTwoFactorRequiredError(data['twoFactorToken']);\n }\n return apiBody.data as T;\n }\n // Check unwrapped responses\n const rawBody = body as Record<string, unknown>;\n if (rawBody['emailVerificationRequired'] === true) {\n throw new SpacelrEmailVerificationRequiredError(rawBody['emailSent'] === true);\n }\n if (rawBody['twoFactorRequired'] === true && typeof rawBody['twoFactorToken'] === 'string') {\n throw new SpacelrTwoFactorRequiredError(rawBody['twoFactorToken']);\n }\n // Otherwise return the whole body (e.g. OIDC endpoints return raw objects)\n return body as T;\n }\n}\n","import { StoredTokens, TokenStorage } from '../types';\n\nexport type { TokenStorage };\n\nexport class MemoryTokenStorage implements TokenStorage {\n private tokens: StoredTokens | null = null;\n\n async getTokens(): Promise<StoredTokens | null> {\n return this.tokens;\n }\n\n async setTokens(tokens: StoredTokens): Promise<void> {\n this.tokens = tokens;\n }\n\n async clearTokens(): Promise<void> {\n this.tokens = null;\n }\n}\n\nexport class BrowserTokenStorage implements TokenStorage {\n private readonly storageKey: string;\n\n constructor(storageKey = 'spacelr_tokens') {\n this.storageKey = storageKey;\n }\n\n async getTokens(): Promise<StoredTokens | null> {\n try {\n const raw = localStorage.getItem(this.storageKey);\n if (!raw) return null;\n return JSON.parse(raw) as StoredTokens;\n } catch {\n return null;\n }\n }\n\n async setTokens(tokens: StoredTokens): Promise<void> {\n try {\n localStorage.setItem(this.storageKey, JSON.stringify(tokens));\n } catch {\n // Quota exceeded or private browsing — silently ignore\n }\n }\n\n async clearTokens(): Promise<void> {\n try {\n localStorage.removeItem(this.storageKey);\n } catch {\n // localStorage unavailable — silently ignore\n }\n }\n}\n","import { StoredTokens, TokenStorage } from '../types';\nimport { MemoryTokenStorage } from './token-storage';\n\nexport type RefreshCallback = (refreshToken: string) => Promise<StoredTokens>;\n\nexport class TokenManager {\n private storage: TokenStorage;\n private refreshBufferSeconds: number;\n private refreshCallback: RefreshCallback | null = null;\n private refreshPromise: Promise<StoredTokens> | null = null;\n\n constructor(storage?: TokenStorage, refreshBufferSeconds = 60) {\n this.storage = storage ?? new MemoryTokenStorage();\n this.refreshBufferSeconds = refreshBufferSeconds;\n }\n\n setRefreshCallback(callback: RefreshCallback): void {\n this.refreshCallback = callback;\n }\n\n async getAccessToken(): Promise<string | null> {\n const tokens = await this.storage.getTokens();\n if (!tokens) return null;\n\n if (this.isTokenExpired(tokens)) {\n const refreshed = await this.tryRefresh(tokens);\n return refreshed?.accessToken ?? null;\n }\n\n if (this.shouldRefresh(tokens)) {\n // Trigger background refresh but return current token\n this.tryRefresh(tokens).catch(() => {\n // Ignore background refresh failures\n });\n }\n\n return tokens.accessToken;\n }\n\n async setTokens(tokens: StoredTokens): Promise<void> {\n await this.storage.setTokens(tokens);\n }\n\n async clearTokens(): Promise<void> {\n await this.storage.clearTokens();\n this.refreshPromise = null;\n }\n\n async getStoredTokens(): Promise<StoredTokens | null> {\n return this.storage.getTokens();\n }\n\n private isTokenExpired(tokens: StoredTokens): boolean {\n if (!tokens.expiresAt) return false;\n return Date.now() >= tokens.expiresAt * 1000;\n }\n\n private shouldRefresh(tokens: StoredTokens): boolean {\n if (!tokens.expiresAt || !tokens.refreshToken) return false;\n const bufferMs = this.refreshBufferSeconds * 1000;\n return Date.now() >= tokens.expiresAt * 1000 - bufferMs;\n }\n\n private async tryRefresh(\n tokens: StoredTokens\n ): Promise<StoredTokens | null> {\n if (!tokens.refreshToken || !this.refreshCallback) return null;\n\n // Deduplicate concurrent refresh calls\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.executeRefresh(tokens.refreshToken);\n\n try {\n const result = await this.refreshPromise;\n return result;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n private async executeRefresh(refreshToken: string): Promise<StoredTokens> {\n const callback = this.refreshCallback as RefreshCallback;\n const newTokens = await callback(refreshToken);\n await this.storage.setTokens(newTokens);\n return newTokens;\n }\n}\n","export enum FileVisibility {\n PRIVATE = 'private',\n SHARED = 'shared',\n PUBLIC = 'public',\n}\n\nexport enum GrantType {\n AUTHORIZATION_CODE = 'authorization_code',\n CLIENT_CREDENTIALS = 'client_credentials',\n REFRESH_TOKEN = 'refresh_token',\n}\n\nexport enum CodeChallengeMethod {\n PLAIN = 'plain',\n S256 = 'S256',\n}\n\nexport enum SharePermission {\n READ = 'read',\n WRITE = 'write',\n}\n\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: {\n message: string;\n code: string;\n details?: Record<string, unknown>;\n };\n}\n","import { PKCEChallenge, CodeChallengeMethod } from '../types';\n\nfunction generateRandomBytes(length: number): Uint8Array {\n if (\n typeof globalThis.crypto !== 'undefined' &&\n globalThis.crypto.getRandomValues\n ) {\n const bytes = new Uint8Array(length);\n globalThis.crypto.getRandomValues(bytes);\n return bytes;\n }\n\n // Node.js fallback\n const nodeCrypto = require('crypto') as typeof import('crypto');\n return new Uint8Array(nodeCrypto.randomBytes(length));\n}\n\nfunction base64UrlEncode(buffer: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < buffer.length; i++) {\n binary += String.fromCharCode(buffer[i]);\n }\n\n const base64 = btoa(binary);\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nasync function sha256(input: string): Promise<Uint8Array> {\n if (\n typeof globalThis.crypto !== 'undefined' &&\n globalThis.crypto.subtle\n ) {\n const encoder = new TextEncoder();\n const data = encoder.encode(input);\n const hash = await globalThis.crypto.subtle.digest('SHA-256', data);\n return new Uint8Array(hash);\n }\n\n // Node.js fallback\n const nodeCrypto = require('crypto') as typeof import('crypto');\n const hash = nodeCrypto.createHash('sha256').update(input).digest();\n return new Uint8Array(hash);\n}\n\nexport async function generatePKCEChallenge(): Promise<PKCEChallenge> {\n const randomBytes = generateRandomBytes(32);\n const codeVerifier = base64UrlEncode(randomBytes);\n\n const hashBytes = await sha256(codeVerifier);\n const codeChallenge = base64UrlEncode(hashBytes);\n\n return {\n codeVerifier,\n codeChallenge,\n codeChallengeMethod: CodeChallengeMethod.S256,\n };\n}\n","import { io, Socket } from 'socket.io-client';\n\n// NOTE: This interface is duplicated in @spacelr-workspace/shared-types (database-events.ts).\n// The SDK cannot import from shared-types since it ships as a standalone npm package.\n// Keep both definitions in sync when making changes.\nexport interface DatabaseChangeEvent {\n type: 'insert' | 'update' | 'delete';\n projectId: string;\n collectionName: string;\n documentId: string;\n document?: Record<string, unknown>;\n timestamp: number;\n}\n\nexport interface RealtimeConfig {\n baseUrl: string;\n getToken: () => Promise<string | null>;\n}\n\nexport class RealtimeClient {\n private socket: Socket | null = null;\n private config: RealtimeConfig;\n private subscriptions = new Map<string, Set<(event: DatabaseChangeEvent) => void>>();\n private connecting: Promise<void> | null = null;\n // Store original where objects per room for reconnect resubscription\n private roomWhereMap = new Map<string, Record<string, string | number | boolean>>();\n\n constructor(config: RealtimeConfig) {\n this.config = config;\n }\n\n async subscribe(\n projectId: string,\n collectionName: string,\n callback: (event: DatabaseChangeEvent) => void,\n onError?: (error: Error) => void,\n where?: Record<string, string | number | boolean>,\n ): Promise<() => void> {\n await this.ensureConnected();\n\n const room = this.buildRoomKey(projectId, collectionName, where);\n\n // Track the callback\n if (!this.subscriptions.has(room)) {\n this.subscriptions.set(room, new Set());\n }\n const callbacks = this.subscriptions.get(room);\n callbacks?.add(callback);\n\n // If this is the first subscription for this room, tell the server\n if (callbacks?.size === 1) {\n if (where && Object.keys(where).length > 0) {\n this.roomWhereMap.set(room, where);\n }\n const payload: Record<string, unknown> = { projectId, collectionName };\n if (where && Object.keys(where).length > 0) {\n payload['where'] = where;\n }\n this.socket?.emit(\n 'subscribe',\n payload,\n (response: { subscribed?: string; error?: string }) => {\n if (response.error && onError) {\n onError(new Error(response.error));\n }\n },\n );\n }\n\n // Return unsubscribe function\n return () => {\n const callbacks = this.subscriptions.get(room);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n this.subscriptions.delete(room);\n this.roomWhereMap.delete(room);\n const payload: Record<string, unknown> = { projectId, collectionName };\n if (where && Object.keys(where).length > 0) {\n payload['where'] = where;\n }\n this.socket?.emit('unsubscribe', payload);\n }\n }\n };\n }\n\n disconnect(): void {\n if (this.socket) {\n this.socket.disconnect();\n this.socket = null;\n }\n this.subscriptions.clear();\n this.roomWhereMap.clear();\n this.connecting = null;\n }\n\n private buildRoomKey(\n projectId: string,\n collectionName: string,\n where?: Record<string, string | number | boolean>,\n ): string {\n const base = `db:${projectId}:${collectionName}`;\n if (!where || Object.keys(where).length === 0) {\n return base;\n }\n const filterStr = Object.keys(where)\n .sort()\n .map((k) => `${k}=${String(where[k])}`)\n .join('&');\n return `${base}?${filterStr}`;\n }\n\n private async ensureConnected(): Promise<void> {\n if (this.socket?.connected) return;\n\n if (this.connecting) {\n return this.connecting;\n }\n\n this.connecting = this.connect();\n try {\n await this.connecting;\n } finally {\n this.connecting = null;\n }\n }\n\n private async connect(): Promise<void> {\n const token = await this.config.getToken();\n if (!token) {\n throw new Error('No authentication token available');\n }\n\n // Derive WebSocket URL from the API URL\n const wsUrl = this.config.baseUrl.replace(/\\/api\\/v\\d+\\/?$/, '');\n\n return new Promise<void>((resolve, reject) => {\n let initialConnect = true;\n\n this.socket = io(`${wsUrl}/database`, {\n auth: async (cb: (data: Record<string, unknown>) => void) => {\n try {\n const freshToken = await this.config.getToken();\n cb({ token: freshToken });\n } catch {\n cb({ token: null });\n }\n },\n transports: ['websocket'],\n reconnection: false, // Disabled until first successful connect\n });\n\n this.socket.on('authenticated', () => {\n if (initialConnect) {\n initialConnect = false;\n // Enable reconnection after first successful connect\n if (this.socket) {\n this.socket.io.opts.reconnection = true;\n this.socket.io.opts.reconnectionDelay = 1000;\n this.socket.io.opts.reconnectionDelayMax = 5000;\n this.socket.io.opts.reconnectionAttempts = 50;\n }\n resolve();\n }\n });\n\n this.socket.on('connect', () => {\n if (!initialConnect) {\n // Reconnect — server will re-authenticate and emit 'authenticated',\n // but we can already re-subscribe since the socket carries the auth callback\n this.resubscribeAll();\n }\n });\n\n this.socket.on('connect_error', (err) => {\n if (initialConnect) {\n reject(new Error(`WebSocket connection failed: ${err.message}`));\n }\n });\n\n this.socket.on('db:event', (event: DatabaseChangeEvent) => {\n const base = `db:${event.projectId}:${event.collectionName}`;\n\n // Dispatch to whole-collection subscribers via direct Map lookup\n const baseCallbacks = this.subscriptions.get(base);\n if (baseCallbacks) {\n for (const cb of baseCallbacks) {\n try { cb(event); } catch { /* ignore callback errors */ }\n }\n }\n\n // Dispatch to matching filtered subscriptions\n for (const [room, callbacks] of this.subscriptions) {\n if (room.startsWith(`${base}?`) && this.eventMatchesRoom(event, room)) {\n for (const cb of callbacks) {\n try { cb(event); } catch { /* ignore callback errors */ }\n }\n }\n }\n });\n\n this.socket.on('disconnect', () => {\n // socket.io handles reconnection automatically\n });\n });\n }\n\n private eventMatchesRoom(event: DatabaseChangeEvent, room: string): boolean {\n const base = `db:${event.projectId}:${event.collectionName}`;\n if (room === base) return true;\n if (!room.startsWith(`${base}?`)) return false;\n\n // For filtered rooms, check the document against the where filter\n const where = this.roomWhereMap.get(room);\n if (!where) return true; // No filter stored for this room\n if (!event.document) return false; // Delete events without document can't match a filter\n\n for (const [key, value] of Object.entries(where)) {\n const docValue = event.document[key];\n if (Array.isArray(docValue)) {\n if (!docValue.some((item) => String(item) === String(value))) {\n return false;\n }\n } else if (String(docValue) !== String(value)) {\n return false;\n }\n }\n return true;\n }\n\n private resubscribeAll(): void {\n for (const [room] of this.subscriptions) {\n // Parse room format: db:{projectId}:{collectionName} or db:{projectId}:{collectionName}?filter\n const queryIdx = room.indexOf('?');\n const basePart = queryIdx >= 0 ? room.substring(0, queryIdx) : room;\n const parts = basePart.split(':');\n if (parts.length >= 3) {\n const projectId = parts[1];\n const collectionName = parts.slice(2).join(':');\n const payload: Record<string, unknown> = { projectId, collectionName };\n\n // Use stored where object to preserve original types (number, boolean)\n const where = this.roomWhereMap.get(room);\n if (where) {\n payload['where'] = where;\n }\n\n this.socket?.emit(\n 'subscribe',\n payload,\n (response: { subscribed?: string; error?: string }) => {\n if (response?.error) {\n // Server rejected resubscription — clean up the stale subscription\n this.subscriptions.delete(room);\n this.roomWhereMap.delete(room);\n }\n },\n );\n }\n }\n }\n}\n","import { HttpClient, TokenManager, generatePKCEChallenge } from '../core';\nimport {\n SpacelrClientConfig,\n GrantType,\n LoginParams,\n LoginResponse,\n RegisterParams,\n RegisterResponse,\n TokenResponse,\n UserInfo,\n UserProfile,\n AuthorizationUrlParams,\n ExchangeCodeParams,\n PKCEChallenge,\n OpenIDConfiguration,\n JWKSResponse,\n TwoFactorVerifyParams,\n} from '../types';\n\nexport class AuthModule {\n private http: HttpClient;\n private tokenManager: TokenManager;\n private config: SpacelrClientConfig;\n\n constructor(\n http: HttpClient,\n tokenManager: TokenManager,\n config: SpacelrClientConfig\n ) {\n this.http = http;\n this.tokenManager = tokenManager;\n this.config = config;\n\n // Wire up refresh callback to avoid circular deps\n this.tokenManager.setRefreshCallback(async (refreshToken: string) => {\n const result = await this.refresh(refreshToken);\n const expiresAt = result.expires_in\n ? Math.floor(Date.now() / 1000) + result.expires_in\n : undefined;\n return {\n accessToken: result.access_token,\n refreshToken: result.refresh_token,\n expiresAt,\n };\n });\n }\n\n async login(params: LoginParams): Promise<LoginResponse> {\n const response = await this.http.request<LoginResponse>({\n method: 'POST',\n path: '/auth/login',\n body: params,\n });\n\n await this.storeTokensFromLogin(response);\n return response;\n }\n\n async register(params: RegisterParams): Promise<RegisterResponse> {\n const response = await this.http.request<RegisterResponse>({\n method: 'POST',\n path: '/auth/register',\n body: params,\n });\n\n // Only store tokens if they were returned (not when email verification is required)\n if (response.access_token) {\n await this.storeTokensFromRegister(response);\n }\n return response;\n }\n\n async refresh(refreshToken: string): Promise<TokenResponse> {\n return this.http.request<TokenResponse>({\n method: 'POST',\n path: '/auth/refresh',\n body: { refreshToken },\n });\n }\n\n async getProfile(): Promise<UserProfile> {\n return this.http.request<UserProfile>({\n method: 'GET',\n path: '/auth/me',\n authenticated: true,\n });\n }\n\n async logout(): Promise<void> {\n await this.http.request<void>({\n method: 'POST',\n path: '/auth/logout',\n authenticated: true,\n });\n await this.tokenManager.clearTokens();\n }\n\n async verifyEmail(token: string): Promise<{ message: string }> {\n return this.http.request<{ message: string }>({\n method: 'GET',\n path: '/auth/verify-email',\n query: { token },\n });\n }\n\n async resendVerification(email: string): Promise<{ message: string }> {\n return this.http.request<{ message: string }>({\n method: 'POST',\n path: '/auth/resend-verification',\n body: { email },\n });\n }\n\n async getUserInfo(): Promise<UserInfo> {\n return this.http.request<UserInfo>({\n method: 'GET',\n path: this.config.userInfoEndpoint ?? '/auth/userinfo',\n authenticated: true,\n });\n }\n\n getAuthorizationUrl(params: AuthorizationUrlParams): string {\n const baseUrl = this.config.apiUrl.replace(/\\/+$/, '');\n const endpoint =\n this.config.authorizationEndpoint ?? '/auth/authorize';\n const url = new URL(`${baseUrl}${endpoint}`);\n\n url.searchParams.set('client_id', this.config.clientId);\n url.searchParams.set('redirect_uri', params.redirectUri);\n url.searchParams.set('response_type', params.responseType ?? 'code');\n\n const scope =\n params.scope ?? this.config.scopes?.join(' ') ?? 'openid';\n url.searchParams.set('scope', scope);\n\n if (params.state) {\n url.searchParams.set('state', params.state);\n }\n if (params.codeChallenge) {\n url.searchParams.set('code_challenge', params.codeChallenge);\n }\n if (params.codeChallengeMethod) {\n url.searchParams.set(\n 'code_challenge_method',\n params.codeChallengeMethod\n );\n }\n\n return url.toString();\n }\n\n async exchangeCode(params: ExchangeCodeParams): Promise<TokenResponse> {\n const body: Record<string, string> = {\n grant_type: params.grantType ?? GrantType.AUTHORIZATION_CODE,\n code: params.code,\n redirect_uri: params.redirectUri,\n client_id: this.config.clientId,\n };\n\n if (params.clientSecret) {\n body['client_secret'] = params.clientSecret;\n }\n if (params.codeVerifier) {\n body['code_verifier'] = params.codeVerifier;\n }\n\n const tokenEndpoint =\n this.config.tokenEndpoint ?? '/auth/token';\n\n const response = await this.http.request<TokenResponse>({\n method: 'POST',\n path: tokenEndpoint,\n body,\n });\n\n const expiresAt = response.expires_in\n ? Math.floor(Date.now() / 1000) + response.expires_in\n : undefined;\n\n await this.tokenManager.setTokens({\n accessToken: response.access_token,\n refreshToken: response.refresh_token,\n expiresAt,\n });\n\n return response;\n }\n\n async generatePKCE(): Promise<PKCEChallenge> {\n return generatePKCEChallenge();\n }\n\n async getOpenIDConfiguration(): Promise<OpenIDConfiguration> {\n return this.http.request<OpenIDConfiguration>({\n method: 'GET',\n path: '/.well-known/openid-configuration',\n });\n }\n\n async getJWKS(): Promise<JWKSResponse> {\n return this.http.request<JWKSResponse>({\n method: 'GET',\n path: '/.well-known/jwks.json',\n });\n }\n\n /**\n * Request a password reset email.\n * Always returns a generic message regardless of whether the email exists.\n */\n async requestPasswordReset(email: string): Promise<{ message: string }> {\n return this.http.request<{ message: string }>({\n method: 'POST',\n path: '/auth/request-password-reset',\n body: { email },\n });\n }\n\n /**\n * Reset password using a token received via email.\n */\n async resetPassword(\n token: string,\n password: string,\n ): Promise<{ message: string }> {\n return this.http.request<{ message: string }>({\n method: 'POST',\n path: '/auth/reset-password',\n body: { token, password },\n });\n }\n\n /**\n * Exchange a one-time verification code for tokens.\n * Use this after email verification redirects the user with a ?loginCode= parameter.\n */\n async exchangeVerificationCode(code: string): Promise<LoginResponse> {\n const response = await this.http.request<LoginResponse>({\n method: 'POST',\n path: '/auth/exchange-code',\n body: { code },\n });\n\n await this.storeTokensFromLogin(response);\n return response;\n }\n\n /**\n * Resend a two-factor authentication code email.\n * Call this when the user hasn't received the code or it expired.\n */\n async resendTwoFactorCode(token: string): Promise<{ message: string }> {\n return this.http.request<{ message: string }>({\n method: 'POST',\n path: '/auth/resend-two-factor-code',\n body: { token },\n });\n }\n\n /**\n * Verify a two-factor authentication code.\n * Call this after catching SpacelrTwoFactorRequiredError from login().\n */\n async verifyTwoFactor(params: TwoFactorVerifyParams): Promise<LoginResponse> {\n const response = await this.http.request<LoginResponse>({\n method: 'POST',\n path: '/auth/verify-two-factor',\n body: { token: params.token, code: params.code },\n });\n\n await this.storeTokensFromLogin(response);\n return response;\n }\n\n private async storeTokensFromLogin(response: LoginResponse): Promise<void> {\n const expiresAt = response.expires_in\n ? Math.floor(Date.now() / 1000) + response.expires_in\n : undefined;\n\n await this.tokenManager.setTokens({\n accessToken: response.access_token,\n refreshToken: response.refresh_token,\n expiresAt,\n });\n }\n\n private async storeTokensFromRegister(\n response: RegisterResponse\n ): Promise<void> {\n if (!response.access_token) return;\n await this.tokenManager.setTokens({\n accessToken: response.access_token,\n refreshToken: response.refresh_token,\n });\n }\n}\n","import { HttpClient, TokenManager } from '../core';\nimport {\n SpacelrClientConfig,\n FileVisibility,\n FileInfo,\n FileListResponse,\n ListFilesParams,\n InitMultipartUploadParams,\n InitMultipartUploadResponse,\n PartEtag,\n ShareFileParams,\n UnshareFileParams,\n QuotaInfo,\n UploadFileParams,\n UploadLargeFileParams,\n UploadProgress,\n DownloadUrlResponse,\n} from '../types';\n\nexport class StorageModule {\n private http: HttpClient;\n private tokenManager: TokenManager;\n private config: SpacelrClientConfig;\n\n constructor(\n http: HttpClient,\n tokenManager: TokenManager,\n config: SpacelrClientConfig\n ) {\n this.http = http;\n this.tokenManager = tokenManager;\n this.config = config;\n }\n\n /**\n * Upload a file through the gateway (no direct MinIO access).\n * Accepts a Blob/File (browser) or ArrayBuffer/Uint8Array (Node).\n */\n async uploadFile(\n file: Blob | ArrayBuffer | Uint8Array,\n params: UploadFileParams,\n onProgress?: (progress: UploadProgress) => void,\n ): Promise<FileInfo> {\n const formData = new FormData();\n const blob =\n file instanceof Blob\n ? file\n : new Blob([file as BlobPart], { type: params.mimeType });\n formData.append('file', blob, params.filename);\n if (params.visibility) formData.append('visibility', params.visibility);\n if (params.description) formData.append('description', params.description);\n\n const progressHandler = onProgress\n ? (e: { loaded: number; total: number }) => {\n onProgress({\n loaded: e.loaded,\n total: e.total,\n percentage: e.total > 0 ? Math.round((e.loaded / e.total) * 100) : 0,\n });\n }\n : undefined;\n\n return this.http.uploadForm<FileInfo>('/storage/files', formData, progressHandler);\n }\n\n /**\n * Upload a large file using multipart upload through the gateway.\n * Splits into parts, uploads concurrently, and completes.\n */\n async uploadLargeFile(\n file: Blob | ArrayBuffer | Uint8Array,\n params: UploadLargeFileParams,\n onProgress?: (progress: UploadProgress) => void\n ): Promise<FileInfo> {\n const fileSize = file instanceof Blob ? file.size : file.byteLength;\n const concurrency = params.concurrency ?? 3;\n\n const init = await this.initMultipartUpload({\n filename: params.filename,\n mimeType: params.mimeType,\n totalSizeBytes: fileSize,\n visibility: params.visibility,\n description: params.description,\n });\n\n const { partSize, totalParts, fileId } = init;\n const completedParts: PartEtag[] = [];\n let completedBytes = 0;\n const partProgressMap = new Map<number, number>();\n\n try {\n const allPartNumbers = Array.from(\n { length: totalParts },\n (_, i) => i + 1\n );\n\n for (let i = 0; i < allPartNumbers.length; i += concurrency) {\n const batch = allPartNumbers.slice(i, i + concurrency);\n\n const uploads = batch.map(async (partNumber) => {\n const start = (partNumber - 1) * partSize;\n const end = Math.min(start + partSize, fileSize);\n const chunkSize = end - start;\n const chunk =\n file instanceof Blob\n ? file.slice(start, end)\n : new Blob([file.slice(start, end)]);\n\n const formData = new FormData();\n formData.append('file', chunk, `part-${partNumber}`);\n formData.append('partNumber', String(partNumber));\n\n const partProgress = onProgress && typeof XMLHttpRequest !== 'undefined'\n ? (e: { loaded: number; total: number }) => {\n const ratio = e.total > 0 ? e.loaded / e.total : 0;\n partProgressMap.set(partNumber, Math.min(ratio * chunkSize, chunkSize));\n const inFlightBytes = Array.from(partProgressMap.values())\n .reduce((sum, v) => sum + v, 0);\n const totalLoaded = Math.min(completedBytes + inFlightBytes, fileSize);\n onProgress({\n loaded: totalLoaded,\n total: fileSize,\n percentage: fileSize > 0\n ? Math.min(100, Math.round((totalLoaded / fileSize) * 100))\n : 0,\n });\n }\n : undefined;\n\n const result = await this.http.uploadForm<{ etag: string }>(\n `/storage/files/${fileId}/multipart/upload-part`,\n formData,\n partProgress,\n );\n\n partProgressMap.delete(partNumber);\n completedBytes += chunkSize;\n\n if (onProgress) {\n onProgress({\n loaded: Math.min(completedBytes, fileSize),\n total: fileSize,\n percentage: fileSize > 0\n ? Math.min(100, Math.round((completedBytes / fileSize) * 100))\n : 0,\n });\n }\n\n completedParts.push({\n partNumber,\n etag: result.etag,\n });\n });\n\n await Promise.all(uploads);\n partProgressMap.clear();\n }\n\n // Sort parts by number before completing\n completedParts.sort((a, b) => a.partNumber - b.partNumber);\n\n await this.completeMultipartUpload(fileId, completedParts);\n return this.getFileInfo(fileId);\n } catch (error) {\n // Clean up the incomplete multipart upload on failure\n try {\n await this.abortMultipartUpload(fileId);\n } catch {\n // Abort is best-effort; ignore cleanup failures\n }\n throw error;\n }\n }\n\n async initMultipartUpload(\n params: InitMultipartUploadParams\n ): Promise<InitMultipartUploadResponse> {\n return this.http.request<InitMultipartUploadResponse>({\n method: 'POST',\n path: '/storage/files/multipart/init',\n body: params,\n authenticated: true,\n });\n }\n\n async completeMultipartUpload(\n fileId: string,\n parts: PartEtag[]\n ): Promise<FileInfo> {\n return this.http.request<FileInfo>({\n method: 'POST',\n path: `/storage/files/${fileId}/multipart/complete`,\n body: { parts },\n authenticated: true,\n });\n }\n\n async abortMultipartUpload(fileId: string): Promise<void> {\n await this.http.request<void>({\n method: 'POST',\n path: `/storage/files/${fileId}/multipart/abort`,\n authenticated: true,\n });\n }\n\n async listFiles(params?: ListFilesParams): Promise<FileListResponse> {\n return this.http.request<FileListResponse>({\n method: 'GET',\n path: '/storage/files',\n query: params as Record<string, string | number | undefined>,\n authenticated: true,\n });\n }\n\n async listSharedFiles(params?: ListFilesParams): Promise<FileListResponse> {\n return this.http.request<FileListResponse>({\n method: 'GET',\n path: '/storage/shared',\n query: params as Record<string, string | number | undefined>,\n authenticated: true,\n });\n }\n\n async getFileInfo(fileId: string): Promise<FileInfo> {\n return this.http.request<FileInfo>({\n method: 'GET',\n path: `/storage/files/${fileId}`,\n authenticated: true,\n });\n }\n\n async downloadFile(fileId: string): Promise<Blob> {\n const baseUrl = this.config.apiUrl.replace(/\\/+$/, '');\n const url = `${baseUrl}/storage/files/${fileId}/download`;\n\n const headers: Record<string, string> = {\n 'x-client-id': this.config.clientId,\n 'x-project-id': this.config.projectId,\n };\n\n const token = await this.tokenManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const response = await fetch(url, { headers });\n\n if (!response.ok) {\n throw new Error(`Download failed: ${response.status}`);\n }\n\n return response.blob();\n }\n\n async getDownloadUrl(fileId: string): Promise<DownloadUrlResponse> {\n return this.http.request<DownloadUrlResponse>({\n method: 'GET',\n path: `/storage/files/${fileId}/download-url`,\n authenticated: true,\n });\n }\n\n async deleteFile(fileId: string): Promise<void> {\n await this.http.request<void>({\n method: 'DELETE',\n path: `/storage/files/${fileId}`,\n authenticated: true,\n });\n }\n\n async shareFile(\n fileId: string,\n params: ShareFileParams\n ): Promise<void> {\n await this.http.request<void>({\n method: 'POST',\n path: `/storage/files/${fileId}/share`,\n body: params,\n authenticated: true,\n });\n }\n\n async unshareFile(\n fileId: string,\n params: UnshareFileParams\n ): Promise<void> {\n await this.http.request<void>({\n method: 'POST',\n path: `/storage/files/${fileId}/unshare`,\n body: params,\n authenticated: true,\n });\n }\n\n async updateVisibility(\n fileId: string,\n visibility: FileVisibility\n ): Promise<FileInfo> {\n return this.http.request<FileInfo>({\n method: 'PATCH',\n path: `/storage/files/${fileId}/visibility`,\n body: { visibility },\n authenticated: true,\n });\n }\n\n async getQuota(): Promise<QuotaInfo> {\n return this.http.request<QuotaInfo>({\n method: 'GET',\n path: '/storage/quota',\n authenticated: true,\n });\n }\n\n async getPublicFileUrl(fileId: string, projectId?: string): Promise<string> {\n const baseUrl = this.config.apiUrl.replace(/\\/+$/, '');\n const resolvedProjectId = projectId ?? this.config.projectId;\n return `${baseUrl}/public/files/${resolvedProjectId}/${fileId}`;\n }\n}\n","import { HttpClient } from '../core';\nimport { RealtimeClient, DatabaseChangeEvent } from '../core';\n\nexport interface PopulateOption {\n field: string;\n collection: string;\n foreignField?: string;\n}\n\nexport interface DocumentResult {\n _id: string;\n [key: string]: unknown;\n}\n\nexport interface FindResult<T = Record<string, unknown>> {\n documents: (T & { _id: string })[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface InsertResult {\n insertedCount: number;\n insertedIds: string[];\n}\n\nexport interface UpdateResult {\n matchedCount: number;\n modifiedCount: number;\n}\n\nexport interface DeleteResult {\n deletedCount: number;\n}\n\nexport interface CountResult {\n count: number;\n}\n\nexport interface FindByIdOptions {\n populate?: PopulateOption[];\n}\n\nexport interface SubscribeHandlers<T = Record<string, unknown>> {\n where?: Record<string, string | number | boolean>;\n onInsert?: (doc: T & { _id: string }) => void;\n onUpdate?: (doc: T & { _id: string }) => void;\n onDelete?: (documentId: string) => void;\n onError?: (error: Error) => void;\n}\n\nclass QueryBuilder<T = Record<string, unknown>> {\n private _filter?: Record<string, unknown>;\n private _sort?: Record<string, 1 | -1>;\n private _limit?: number;\n private _offset?: number;\n private _fields?: string[];\n private _populate: PopulateOption[] = [];\n\n constructor(\n private http: HttpClient,\n private basePath: string,\n filter?: Record<string, unknown>,\n ) {\n this._filter = filter;\n }\n\n sort(sort: Record<string, 1 | -1>): QueryBuilder<T> {\n this._sort = sort;\n return this;\n }\n\n limit(limit: number): QueryBuilder<T> {\n this._limit = limit;\n return this;\n }\n\n offset(offset: number): QueryBuilder<T> {\n this._offset = offset;\n return this;\n }\n\n select(fields: string[]): QueryBuilder<T> {\n this._fields = fields;\n return this;\n }\n\n populate(\n field: string,\n collection: string,\n foreignField?: string,\n ): QueryBuilder<T> {\n this._populate.push({ field, collection, foreignField });\n return this;\n }\n\n async execute(): Promise<FindResult<T>> {\n const query: Record<string, string | number | undefined> = {};\n if (this._filter) query['filter'] = JSON.stringify(this._filter);\n if (this._sort) query['sort'] = JSON.stringify(this._sort);\n if (this._limit !== undefined) query['limit'] = this._limit;\n if (this._offset !== undefined) query['offset'] = this._offset;\n if (this._fields) query['fields'] = this._fields.join(',');\n if (this._populate.length) {\n query['populate'] = this._populate\n .map((p) =>\n p.foreignField\n ? `${p.field}:${p.collection}:${p.foreignField}`\n : `${p.field}:${p.collection}`,\n )\n .join(',');\n }\n\n return this.http.request<FindResult<T>>({\n method: 'GET',\n path: this.basePath,\n query,\n authenticated: true,\n });\n }\n}\n\nclass CollectionRef<T = Record<string, unknown>> {\n private basePath: string;\n private collectionName: string;\n\n constructor(\n private http: HttpClient,\n private realtime: RealtimeClient | null,\n private projectId: string,\n collectionName: string,\n ) {\n this.collectionName = collectionName;\n this.basePath = `/db/${collectionName}`;\n }\n\n async insert(\n document: Partial<T> & { _id?: string },\n ): Promise<InsertResult> {\n return this.http.request<InsertResult>({\n method: 'POST',\n path: this.basePath,\n body: { documents: [document] },\n authenticated: true,\n });\n }\n\n async insertMany(\n documents: (Partial<T> & { _id?: string })[],\n ): Promise<InsertResult> {\n return this.http.request<InsertResult>({\n method: 'POST',\n path: this.basePath,\n body: { documents },\n authenticated: true,\n });\n }\n\n find(filter?: Record<string, unknown>): QueryBuilder<T> {\n return new QueryBuilder<T>(this.http, this.basePath, filter);\n }\n\n async findById(\n id: string,\n options?: FindByIdOptions,\n ): Promise<T & { _id: string }> {\n const query: Record<string, string> = {};\n if (options?.populate?.length) {\n query['populate'] = options.populate\n .map((p) =>\n p.foreignField\n ? `${p.field}:${p.collection}:${p.foreignField}`\n : `${p.field}:${p.collection}`,\n )\n .join(',');\n }\n\n return this.http.request<T & { _id: string }>({\n method: 'GET',\n path: `${this.basePath}/${id}`,\n query,\n authenticated: true,\n });\n }\n\n async update(id: string, update: Partial<T>): Promise<UpdateResult> {\n return this.http.request<UpdateResult>({\n method: 'PATCH',\n path: `${this.basePath}/${id}`,\n body: { update },\n authenticated: true,\n });\n }\n\n async delete(id: string): Promise<DeleteResult> {\n return this.http.request<DeleteResult>({\n method: 'DELETE',\n path: `${this.basePath}/${id}`,\n authenticated: true,\n });\n }\n\n async count(filter?: Record<string, unknown>): Promise<number> {\n const result = await this.http.request<CountResult>({\n method: 'POST',\n path: `${this.basePath}/count`,\n body: { filter },\n authenticated: true,\n });\n return result.count;\n }\n\n subscribe(handlers: SubscribeHandlers<T>): () => void {\n if (!this.realtime) {\n throw new Error('Realtime not available: no RealtimeClient configured');\n }\n\n let unsubscribeFn: (() => void) | null = null;\n let pendingUnsub = false;\n\n const callback = (event: DatabaseChangeEvent) => {\n switch (event.type) {\n case 'insert':\n if (handlers.onInsert && event.document) {\n handlers.onInsert(event.document as T & { _id: string });\n }\n break;\n case 'update':\n if (handlers.onUpdate && event.document) {\n handlers.onUpdate(event.document as T & { _id: string });\n }\n break;\n case 'delete':\n if (handlers.onDelete) {\n handlers.onDelete(event.documentId);\n }\n break;\n }\n };\n\n this.realtime\n .subscribe(this.projectId, this.collectionName, callback, handlers.onError, handlers.where)\n .then((unsub) => {\n if (pendingUnsub) {\n // Unsubscribe was called before async subscribe resolved\n unsub();\n } else {\n unsubscribeFn = unsub;\n }\n })\n .catch((err) => {\n if (handlers.onError) {\n handlers.onError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // Return synchronous unsubscribe\n return () => {\n if (unsubscribeFn) {\n unsubscribeFn();\n } else {\n pendingUnsub = true;\n }\n };\n }\n}\n\nexport class DatabaseModule {\n private http: HttpClient;\n private realtime: RealtimeClient | null;\n private projectId: string;\n\n constructor(http: HttpClient, projectId: string, realtime?: RealtimeClient) {\n this.http = http;\n this.projectId = projectId;\n this.realtime = realtime ?? null;\n }\n\n collection<T = Record<string, unknown>>(name: string): CollectionRef<T> {\n return new CollectionRef<T>(this.http, this.realtime, this.projectId, name);\n }\n}\n","import { HttpClient } from '../core';\n\nexport interface PushSubscriptionInfo {\n id: string;\n platform: 'web' | 'android' | 'ios';\n endpoint?: string;\n deviceToken?: string;\n deviceId?: string;\n deviceName?: string;\n userAgent?: string;\n isActive: boolean;\n lastUsedAt?: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface VapidKeyResponse {\n publicKey: string;\n}\n\nconst DEVICE_ID_KEY = 'spacelr_device_id';\n\nexport class NotificationsModule {\n private customDeviceId: string | null = null;\n private customDeviceName: string | null = null;\n\n constructor(private http: HttpClient) {}\n\n /** Set a custom device ID (e.g. from Capacitor Preferences for persistence beyond localStorage) */\n setDeviceId(id: string): void {\n this.customDeviceId = id;\n }\n\n /** Set a custom device name (e.g. \"iOS App\", \"macOS - Chrome\") */\n setDeviceName(name: string): void {\n this.customDeviceName = name;\n }\n\n /** Get or generate a stable device identifier. Custom ID takes priority over localStorage. */\n private getDeviceId(): string | undefined {\n if (this.customDeviceId) return this.customDeviceId;\n if (typeof localStorage === 'undefined') return undefined;\n let id = localStorage.getItem(DEVICE_ID_KEY);\n if (!id) {\n id = crypto.randomUUID();\n localStorage.setItem(DEVICE_ID_KEY, id);\n }\n return id;\n }\n\n /** Get device name: custom name > auto-detected from user agent > undefined */\n private getDeviceName(): string | undefined {\n if (this.customDeviceName) return this.customDeviceName;\n return this.detectDeviceName();\n }\n\n /** Auto-detect a short device label from navigator.userAgent (e.g. \"macOS - Chrome\") */\n private detectDeviceName(): string | undefined {\n if (typeof navigator === 'undefined' || !navigator.userAgent) return undefined;\n const ua = navigator.userAgent;\n\n let os = 'Unknown';\n if (/iPad|iPhone|iPod/.test(ua)) os = 'iOS';\n else if (/Android/.test(ua)) os = 'Android';\n else if (/Mac OS X/.test(ua)) os = 'macOS';\n else if (/Windows/.test(ua)) os = 'Windows';\n else if (/Linux/.test(ua)) os = 'Linux';\n\n let browser = 'Unknown';\n if (/Edg\\//.test(ua)) browser = 'Edge';\n else if (/OPR\\/|Opera/.test(ua)) browser = 'Opera';\n else if (/Chrome\\//.test(ua)) browser = 'Chrome';\n else if (/Safari\\//.test(ua) && !/Chrome/.test(ua)) browser = 'Safari';\n else if (/Firefox\\//.test(ua)) browser = 'Firefox';\n\n return `${os} - ${browser}`;\n }\n\n /** Get the VAPID public key for Web Push setup */\n async getVapidPublicKey(): Promise<VapidKeyResponse> {\n return this.http.request<VapidKeyResponse>({\n method: 'GET',\n path: '/notifications/vapid-key',\n authenticated: true,\n });\n }\n\n /** Register a push subscription (web, android, or ios) */\n async subscribe(\n subscription: {\n platform: 'web' | 'android' | 'ios';\n endpoint?: string;\n keys?: { p256dh: string; auth: string };\n deviceToken?: string;\n },\n deviceName?: string,\n ): Promise<PushSubscriptionInfo> {\n return this.http.request<PushSubscriptionInfo>({\n method: 'POST',\n path: '/notifications/subscribe',\n body: {\n ...subscription,\n deviceName: deviceName ?? this.getDeviceName(),\n deviceId: this.getDeviceId(),\n },\n authenticated: true,\n });\n }\n\n /** Unregister a push subscription */\n async unsubscribe(\n platform: 'web' | 'android' | 'ios',\n identifier: string,\n ): Promise<{ deleted: boolean }> {\n const body: Record<string, string> = { platform };\n if (platform === 'web') {\n body['endpoint'] = identifier;\n } else {\n body['deviceToken'] = identifier;\n }\n\n return this.http.request<{ deleted: boolean }>({\n method: 'DELETE',\n path: '/notifications/subscribe',\n body,\n authenticated: true,\n });\n }\n\n /** Get all subscriptions for the current user */\n async getSubscriptions(): Promise<PushSubscriptionInfo[]> {\n return this.http.request<PushSubscriptionInfo[]>({\n method: 'GET',\n path: '/notifications/subscriptions',\n authenticated: true,\n });\n }\n\n /**\n * Helper: Register browser Web Push subscription.\n * Requests notification permission, subscribes via Push API,\n * and registers the subscription with the server.\n */\n async registerBrowserPush(\n serviceWorkerRegistration: ServiceWorkerRegistration,\n deviceName?: string,\n ): Promise<PushSubscriptionInfo> {\n // Get VAPID key\n const { publicKey } = await this.getVapidPublicKey();\n\n if (!publicKey) {\n throw new Error(\n 'VAPID public key not configured on the server',\n );\n }\n\n // Request notification permission\n const permission = await Notification.requestPermission();\n if (permission !== 'granted') {\n throw new Error(\n `Notification permission denied: ${permission}`,\n );\n }\n\n // Convert VAPID key to Uint8Array\n const applicationServerKey = this.urlBase64ToUint8Array(publicKey);\n\n // Subscribe via Push API\n const pushSubscription =\n await serviceWorkerRegistration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey,\n });\n\n const subJson = pushSubscription.toJSON();\n const p256dh = subJson.keys?.['p256dh'];\n const auth = subJson.keys?.['auth'];\n\n if (!subJson.endpoint || !p256dh || !auth) {\n throw new Error('Invalid push subscription: missing endpoint or keys');\n }\n\n // Register with server\n return this.subscribe(\n {\n platform: 'web',\n endpoint: subJson.endpoint,\n keys: { p256dh, auth },\n },\n deviceName,\n );\n }\n\n /**\n * Helper: Register a mobile device push token (FCM or APNs).\n */\n async registerDevicePush(\n deviceToken: string,\n platform: 'android' | 'ios',\n deviceName?: string,\n ): Promise<PushSubscriptionInfo> {\n return this.subscribe(\n {\n platform,\n deviceToken,\n },\n deviceName,\n );\n }\n\n private urlBase64ToUint8Array(base64String: string): ArrayBuffer {\n const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding)\n .replace(/-/g, '+')\n .replace(/_/g, '/');\n\n const rawData = atob(base64);\n const outputArray = new Uint8Array(rawData.length);\n\n for (let i = 0; i < rawData.length; ++i) {\n outputArray[i] = rawData.charCodeAt(i);\n }\n return outputArray.buffer as ArrayBuffer;\n }\n}\n","import { SpacelrClientConfig } from './types';\nimport { HttpClient, TokenManager, MemoryTokenStorage, BrowserTokenStorage, RealtimeClient } from './core';\nimport { AuthModule, StorageModule, DatabaseModule, NotificationsModule } from './modules';\n\nexport interface SpacelrClient {\n readonly auth: AuthModule;\n readonly storage: StorageModule;\n readonly db: DatabaseModule;\n readonly notifications: NotificationsModule;\n /** Disconnect realtime WebSocket (if connected) */\n disconnect(): void;\n}\n\nexport function createClient(config: SpacelrClientConfig): SpacelrClient {\n const tokenStorage = config.tokenStorage\n ?? (typeof window !== 'undefined' && typeof window.localStorage !== 'undefined'\n ? new BrowserTokenStorage()\n : new MemoryTokenStorage());\n const tokenManager = new TokenManager(\n tokenStorage,\n config.refreshBufferSeconds ?? 60\n );\n const httpClient = new HttpClient(config, tokenManager);\n\n const realtime = new RealtimeClient({\n baseUrl: config.apiUrl,\n getToken: () => tokenManager.getAccessToken(),\n });\n\n const auth = new AuthModule(httpClient, tokenManager, config);\n const storage = new StorageModule(httpClient, tokenManager, config);\n const db = new DatabaseModule(httpClient, config.projectId, realtime);\n const notifications = new NotificationsModule(httpClient);\n\n return {\n auth,\n storage,\n db,\n notifications,\n disconnect() {\n realtime.disconnect();\n },\n };\n}\n"],"mappings":"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","names":["FileVisibility","GrantType","CodeChallengeMethod","SharePermission","hash","callbacks"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spacelr/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript SDK for the Spacelr API - auth and storage",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"keywords": [
|
|
20
|
+
"spacelr",
|
|
21
|
+
"sdk",
|
|
22
|
+
"oauth2",
|
|
23
|
+
"storage",
|
|
24
|
+
"api-client"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18.0.0"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/Scan0815/spacelr-workspace",
|
|
35
|
+
"directory": "libs/sdk"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"socket.io-client": "^4.8.3"
|
|
39
|
+
}
|
|
40
|
+
}
|