@codixus/client 0.1.4 → 0.1.6

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.js CHANGED
@@ -1,9 +1,12 @@
1
1
  // src/auth/auth-manager.ts
2
2
  var AuthManager = class {
3
- constructor(storage, storageKey) {
3
+ constructor(storage, storageKey, options) {
4
4
  this.storage = storage;
5
5
  this.storageKey = storageKey;
6
+ this.deviceIdProvider = options?.deviceIdProvider ?? null;
7
+ this.autoSignInConfig = options?.autoSignIn ?? null;
6
8
  }
9
+ storage;
7
10
  accessToken = null;
8
11
  refreshTokenValue = null;
9
12
  user = null;
@@ -12,45 +15,72 @@ var AuthManager = class {
12
15
  storageKey;
13
16
  api;
14
17
  deviceId = null;
18
+ deviceIdProvider;
19
+ autoSignInConfig;
20
+ initPromise = null;
21
+ signInPromise = null;
15
22
  /** @internal */
16
23
  _setApi(api) {
17
24
  this.api = api;
18
25
  }
19
26
  async init() {
20
- if (!this.storage) {
21
- this._isLoading = false;
22
- return;
23
- }
24
- try {
25
- const storedRefresh = await this.storage.getItem(
26
- `${this.storageKey}_refresh_token`
27
- );
28
- const storedUser = await this.storage.getItem(
29
- `${this.storageKey}_user`
30
- );
31
- const storedDeviceId = await this.storage.getItem(
32
- `${this.storageKey}_device_id`
33
- );
34
- if (storedRefresh) {
35
- this.refreshTokenValue = storedRefresh;
36
- }
37
- if (storedUser) {
38
- try {
39
- this.user = JSON.parse(storedUser);
40
- } catch {
27
+ if (this.initPromise) return this.initPromise;
28
+ this.initPromise = this._init().catch((err) => {
29
+ this.initPromise = null;
30
+ throw err;
31
+ });
32
+ return this.initPromise;
33
+ }
34
+ async _init() {
35
+ if (this.storage) {
36
+ try {
37
+ const storedRefresh = await this.storage.getItem(
38
+ `${this.storageKey}_refresh_token`
39
+ );
40
+ const storedUser = await this.storage.getItem(
41
+ `${this.storageKey}_user`
42
+ );
43
+ const storedDeviceId = await this.storage.getItem(
44
+ `${this.storageKey}_device_id`
45
+ );
46
+ if (storedRefresh) {
47
+ this.refreshTokenValue = storedRefresh;
48
+ }
49
+ if (storedUser) {
50
+ try {
51
+ this.user = JSON.parse(storedUser);
52
+ } catch {
53
+ }
41
54
  }
55
+ if (storedDeviceId) {
56
+ this.deviceId = storedDeviceId;
57
+ }
58
+ } catch (error) {
59
+ console.warn("[CodixusClient] Failed to restore auth state from storage:", error);
42
60
  }
43
- if (storedDeviceId) {
44
- this.deviceId = storedDeviceId;
61
+ }
62
+ if (this.autoSignInConfig?.enabled && !this.refreshTokenValue) {
63
+ try {
64
+ const deviceInfo = await this.autoSignInConfig.getDeviceInfo();
65
+ const metadata = this.autoSignInConfig.getMetadata ? await this.autoSignInConfig.getMetadata() : void 0;
66
+ await this.signIn({ deviceInfo, metadata });
67
+ } catch (error) {
68
+ this.autoSignInConfig.onError?.(error);
45
69
  }
46
- } catch (error) {
47
- console.warn("[CodixusClient] Failed to restore auth state from storage:", error);
48
70
  }
49
71
  this._isLoading = false;
50
72
  this.notify();
51
73
  }
52
74
  async signIn(params) {
53
- const deviceId = params.deviceId ?? this.deviceId ?? this.generateDeviceId();
75
+ if (this.signInPromise) return this.signInPromise;
76
+ this.signInPromise = this._signIn(params).finally(() => {
77
+ this.signInPromise = null;
78
+ });
79
+ return this.signInPromise;
80
+ }
81
+ async _signIn(params) {
82
+ const providerId = this.deviceIdProvider ? await this.deviceIdProvider.getDeviceId() : null;
83
+ const deviceId = params.deviceId ?? this.deviceId ?? providerId ?? this.generateDeviceId();
54
84
  const response = await this.api.post("/auth/token", {
55
85
  deviceId,
56
86
  deviceInfo: params.deviceInfo,
@@ -62,15 +92,19 @@ var AuthManager = class {
62
92
  this.user = data.user;
63
93
  this.deviceId = deviceId;
64
94
  if (this.storage) {
65
- await this.storage.setItem(
66
- `${this.storageKey}_refresh_token`,
67
- data.refreshToken
68
- );
69
- await this.storage.setItem(
70
- `${this.storageKey}_user`,
71
- JSON.stringify(data.user)
72
- );
73
- await this.storage.setItem(`${this.storageKey}_device_id`, deviceId);
95
+ try {
96
+ await this.storage.setItem(
97
+ `${this.storageKey}_refresh_token`,
98
+ data.refreshToken
99
+ );
100
+ await this.storage.setItem(
101
+ `${this.storageKey}_user`,
102
+ JSON.stringify(data.user)
103
+ );
104
+ await this.storage.setItem(`${this.storageKey}_device_id`, deviceId);
105
+ } catch (error) {
106
+ console.warn("[CodixusClient] Failed to persist auth state:", error);
107
+ }
74
108
  }
75
109
  this.notify();
76
110
  return { user: data.user, isNewUser: data.isNewUser };
@@ -119,6 +153,8 @@ var AuthManager = class {
119
153
  this.accessToken = null;
120
154
  this.refreshTokenValue = null;
121
155
  this.user = null;
156
+ this.initPromise = null;
157
+ this.signInPromise = null;
122
158
  if (this.storage) {
123
159
  await this.storage.removeItem(`${this.storageKey}_refresh_token`);
124
160
  await this.storage.removeItem(`${this.storageKey}_user`);
@@ -233,6 +269,7 @@ var ApiClient = class {
233
269
  }
234
270
  );
235
271
  }
272
+ authManager;
236
273
  instance;
237
274
  refreshPromise = null;
238
275
  appSecret;
@@ -259,6 +296,8 @@ var Collection = class {
259
296
  this.api = api;
260
297
  this.basePath = basePath;
261
298
  }
299
+ api;
300
+ basePath;
262
301
  async find(filter, options) {
263
302
  const params = new URLSearchParams();
264
303
  if (filter && Object.keys(filter).length > 0) {
@@ -323,6 +362,84 @@ var Collection = class {
323
362
  }
324
363
  };
325
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
+
326
443
  // src/index.ts
327
444
  import {
328
445
  CodixusError,
@@ -331,12 +448,19 @@ import {
331
448
  var CodixusClient = class {
332
449
  auth;
333
450
  api;
451
+ push;
334
452
  constructor(config) {
335
453
  const storageKey = config.storageKey ?? "codixus";
336
454
  const storage = config.storage ?? null;
337
- this.auth = new AuthManager(storage, storageKey);
455
+ this.auth = new AuthManager(storage, storageKey, {
456
+ deviceIdProvider: config.deviceIdProvider ?? null,
457
+ autoSignIn: config.autoSignIn ?? null
458
+ });
338
459
  this.api = new ApiClient(config.apiUrl, this.auth, config.appSecret);
339
460
  this.auth._setApi(this.api);
461
+ if (config.push) {
462
+ this.push = new PushManager(config.push, this.api, this.auth);
463
+ }
340
464
  }
341
465
  /**
342
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\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\n constructor(\n private storage: StorageAdapter | null,\n storageKey: string,\n ) {\n this.storageKey = storageKey;\n }\n\n /** @internal */\n _setApi(api: ApiClient): void {\n this.api = api;\n }\n\n async init(): Promise<void> {\n if (!this.storage) {\n this._isLoading = false;\n return;\n }\n\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 this._isLoading = false;\n this.notify();\n }\n\n async signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n const deviceId = params.deviceId ?? this.deviceId ?? 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\n if (this.storage) {\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 }\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\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} 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}\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 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} 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