@codixus/client 0.1.5 → 0.1.7

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.cjs CHANGED
@@ -47,6 +47,7 @@ var AuthManager = class {
47
47
  this.deviceIdProvider = options?.deviceIdProvider ?? null;
48
48
  this.autoSignInConfig = options?.autoSignIn ?? null;
49
49
  }
50
+ storage;
50
51
  accessToken = null;
51
52
  refreshTokenValue = null;
52
53
  user = null;
@@ -309,6 +310,7 @@ var ApiClient = class {
309
310
  }
310
311
  );
311
312
  }
313
+ authManager;
312
314
  instance;
313
315
  refreshPromise = null;
314
316
  appSecret;
@@ -335,6 +337,8 @@ var Collection = class {
335
337
  this.api = api;
336
338
  this.basePath = basePath;
337
339
  }
340
+ api;
341
+ basePath;
338
342
  async find(filter, options) {
339
343
  const params = new URLSearchParams();
340
344
  if (filter && Object.keys(filter).length > 0) {
@@ -399,11 +403,90 @@ var Collection = class {
399
403
  }
400
404
  };
401
405
 
406
+ // src/push/push-manager.ts
407
+ function extractDeliveryId(payload) {
408
+ if (typeof payload.deliveryId === "string" && payload.deliveryId) {
409
+ return payload.deliveryId;
410
+ }
411
+ const data = payload.data;
412
+ if (data && typeof data === "object" && !Array.isArray(data)) {
413
+ const nested = data.deliveryId;
414
+ if (typeof nested === "string" && nested) {
415
+ return nested;
416
+ }
417
+ }
418
+ return void 0;
419
+ }
420
+ var PushManager = class {
421
+ constructor(adapter, api, auth) {
422
+ this.adapter = adapter;
423
+ this.api = api;
424
+ this.auth = auth;
425
+ }
426
+ adapter;
427
+ api;
428
+ auth;
429
+ async register() {
430
+ const authToken = await this.auth.getToken();
431
+ if (!authToken) {
432
+ throw new Error("Not authenticated");
433
+ }
434
+ const adapterToken = await this.adapter.getToken();
435
+ if (!adapterToken) {
436
+ return;
437
+ }
438
+ const body = {
439
+ token: adapterToken.token,
440
+ provider: adapterToken.provider,
441
+ platform: adapterToken.platform
442
+ };
443
+ try {
444
+ body.permissionStatus = await this.adapter.getPermissionStatus();
445
+ } catch {
446
+ }
447
+ await this.api.post("/push/register", body);
448
+ }
449
+ async unregister() {
450
+ const authToken = await this.auth.getToken();
451
+ if (!authToken) {
452
+ throw new Error("Not authenticated");
453
+ }
454
+ await this.api.post("/push/unregister", {});
455
+ }
456
+ async requestPermission() {
457
+ return this.adapter.requestPermission();
458
+ }
459
+ async getPermissionStatus() {
460
+ return this.adapter.getPermissionStatus();
461
+ }
462
+ addNotificationOpenedListener(handler) {
463
+ return this.adapter.addNotificationOpenedListener((payload) => {
464
+ handler(payload);
465
+ const deliveryId = extractDeliveryId(payload);
466
+ if (deliveryId) {
467
+ void this.reportOpen(deliveryId);
468
+ }
469
+ });
470
+ }
471
+ addNotificationReceivedListener(handler) {
472
+ return this.adapter.addNotificationReceivedListener(handler);
473
+ }
474
+ async reportOpen(deliveryId) {
475
+ try {
476
+ const authToken = await this.auth.getToken();
477
+ if (!authToken) return;
478
+ await this.api.post("/push/open", { deliveryId });
479
+ } catch {
480
+ }
481
+ }
482
+ };
483
+
402
484
  // src/index.ts
403
485
  var import_shared = require("@codixus/shared");
404
486
  var CodixusClient = class {
405
487
  auth;
406
488
  api;
489
+ push;
407
490
  constructor(config) {
408
491
  const storageKey = config.storageKey ?? "codixus";
409
492
  const storage = config.storage ?? null;
@@ -413,6 +496,9 @@ var CodixusClient = class {
413
496
  });
414
497
  this.api = new ApiClient(config.apiUrl, this.auth, config.appSecret);
415
498
  this.auth._setApi(this.api);
499
+ if (config.push) {
500
+ this.push = new PushManager(config.push, this.api, this.auth);
501
+ }
416
502
  }
417
503
  /**
418
504
  * Create a typed collection accessor.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/auth/auth-manager.ts","../src/api/api-client.ts","../src/db/collection.ts"],"sourcesContent":["import {\n AuthManager,\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n type DeviceIdProvider,\n type AutoSignInConfig,\n} from \"./auth/auth-manager.js\";\nimport { ApiClient } from \"./api/api-client.js\";\nimport { Collection, type FindOptions } from \"./db/collection.js\";\n\nexport interface CodixusClientConfig {\n apiUrl: string;\n storageKey?: string;\n storage?: StorageAdapter | null;\n appSecret?: string;\n deviceIdProvider?: DeviceIdProvider | null;\n autoSignIn?: AutoSignInConfig | null;\n}\n\nexport class CodixusClient {\n readonly auth: AuthManager;\n readonly api: ApiClient;\n\n constructor(config: CodixusClientConfig) {\n const storageKey = config.storageKey ?? \"codixus\";\n const storage = config.storage ?? null;\n\n this.auth = new AuthManager(storage, storageKey, {\n deviceIdProvider: config.deviceIdProvider ?? null,\n autoSignIn: config.autoSignIn ?? null,\n });\n this.api = new ApiClient(config.apiUrl, this.auth, config.appSecret);\n this.auth._setApi(this.api);\n }\n\n /**\n * Create a typed collection accessor.\n * Maps to auto REST routes on server: codixus.rest(Model)\n *\n * @example\n * interface Product { _id: string; name: string; price: number; }\n * const products = codixus.collection<Product>(\"products\");\n * const all = await products.find(); // Product[]\n * const one = await products.findById(\"abc\"); // Product | null\n */\n collection<T>(name: string): Collection<T> {\n return new Collection<T>(this.api, `/api/${name}`);\n }\n\n async init(): Promise<void> {\n await this.auth.init();\n }\n}\n\nexport {\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n type DeviceIdProvider,\n type AutoSignInConfig,\n} from \"./auth/auth-manager.js\";\nexport { ApiClient, setCryptoProvider, type CryptoProvider } from \"./api/api-client.js\";\nexport { Collection, type FindOptions } from \"./db/collection.js\";\n\n// Re-export shared types\nexport {\n type AuthUser,\n type TokenPair,\n type DeviceInfo,\n type DeviceMetadata,\n type AuthTokenRequest,\n type AuthTokenResponse,\n type ApiResponse,\n CodixusError,\n ErrorCodes,\n} from \"@codixus/shared\";\n","import type {\n AuthTokenResponse,\n DeviceInfo,\n DeviceMetadata,\n} from \"@codixus/shared\";\nimport type { ApiClient } from \"../api/api-client.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): Promise<string | null> | string | null;\n setItem(key: string, value: string): Promise<void> | void;\n removeItem(key: string): Promise<void> | void;\n}\n\n// Host-injected source for a stable, OS-level device identifier (IDFV on\n// iOS, ANDROID_ID on Android, etc.). The SDK calls this when it needs to\n// obtain a deviceId and has nothing in storage. Returning null lets the\n// SDK fall back to a generated UUID. Keeping this an interface (instead\n// of importing expo-application) keeps the SDK platform-agnostic.\nexport interface DeviceIdProvider {\n getDeviceId(): Promise<string | null> | string | null;\n}\n\n// Optional auto signIn driven by the SDK on init(). When provided, after\n// init() restores from storage and the user is still unauthenticated, the\n// SDK calls signIn with the host-supplied device info/metadata. This\n// removes the need for every host app to wire its own boot signIn.\nexport interface AutoSignInConfig {\n enabled: boolean;\n getDeviceInfo(): DeviceInfo | Promise<DeviceInfo>;\n getMetadata?(): DeviceMetadata | Promise<DeviceMetadata>;\n onError?(error: unknown): void;\n}\n\nexport interface SignInParams {\n deviceId?: string;\n deviceInfo: DeviceInfo;\n metadata?: DeviceMetadata;\n}\n\nexport interface AuthState {\n isAuthenticated: boolean;\n isLoading: boolean;\n user: Record<string, unknown> | null;\n}\n\ntype AuthStateListener = (state: AuthState) => void;\n\nexport class AuthManager {\n private accessToken: string | null = null;\n private refreshTokenValue: string | null = null;\n private user: Record<string, unknown> | null = null;\n private listeners: Set<AuthStateListener> = new Set();\n private _isLoading = true;\n private storageKey: string;\n private api!: ApiClient;\n private deviceId: string | null = null;\n private deviceIdProvider: DeviceIdProvider | null;\n private autoSignInConfig: AutoSignInConfig | null;\n private initPromise: Promise<void> | null = null;\n private signInPromise: Promise<{ user: Record<string, unknown>; isNewUser: boolean }> | null = null;\n\n constructor(\n private storage: StorageAdapter | null,\n storageKey: string,\n options?: {\n deviceIdProvider?: DeviceIdProvider | null;\n autoSignIn?: AutoSignInConfig | null;\n },\n ) {\n this.storageKey = storageKey;\n this.deviceIdProvider = options?.deviceIdProvider ?? null;\n this.autoSignInConfig = options?.autoSignIn ?? null;\n }\n\n /** @internal */\n _setApi(api: ApiClient): void {\n this.api = api;\n }\n\n async init(): Promise<void> {\n // Idempotent: concurrent or repeat callers (e.g. host module-load\n // init plus the React provider's useEffect init) share a single run\n // so autoSignIn does not fire twice and race against itself on the\n // backend. On rejection we clear the cached promise so a retry can\n // run — caching a rejected promise would brick init() for the rest\n // of the app lifetime.\n if (this.initPromise) return this.initPromise;\n this.initPromise = this._init().catch((err) => {\n this.initPromise = null;\n throw err;\n });\n return this.initPromise;\n }\n\n private async _init(): Promise<void> {\n if (this.storage) {\n try {\n const storedRefresh = await this.storage.getItem(\n `${this.storageKey}_refresh_token`,\n );\n const storedUser = await this.storage.getItem(\n `${this.storageKey}_user`,\n );\n const storedDeviceId = await this.storage.getItem(\n `${this.storageKey}_device_id`,\n );\n\n if (storedRefresh) {\n this.refreshTokenValue = storedRefresh;\n }\n if (storedUser) {\n try {\n this.user = JSON.parse(storedUser);\n } catch {\n // Corrupted user data in storage, ignore\n }\n }\n if (storedDeviceId) {\n this.deviceId = storedDeviceId;\n }\n } catch (error) {\n console.warn(\"[CodixusClient] Failed to restore auth state from storage:\", error);\n }\n }\n\n // Auto signIn: if the host app opted in and we have no live session yet\n // (cold start, app data cleared, fresh install), reach out to the\n // backend with the device-bound identifier so the existing user is\n // restored before any UI hits an authenticated route.\n if (\n this.autoSignInConfig?.enabled &&\n !this.refreshTokenValue\n ) {\n try {\n const deviceInfo = await this.autoSignInConfig.getDeviceInfo();\n const metadata = this.autoSignInConfig.getMetadata\n ? await this.autoSignInConfig.getMetadata()\n : undefined;\n await this.signIn({ deviceInfo, metadata });\n } catch (error) {\n this.autoSignInConfig.onError?.(error);\n }\n }\n\n this._isLoading = false;\n this.notify();\n }\n\n async signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n // Coalesce concurrent signIn calls (e.g. autoSignIn racing a manual\n // signIn from a UI handler) onto a single network request.\n if (this.signInPromise) return this.signInPromise;\n this.signInPromise = this._signIn(params).finally(() => {\n this.signInPromise = null;\n });\n return this.signInPromise;\n }\n\n private async _signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n const providerId = this.deviceIdProvider\n ? await this.deviceIdProvider.getDeviceId()\n : null;\n const deviceId =\n params.deviceId ??\n this.deviceId ??\n providerId ??\n this.generateDeviceId();\n\n const response = await this.api.post<AuthTokenResponse>(\"/auth/token\", {\n deviceId,\n deviceInfo: params.deviceInfo,\n metadata: params.metadata,\n });\n\n const data = response.data;\n this.accessToken = data.accessToken;\n this.refreshTokenValue = data.refreshToken;\n this.user = data.user;\n this.deviceId = deviceId;\n\n // Persist. Storage failures (full disk, locked keychain post-restore,\n // EncryptedSharedPreferences key invalidation) must not strand the\n // in-memory session — the user is signed in for this run; the next\n // cold start will simply re-trigger autoSignIn.\n if (this.storage) {\n try {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n data.refreshToken,\n );\n await this.storage.setItem(\n `${this.storageKey}_user`,\n JSON.stringify(data.user),\n );\n await this.storage.setItem(`${this.storageKey}_device_id`, deviceId);\n } catch (error) {\n console.warn(\"[CodixusClient] Failed to persist auth state:\", error);\n }\n }\n\n this.notify();\n return { user: data.user, isNewUser: data.isNewUser };\n }\n\n async getToken(): Promise<string | null> {\n if (this.accessToken) return this.accessToken;\n\n // Try refresh\n if (this.refreshTokenValue) {\n try {\n await this.forceRefresh();\n return this.accessToken;\n } catch {\n return null;\n }\n }\n\n return null;\n }\n\n async forceRefresh(): Promise<string | null> {\n if (!this.refreshTokenValue) return null;\n\n try {\n const response = await this.api.post<{\n success: boolean;\n accessToken: string;\n refreshToken: string;\n }>(\"/auth/refresh\", {\n refreshToken: this.refreshTokenValue,\n });\n\n this.accessToken = response.data.accessToken;\n this.refreshTokenValue = response.data.refreshToken;\n\n if (this.storage) {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n response.data.refreshToken,\n );\n }\n\n return this.accessToken;\n } catch {\n // Refresh failed, clear auth state\n await this.signOut();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n // Notify server\n if (this.refreshTokenValue) {\n try {\n await this.api.post(\"/auth/logout\", {\n refreshToken: this.refreshTokenValue,\n });\n } catch {}\n }\n\n this.accessToken = null;\n this.refreshTokenValue = null;\n this.user = null;\n // Reset guards so a fresh signIn flow (or a re-init triggered by a\n // host that wants to re-authenticate after sign-out) can run. The\n // signInPromise is also cleared by its own .finally, but a signOut\n // racing against an in-flight signIn shouldn't keep the stale guard.\n this.initPromise = null;\n this.signInPromise = null;\n\n if (this.storage) {\n await this.storage.removeItem(`${this.storageKey}_refresh_token`);\n await this.storage.removeItem(`${this.storageKey}_user`);\n await this.storage.removeItem(`${this.storageKey}_device_id`);\n }\n\n this.notify();\n }\n\n getState(): AuthState {\n return {\n isAuthenticated: this.accessToken !== null || this.refreshTokenValue !== null,\n isLoading: this._isLoading,\n user: this.user,\n };\n }\n\n getDeviceId(): string | null {\n return this.deviceId;\n }\n\n onAuthStateChange(listener: AuthStateListener): () => void {\n this.listeners.add(listener);\n // Call immediately with current state\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** @internal - used by API interceptor */\n _getAccessToken(): string | null {\n return this.accessToken;\n }\n\n /** @internal - called by API interceptor after refresh */\n _setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n private notify(): void {\n const state = this.getState();\n for (const listener of this.listeners) {\n listener(state);\n }\n }\n\n private generateDeviceId(): string {\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n return \"dev-\" + Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n }\n}\n","import axios, {\n type AxiosInstance,\n type AxiosRequestConfig,\n type AxiosResponse,\n} from \"axios\";\nimport type { AuthManager } from \"../auth/auth-manager.js\";\n\n// Crypto functions — injected from outside to avoid platform-specific imports\nexport interface CryptoProvider {\n sha256(data: string): Promise<string>;\n hmacSha256(secret: string, data: string): Promise<string>;\n randomUUID(): string;\n}\n\n// Default: no-op (signing disabled if no crypto provider)\nlet _crypto: CryptoProvider | null = null;\n\nexport function setCryptoProvider(provider: CryptoProvider): void {\n _crypto = provider;\n}\n\nfunction generateNonce(): string {\n if (_crypto) return _crypto.randomUUID();\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport class ApiClient {\n readonly instance: AxiosInstance;\n private refreshPromise: Promise<string | null> | null = null;\n private appSecret: string | undefined;\n\n constructor(\n baseURL: string,\n private authManager: AuthManager,\n appSecret?: string,\n ) {\n this.appSecret = appSecret;\n\n this.instance = axios.create({\n baseURL,\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n // Request interceptor: add Bearer token + signing\n this.instance.interceptors.request.use(async (config) => {\n // Skip auth for auth endpoints\n if (!config.url?.includes(\"/auth/\")) {\n const token = this.authManager._getAccessToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n }\n\n // Request signing (only if crypto provider is set)\n if (this.appSecret && _crypto) {\n const timestamp = Date.now().toString();\n const nonce = _crypto.randomUUID();\n const body =\n config.data && typeof config.data === \"object\"\n ? JSON.stringify(config.data)\n : (config.data ?? \"\");\n const bodyHash = body ? await _crypto.sha256(body) : \"\";\n const method = (config.method ?? \"GET\").toUpperCase();\n const url = config.url ?? \"/\";\n const payload = [method, url, timestamp, nonce, bodyHash].join(\"\\n\");\n const signature = await _crypto.hmacSha256(this.appSecret, payload);\n\n config.headers[\"X-Codixus-Timestamp\"] = timestamp;\n config.headers[\"X-Codixus-Nonce\"] = nonce;\n config.headers[\"X-Codixus-Signature\"] = signature;\n }\n\n return config;\n });\n\n // Response interceptor: handle 401 with token refresh\n this.instance.interceptors.response.use(\n (response) => response,\n async (error) => {\n if (error.response?.status === 401) {\n const originalRequest = error.config;\n if (originalRequest && !originalRequest._retry) {\n originalRequest._retry = true;\n\n try {\n if (!this.refreshPromise) {\n this.refreshPromise = this.authManager\n .forceRefresh()\n .finally(() => {\n this.refreshPromise = null;\n });\n }\n\n const newToken = await this.refreshPromise;\n if (newToken) {\n originalRequest.headers.Authorization = `Bearer ${newToken}`;\n return this.instance(originalRequest);\n }\n } catch (refreshError) {\n console.warn(\"[CodixusClient] Token refresh failed:\", refreshError);\n }\n }\n }\n return Promise.reject(error);\n },\n );\n }\n\n async get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.get<T>(url, config);\n }\n\n async post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.post<T>(url, data, config);\n }\n\n async patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.patch<T>(url, data, config);\n }\n\n async delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.delete<T>(url, config);\n }\n\n async put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.put<T>(url, data, config);\n }\n}\n","import type { ApiClient } from \"../api/api-client.js\";\n\nexport interface FindOptions {\n sort?: Record<string, 1 | -1>;\n limit?: number;\n skip?: number;\n cursor?: string | number;\n}\n\nexport class Collection<T = Record<string, unknown>> {\n constructor(\n private api: ApiClient,\n private basePath: string,\n ) {}\n\n async find(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<T[]> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.skip) params.set(\"skip\", String(options.skip));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor?: string | null }>(url);\n return data.data;\n }\n\n async findWithCursor(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<{ data: T[]; nextCursor: string | number | null }> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor: string | number | null }>(url);\n return { data: data.data, nextCursor: data.nextCursor };\n }\n\n async findById(id: string): Promise<T | null> {\n try {\n const { data } = await this.api.get<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n );\n return data.data;\n } catch (error: any) {\n if (error.response?.status === 404) return null;\n throw error;\n }\n }\n\n async create(doc: Partial<T> & Record<string, unknown>): Promise<T> {\n const { data } = await this.api.post<{ success: boolean; data: T }>(\n this.basePath,\n doc,\n );\n return data.data;\n }\n\n async updateById(\n id: string,\n update: Record<string, unknown>,\n ): Promise<T> {\n const { data } = await this.api.patch<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n { update },\n );\n return data.data;\n }\n\n async deleteById(id: string): Promise<void> {\n await this.api.delete(`${this.basePath}/${id}`);\n }\n\n async count(filter?: Record<string, unknown>): Promise<number> {\n const { data } = await this.api.post<{ success: boolean; count: number }>(\n `${this.basePath}/count`,\n { filter: filter ?? {} },\n );\n return data.count;\n }\n}\n"],"mappings":"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","names":["axios"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/auth/auth-manager.ts","../src/api/api-client.ts","../src/db/collection.ts","../src/push/push-manager.ts"],"sourcesContent":["import {\n AuthManager,\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n type DeviceIdProvider,\n type AutoSignInConfig,\n} from \"./auth/auth-manager.js\";\nimport { ApiClient } from \"./api/api-client.js\";\nimport { Collection, type FindOptions } from \"./db/collection.js\";\nimport { PushManager } from \"./push/push-manager.js\";\nimport type { PushAdapter } from \"./push/types.js\";\n\nexport interface CodixusClientConfig {\n apiUrl: string;\n storageKey?: string;\n storage?: StorageAdapter | null;\n appSecret?: string;\n deviceIdProvider?: DeviceIdProvider | null;\n autoSignIn?: AutoSignInConfig | null;\n push?: PushAdapter;\n}\n\nexport class CodixusClient {\n readonly auth: AuthManager;\n readonly api: ApiClient;\n readonly push?: PushManager;\n\n constructor(config: CodixusClientConfig) {\n const storageKey = config.storageKey ?? \"codixus\";\n const storage = config.storage ?? null;\n\n this.auth = new AuthManager(storage, storageKey, {\n deviceIdProvider: config.deviceIdProvider ?? null,\n autoSignIn: config.autoSignIn ?? null,\n });\n this.api = new ApiClient(config.apiUrl, this.auth, config.appSecret);\n this.auth._setApi(this.api);\n\n if (config.push) {\n this.push = new PushManager(config.push, this.api, this.auth);\n }\n }\n\n /**\n * Create a typed collection accessor.\n * Maps to auto REST routes on server: codixus.rest(Model)\n *\n * @example\n * interface Product { _id: string; name: string; price: number; }\n * const products = codixus.collection<Product>(\"products\");\n * const all = await products.find(); // Product[]\n * const one = await products.findById(\"abc\"); // Product | null\n */\n collection<T>(name: string): Collection<T> {\n return new Collection<T>(this.api, `/api/${name}`);\n }\n\n async init(): Promise<void> {\n await this.auth.init();\n }\n}\n\nexport {\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n type DeviceIdProvider,\n type AutoSignInConfig,\n} from \"./auth/auth-manager.js\";\nexport { ApiClient, setCryptoProvider, type CryptoProvider } from \"./api/api-client.js\";\nexport { Collection, type FindOptions } from \"./db/collection.js\";\nexport { type PushAdapter, type PushAdapterToken } from \"./push/types.js\";\n\n// Re-export shared types\nexport {\n type AuthUser,\n type TokenPair,\n type DeviceInfo,\n type DeviceMetadata,\n type AuthTokenRequest,\n type AuthTokenResponse,\n type ApiResponse,\n CodixusError,\n ErrorCodes,\n} from \"@codixus/shared\";\n","import type {\n AuthTokenResponse,\n DeviceInfo,\n DeviceMetadata,\n} from \"@codixus/shared\";\nimport type { ApiClient } from \"../api/api-client.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): Promise<string | null> | string | null;\n setItem(key: string, value: string): Promise<void> | void;\n removeItem(key: string): Promise<void> | void;\n}\n\n// Host-injected source for a stable, OS-level device identifier (IDFV on\n// iOS, ANDROID_ID on Android, etc.). The SDK calls this when it needs to\n// obtain a deviceId and has nothing in storage. Returning null lets the\n// SDK fall back to a generated UUID. Keeping this an interface (instead\n// of importing expo-application) keeps the SDK platform-agnostic.\nexport interface DeviceIdProvider {\n getDeviceId(): Promise<string | null> | string | null;\n}\n\n// Optional auto signIn driven by the SDK on init(). When provided, after\n// init() restores from storage and the user is still unauthenticated, the\n// SDK calls signIn with the host-supplied device info/metadata. This\n// removes the need for every host app to wire its own boot signIn.\nexport interface AutoSignInConfig {\n enabled: boolean;\n getDeviceInfo(): DeviceInfo | Promise<DeviceInfo>;\n getMetadata?(): DeviceMetadata | Promise<DeviceMetadata>;\n onError?(error: unknown): void;\n}\n\nexport interface SignInParams {\n deviceId?: string;\n deviceInfo: DeviceInfo;\n metadata?: DeviceMetadata;\n}\n\nexport interface AuthState {\n isAuthenticated: boolean;\n isLoading: boolean;\n user: Record<string, unknown> | null;\n}\n\ntype AuthStateListener = (state: AuthState) => void;\n\nexport class AuthManager {\n private accessToken: string | null = null;\n private refreshTokenValue: string | null = null;\n private user: Record<string, unknown> | null = null;\n private listeners: Set<AuthStateListener> = new Set();\n private _isLoading = true;\n private storageKey: string;\n private api!: ApiClient;\n private deviceId: string | null = null;\n private deviceIdProvider: DeviceIdProvider | null;\n private autoSignInConfig: AutoSignInConfig | null;\n private initPromise: Promise<void> | null = null;\n private signInPromise: Promise<{ user: Record<string, unknown>; isNewUser: boolean }> | null = null;\n\n constructor(\n private storage: StorageAdapter | null,\n storageKey: string,\n options?: {\n deviceIdProvider?: DeviceIdProvider | null;\n autoSignIn?: AutoSignInConfig | null;\n },\n ) {\n this.storageKey = storageKey;\n this.deviceIdProvider = options?.deviceIdProvider ?? null;\n this.autoSignInConfig = options?.autoSignIn ?? null;\n }\n\n /** @internal */\n _setApi(api: ApiClient): void {\n this.api = api;\n }\n\n async init(): Promise<void> {\n // Idempotent: concurrent or repeat callers (e.g. host module-load\n // init plus the React provider's useEffect init) share a single run\n // so autoSignIn does not fire twice and race against itself on the\n // backend. On rejection we clear the cached promise so a retry can\n // run — caching a rejected promise would brick init() for the rest\n // of the app lifetime.\n if (this.initPromise) return this.initPromise;\n this.initPromise = this._init().catch((err) => {\n this.initPromise = null;\n throw err;\n });\n return this.initPromise;\n }\n\n private async _init(): Promise<void> {\n if (this.storage) {\n try {\n const storedRefresh = await this.storage.getItem(\n `${this.storageKey}_refresh_token`,\n );\n const storedUser = await this.storage.getItem(\n `${this.storageKey}_user`,\n );\n const storedDeviceId = await this.storage.getItem(\n `${this.storageKey}_device_id`,\n );\n\n if (storedRefresh) {\n this.refreshTokenValue = storedRefresh;\n }\n if (storedUser) {\n try {\n this.user = JSON.parse(storedUser);\n } catch {\n // Corrupted user data in storage, ignore\n }\n }\n if (storedDeviceId) {\n this.deviceId = storedDeviceId;\n }\n } catch (error) {\n console.warn(\"[CodixusClient] Failed to restore auth state from storage:\", error);\n }\n }\n\n // Auto signIn: if the host app opted in and we have no live session yet\n // (cold start, app data cleared, fresh install), reach out to the\n // backend with the device-bound identifier so the existing user is\n // restored before any UI hits an authenticated route.\n if (\n this.autoSignInConfig?.enabled &&\n !this.refreshTokenValue\n ) {\n try {\n const deviceInfo = await this.autoSignInConfig.getDeviceInfo();\n const metadata = this.autoSignInConfig.getMetadata\n ? await this.autoSignInConfig.getMetadata()\n : undefined;\n await this.signIn({ deviceInfo, metadata });\n } catch (error) {\n this.autoSignInConfig.onError?.(error);\n }\n }\n\n this._isLoading = false;\n this.notify();\n }\n\n async signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n // Coalesce concurrent signIn calls (e.g. autoSignIn racing a manual\n // signIn from a UI handler) onto a single network request.\n if (this.signInPromise) return this.signInPromise;\n this.signInPromise = this._signIn(params).finally(() => {\n this.signInPromise = null;\n });\n return this.signInPromise;\n }\n\n private async _signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n const providerId = this.deviceIdProvider\n ? await this.deviceIdProvider.getDeviceId()\n : null;\n const deviceId =\n params.deviceId ??\n this.deviceId ??\n providerId ??\n this.generateDeviceId();\n\n const response = await this.api.post<AuthTokenResponse>(\"/auth/token\", {\n deviceId,\n deviceInfo: params.deviceInfo,\n metadata: params.metadata,\n });\n\n const data = response.data;\n this.accessToken = data.accessToken;\n this.refreshTokenValue = data.refreshToken;\n this.user = data.user;\n this.deviceId = deviceId;\n\n // Persist. Storage failures (full disk, locked keychain post-restore,\n // EncryptedSharedPreferences key invalidation) must not strand the\n // in-memory session — the user is signed in for this run; the next\n // cold start will simply re-trigger autoSignIn.\n if (this.storage) {\n try {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n data.refreshToken,\n );\n await this.storage.setItem(\n `${this.storageKey}_user`,\n JSON.stringify(data.user),\n );\n await this.storage.setItem(`${this.storageKey}_device_id`, deviceId);\n } catch (error) {\n console.warn(\"[CodixusClient] Failed to persist auth state:\", error);\n }\n }\n\n this.notify();\n return { user: data.user, isNewUser: data.isNewUser };\n }\n\n async getToken(): Promise<string | null> {\n if (this.accessToken) return this.accessToken;\n\n // Try refresh\n if (this.refreshTokenValue) {\n try {\n await this.forceRefresh();\n return this.accessToken;\n } catch {\n return null;\n }\n }\n\n return null;\n }\n\n async forceRefresh(): Promise<string | null> {\n if (!this.refreshTokenValue) return null;\n\n try {\n const response = await this.api.post<{\n success: boolean;\n accessToken: string;\n refreshToken: string;\n }>(\"/auth/refresh\", {\n refreshToken: this.refreshTokenValue,\n });\n\n this.accessToken = response.data.accessToken;\n this.refreshTokenValue = response.data.refreshToken;\n\n if (this.storage) {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n response.data.refreshToken,\n );\n }\n\n return this.accessToken;\n } catch {\n // Refresh failed, clear auth state\n await this.signOut();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n // Notify server\n if (this.refreshTokenValue) {\n try {\n await this.api.post(\"/auth/logout\", {\n refreshToken: this.refreshTokenValue,\n });\n } catch {}\n }\n\n this.accessToken = null;\n this.refreshTokenValue = null;\n this.user = null;\n // Reset guards so a fresh signIn flow (or a re-init triggered by a\n // host that wants to re-authenticate after sign-out) can run. The\n // signInPromise is also cleared by its own .finally, but a signOut\n // racing against an in-flight signIn shouldn't keep the stale guard.\n this.initPromise = null;\n this.signInPromise = null;\n\n if (this.storage) {\n await this.storage.removeItem(`${this.storageKey}_refresh_token`);\n await this.storage.removeItem(`${this.storageKey}_user`);\n await this.storage.removeItem(`${this.storageKey}_device_id`);\n }\n\n this.notify();\n }\n\n getState(): AuthState {\n return {\n isAuthenticated: this.accessToken !== null || this.refreshTokenValue !== null,\n isLoading: this._isLoading,\n user: this.user,\n };\n }\n\n getDeviceId(): string | null {\n return this.deviceId;\n }\n\n onAuthStateChange(listener: AuthStateListener): () => void {\n this.listeners.add(listener);\n // Call immediately with current state\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** @internal - used by API interceptor */\n _getAccessToken(): string | null {\n return this.accessToken;\n }\n\n /** @internal - called by API interceptor after refresh */\n _setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n private notify(): void {\n const state = this.getState();\n for (const listener of this.listeners) {\n listener(state);\n }\n }\n\n private generateDeviceId(): string {\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n return \"dev-\" + Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n }\n}\n","import axios, {\n type AxiosInstance,\n type AxiosRequestConfig,\n type AxiosResponse,\n} from \"axios\";\nimport type { AuthManager } from \"../auth/auth-manager.js\";\n\n// Crypto functions — injected from outside to avoid platform-specific imports\nexport interface CryptoProvider {\n sha256(data: string): Promise<string>;\n hmacSha256(secret: string, data: string): Promise<string>;\n randomUUID(): string;\n}\n\n// Default: no-op (signing disabled if no crypto provider)\nlet _crypto: CryptoProvider | null = null;\n\nexport function setCryptoProvider(provider: CryptoProvider): void {\n _crypto = provider;\n}\n\nfunction generateNonce(): string {\n if (_crypto) return _crypto.randomUUID();\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport class ApiClient {\n readonly instance: AxiosInstance;\n private refreshPromise: Promise<string | null> | null = null;\n private appSecret: string | undefined;\n\n constructor(\n baseURL: string,\n private authManager: AuthManager,\n appSecret?: string,\n ) {\n this.appSecret = appSecret;\n\n this.instance = axios.create({\n baseURL,\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n // Request interceptor: add Bearer token + signing\n this.instance.interceptors.request.use(async (config) => {\n // Skip auth for auth endpoints\n if (!config.url?.includes(\"/auth/\")) {\n const token = this.authManager._getAccessToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n }\n\n // Request signing (only if crypto provider is set)\n if (this.appSecret && _crypto) {\n const timestamp = Date.now().toString();\n const nonce = _crypto.randomUUID();\n const body =\n config.data && typeof config.data === \"object\"\n ? JSON.stringify(config.data)\n : (config.data ?? \"\");\n const bodyHash = body ? await _crypto.sha256(body) : \"\";\n const method = (config.method ?? \"GET\").toUpperCase();\n const url = config.url ?? \"/\";\n const payload = [method, url, timestamp, nonce, bodyHash].join(\"\\n\");\n const signature = await _crypto.hmacSha256(this.appSecret, payload);\n\n config.headers[\"X-Codixus-Timestamp\"] = timestamp;\n config.headers[\"X-Codixus-Nonce\"] = nonce;\n config.headers[\"X-Codixus-Signature\"] = signature;\n }\n\n return config;\n });\n\n // Response interceptor: handle 401 with token refresh\n this.instance.interceptors.response.use(\n (response) => response,\n async (error) => {\n if (error.response?.status === 401) {\n const originalRequest = error.config;\n if (originalRequest && !originalRequest._retry) {\n originalRequest._retry = true;\n\n try {\n if (!this.refreshPromise) {\n this.refreshPromise = this.authManager\n .forceRefresh()\n .finally(() => {\n this.refreshPromise = null;\n });\n }\n\n const newToken = await this.refreshPromise;\n if (newToken) {\n originalRequest.headers.Authorization = `Bearer ${newToken}`;\n return this.instance(originalRequest);\n }\n } catch (refreshError) {\n console.warn(\"[CodixusClient] Token refresh failed:\", refreshError);\n }\n }\n }\n return Promise.reject(error);\n },\n );\n }\n\n async get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.get<T>(url, config);\n }\n\n async post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.post<T>(url, data, config);\n }\n\n async patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.patch<T>(url, data, config);\n }\n\n async delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.delete<T>(url, config);\n }\n\n async put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.put<T>(url, data, config);\n }\n}\n","import type { ApiClient } from \"../api/api-client.js\";\n\nexport interface FindOptions {\n sort?: Record<string, 1 | -1>;\n limit?: number;\n skip?: number;\n cursor?: string | number;\n}\n\nexport class Collection<T = Record<string, unknown>> {\n constructor(\n private api: ApiClient,\n private basePath: string,\n ) {}\n\n async find(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<T[]> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.skip) params.set(\"skip\", String(options.skip));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor?: string | null }>(url);\n return data.data;\n }\n\n async findWithCursor(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<{ data: T[]; nextCursor: string | number | null }> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor: string | number | null }>(url);\n return { data: data.data, nextCursor: data.nextCursor };\n }\n\n async findById(id: string): Promise<T | null> {\n try {\n const { data } = await this.api.get<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n );\n return data.data;\n } catch (error: any) {\n if (error.response?.status === 404) return null;\n throw error;\n }\n }\n\n async create(doc: Partial<T> & Record<string, unknown>): Promise<T> {\n const { data } = await this.api.post<{ success: boolean; data: T }>(\n this.basePath,\n doc,\n );\n return data.data;\n }\n\n async updateById(\n id: string,\n update: Record<string, unknown>,\n ): Promise<T> {\n const { data } = await this.api.patch<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n { update },\n );\n return data.data;\n }\n\n async deleteById(id: string): Promise<void> {\n await this.api.delete(`${this.basePath}/${id}`);\n }\n\n async count(filter?: Record<string, unknown>): Promise<number> {\n const { data } = await this.api.post<{ success: boolean; count: number }>(\n `${this.basePath}/count`,\n { filter: filter ?? {} },\n );\n return data.count;\n }\n}\n","import type { ApiClient } from \"../api/api-client.js\";\nimport type { AuthManager } from \"../auth/auth-manager.js\";\nimport type { PushAdapter } from \"./types.js\";\n\nfunction extractDeliveryId(\n payload: Record<string, unknown>,\n): string | undefined {\n if (typeof payload.deliveryId === \"string\" && payload.deliveryId) {\n return payload.deliveryId;\n }\n const data = payload.data;\n if (data && typeof data === \"object\" && !Array.isArray(data)) {\n const nested = (data as Record<string, unknown>).deliveryId;\n if (typeof nested === \"string\" && nested) {\n return nested;\n }\n }\n return undefined;\n}\n\nexport class PushManager {\n constructor(\n private adapter: PushAdapter,\n private api: ApiClient,\n private auth: AuthManager,\n ) {}\n\n async register(): Promise<void> {\n const authToken = await this.auth.getToken();\n if (!authToken) {\n throw new Error(\"Not authenticated\");\n }\n\n const adapterToken = await this.adapter.getToken();\n if (!adapterToken) {\n return;\n }\n\n const body: Record<string, unknown> = {\n token: adapterToken.token,\n provider: adapterToken.provider,\n platform: adapterToken.platform,\n };\n\n try {\n body.permissionStatus = await this.adapter.getPermissionStatus();\n } catch {\n // omit permissionStatus, still POST\n }\n\n await this.api.post(\"/push/register\", body);\n }\n\n async unregister(): Promise<void> {\n const authToken = await this.auth.getToken();\n if (!authToken) {\n throw new Error(\"Not authenticated\");\n }\n\n await this.api.post(\"/push/unregister\", {});\n }\n\n async requestPermission(): Promise<boolean> {\n return this.adapter.requestPermission();\n }\n\n async getPermissionStatus(): Promise<\n \"granted\" | \"denied\" | \"undetermined\"\n > {\n return this.adapter.getPermissionStatus();\n }\n\n addNotificationOpenedListener(\n handler: (payload: Record<string, unknown>) => void,\n ): () => void {\n return this.adapter.addNotificationOpenedListener((payload) => {\n handler(payload);\n const deliveryId = extractDeliveryId(payload);\n if (deliveryId) {\n void this.reportOpen(deliveryId);\n }\n });\n }\n\n addNotificationReceivedListener(\n handler: (payload: Record<string, unknown>) => void,\n ): () => void {\n return this.adapter.addNotificationReceivedListener(handler);\n }\n\n private async reportOpen(deliveryId: string): Promise<void> {\n try {\n const authToken = await this.auth.getToken();\n if (!authToken) return;\n await this.api.post(\"/push/open\", { deliveryId });\n } catch {\n // fire-and-forget: swallow 404, 401, 5xx, network errors\n }\n }\n}\n"],"mappings":"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","names":["axios"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { DeviceInfo, DeviceMetadata } from '@codixus/shared';
2
2
  export { ApiResponse, AuthTokenRequest, AuthTokenResponse, AuthUser, CodixusError, DeviceInfo, DeviceMetadata, ErrorCodes, TokenPair } from '@codixus/shared';
3
3
  import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
4
+ import { P as PushAdapter } from './types-maS8y9s9.cjs';
5
+ export { a as PushAdapterToken } from './types-maS8y9s9.cjs';
4
6
 
5
7
  interface CryptoProvider {
6
8
  sha256(data: string): Promise<string>;
@@ -109,6 +111,20 @@ declare class Collection<T = Record<string, unknown>> {
109
111
  count(filter?: Record<string, unknown>): Promise<number>;
110
112
  }
111
113
 
114
+ declare class PushManager {
115
+ private adapter;
116
+ private api;
117
+ private auth;
118
+ constructor(adapter: PushAdapter, api: ApiClient, auth: AuthManager);
119
+ register(): Promise<void>;
120
+ unregister(): Promise<void>;
121
+ requestPermission(): Promise<boolean>;
122
+ getPermissionStatus(): Promise<"granted" | "denied" | "undetermined">;
123
+ addNotificationOpenedListener(handler: (payload: Record<string, unknown>) => void): () => void;
124
+ addNotificationReceivedListener(handler: (payload: Record<string, unknown>) => void): () => void;
125
+ private reportOpen;
126
+ }
127
+
112
128
  interface CodixusClientConfig {
113
129
  apiUrl: string;
114
130
  storageKey?: string;
@@ -116,10 +132,12 @@ interface CodixusClientConfig {
116
132
  appSecret?: string;
117
133
  deviceIdProvider?: DeviceIdProvider | null;
118
134
  autoSignIn?: AutoSignInConfig | null;
135
+ push?: PushAdapter;
119
136
  }
120
137
  declare class CodixusClient {
121
138
  readonly auth: AuthManager;
122
139
  readonly api: ApiClient;
140
+ readonly push?: PushManager;
123
141
  constructor(config: CodixusClientConfig);
124
142
  /**
125
143
  * Create a typed collection accessor.
@@ -135,4 +153,4 @@ declare class CodixusClient {
135
153
  init(): Promise<void>;
136
154
  }
137
155
 
138
- export { ApiClient, type AuthState, type AutoSignInConfig, CodixusClient, type CodixusClientConfig, Collection, type CryptoProvider, type DeviceIdProvider, type FindOptions, type SignInParams, type StorageAdapter, setCryptoProvider };
156
+ export { ApiClient, type AuthState, type AutoSignInConfig, CodixusClient, type CodixusClientConfig, Collection, type CryptoProvider, type DeviceIdProvider, type FindOptions, PushAdapter, type SignInParams, type StorageAdapter, setCryptoProvider };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { DeviceInfo, DeviceMetadata } from '@codixus/shared';
2
2
  export { ApiResponse, AuthTokenRequest, AuthTokenResponse, AuthUser, CodixusError, DeviceInfo, DeviceMetadata, ErrorCodes, TokenPair } from '@codixus/shared';
3
3
  import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
4
+ import { P as PushAdapter } from './types-maS8y9s9.js';
5
+ export { a as PushAdapterToken } from './types-maS8y9s9.js';
4
6
 
5
7
  interface CryptoProvider {
6
8
  sha256(data: string): Promise<string>;
@@ -109,6 +111,20 @@ declare class Collection<T = Record<string, unknown>> {
109
111
  count(filter?: Record<string, unknown>): Promise<number>;
110
112
  }
111
113
 
114
+ declare class PushManager {
115
+ private adapter;
116
+ private api;
117
+ private auth;
118
+ constructor(adapter: PushAdapter, api: ApiClient, auth: AuthManager);
119
+ register(): Promise<void>;
120
+ unregister(): Promise<void>;
121
+ requestPermission(): Promise<boolean>;
122
+ getPermissionStatus(): Promise<"granted" | "denied" | "undetermined">;
123
+ addNotificationOpenedListener(handler: (payload: Record<string, unknown>) => void): () => void;
124
+ addNotificationReceivedListener(handler: (payload: Record<string, unknown>) => void): () => void;
125
+ private reportOpen;
126
+ }
127
+
112
128
  interface CodixusClientConfig {
113
129
  apiUrl: string;
114
130
  storageKey?: string;
@@ -116,10 +132,12 @@ interface CodixusClientConfig {
116
132
  appSecret?: string;
117
133
  deviceIdProvider?: DeviceIdProvider | null;
118
134
  autoSignIn?: AutoSignInConfig | null;
135
+ push?: PushAdapter;
119
136
  }
120
137
  declare class CodixusClient {
121
138
  readonly auth: AuthManager;
122
139
  readonly api: ApiClient;
140
+ readonly push?: PushManager;
123
141
  constructor(config: CodixusClientConfig);
124
142
  /**
125
143
  * Create a typed collection accessor.
@@ -135,4 +153,4 @@ declare class CodixusClient {
135
153
  init(): Promise<void>;
136
154
  }
137
155
 
138
- export { ApiClient, type AuthState, type AutoSignInConfig, CodixusClient, type CodixusClientConfig, Collection, type CryptoProvider, type DeviceIdProvider, type FindOptions, type SignInParams, type StorageAdapter, setCryptoProvider };
156
+ export { ApiClient, type AuthState, type AutoSignInConfig, CodixusClient, type CodixusClientConfig, Collection, type CryptoProvider, type DeviceIdProvider, type FindOptions, PushAdapter, type SignInParams, type StorageAdapter, setCryptoProvider };
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ var AuthManager = class {
6
6
  this.deviceIdProvider = options?.deviceIdProvider ?? null;
7
7
  this.autoSignInConfig = options?.autoSignIn ?? null;
8
8
  }
9
+ storage;
9
10
  accessToken = null;
10
11
  refreshTokenValue = null;
11
12
  user = null;
@@ -268,6 +269,7 @@ var ApiClient = class {
268
269
  }
269
270
  );
270
271
  }
272
+ authManager;
271
273
  instance;
272
274
  refreshPromise = null;
273
275
  appSecret;
@@ -294,6 +296,8 @@ var Collection = class {
294
296
  this.api = api;
295
297
  this.basePath = basePath;
296
298
  }
299
+ api;
300
+ basePath;
297
301
  async find(filter, options) {
298
302
  const params = new URLSearchParams();
299
303
  if (filter && Object.keys(filter).length > 0) {
@@ -358,6 +362,84 @@ var Collection = class {
358
362
  }
359
363
  };
360
364
 
365
+ // src/push/push-manager.ts
366
+ function extractDeliveryId(payload) {
367
+ if (typeof payload.deliveryId === "string" && payload.deliveryId) {
368
+ return payload.deliveryId;
369
+ }
370
+ const data = payload.data;
371
+ if (data && typeof data === "object" && !Array.isArray(data)) {
372
+ const nested = data.deliveryId;
373
+ if (typeof nested === "string" && nested) {
374
+ return nested;
375
+ }
376
+ }
377
+ return void 0;
378
+ }
379
+ var PushManager = class {
380
+ constructor(adapter, api, auth) {
381
+ this.adapter = adapter;
382
+ this.api = api;
383
+ this.auth = auth;
384
+ }
385
+ adapter;
386
+ api;
387
+ auth;
388
+ async register() {
389
+ const authToken = await this.auth.getToken();
390
+ if (!authToken) {
391
+ throw new Error("Not authenticated");
392
+ }
393
+ const adapterToken = await this.adapter.getToken();
394
+ if (!adapterToken) {
395
+ return;
396
+ }
397
+ const body = {
398
+ token: adapterToken.token,
399
+ provider: adapterToken.provider,
400
+ platform: adapterToken.platform
401
+ };
402
+ try {
403
+ body.permissionStatus = await this.adapter.getPermissionStatus();
404
+ } catch {
405
+ }
406
+ await this.api.post("/push/register", body);
407
+ }
408
+ async unregister() {
409
+ const authToken = await this.auth.getToken();
410
+ if (!authToken) {
411
+ throw new Error("Not authenticated");
412
+ }
413
+ await this.api.post("/push/unregister", {});
414
+ }
415
+ async requestPermission() {
416
+ return this.adapter.requestPermission();
417
+ }
418
+ async getPermissionStatus() {
419
+ return this.adapter.getPermissionStatus();
420
+ }
421
+ addNotificationOpenedListener(handler) {
422
+ return this.adapter.addNotificationOpenedListener((payload) => {
423
+ handler(payload);
424
+ const deliveryId = extractDeliveryId(payload);
425
+ if (deliveryId) {
426
+ void this.reportOpen(deliveryId);
427
+ }
428
+ });
429
+ }
430
+ addNotificationReceivedListener(handler) {
431
+ return this.adapter.addNotificationReceivedListener(handler);
432
+ }
433
+ async reportOpen(deliveryId) {
434
+ try {
435
+ const authToken = await this.auth.getToken();
436
+ if (!authToken) return;
437
+ await this.api.post("/push/open", { deliveryId });
438
+ } catch {
439
+ }
440
+ }
441
+ };
442
+
361
443
  // src/index.ts
362
444
  import {
363
445
  CodixusError,
@@ -366,6 +448,7 @@ import {
366
448
  var CodixusClient = class {
367
449
  auth;
368
450
  api;
451
+ push;
369
452
  constructor(config) {
370
453
  const storageKey = config.storageKey ?? "codixus";
371
454
  const storage = config.storage ?? null;
@@ -375,6 +458,9 @@ var CodixusClient = class {
375
458
  });
376
459
  this.api = new ApiClient(config.apiUrl, this.auth, config.appSecret);
377
460
  this.auth._setApi(this.api);
461
+ if (config.push) {
462
+ this.push = new PushManager(config.push, this.api, this.auth);
463
+ }
378
464
  }
379
465
  /**
380
466
  * Create a typed collection accessor.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/auth/auth-manager.ts","../src/api/api-client.ts","../src/db/collection.ts","../src/index.ts"],"sourcesContent":["import type {\n AuthTokenResponse,\n DeviceInfo,\n DeviceMetadata,\n} from \"@codixus/shared\";\nimport type { ApiClient } from \"../api/api-client.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): Promise<string | null> | string | null;\n setItem(key: string, value: string): Promise<void> | void;\n removeItem(key: string): Promise<void> | void;\n}\n\n// Host-injected source for a stable, OS-level device identifier (IDFV on\n// iOS, ANDROID_ID on Android, etc.). The SDK calls this when it needs to\n// obtain a deviceId and has nothing in storage. Returning null lets the\n// SDK fall back to a generated UUID. Keeping this an interface (instead\n// of importing expo-application) keeps the SDK platform-agnostic.\nexport interface DeviceIdProvider {\n getDeviceId(): Promise<string | null> | string | null;\n}\n\n// Optional auto signIn driven by the SDK on init(). When provided, after\n// init() restores from storage and the user is still unauthenticated, the\n// SDK calls signIn with the host-supplied device info/metadata. This\n// removes the need for every host app to wire its own boot signIn.\nexport interface AutoSignInConfig {\n enabled: boolean;\n getDeviceInfo(): DeviceInfo | Promise<DeviceInfo>;\n getMetadata?(): DeviceMetadata | Promise<DeviceMetadata>;\n onError?(error: unknown): void;\n}\n\nexport interface SignInParams {\n deviceId?: string;\n deviceInfo: DeviceInfo;\n metadata?: DeviceMetadata;\n}\n\nexport interface AuthState {\n isAuthenticated: boolean;\n isLoading: boolean;\n user: Record<string, unknown> | null;\n}\n\ntype AuthStateListener = (state: AuthState) => void;\n\nexport class AuthManager {\n private accessToken: string | null = null;\n private refreshTokenValue: string | null = null;\n private user: Record<string, unknown> | null = null;\n private listeners: Set<AuthStateListener> = new Set();\n private _isLoading = true;\n private storageKey: string;\n private api!: ApiClient;\n private deviceId: string | null = null;\n private deviceIdProvider: DeviceIdProvider | null;\n private autoSignInConfig: AutoSignInConfig | null;\n private initPromise: Promise<void> | null = null;\n private signInPromise: Promise<{ user: Record<string, unknown>; isNewUser: boolean }> | null = null;\n\n constructor(\n private storage: StorageAdapter | null,\n storageKey: string,\n options?: {\n deviceIdProvider?: DeviceIdProvider | null;\n autoSignIn?: AutoSignInConfig | null;\n },\n ) {\n this.storageKey = storageKey;\n this.deviceIdProvider = options?.deviceIdProvider ?? null;\n this.autoSignInConfig = options?.autoSignIn ?? null;\n }\n\n /** @internal */\n _setApi(api: ApiClient): void {\n this.api = api;\n }\n\n async init(): Promise<void> {\n // Idempotent: concurrent or repeat callers (e.g. host module-load\n // init plus the React provider's useEffect init) share a single run\n // so autoSignIn does not fire twice and race against itself on the\n // backend. On rejection we clear the cached promise so a retry can\n // run — caching a rejected promise would brick init() for the rest\n // of the app lifetime.\n if (this.initPromise) return this.initPromise;\n this.initPromise = this._init().catch((err) => {\n this.initPromise = null;\n throw err;\n });\n return this.initPromise;\n }\n\n private async _init(): Promise<void> {\n if (this.storage) {\n try {\n const storedRefresh = await this.storage.getItem(\n `${this.storageKey}_refresh_token`,\n );\n const storedUser = await this.storage.getItem(\n `${this.storageKey}_user`,\n );\n const storedDeviceId = await this.storage.getItem(\n `${this.storageKey}_device_id`,\n );\n\n if (storedRefresh) {\n this.refreshTokenValue = storedRefresh;\n }\n if (storedUser) {\n try {\n this.user = JSON.parse(storedUser);\n } catch {\n // Corrupted user data in storage, ignore\n }\n }\n if (storedDeviceId) {\n this.deviceId = storedDeviceId;\n }\n } catch (error) {\n console.warn(\"[CodixusClient] Failed to restore auth state from storage:\", error);\n }\n }\n\n // Auto signIn: if the host app opted in and we have no live session yet\n // (cold start, app data cleared, fresh install), reach out to the\n // backend with the device-bound identifier so the existing user is\n // restored before any UI hits an authenticated route.\n if (\n this.autoSignInConfig?.enabled &&\n !this.refreshTokenValue\n ) {\n try {\n const deviceInfo = await this.autoSignInConfig.getDeviceInfo();\n const metadata = this.autoSignInConfig.getMetadata\n ? await this.autoSignInConfig.getMetadata()\n : undefined;\n await this.signIn({ deviceInfo, metadata });\n } catch (error) {\n this.autoSignInConfig.onError?.(error);\n }\n }\n\n this._isLoading = false;\n this.notify();\n }\n\n async signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n // Coalesce concurrent signIn calls (e.g. autoSignIn racing a manual\n // signIn from a UI handler) onto a single network request.\n if (this.signInPromise) return this.signInPromise;\n this.signInPromise = this._signIn(params).finally(() => {\n this.signInPromise = null;\n });\n return this.signInPromise;\n }\n\n private async _signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n const providerId = this.deviceIdProvider\n ? await this.deviceIdProvider.getDeviceId()\n : null;\n const deviceId =\n params.deviceId ??\n this.deviceId ??\n providerId ??\n this.generateDeviceId();\n\n const response = await this.api.post<AuthTokenResponse>(\"/auth/token\", {\n deviceId,\n deviceInfo: params.deviceInfo,\n metadata: params.metadata,\n });\n\n const data = response.data;\n this.accessToken = data.accessToken;\n this.refreshTokenValue = data.refreshToken;\n this.user = data.user;\n this.deviceId = deviceId;\n\n // Persist. Storage failures (full disk, locked keychain post-restore,\n // EncryptedSharedPreferences key invalidation) must not strand the\n // in-memory session — the user is signed in for this run; the next\n // cold start will simply re-trigger autoSignIn.\n if (this.storage) {\n try {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n data.refreshToken,\n );\n await this.storage.setItem(\n `${this.storageKey}_user`,\n JSON.stringify(data.user),\n );\n await this.storage.setItem(`${this.storageKey}_device_id`, deviceId);\n } catch (error) {\n console.warn(\"[CodixusClient] Failed to persist auth state:\", error);\n }\n }\n\n this.notify();\n return { user: data.user, isNewUser: data.isNewUser };\n }\n\n async getToken(): Promise<string | null> {\n if (this.accessToken) return this.accessToken;\n\n // Try refresh\n if (this.refreshTokenValue) {\n try {\n await this.forceRefresh();\n return this.accessToken;\n } catch {\n return null;\n }\n }\n\n return null;\n }\n\n async forceRefresh(): Promise<string | null> {\n if (!this.refreshTokenValue) return null;\n\n try {\n const response = await this.api.post<{\n success: boolean;\n accessToken: string;\n refreshToken: string;\n }>(\"/auth/refresh\", {\n refreshToken: this.refreshTokenValue,\n });\n\n this.accessToken = response.data.accessToken;\n this.refreshTokenValue = response.data.refreshToken;\n\n if (this.storage) {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n response.data.refreshToken,\n );\n }\n\n return this.accessToken;\n } catch {\n // Refresh failed, clear auth state\n await this.signOut();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n // Notify server\n if (this.refreshTokenValue) {\n try {\n await this.api.post(\"/auth/logout\", {\n refreshToken: this.refreshTokenValue,\n });\n } catch {}\n }\n\n this.accessToken = null;\n this.refreshTokenValue = null;\n this.user = null;\n // Reset guards so a fresh signIn flow (or a re-init triggered by a\n // host that wants to re-authenticate after sign-out) can run. The\n // signInPromise is also cleared by its own .finally, but a signOut\n // racing against an in-flight signIn shouldn't keep the stale guard.\n this.initPromise = null;\n this.signInPromise = null;\n\n if (this.storage) {\n await this.storage.removeItem(`${this.storageKey}_refresh_token`);\n await this.storage.removeItem(`${this.storageKey}_user`);\n await this.storage.removeItem(`${this.storageKey}_device_id`);\n }\n\n this.notify();\n }\n\n getState(): AuthState {\n return {\n isAuthenticated: this.accessToken !== null || this.refreshTokenValue !== null,\n isLoading: this._isLoading,\n user: this.user,\n };\n }\n\n getDeviceId(): string | null {\n return this.deviceId;\n }\n\n onAuthStateChange(listener: AuthStateListener): () => void {\n this.listeners.add(listener);\n // Call immediately with current state\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** @internal - used by API interceptor */\n _getAccessToken(): string | null {\n return this.accessToken;\n }\n\n /** @internal - called by API interceptor after refresh */\n _setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n private notify(): void {\n const state = this.getState();\n for (const listener of this.listeners) {\n listener(state);\n }\n }\n\n private generateDeviceId(): string {\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n return \"dev-\" + Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n }\n}\n","import axios, {\n type AxiosInstance,\n type AxiosRequestConfig,\n type AxiosResponse,\n} from \"axios\";\nimport type { AuthManager } from \"../auth/auth-manager.js\";\n\n// Crypto functions — injected from outside to avoid platform-specific imports\nexport interface CryptoProvider {\n sha256(data: string): Promise<string>;\n hmacSha256(secret: string, data: string): Promise<string>;\n randomUUID(): string;\n}\n\n// Default: no-op (signing disabled if no crypto provider)\nlet _crypto: CryptoProvider | null = null;\n\nexport function setCryptoProvider(provider: CryptoProvider): void {\n _crypto = provider;\n}\n\nfunction generateNonce(): string {\n if (_crypto) return _crypto.randomUUID();\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport class ApiClient {\n readonly instance: AxiosInstance;\n private refreshPromise: Promise<string | null> | null = null;\n private appSecret: string | undefined;\n\n constructor(\n baseURL: string,\n private authManager: AuthManager,\n appSecret?: string,\n ) {\n this.appSecret = appSecret;\n\n this.instance = axios.create({\n baseURL,\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n // Request interceptor: add Bearer token + signing\n this.instance.interceptors.request.use(async (config) => {\n // Skip auth for auth endpoints\n if (!config.url?.includes(\"/auth/\")) {\n const token = this.authManager._getAccessToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n }\n\n // Request signing (only if crypto provider is set)\n if (this.appSecret && _crypto) {\n const timestamp = Date.now().toString();\n const nonce = _crypto.randomUUID();\n const body =\n config.data && typeof config.data === \"object\"\n ? JSON.stringify(config.data)\n : (config.data ?? \"\");\n const bodyHash = body ? await _crypto.sha256(body) : \"\";\n const method = (config.method ?? \"GET\").toUpperCase();\n const url = config.url ?? \"/\";\n const payload = [method, url, timestamp, nonce, bodyHash].join(\"\\n\");\n const signature = await _crypto.hmacSha256(this.appSecret, payload);\n\n config.headers[\"X-Codixus-Timestamp\"] = timestamp;\n config.headers[\"X-Codixus-Nonce\"] = nonce;\n config.headers[\"X-Codixus-Signature\"] = signature;\n }\n\n return config;\n });\n\n // Response interceptor: handle 401 with token refresh\n this.instance.interceptors.response.use(\n (response) => response,\n async (error) => {\n if (error.response?.status === 401) {\n const originalRequest = error.config;\n if (originalRequest && !originalRequest._retry) {\n originalRequest._retry = true;\n\n try {\n if (!this.refreshPromise) {\n this.refreshPromise = this.authManager\n .forceRefresh()\n .finally(() => {\n this.refreshPromise = null;\n });\n }\n\n const newToken = await this.refreshPromise;\n if (newToken) {\n originalRequest.headers.Authorization = `Bearer ${newToken}`;\n return this.instance(originalRequest);\n }\n } catch (refreshError) {\n console.warn(\"[CodixusClient] Token refresh failed:\", refreshError);\n }\n }\n }\n return Promise.reject(error);\n },\n );\n }\n\n async get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.get<T>(url, config);\n }\n\n async post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.post<T>(url, data, config);\n }\n\n async patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.patch<T>(url, data, config);\n }\n\n async delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.delete<T>(url, config);\n }\n\n async put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.put<T>(url, data, config);\n }\n}\n","import type { ApiClient } from \"../api/api-client.js\";\n\nexport interface FindOptions {\n sort?: Record<string, 1 | -1>;\n limit?: number;\n skip?: number;\n cursor?: string | number;\n}\n\nexport class Collection<T = Record<string, unknown>> {\n constructor(\n private api: ApiClient,\n private basePath: string,\n ) {}\n\n async find(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<T[]> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.skip) params.set(\"skip\", String(options.skip));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor?: string | null }>(url);\n return data.data;\n }\n\n async findWithCursor(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<{ data: T[]; nextCursor: string | number | null }> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor: string | number | null }>(url);\n return { data: data.data, nextCursor: data.nextCursor };\n }\n\n async findById(id: string): Promise<T | null> {\n try {\n const { data } = await this.api.get<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n );\n return data.data;\n } catch (error: any) {\n if (error.response?.status === 404) return null;\n throw error;\n }\n }\n\n async create(doc: Partial<T> & Record<string, unknown>): Promise<T> {\n const { data } = await this.api.post<{ success: boolean; data: T }>(\n this.basePath,\n doc,\n );\n return data.data;\n }\n\n async updateById(\n id: string,\n update: Record<string, unknown>,\n ): Promise<T> {\n const { data } = await this.api.patch<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n { update },\n );\n return data.data;\n }\n\n async deleteById(id: string): Promise<void> {\n await this.api.delete(`${this.basePath}/${id}`);\n }\n\n async count(filter?: Record<string, unknown>): Promise<number> {\n const { data } = await this.api.post<{ success: boolean; count: number }>(\n `${this.basePath}/count`,\n { filter: filter ?? {} },\n );\n return data.count;\n }\n}\n","import {\n AuthManager,\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n type DeviceIdProvider,\n type AutoSignInConfig,\n} from \"./auth/auth-manager.js\";\nimport { ApiClient } from \"./api/api-client.js\";\nimport { Collection, type FindOptions } from \"./db/collection.js\";\n\nexport interface CodixusClientConfig {\n apiUrl: string;\n storageKey?: string;\n storage?: StorageAdapter | null;\n appSecret?: string;\n deviceIdProvider?: DeviceIdProvider | null;\n autoSignIn?: AutoSignInConfig | null;\n}\n\nexport class CodixusClient {\n readonly auth: AuthManager;\n readonly api: ApiClient;\n\n constructor(config: CodixusClientConfig) {\n const storageKey = config.storageKey ?? \"codixus\";\n const storage = config.storage ?? null;\n\n this.auth = new AuthManager(storage, storageKey, {\n deviceIdProvider: config.deviceIdProvider ?? null,\n autoSignIn: config.autoSignIn ?? null,\n });\n this.api = new ApiClient(config.apiUrl, this.auth, config.appSecret);\n this.auth._setApi(this.api);\n }\n\n /**\n * Create a typed collection accessor.\n * Maps to auto REST routes on server: codixus.rest(Model)\n *\n * @example\n * interface Product { _id: string; name: string; price: number; }\n * const products = codixus.collection<Product>(\"products\");\n * const all = await products.find(); // Product[]\n * const one = await products.findById(\"abc\"); // Product | null\n */\n collection<T>(name: string): Collection<T> {\n return new Collection<T>(this.api, `/api/${name}`);\n }\n\n async init(): Promise<void> {\n await this.auth.init();\n }\n}\n\nexport {\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n type DeviceIdProvider,\n type AutoSignInConfig,\n} from \"./auth/auth-manager.js\";\nexport { ApiClient, setCryptoProvider, type CryptoProvider } from \"./api/api-client.js\";\nexport { Collection, type FindOptions } from \"./db/collection.js\";\n\n// Re-export shared types\nexport {\n type AuthUser,\n type TokenPair,\n type DeviceInfo,\n type DeviceMetadata,\n type AuthTokenRequest,\n type AuthTokenResponse,\n type ApiResponse,\n CodixusError,\n ErrorCodes,\n} from \"@codixus/shared\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/auth/auth-manager.ts","../src/api/api-client.ts","../src/db/collection.ts","../src/push/push-manager.ts","../src/index.ts"],"sourcesContent":["import type {\n AuthTokenResponse,\n DeviceInfo,\n DeviceMetadata,\n} from \"@codixus/shared\";\nimport type { ApiClient } from \"../api/api-client.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): Promise<string | null> | string | null;\n setItem(key: string, value: string): Promise<void> | void;\n removeItem(key: string): Promise<void> | void;\n}\n\n// Host-injected source for a stable, OS-level device identifier (IDFV on\n// iOS, ANDROID_ID on Android, etc.). The SDK calls this when it needs to\n// obtain a deviceId and has nothing in storage. Returning null lets the\n// SDK fall back to a generated UUID. Keeping this an interface (instead\n// of importing expo-application) keeps the SDK platform-agnostic.\nexport interface DeviceIdProvider {\n getDeviceId(): Promise<string | null> | string | null;\n}\n\n// Optional auto signIn driven by the SDK on init(). When provided, after\n// init() restores from storage and the user is still unauthenticated, the\n// SDK calls signIn with the host-supplied device info/metadata. This\n// removes the need for every host app to wire its own boot signIn.\nexport interface AutoSignInConfig {\n enabled: boolean;\n getDeviceInfo(): DeviceInfo | Promise<DeviceInfo>;\n getMetadata?(): DeviceMetadata | Promise<DeviceMetadata>;\n onError?(error: unknown): void;\n}\n\nexport interface SignInParams {\n deviceId?: string;\n deviceInfo: DeviceInfo;\n metadata?: DeviceMetadata;\n}\n\nexport interface AuthState {\n isAuthenticated: boolean;\n isLoading: boolean;\n user: Record<string, unknown> | null;\n}\n\ntype AuthStateListener = (state: AuthState) => void;\n\nexport class AuthManager {\n private accessToken: string | null = null;\n private refreshTokenValue: string | null = null;\n private user: Record<string, unknown> | null = null;\n private listeners: Set<AuthStateListener> = new Set();\n private _isLoading = true;\n private storageKey: string;\n private api!: ApiClient;\n private deviceId: string | null = null;\n private deviceIdProvider: DeviceIdProvider | null;\n private autoSignInConfig: AutoSignInConfig | null;\n private initPromise: Promise<void> | null = null;\n private signInPromise: Promise<{ user: Record<string, unknown>; isNewUser: boolean }> | null = null;\n\n constructor(\n private storage: StorageAdapter | null,\n storageKey: string,\n options?: {\n deviceIdProvider?: DeviceIdProvider | null;\n autoSignIn?: AutoSignInConfig | null;\n },\n ) {\n this.storageKey = storageKey;\n this.deviceIdProvider = options?.deviceIdProvider ?? null;\n this.autoSignInConfig = options?.autoSignIn ?? null;\n }\n\n /** @internal */\n _setApi(api: ApiClient): void {\n this.api = api;\n }\n\n async init(): Promise<void> {\n // Idempotent: concurrent or repeat callers (e.g. host module-load\n // init plus the React provider's useEffect init) share a single run\n // so autoSignIn does not fire twice and race against itself on the\n // backend. On rejection we clear the cached promise so a retry can\n // run — caching a rejected promise would brick init() for the rest\n // of the app lifetime.\n if (this.initPromise) return this.initPromise;\n this.initPromise = this._init().catch((err) => {\n this.initPromise = null;\n throw err;\n });\n return this.initPromise;\n }\n\n private async _init(): Promise<void> {\n if (this.storage) {\n try {\n const storedRefresh = await this.storage.getItem(\n `${this.storageKey}_refresh_token`,\n );\n const storedUser = await this.storage.getItem(\n `${this.storageKey}_user`,\n );\n const storedDeviceId = await this.storage.getItem(\n `${this.storageKey}_device_id`,\n );\n\n if (storedRefresh) {\n this.refreshTokenValue = storedRefresh;\n }\n if (storedUser) {\n try {\n this.user = JSON.parse(storedUser);\n } catch {\n // Corrupted user data in storage, ignore\n }\n }\n if (storedDeviceId) {\n this.deviceId = storedDeviceId;\n }\n } catch (error) {\n console.warn(\"[CodixusClient] Failed to restore auth state from storage:\", error);\n }\n }\n\n // Auto signIn: if the host app opted in and we have no live session yet\n // (cold start, app data cleared, fresh install), reach out to the\n // backend with the device-bound identifier so the existing user is\n // restored before any UI hits an authenticated route.\n if (\n this.autoSignInConfig?.enabled &&\n !this.refreshTokenValue\n ) {\n try {\n const deviceInfo = await this.autoSignInConfig.getDeviceInfo();\n const metadata = this.autoSignInConfig.getMetadata\n ? await this.autoSignInConfig.getMetadata()\n : undefined;\n await this.signIn({ deviceInfo, metadata });\n } catch (error) {\n this.autoSignInConfig.onError?.(error);\n }\n }\n\n this._isLoading = false;\n this.notify();\n }\n\n async signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n // Coalesce concurrent signIn calls (e.g. autoSignIn racing a manual\n // signIn from a UI handler) onto a single network request.\n if (this.signInPromise) return this.signInPromise;\n this.signInPromise = this._signIn(params).finally(() => {\n this.signInPromise = null;\n });\n return this.signInPromise;\n }\n\n private async _signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n const providerId = this.deviceIdProvider\n ? await this.deviceIdProvider.getDeviceId()\n : null;\n const deviceId =\n params.deviceId ??\n this.deviceId ??\n providerId ??\n this.generateDeviceId();\n\n const response = await this.api.post<AuthTokenResponse>(\"/auth/token\", {\n deviceId,\n deviceInfo: params.deviceInfo,\n metadata: params.metadata,\n });\n\n const data = response.data;\n this.accessToken = data.accessToken;\n this.refreshTokenValue = data.refreshToken;\n this.user = data.user;\n this.deviceId = deviceId;\n\n // Persist. Storage failures (full disk, locked keychain post-restore,\n // EncryptedSharedPreferences key invalidation) must not strand the\n // in-memory session — the user is signed in for this run; the next\n // cold start will simply re-trigger autoSignIn.\n if (this.storage) {\n try {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n data.refreshToken,\n );\n await this.storage.setItem(\n `${this.storageKey}_user`,\n JSON.stringify(data.user),\n );\n await this.storage.setItem(`${this.storageKey}_device_id`, deviceId);\n } catch (error) {\n console.warn(\"[CodixusClient] Failed to persist auth state:\", error);\n }\n }\n\n this.notify();\n return { user: data.user, isNewUser: data.isNewUser };\n }\n\n async getToken(): Promise<string | null> {\n if (this.accessToken) return this.accessToken;\n\n // Try refresh\n if (this.refreshTokenValue) {\n try {\n await this.forceRefresh();\n return this.accessToken;\n } catch {\n return null;\n }\n }\n\n return null;\n }\n\n async forceRefresh(): Promise<string | null> {\n if (!this.refreshTokenValue) return null;\n\n try {\n const response = await this.api.post<{\n success: boolean;\n accessToken: string;\n refreshToken: string;\n }>(\"/auth/refresh\", {\n refreshToken: this.refreshTokenValue,\n });\n\n this.accessToken = response.data.accessToken;\n this.refreshTokenValue = response.data.refreshToken;\n\n if (this.storage) {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n response.data.refreshToken,\n );\n }\n\n return this.accessToken;\n } catch {\n // Refresh failed, clear auth state\n await this.signOut();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n // Notify server\n if (this.refreshTokenValue) {\n try {\n await this.api.post(\"/auth/logout\", {\n refreshToken: this.refreshTokenValue,\n });\n } catch {}\n }\n\n this.accessToken = null;\n this.refreshTokenValue = null;\n this.user = null;\n // Reset guards so a fresh signIn flow (or a re-init triggered by a\n // host that wants to re-authenticate after sign-out) can run. The\n // signInPromise is also cleared by its own .finally, but a signOut\n // racing against an in-flight signIn shouldn't keep the stale guard.\n this.initPromise = null;\n this.signInPromise = null;\n\n if (this.storage) {\n await this.storage.removeItem(`${this.storageKey}_refresh_token`);\n await this.storage.removeItem(`${this.storageKey}_user`);\n await this.storage.removeItem(`${this.storageKey}_device_id`);\n }\n\n this.notify();\n }\n\n getState(): AuthState {\n return {\n isAuthenticated: this.accessToken !== null || this.refreshTokenValue !== null,\n isLoading: this._isLoading,\n user: this.user,\n };\n }\n\n getDeviceId(): string | null {\n return this.deviceId;\n }\n\n onAuthStateChange(listener: AuthStateListener): () => void {\n this.listeners.add(listener);\n // Call immediately with current state\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** @internal - used by API interceptor */\n _getAccessToken(): string | null {\n return this.accessToken;\n }\n\n /** @internal - called by API interceptor after refresh */\n _setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n private notify(): void {\n const state = this.getState();\n for (const listener of this.listeners) {\n listener(state);\n }\n }\n\n private generateDeviceId(): string {\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n return \"dev-\" + Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n }\n}\n","import axios, {\n type AxiosInstance,\n type AxiosRequestConfig,\n type AxiosResponse,\n} from \"axios\";\nimport type { AuthManager } from \"../auth/auth-manager.js\";\n\n// Crypto functions — injected from outside to avoid platform-specific imports\nexport interface CryptoProvider {\n sha256(data: string): Promise<string>;\n hmacSha256(secret: string, data: string): Promise<string>;\n randomUUID(): string;\n}\n\n// Default: no-op (signing disabled if no crypto provider)\nlet _crypto: CryptoProvider | null = null;\n\nexport function setCryptoProvider(provider: CryptoProvider): void {\n _crypto = provider;\n}\n\nfunction generateNonce(): string {\n if (_crypto) return _crypto.randomUUID();\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport class ApiClient {\n readonly instance: AxiosInstance;\n private refreshPromise: Promise<string | null> | null = null;\n private appSecret: string | undefined;\n\n constructor(\n baseURL: string,\n private authManager: AuthManager,\n appSecret?: string,\n ) {\n this.appSecret = appSecret;\n\n this.instance = axios.create({\n baseURL,\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n // Request interceptor: add Bearer token + signing\n this.instance.interceptors.request.use(async (config) => {\n // Skip auth for auth endpoints\n if (!config.url?.includes(\"/auth/\")) {\n const token = this.authManager._getAccessToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n }\n\n // Request signing (only if crypto provider is set)\n if (this.appSecret && _crypto) {\n const timestamp = Date.now().toString();\n const nonce = _crypto.randomUUID();\n const body =\n config.data && typeof config.data === \"object\"\n ? JSON.stringify(config.data)\n : (config.data ?? \"\");\n const bodyHash = body ? await _crypto.sha256(body) : \"\";\n const method = (config.method ?? \"GET\").toUpperCase();\n const url = config.url ?? \"/\";\n const payload = [method, url, timestamp, nonce, bodyHash].join(\"\\n\");\n const signature = await _crypto.hmacSha256(this.appSecret, payload);\n\n config.headers[\"X-Codixus-Timestamp\"] = timestamp;\n config.headers[\"X-Codixus-Nonce\"] = nonce;\n config.headers[\"X-Codixus-Signature\"] = signature;\n }\n\n return config;\n });\n\n // Response interceptor: handle 401 with token refresh\n this.instance.interceptors.response.use(\n (response) => response,\n async (error) => {\n if (error.response?.status === 401) {\n const originalRequest = error.config;\n if (originalRequest && !originalRequest._retry) {\n originalRequest._retry = true;\n\n try {\n if (!this.refreshPromise) {\n this.refreshPromise = this.authManager\n .forceRefresh()\n .finally(() => {\n this.refreshPromise = null;\n });\n }\n\n const newToken = await this.refreshPromise;\n if (newToken) {\n originalRequest.headers.Authorization = `Bearer ${newToken}`;\n return this.instance(originalRequest);\n }\n } catch (refreshError) {\n console.warn(\"[CodixusClient] Token refresh failed:\", refreshError);\n }\n }\n }\n return Promise.reject(error);\n },\n );\n }\n\n async get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.get<T>(url, config);\n }\n\n async post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.post<T>(url, data, config);\n }\n\n async patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.patch<T>(url, data, config);\n }\n\n async delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.delete<T>(url, config);\n }\n\n async put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {\n return this.instance.put<T>(url, data, config);\n }\n}\n","import type { ApiClient } from \"../api/api-client.js\";\n\nexport interface FindOptions {\n sort?: Record<string, 1 | -1>;\n limit?: number;\n skip?: number;\n cursor?: string | number;\n}\n\nexport class Collection<T = Record<string, unknown>> {\n constructor(\n private api: ApiClient,\n private basePath: string,\n ) {}\n\n async find(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<T[]> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.skip) params.set(\"skip\", String(options.skip));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor?: string | null }>(url);\n return data.data;\n }\n\n async findWithCursor(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<{ data: T[]; nextCursor: string | number | null }> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor: string | number | null }>(url);\n return { data: data.data, nextCursor: data.nextCursor };\n }\n\n async findById(id: string): Promise<T | null> {\n try {\n const { data } = await this.api.get<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n );\n return data.data;\n } catch (error: any) {\n if (error.response?.status === 404) return null;\n throw error;\n }\n }\n\n async create(doc: Partial<T> & Record<string, unknown>): Promise<T> {\n const { data } = await this.api.post<{ success: boolean; data: T }>(\n this.basePath,\n doc,\n );\n return data.data;\n }\n\n async updateById(\n id: string,\n update: Record<string, unknown>,\n ): Promise<T> {\n const { data } = await this.api.patch<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n { update },\n );\n return data.data;\n }\n\n async deleteById(id: string): Promise<void> {\n await this.api.delete(`${this.basePath}/${id}`);\n }\n\n async count(filter?: Record<string, unknown>): Promise<number> {\n const { data } = await this.api.post<{ success: boolean; count: number }>(\n `${this.basePath}/count`,\n { filter: filter ?? {} },\n );\n return data.count;\n }\n}\n","import type { ApiClient } from \"../api/api-client.js\";\nimport type { AuthManager } from \"../auth/auth-manager.js\";\nimport type { PushAdapter } from \"./types.js\";\n\nfunction extractDeliveryId(\n payload: Record<string, unknown>,\n): string | undefined {\n if (typeof payload.deliveryId === \"string\" && payload.deliveryId) {\n return payload.deliveryId;\n }\n const data = payload.data;\n if (data && typeof data === \"object\" && !Array.isArray(data)) {\n const nested = (data as Record<string, unknown>).deliveryId;\n if (typeof nested === \"string\" && nested) {\n return nested;\n }\n }\n return undefined;\n}\n\nexport class PushManager {\n constructor(\n private adapter: PushAdapter,\n private api: ApiClient,\n private auth: AuthManager,\n ) {}\n\n async register(): Promise<void> {\n const authToken = await this.auth.getToken();\n if (!authToken) {\n throw new Error(\"Not authenticated\");\n }\n\n const adapterToken = await this.adapter.getToken();\n if (!adapterToken) {\n return;\n }\n\n const body: Record<string, unknown> = {\n token: adapterToken.token,\n provider: adapterToken.provider,\n platform: adapterToken.platform,\n };\n\n try {\n body.permissionStatus = await this.adapter.getPermissionStatus();\n } catch {\n // omit permissionStatus, still POST\n }\n\n await this.api.post(\"/push/register\", body);\n }\n\n async unregister(): Promise<void> {\n const authToken = await this.auth.getToken();\n if (!authToken) {\n throw new Error(\"Not authenticated\");\n }\n\n await this.api.post(\"/push/unregister\", {});\n }\n\n async requestPermission(): Promise<boolean> {\n return this.adapter.requestPermission();\n }\n\n async getPermissionStatus(): Promise<\n \"granted\" | \"denied\" | \"undetermined\"\n > {\n return this.adapter.getPermissionStatus();\n }\n\n addNotificationOpenedListener(\n handler: (payload: Record<string, unknown>) => void,\n ): () => void {\n return this.adapter.addNotificationOpenedListener((payload) => {\n handler(payload);\n const deliveryId = extractDeliveryId(payload);\n if (deliveryId) {\n void this.reportOpen(deliveryId);\n }\n });\n }\n\n addNotificationReceivedListener(\n handler: (payload: Record<string, unknown>) => void,\n ): () => void {\n return this.adapter.addNotificationReceivedListener(handler);\n }\n\n private async reportOpen(deliveryId: string): Promise<void> {\n try {\n const authToken = await this.auth.getToken();\n if (!authToken) return;\n await this.api.post(\"/push/open\", { deliveryId });\n } catch {\n // fire-and-forget: swallow 404, 401, 5xx, network errors\n }\n }\n}\n","import {\n AuthManager,\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n type DeviceIdProvider,\n type AutoSignInConfig,\n} from \"./auth/auth-manager.js\";\nimport { ApiClient } from \"./api/api-client.js\";\nimport { Collection, type FindOptions } from \"./db/collection.js\";\nimport { PushManager } from \"./push/push-manager.js\";\nimport type { PushAdapter } from \"./push/types.js\";\n\nexport interface CodixusClientConfig {\n apiUrl: string;\n storageKey?: string;\n storage?: StorageAdapter | null;\n appSecret?: string;\n deviceIdProvider?: DeviceIdProvider | null;\n autoSignIn?: AutoSignInConfig | null;\n push?: PushAdapter;\n}\n\nexport class CodixusClient {\n readonly auth: AuthManager;\n readonly api: ApiClient;\n readonly push?: PushManager;\n\n constructor(config: CodixusClientConfig) {\n const storageKey = config.storageKey ?? \"codixus\";\n const storage = config.storage ?? null;\n\n this.auth = new AuthManager(storage, storageKey, {\n deviceIdProvider: config.deviceIdProvider ?? null,\n autoSignIn: config.autoSignIn ?? null,\n });\n this.api = new ApiClient(config.apiUrl, this.auth, config.appSecret);\n this.auth._setApi(this.api);\n\n if (config.push) {\n this.push = new PushManager(config.push, this.api, this.auth);\n }\n }\n\n /**\n * Create a typed collection accessor.\n * Maps to auto REST routes on server: codixus.rest(Model)\n *\n * @example\n * interface Product { _id: string; name: string; price: number; }\n * const products = codixus.collection<Product>(\"products\");\n * const all = await products.find(); // Product[]\n * const one = await products.findById(\"abc\"); // Product | null\n */\n collection<T>(name: string): Collection<T> {\n return new Collection<T>(this.api, `/api/${name}`);\n }\n\n async init(): Promise<void> {\n await this.auth.init();\n }\n}\n\nexport {\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n type DeviceIdProvider,\n type AutoSignInConfig,\n} from \"./auth/auth-manager.js\";\nexport { ApiClient, setCryptoProvider, type CryptoProvider } from \"./api/api-client.js\";\nexport { Collection, type FindOptions } from \"./db/collection.js\";\nexport { type PushAdapter, type PushAdapterToken } from \"./push/types.js\";\n\n// Re-export shared types\nexport {\n type AuthUser,\n type TokenPair,\n type DeviceInfo,\n type DeviceMetadata,\n type AuthTokenRequest,\n type AuthTokenResponse,\n type ApiResponse,\n CodixusError,\n ErrorCodes,\n} from \"@codixus/shared\";\n"],"mappings":"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","names":[]}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/push-expo/index.ts
31
+ var push_expo_exports = {};
32
+ __export(push_expo_exports, {
33
+ createExpoAdapter: () => createExpoAdapter
34
+ });
35
+ module.exports = __toCommonJS(push_expo_exports);
36
+ var Notifications = __toESM(require("expo-notifications"), 1);
37
+ var import_react_native = require("react-native");
38
+ function resolvePlatform() {
39
+ if (import_react_native.Platform.OS === "ios" || import_react_native.Platform.OS === "android") {
40
+ return import_react_native.Platform.OS;
41
+ }
42
+ return null;
43
+ }
44
+ function flattenPayload(notification) {
45
+ const data = notification.request.content.data;
46
+ if (data && typeof data === "object" && !Array.isArray(data)) {
47
+ return { ...data };
48
+ }
49
+ return {};
50
+ }
51
+ function mapPermissionStatus(status) {
52
+ if (status === "granted") {
53
+ return "granted";
54
+ }
55
+ if (status === "denied") {
56
+ return "denied";
57
+ }
58
+ return "undetermined";
59
+ }
60
+ var noopUnsubscribe = () => {
61
+ };
62
+ function createNoopAdapter() {
63
+ return {
64
+ getPermissionStatus: async () => "denied",
65
+ requestPermission: async () => false,
66
+ getToken: async () => null,
67
+ addNotificationReceivedListener: () => noopUnsubscribe,
68
+ addNotificationOpenedListener: () => noopUnsubscribe
69
+ };
70
+ }
71
+ function createExpoAdapter(opts) {
72
+ const platform = resolvePlatform();
73
+ if (!platform) {
74
+ return createNoopAdapter();
75
+ }
76
+ return {
77
+ async getPermissionStatus() {
78
+ const { status } = await Notifications.getPermissionsAsync();
79
+ return mapPermissionStatus(status);
80
+ },
81
+ async requestPermission() {
82
+ const { status } = await Notifications.requestPermissionsAsync();
83
+ return status === "granted";
84
+ },
85
+ async getToken() {
86
+ const permission = await this.getPermissionStatus();
87
+ if (permission !== "granted") {
88
+ return null;
89
+ }
90
+ try {
91
+ const result = await Notifications.getExpoPushTokenAsync({
92
+ projectId: opts.projectId
93
+ });
94
+ return {
95
+ token: result.data,
96
+ provider: "expo",
97
+ platform
98
+ };
99
+ } catch {
100
+ return null;
101
+ }
102
+ },
103
+ addNotificationReceivedListener(handler) {
104
+ const subscription = Notifications.addNotificationReceivedListener(
105
+ (notification) => {
106
+ handler(flattenPayload(notification));
107
+ }
108
+ );
109
+ return () => subscription.remove();
110
+ },
111
+ addNotificationOpenedListener(handler) {
112
+ const subscription = Notifications.addNotificationResponseReceivedListener((response) => {
113
+ handler(flattenPayload(response.notification));
114
+ });
115
+ return () => subscription.remove();
116
+ }
117
+ };
118
+ }
119
+ // Annotate the CommonJS export names for ESM import in node:
120
+ 0 && (module.exports = {
121
+ createExpoAdapter
122
+ });
123
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/push-expo/index.ts"],"sourcesContent":["import * as Notifications from \"expo-notifications\";\nimport { Platform } from \"react-native\";\nimport type { PushAdapter, PushAdapterToken } from \"../push/types.js\";\n\nexport type { PushAdapter, PushAdapterToken } from \"../push/types.js\";\n\ntype PlatformOS = \"ios\" | \"android\";\n\nfunction resolvePlatform(): PlatformOS | null {\n if (Platform.OS === \"ios\" || Platform.OS === \"android\") {\n return Platform.OS;\n }\n return null;\n}\n\nfunction flattenPayload(\n notification: Notifications.Notification,\n): Record<string, unknown> {\n const data = notification.request.content.data;\n if (data && typeof data === \"object\" && !Array.isArray(data)) {\n return { ...(data as Record<string, unknown>) };\n }\n return {};\n}\n\nfunction mapPermissionStatus(\n status: string,\n): \"granted\" | \"denied\" | \"undetermined\" {\n if (status === \"granted\") {\n return \"granted\";\n }\n if (status === \"denied\") {\n return \"denied\";\n }\n return \"undetermined\";\n}\n\nconst noopUnsubscribe = (): void => {};\n\nfunction createNoopAdapter(): PushAdapter {\n return {\n getPermissionStatus: async () => \"denied\",\n requestPermission: async () => false,\n getToken: async () => null,\n addNotificationReceivedListener: () => noopUnsubscribe,\n addNotificationOpenedListener: () => noopUnsubscribe,\n };\n}\n\nexport function createExpoAdapter(opts: { projectId: string }): PushAdapter {\n const platform = resolvePlatform();\n if (!platform) {\n return createNoopAdapter();\n }\n\n return {\n async getPermissionStatus() {\n const { status } = await Notifications.getPermissionsAsync();\n return mapPermissionStatus(status);\n },\n\n async requestPermission() {\n const { status } = await Notifications.requestPermissionsAsync();\n return status === \"granted\";\n },\n\n async getToken(): Promise<PushAdapterToken | null> {\n const permission = await this.getPermissionStatus();\n if (permission !== \"granted\") {\n return null;\n }\n\n try {\n const result = await Notifications.getExpoPushTokenAsync({\n projectId: opts.projectId,\n });\n return {\n token: result.data,\n provider: \"expo\",\n platform,\n };\n } catch {\n return null;\n }\n },\n\n addNotificationReceivedListener(handler) {\n const subscription = Notifications.addNotificationReceivedListener(\n (notification) => {\n handler(flattenPayload(notification));\n },\n );\n return () => subscription.remove();\n },\n\n addNotificationOpenedListener(handler) {\n const subscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n handler(flattenPayload(response.notification));\n });\n return () => subscription.remove();\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA+B;AAC/B,0BAAyB;AAOzB,SAAS,kBAAqC;AAC5C,MAAI,6BAAS,OAAO,SAAS,6BAAS,OAAO,WAAW;AACtD,WAAO,6BAAS;AAAA,EAClB;AACA,SAAO;AACT;AAEA,SAAS,eACP,cACyB;AACzB,QAAM,OAAO,aAAa,QAAQ,QAAQ;AAC1C,MAAI,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,GAAG;AAC5D,WAAO,EAAE,GAAI,KAAiC;AAAA,EAChD;AACA,SAAO,CAAC;AACV;AAEA,SAAS,oBACP,QACuC;AACvC,MAAI,WAAW,WAAW;AACxB,WAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,IAAM,kBAAkB,MAAY;AAAC;AAErC,SAAS,oBAAiC;AACxC,SAAO;AAAA,IACL,qBAAqB,YAAY;AAAA,IACjC,mBAAmB,YAAY;AAAA,IAC/B,UAAU,YAAY;AAAA,IACtB,iCAAiC,MAAM;AAAA,IACvC,+BAA+B,MAAM;AAAA,EACvC;AACF;AAEO,SAAS,kBAAkB,MAA0C;AAC1E,QAAM,WAAW,gBAAgB;AACjC,MAAI,CAAC,UAAU;AACb,WAAO,kBAAkB;AAAA,EAC3B;AAEA,SAAO;AAAA,IACL,MAAM,sBAAsB;AAC1B,YAAM,EAAE,OAAO,IAAI,MAAoB,kCAAoB;AAC3D,aAAO,oBAAoB,MAAM;AAAA,IACnC;AAAA,IAEA,MAAM,oBAAoB;AACxB,YAAM,EAAE,OAAO,IAAI,MAAoB,sCAAwB;AAC/D,aAAO,WAAW;AAAA,IACpB;AAAA,IAEA,MAAM,WAA6C;AACjD,YAAM,aAAa,MAAM,KAAK,oBAAoB;AAClD,UAAI,eAAe,WAAW;AAC5B,eAAO;AAAA,MACT;AAEA,UAAI;AACF,cAAM,SAAS,MAAoB,oCAAsB;AAAA,UACvD,WAAW,KAAK;AAAA,QAClB,CAAC;AACD,eAAO;AAAA,UACL,OAAO,OAAO;AAAA,UACd,UAAU;AAAA,UACV;AAAA,QACF;AAAA,MACF,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,gCAAgC,SAAS;AACvC,YAAM,eAA6B;AAAA,QACjC,CAAC,iBAAiB;AAChB,kBAAQ,eAAe,YAAY,CAAC;AAAA,QACtC;AAAA,MACF;AACA,aAAO,MAAM,aAAa,OAAO;AAAA,IACnC;AAAA,IAEA,8BAA8B,SAAS;AACrC,YAAM,eACU,sDAAwC,CAAC,aAAa;AAClE,gBAAQ,eAAe,SAAS,YAAY,CAAC;AAAA,MAC/C,CAAC;AACH,aAAO,MAAM,aAAa,OAAO;AAAA,IACnC;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,8 @@
1
+ import { P as PushAdapter } from '../types-maS8y9s9.cjs';
2
+ export { a as PushAdapterToken } from '../types-maS8y9s9.cjs';
3
+
4
+ declare function createExpoAdapter(opts: {
5
+ projectId: string;
6
+ }): PushAdapter;
7
+
8
+ export { PushAdapter, createExpoAdapter };
@@ -0,0 +1,8 @@
1
+ import { P as PushAdapter } from '../types-maS8y9s9.js';
2
+ export { a as PushAdapterToken } from '../types-maS8y9s9.js';
3
+
4
+ declare function createExpoAdapter(opts: {
5
+ projectId: string;
6
+ }): PushAdapter;
7
+
8
+ export { PushAdapter, createExpoAdapter };
@@ -0,0 +1,88 @@
1
+ // src/push-expo/index.ts
2
+ import * as Notifications from "expo-notifications";
3
+ import { Platform } from "react-native";
4
+ function resolvePlatform() {
5
+ if (Platform.OS === "ios" || Platform.OS === "android") {
6
+ return Platform.OS;
7
+ }
8
+ return null;
9
+ }
10
+ function flattenPayload(notification) {
11
+ const data = notification.request.content.data;
12
+ if (data && typeof data === "object" && !Array.isArray(data)) {
13
+ return { ...data };
14
+ }
15
+ return {};
16
+ }
17
+ function mapPermissionStatus(status) {
18
+ if (status === "granted") {
19
+ return "granted";
20
+ }
21
+ if (status === "denied") {
22
+ return "denied";
23
+ }
24
+ return "undetermined";
25
+ }
26
+ var noopUnsubscribe = () => {
27
+ };
28
+ function createNoopAdapter() {
29
+ return {
30
+ getPermissionStatus: async () => "denied",
31
+ requestPermission: async () => false,
32
+ getToken: async () => null,
33
+ addNotificationReceivedListener: () => noopUnsubscribe,
34
+ addNotificationOpenedListener: () => noopUnsubscribe
35
+ };
36
+ }
37
+ function createExpoAdapter(opts) {
38
+ const platform = resolvePlatform();
39
+ if (!platform) {
40
+ return createNoopAdapter();
41
+ }
42
+ return {
43
+ async getPermissionStatus() {
44
+ const { status } = await Notifications.getPermissionsAsync();
45
+ return mapPermissionStatus(status);
46
+ },
47
+ async requestPermission() {
48
+ const { status } = await Notifications.requestPermissionsAsync();
49
+ return status === "granted";
50
+ },
51
+ async getToken() {
52
+ const permission = await this.getPermissionStatus();
53
+ if (permission !== "granted") {
54
+ return null;
55
+ }
56
+ try {
57
+ const result = await Notifications.getExpoPushTokenAsync({
58
+ projectId: opts.projectId
59
+ });
60
+ return {
61
+ token: result.data,
62
+ provider: "expo",
63
+ platform
64
+ };
65
+ } catch {
66
+ return null;
67
+ }
68
+ },
69
+ addNotificationReceivedListener(handler) {
70
+ const subscription = Notifications.addNotificationReceivedListener(
71
+ (notification) => {
72
+ handler(flattenPayload(notification));
73
+ }
74
+ );
75
+ return () => subscription.remove();
76
+ },
77
+ addNotificationOpenedListener(handler) {
78
+ const subscription = Notifications.addNotificationResponseReceivedListener((response) => {
79
+ handler(flattenPayload(response.notification));
80
+ });
81
+ return () => subscription.remove();
82
+ }
83
+ };
84
+ }
85
+ export {
86
+ createExpoAdapter
87
+ };
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/push-expo/index.ts"],"sourcesContent":["import * as Notifications from \"expo-notifications\";\nimport { Platform } from \"react-native\";\nimport type { PushAdapter, PushAdapterToken } from \"../push/types.js\";\n\nexport type { PushAdapter, PushAdapterToken } from \"../push/types.js\";\n\ntype PlatformOS = \"ios\" | \"android\";\n\nfunction resolvePlatform(): PlatformOS | null {\n if (Platform.OS === \"ios\" || Platform.OS === \"android\") {\n return Platform.OS;\n }\n return null;\n}\n\nfunction flattenPayload(\n notification: Notifications.Notification,\n): Record<string, unknown> {\n const data = notification.request.content.data;\n if (data && typeof data === \"object\" && !Array.isArray(data)) {\n return { ...(data as Record<string, unknown>) };\n }\n return {};\n}\n\nfunction mapPermissionStatus(\n status: string,\n): \"granted\" | \"denied\" | \"undetermined\" {\n if (status === \"granted\") {\n return \"granted\";\n }\n if (status === \"denied\") {\n return \"denied\";\n }\n return \"undetermined\";\n}\n\nconst noopUnsubscribe = (): void => {};\n\nfunction createNoopAdapter(): PushAdapter {\n return {\n getPermissionStatus: async () => \"denied\",\n requestPermission: async () => false,\n getToken: async () => null,\n addNotificationReceivedListener: () => noopUnsubscribe,\n addNotificationOpenedListener: () => noopUnsubscribe,\n };\n}\n\nexport function createExpoAdapter(opts: { projectId: string }): PushAdapter {\n const platform = resolvePlatform();\n if (!platform) {\n return createNoopAdapter();\n }\n\n return {\n async getPermissionStatus() {\n const { status } = await Notifications.getPermissionsAsync();\n return mapPermissionStatus(status);\n },\n\n async requestPermission() {\n const { status } = await Notifications.requestPermissionsAsync();\n return status === \"granted\";\n },\n\n async getToken(): Promise<PushAdapterToken | null> {\n const permission = await this.getPermissionStatus();\n if (permission !== \"granted\") {\n return null;\n }\n\n try {\n const result = await Notifications.getExpoPushTokenAsync({\n projectId: opts.projectId,\n });\n return {\n token: result.data,\n provider: \"expo\",\n platform,\n };\n } catch {\n return null;\n }\n },\n\n addNotificationReceivedListener(handler) {\n const subscription = Notifications.addNotificationReceivedListener(\n (notification) => {\n handler(flattenPayload(notification));\n },\n );\n return () => subscription.remove();\n },\n\n addNotificationOpenedListener(handler) {\n const subscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n handler(flattenPayload(response.notification));\n });\n return () => subscription.remove();\n },\n };\n}\n"],"mappings":";AAAA,YAAY,mBAAmB;AAC/B,SAAS,gBAAgB;AAOzB,SAAS,kBAAqC;AAC5C,MAAI,SAAS,OAAO,SAAS,SAAS,OAAO,WAAW;AACtD,WAAO,SAAS;AAAA,EAClB;AACA,SAAO;AACT;AAEA,SAAS,eACP,cACyB;AACzB,QAAM,OAAO,aAAa,QAAQ,QAAQ;AAC1C,MAAI,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,GAAG;AAC5D,WAAO,EAAE,GAAI,KAAiC;AAAA,EAChD;AACA,SAAO,CAAC;AACV;AAEA,SAAS,oBACP,QACuC;AACvC,MAAI,WAAW,WAAW;AACxB,WAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,IAAM,kBAAkB,MAAY;AAAC;AAErC,SAAS,oBAAiC;AACxC,SAAO;AAAA,IACL,qBAAqB,YAAY;AAAA,IACjC,mBAAmB,YAAY;AAAA,IAC/B,UAAU,YAAY;AAAA,IACtB,iCAAiC,MAAM;AAAA,IACvC,+BAA+B,MAAM;AAAA,EACvC;AACF;AAEO,SAAS,kBAAkB,MAA0C;AAC1E,QAAM,WAAW,gBAAgB;AACjC,MAAI,CAAC,UAAU;AACb,WAAO,kBAAkB;AAAA,EAC3B;AAEA,SAAO;AAAA,IACL,MAAM,sBAAsB;AAC1B,YAAM,EAAE,OAAO,IAAI,MAAoB,kCAAoB;AAC3D,aAAO,oBAAoB,MAAM;AAAA,IACnC;AAAA,IAEA,MAAM,oBAAoB;AACxB,YAAM,EAAE,OAAO,IAAI,MAAoB,sCAAwB;AAC/D,aAAO,WAAW;AAAA,IACpB;AAAA,IAEA,MAAM,WAA6C;AACjD,YAAM,aAAa,MAAM,KAAK,oBAAoB;AAClD,UAAI,eAAe,WAAW;AAC5B,eAAO;AAAA,MACT;AAEA,UAAI;AACF,cAAM,SAAS,MAAoB,oCAAsB;AAAA,UACvD,WAAW,KAAK;AAAA,QAClB,CAAC;AACD,eAAO;AAAA,UACL,OAAO,OAAO;AAAA,UACd,UAAU;AAAA,UACV;AAAA,QACF;AAAA,MACF,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,gCAAgC,SAAS;AACvC,YAAM,eAA6B;AAAA,QACjC,CAAC,iBAAiB;AAChB,kBAAQ,eAAe,YAAY,CAAC;AAAA,QACtC;AAAA,MACF;AACA,aAAO,MAAM,aAAa,OAAO;AAAA,IACnC;AAAA,IAEA,8BAA8B,SAAS;AACrC,YAAM,eACU,sDAAwC,CAAC,aAAa;AAClE,gBAAQ,eAAe,SAAS,YAAY,CAAC;AAAA,MAC/C,CAAC;AACH,aAAO,MAAM,aAAa,OAAO;AAAA,IACnC;AAAA,EACF;AACF;","names":[]}
@@ -1,8 +1,9 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import { CodixusClient, AuthState, SignInParams } from '../index.cjs';
4
4
  import '@codixus/shared';
5
5
  import 'axios';
6
+ import '../types-maS8y9s9.cjs';
6
7
 
7
8
  interface CodixusContextValue {
8
9
  client: CodixusClient;
@@ -18,7 +19,7 @@ interface CodixusContextValue {
18
19
  declare function CodixusProvider({ client, children, }: {
19
20
  client: CodixusClient;
20
21
  children: ReactNode;
21
- }): react_jsx_runtime.JSX.Element;
22
+ }): react.JSX.Element;
22
23
  declare function useCodixus(): CodixusContextValue;
23
24
  declare function useAuth(): AuthState & {
24
25
  signIn: (params: SignInParams) => Promise<{
@@ -1,8 +1,9 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import { CodixusClient, AuthState, SignInParams } from '../index.js';
4
4
  import '@codixus/shared';
5
5
  import 'axios';
6
+ import '../types-maS8y9s9.js';
6
7
 
7
8
  interface CodixusContextValue {
8
9
  client: CodixusClient;
@@ -18,7 +19,7 @@ interface CodixusContextValue {
18
19
  declare function CodixusProvider({ client, children, }: {
19
20
  client: CodixusClient;
20
21
  children: ReactNode;
21
- }): react_jsx_runtime.JSX.Element;
22
+ }): react.JSX.Element;
22
23
  declare function useCodixus(): CodixusContextValue;
23
24
  declare function useAuth(): AuthState & {
24
25
  signIn: (params: SignInParams) => Promise<{
@@ -0,0 +1,14 @@
1
+ type PushAdapterToken = {
2
+ token: string;
3
+ provider: "expo" | "fcm" | "apns";
4
+ platform: "ios" | "android";
5
+ };
6
+ interface PushAdapter {
7
+ getPermissionStatus(): Promise<"granted" | "denied" | "undetermined">;
8
+ requestPermission(): Promise<boolean>;
9
+ getToken(): Promise<PushAdapterToken | null>;
10
+ addNotificationReceivedListener(handler: (payload: Record<string, unknown>) => void): () => void;
11
+ addNotificationOpenedListener(handler: (payload: Record<string, unknown>) => void): () => void;
12
+ }
13
+
14
+ export type { PushAdapter as P, PushAdapterToken as a };
@@ -0,0 +1,14 @@
1
+ type PushAdapterToken = {
2
+ token: string;
3
+ provider: "expo" | "fcm" | "apns";
4
+ platform: "ios" | "android";
5
+ };
6
+ interface PushAdapter {
7
+ getPermissionStatus(): Promise<"granted" | "denied" | "undetermined">;
8
+ requestPermission(): Promise<boolean>;
9
+ getToken(): Promise<PushAdapterToken | null>;
10
+ addNotificationReceivedListener(handler: (payload: Record<string, unknown>) => void): () => void;
11
+ addNotificationOpenedListener(handler: (payload: Record<string, unknown>) => void): () => void;
12
+ }
13
+
14
+ export type { PushAdapter as P, PushAdapterToken as a };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@codixus/client",
3
- "version": "0.1.5",
4
- "description": "Client SDK for React Native and web auth, API client, typed collections",
3
+ "version": "0.1.7",
4
+ "description": "Client SDK for React Native and web: auth, API client, typed collections",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
7
7
  "main": "./dist/index.cjs",
@@ -17,10 +17,25 @@
17
17
  "types": "./dist/react/index.d.ts",
18
18
  "import": "./dist/react/index.js",
19
19
  "require": "./dist/react/index.cjs"
20
+ },
21
+ "./push-expo": {
22
+ "types": "./dist/push-expo/index.d.ts",
23
+ "import": "./dist/push-expo/index.js",
24
+ "require": "./dist/push-expo/index.cjs"
20
25
  }
21
26
  },
22
- "files": ["dist", "LICENSE"],
23
- "keywords": ["codixus", "sdk", "client", "react-native", "auth", "api"],
27
+ "files": [
28
+ "dist",
29
+ "LICENSE"
30
+ ],
31
+ "keywords": [
32
+ "codixus",
33
+ "sdk",
34
+ "client",
35
+ "react-native",
36
+ "auth",
37
+ "api"
38
+ ],
24
39
  "repository": {
25
40
  "type": "git",
26
41
  "url": "https://github.com/codixus/sdk",
@@ -34,11 +49,17 @@
34
49
  "clean": "rm -rf dist"
35
50
  },
36
51
  "dependencies": {
37
- "@codixus/shared": "0.1.0",
52
+ "@codixus/shared": "0.1.7",
38
53
  "axios": "^1.7.0"
39
54
  },
40
55
  "peerDependencies": {
41
- "react": "^18.0.0 || ^19.0.0"
56
+ "react": "^18.0.0 || ^19.0.0",
57
+ "expo-notifications": "*"
58
+ },
59
+ "peerDependenciesMeta": {
60
+ "expo-notifications": {
61
+ "optional": true
62
+ }
42
63
  },
43
64
  "devDependencies": {
44
65
  "@types/react": "^19",