@layers/amba-web 4.0.1 → 4.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +161 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +196 -3
- package/dist/index.js.map +1 -1
- package/dist-rn/index.d.ts +161 -2
- package/dist-rn/index.js +196 -3
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["prefix: string","coreInstance: AmbaCoreWasm | null","_configuredProjectId: string | null","wasmJsUrl: string","uploadHeaders: Record<string, string>"],"sources":["../src/storage-adapter.ts","../src/json.ts","../src/error.ts","../src/index.ts"],"sourcesContent":["/**\n * Browser localStorage adapter for SDK identity persistence.\n *\n * The SDK runtime currently re-seeds an `anonymous_id` on every page load.\n * This adapter is the documented home for storage-prefix handling so\n * customers can override the localStorage key prefix used by the\n * (eventual) identity cache.\n */\nexport class LocalStoragePersistence {\n constructor(private readonly prefix: string) {}\n\n /** Read everything we'd want to hydrate at init. No-op until wired through. */\n hydrate(): void {\n // Reserved for v0.2 — the SDK runtime will gain a persistence bridge\n // that calls into JS for read/write/list/delete.\n }\n\n read(key: string): string | null {\n if (typeof localStorage === \"undefined\") return null;\n return localStorage.getItem(`${this.prefix}:${key}`);\n }\n\n write(key: string, value: string): void {\n if (typeof localStorage === \"undefined\") return;\n localStorage.setItem(`${this.prefix}:${key}`, value);\n }\n\n delete(key: string): void {\n if (typeof localStorage === \"undefined\") return;\n localStorage.removeItem(`${this.prefix}:${key}`);\n }\n}\n","/**\n * JSON encode helper — guarantees stable serialization across browser\n * runtimes and provides a single hook for future schema validation.\n */\nexport function encodeJson(value: unknown): string {\n return JSON.stringify(value);\n}\n","/**\n * Typed error class for the amba SDK + helper that converts arbitrary\n * thrown values (native Error, plain objects, runtime-emitted errors)\n * into a stable `AmbaApiError` instance.\n *\n * Callers can `instanceof`-narrow safely, branch on `.code`, and pull\n * extra payload from `.details` (raw HTTP body, validation field paths,\n * etc.). The wrapper methods on `Amba` wrap every async call in\n * `toAmbaApiError`, so consumers see one error shape regardless of\n * which layer (network, runtime, validation) failed.\n */\n\n/**\n * Stable error codes surfaced by the SDK. Strings rather than an enum\n * so customers can extend with custom codes by simply throwing\n * `new AmbaApiError(\"MY_CODE\", \"...\")` without coordinating with this\n * package's TypeScript types.\n */\nexport type AmbaApiErrorCode =\n | \"UNAUTHORIZED\"\n | \"FORBIDDEN\"\n | \"NOT_FOUND\"\n | \"CONFLICT\"\n | \"RATE_LIMITED\"\n | \"VALIDATION_ERROR\"\n | \"NETWORK_ERROR\"\n | \"HTTP_ERROR\"\n | \"CIRCUIT_OPEN\"\n | \"CONSENT_NOT_GRANTED\"\n | \"NOT_INITIALIZED\"\n | \"INVALID_CONFIG\"\n | \"INVALID_ARGUMENT\"\n | \"PUSH_PERMISSION_DENIED\"\n | \"PUSH_REGISTRATION_FAILED\"\n | \"NOT_SANDBOX_TIER\"\n | \"UNKNOWN_ERROR\"\n | (string & {});\n\nexport class AmbaApiError extends Error {\n readonly code: AmbaApiErrorCode;\n readonly details?: unknown;\n constructor(\n code: AmbaApiErrorCode,\n message: string,\n details?: unknown,\n ) {\n super(message);\n this.name = \"AmbaApiError\";\n this.code = code;\n this.details = details;\n // Restore prototype chain when transpiled to ES5 targets — Error\n // subclasses lose their prototype otherwise and `instanceof` breaks.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Best-effort: pull a stable error code out of a Rust `AmbaError`\n * Display string. Used by `toAmbaApiError` when the underlying thrown\n * value is a generic `Error` produced by `wasm-bindgen`'s `JsError::new`.\n *\n * Keep in sync with `sdks/core/src/error.rs::AmbaError`'s `#[error]`\n * format strings — but the parser falls back to UNKNOWN_ERROR for any\n * pattern it doesn't recognize, so a stale match list isn't a footgun,\n * just a quality-of-life regression.\n */\nfunction codeFromMessage(message: string): AmbaApiErrorCode {\n // Cheapest checks first — most production errors are auth or HTTP.\n if (message.startsWith(\"Unauthorized\")) return \"UNAUTHORIZED\";\n if (message.startsWith(\"Forbidden\")) return \"FORBIDDEN\";\n if (message.startsWith(\"Not found\")) return \"NOT_FOUND\";\n if (message.startsWith(\"Conflict\")) return \"CONFLICT\";\n if (message.startsWith(\"Rate limited\")) return \"RATE_LIMITED\";\n if (message.startsWith(\"Validation error\")) return \"VALIDATION_ERROR\";\n if (message.startsWith(\"Network error\")) return \"NETWORK_ERROR\";\n if (message.startsWith(\"HTTP error\")) return \"HTTP_ERROR\";\n if (message.startsWith(\"Circuit breaker\")) return \"CIRCUIT_OPEN\";\n if (message.startsWith(\"Consent not granted\")) return \"CONSENT_NOT_GRANTED\";\n if (message.includes(\"not initialized\")) return \"NOT_INITIALIZED\";\n if (message.startsWith(\"Invalid configuration\")) return \"INVALID_CONFIG\";\n if (message.startsWith(\"Invalid argument\")) return \"INVALID_ARGUMENT\";\n return \"UNKNOWN_ERROR\";\n}\n\n/**\n * Coerce any thrown value into an `AmbaApiError`. Idempotent — passing\n * an existing `AmbaApiError` returns it unchanged so wrappers can stack\n * without re-wrapping.\n *\n * Heuristics:\n * 1. Existing `AmbaApiError` → returned as-is.\n * 2. Object with `.code` → use that code + `.message` + `.details`.\n * 3. `Error` (e.g. runtime-emitted error) → infer code from message prefix.\n * 4. Anything else → stringify and tag UNKNOWN_ERROR.\n */\nexport function toAmbaApiError(err: unknown): AmbaApiError {\n if (err instanceof AmbaApiError) return err;\n if (err && typeof err === \"object\") {\n const obj = err as { code?: unknown; message?: unknown; details?: unknown };\n if (typeof obj.code === \"string\") {\n return new AmbaApiError(\n obj.code,\n typeof obj.message === \"string\" ? obj.message : \"unknown\",\n obj.details,\n );\n }\n }\n if (err instanceof Error) {\n return new AmbaApiError(codeFromMessage(err.message), err.message);\n }\n return new AmbaApiError(\"UNKNOWN_ERROR\", String(err));\n}\n\n/**\n * Wrap a thunk so any thrown value becomes an `AmbaApiError`. The\n * wrapper methods on `Amba` use this to convert runtime-emitted errors\n * uniformly at the SDK boundary.\n */\nexport async function withAmbaError<T>(thunk: () => Promise<T>): Promise<T> {\n try {\n return await thunk();\n } catch (err) {\n throw toAmbaApiError(err);\n }\n}\n","/**\n * @layers/amba-web — browser SDK for the amba platform.\n *\n * Exposes the full SDK 4.0 amba surface (34 modules) as idiomatic\n * TypeScript. All async operations return native Promises.\n *\n * @example\n * ```ts\n * import { Amba } from '@layers/amba-web';\n *\n * await Amba.configure({ projectId: 'proj_...', clientKey: 'amba_ck_...' });\n *\n * const session = await Amba.auth.signInAnonymously();\n * await Amba.events.track('app_opened', { source: 'deep_link' });\n *\n * const todos = await Amba.collections.find('todos', { limit: 20 });\n * await Amba.collections.insert('todos', { title: 'Buy milk' });\n * ```\n */\n\nimport init, { AmbaCoreWasm } from \"@layers/amba-core\";\n\nexport type * from \"./types\";\nimport type {\n AmbaConfig,\n AuthResult,\n User,\n FindOptions,\n FindResponse,\n Filter,\n FilterValue,\n ConfigBundle,\n FlagAssignment,\n PingResult,\n UserEntitlement,\n MediaAsset,\n MediaListResponse,\n PresignData,\n PushPlatform,\n PushToken,\n AiMessageRequest,\n AiMessageResponse,\n Achievement,\n AchievementProgress,\n Challenge,\n ChallengeProgress,\n CurrencyBalance,\n CurrencyTransaction,\n InventoryItem,\n PurchaseRequest,\n ConsumeRequest,\n Leaderboard,\n LeaderboardEntry,\n Store,\n PurchaseOption,\n PurchaseResult,\n XpBalance,\n XpTransaction,\n Streak,\n FeedResponse,\n Friendship,\n Group,\n GroupMember,\n GroupCreate,\n GroupUpdate,\n Conversation,\n Message,\n SendMessageRequest,\n CreateConversationRequest,\n ListMessagesOptions,\n MarkReadResult,\n Report,\n ReportRequest,\n ReferralCode,\n ReferralClaim,\n Review,\n ReviewCreate,\n ReviewUpdate,\n Role,\n CatalogItem,\n ContentItem,\n DeepLink,\n DeepLinkCreate,\n OnboardingStatus,\n AppSession,\n SyncChange,\n PushChangesResult,\n PullChangesResult,\n PullChangesCursor,\n LeagueMembership,\n LeagueCohortView,\n NearestOptions,\n NearestResponse,\n LinkedIdentifier,\n} from \"./types\";\n\nimport { LocalStoragePersistence } from \"./storage-adapter\";\nimport { encodeJson } from \"./json\";\nimport { AmbaApiError, toAmbaApiError } from \"./error\";\nimport type { Session } from \"./types\";\n\nexport { AmbaApiError } from \"./error\";\nexport type { AmbaApiErrorCode } from \"./error\";\n\n/**\n * Internal state — one instance per page. Created lazily by `Amba.configure()`.\n */\nlet coreInstance: AmbaCoreWasm | null = null;\n\n/**\n * Stored at configure-time so `Amba.projectId` returns the configured\n * value without going through the engine. Cached only after the\n * core finishes initializing.\n */\nlet _configuredProjectId: string | null = null;\n\nfunction requireCore(): AmbaCoreWasm {\n if (!coreInstance) {\n throw new AmbaApiError(\n \"NOT_INITIALIZED\",\n \"amba SDK not configured. Call Amba.configure({ projectId, clientKey }) at app start before any other API.\",\n );\n }\n return coreInstance;\n}\n\n/**\n * Run a single SDK-runtime call and rewrap any thrown value into a\n * stable `AmbaApiError`. Every method on `Amba` funnels through this\n * so callers see one error shape regardless of which layer failed\n * (network, validation, etc.). Sync `requireCore()` accessors\n * (e.g. the `anonymousId` getter) already throw the typed shape on\n * their own.\n */\nasync function coreCall<T>(fn: (c: AmbaCoreWasm) => Promise<T>): Promise<T> {\n try {\n return await fn(requireCore());\n } catch (err) {\n throw toAmbaApiError(err);\n }\n}\n\n/**\n * In-SDK auth-state pub/sub. `signIn*` / `signUp*` / `signOut` /\n * `refresh` call `notifyAuthSubscribers` after their underlying core\n * call resolves so subscribers always see a consistent `Session | null`\n * snapshot. Subscriber callbacks run synchronously inside the\n * notification path — keep them light; offload heavy work to your own\n * scheduler.\n */\ntype AuthSubscriber = (session: Session | null) => void;\nconst authSubscribers = new Set<AuthSubscriber>();\n\nfunction snapshotSession(user: User | null): Session | null {\n if (!user) return null;\n return {\n sessionToken: \"\",\n refreshToken: \"\",\n user,\n expiresAt: \"\",\n };\n}\n\nfunction notifyAuthSubscribers(session: Session | null): void {\n for (const cb of authSubscribers) {\n try {\n cb(session);\n } catch (err) {\n // Subscriber errors are isolated — one bad callback doesn't\n // block the rest. Surface in debug logs but don't rethrow into\n // the auth call path, which would mask the success result.\n if (typeof console !== \"undefined\") {\n console.error(\"[amba] onAuthStateChange callback threw\", err);\n }\n }\n }\n}\n\nasync function notifyFromAuthResult(result: AuthResult): Promise<void> {\n notifyAuthSubscribers(snapshotSession(result.user));\n}\n\n/**\n * Top-level SDK namespace.\n *\n * Stateless from the JS side — all state lives in the SDK runtime. Calling\n * `Amba.configure()` multiple times replaces the previous instance.\n */\nexport const Amba = {\n /**\n * Initialize the SDK. Must be called once at app start.\n *\n * Seeds an `anonymous_id` from localStorage (if present) or generates a\n * fresh one.\n */\n configure: async (config: AmbaConfig): Promise<void> => {\n if (!config.projectId || config.projectId.trim() === \"\") {\n throw new Error(\"Amba.configure: projectId is required\");\n }\n if (!config.clientKey || config.clientKey.trim() === \"\") {\n throw new Error(\"Amba.configure: clientKey is required\");\n }\n // wasm-pack --target web's auto-loader does `fetch(new URL(\"./amba_core_bg.wasm\", import.meta.url))`.\n // That resolves to a `file://` URL in Node, and Node's undici doesn't\n // support the `file:` scheme — throws `fetch failed: not implemented`.\n // In Node (server-rendering, Jest/Vitest under jsdom, customer-shoes\n // smoke), read the wasm via fs and pass the bytes to init() directly.\n // In browsers, default behavior fetches the wasm from the asset URL.\n const isNode =\n typeof process !== \"undefined\" &&\n !!(process.versions && process.versions.node);\n if (isNode) {\n const [\n { readFile },\n { fileURLToPath, pathToFileURL },\n { createRequire },\n ] = await Promise.all([\n import(\"node:fs/promises\"),\n import(\"node:url\"),\n import(\"node:module\"),\n ]);\n // Resolve the wasm path through @layers/amba-core's package\n // root so we follow the same module resolution as the .js glue\n // — works whether the consumer used a bundler or a raw `node`.\n //\n // Resolution strategy, in order:\n // 1. `import.meta.resolve` (Node ≥20.6, stable in 22). Async or sync\n // depending on Node version — both return a string when awaited.\n // 2. `require.resolve` via `createRequire(import.meta.url)`. Uses\n // Node's standard module resolution which honors pnpm's\n // `.pnpm/<pkg>@<ver>/node_modules/<pkg>` layout. The previous\n // `../node_modules/...` hard-coded fallback failed on pnpm.\n // This mirrors the Node SDK fix at `packages/node/src/index.ts:124`.\n const resolveFn = (\n import.meta as unknown as {\n resolve?: (s: string) => string | Promise<string>;\n }\n ).resolve;\n let wasmJsUrl: string;\n if (resolveFn) {\n wasmJsUrl = await resolveFn(\"@layers/amba-core/wasm\");\n } else {\n const req = createRequire(import.meta.url);\n // `require.resolve` returns a filesystem path; convert to a\n // file:// URL so `fileURLToPath` below works uniformly with the\n // `import.meta.resolve` branch.\n wasmJsUrl = pathToFileURL(\n req.resolve(\"@layers/amba-core/wasm\"),\n ).href;\n }\n const bytes = await readFile(fileURLToPath(wasmJsUrl));\n await init(bytes);\n } else {\n await init();\n }\n const persistence = new LocalStoragePersistence(\n config.storagePrefix ?? \"amba\",\n );\n persistence.hydrate(); // no-op for now; reserved for future identity-cache restoration\n\n // Wrap `AmbaCoreWasm.init`'s throw with `toAmbaApiError` so\n // configure() rejects with an `AmbaApiError` instance — same\n // contract as every method call. Without this, the engine's\n // post-#63 `JsValue` throws would surface to customers as plain\n // objects, breaking `e instanceof Error` checks in\n // configure-failure handlers. (Reported by Cursor BugBot on\n // PR #156, high.)\n try {\n coreInstance = AmbaCoreWasm.init(\n encodeJson({\n api_key: config.clientKey,\n base_url: config.apiUrl,\n project_id: config.projectId,\n sdk_platform: \"web\",\n sdk_wrapper_version: `amba-web/${SDK_VERSION}`,\n consent_required: config.consentRequired,\n debug: config.debug,\n }),\n globalThis.fetch.bind(globalThis),\n );\n } catch (err) {\n throw toAmbaApiError(err);\n }\n\n // Cache the projectId only after WASM init succeeds — leaving the\n // module in a half-initialized state would let `Amba.projectId`\n // return a value while every other method (which checks\n // `coreInstance` via `requireCore()`) correctly throws\n // `NOT_INITIALIZED`.\n _configuredProjectId = config.projectId;\n },\n\n /** Project id this SDK instance is scoped to. */\n get projectId(): string {\n if (!_configuredProjectId) {\n throw new AmbaApiError(\n \"NOT_INITIALIZED\",\n \"amba SDK not configured. Call Amba.configure({ projectId, clientKey }) at app start before any other API.\",\n );\n }\n return _configuredProjectId;\n },\n\n /** Anonymous id — stable per browser. */\n get anonymousId(): string {\n return requireCore().anonymousId();\n },\n\n /** Authenticated user id, if a session is live. */\n get appUserId(): string | undefined {\n return requireCore().appUserId() ?? undefined;\n },\n\n /** Whether a session token is currently held. */\n get isAuthenticated(): boolean {\n return requireCore().isAuthenticated();\n },\n\n /** Toggle verbose logging at runtime. */\n setDebug: (enabled: boolean): void => {\n requireCore().setDebug(enabled);\n },\n\n // ── Core 9 namespaces ─────────────────────────────────────────────\n\n /** Track engagement events. */\n events: {\n /**\n * Track an event.\n *\n * The default route writes to the engagement meter — events that\n * fan out to segments, workflows, and push. Pass\n * `{ telemetry: true }` for high-volume, fire-and-forget events\n * that DON'T need fan-out: UI button clicks, scroll-depth markers,\n * game-loop telemetry. Telemetry events are billed at $0.10 per 1M\n * overage vs $0.50 per 10K for engagement events — a ~500×\n * difference that mirrors the underlying compute cost.\n *\n * Telemetry events are persisted and queryable via analytics, but\n * skip segment recompute, streak qualification, currency grant\n * rules, and `last_seen_at` updates.\n *\n * @example\n * await Amba.events.track('purchase_completed', { amount: 9.99 });\n * await Amba.events.track('scroll_depth', { px: 1024 }, { telemetry: true });\n */\n track: async (\n event: string,\n properties?: Record<string, unknown>,\n options?: { telemetry?: boolean },\n ): Promise<void> => {\n await coreCall((c) => c.track(\n event,\n properties ? encodeJson(properties) : undefined,\n options?.telemetry,\n ));\n },\n },\n\n /** Authentication flows. */\n auth: {\n signInAnonymously: async (): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signInAnonymously())) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n signInWithEmail: async (\n email: string,\n password: string,\n ): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signInWithEmail(\n email,\n password,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n signUpWithEmail: async (\n email: string,\n password: string,\n ): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signUpWithEmail(\n email,\n password,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Sign in with an Apple identity token (the JWT returned by Sign\n * in with Apple). Replaces the SDK 3.x polymorphic\n * `signInWithSocial('apple', token)` form — that surface is\n * removed in 4.0.\n */\n signInWithApple: async (identityToken: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signInWithSocial(\n \"apple\",\n identityToken,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Sign in with a Google ID token (the JWT returned by Google\n * Sign-In). Replaces the SDK 3.x polymorphic\n * `signInWithSocial('google', token)` form — that surface is\n * removed in 4.0.\n */\n signInWithGoogle: async (idToken: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signInWithSocial(\n \"google\",\n idToken,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Request a one-time passcode for `email`. The server emails a\n * 6-digit code; the user types it into the app, then call\n * `verifyEmailOtp(email, code)` to exchange for a session. Always\n * resolves successfully regardless of email registration — the\n * server uses uniform responses to prevent account enumeration.\n */\n requestEmailOtp: async (email: string): Promise<void> => {\n await coreCall((c) => c.requestEmailOtp(email));\n },\n /**\n * Exchange `(email, code)` for a session. Returns the same\n * `AuthResult` shape as `signInWithEmail` and persists tokens for\n * subsequent calls. Rejects with a single error code for every\n * failure mode (wrong/expired/exhausted) — the server intentionally\n * does not distinguish them to prevent enumeration.\n */\n verifyEmailOtp: async (email: string, code: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.verifyEmailOtp(email, code))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Request a one-time passcode by SMS. `phone` MUST be E.164\n * (starts with `+`, 8–15 total digits). The SDK rejects\n * anything else with a `VALIDATION_ERROR` before the network\n * call. Server sends a 6-digit code; user types it into the\n * app, then call `verifySmsOtp(phone, code)` to exchange for\n * a session. Always resolves successfully regardless of phone\n * registration — uniform responses prevent enumeration.\n */\n requestSmsOtp: async (phone: string): Promise<void> => {\n await coreCall((c) => c.requestSmsOtp(phone));\n },\n /**\n * Exchange `(phone, code)` for a session. Same shape +\n * failure semantics as `verifyEmailOtp`. Persists tokens for\n * subsequent calls.\n */\n verifySmsOtp: async (phone: string, code: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.verifySmsOtp(phone, code))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Request a magic-link email for `email`. The server emails the\n * link; the user clicks it, which delivers a one-time token back\n * to the app. Exchange that token for a session with\n * `verifyMagicLink(token)`. Always resolves successfully\n * regardless of email registration (uniform responses prevent\n * account enumeration).\n */\n requestMagicLink: async (email: string): Promise<void> => {\n await coreCall((c) => c.requestMagicLink(email));\n },\n /**\n * Exchange a magic-link `token` for a session. Returns the same\n * `AuthResult` shape as `signInWithEmail` and persists tokens for\n * subsequent calls.\n */\n verifyMagicLink: async (token: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.verifyMagicLink(token))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Link an additional auth provider to the current session — used to\n * upgrade an anonymous session to an identified one without losing\n * the user's data. `provider` is one of the supported identity\n * strings (e.g. `\"apple\"`, `\"google\"`); `credential` is the\n * provider-issued token (identity-token / id-token / OTP code).\n */\n linkAccount: async (\n provider: string,\n credential: string,\n ): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.linkAccount(\n provider,\n credential,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n\n /**\n * Attach a verified phone number to the **current session's user** —\n * without minting new tokens and without changing `user_id`.\n *\n * Flow: call `requestSmsOtp(phone)` first to mail the 6-digit code,\n * then call THIS instead of `verifySmsOtp` when the desired outcome\n * is \"decorate the current (often anonymous) user with this phone\"\n * rather than \"switch to the user who owns this phone\".\n *\n * Guarantees (symmetric to `linkEmailOtp`):\n *\n * - **Same `user_id`** before and after — collections, holds, XP,\n * `anonymous_id` all carry over.\n * - **Session token unchanged.** The existing token stays valid;\n * `onAuthStateChange` does NOT fire (no rotation).\n * - **Idempotent.** Re-linking the same phone to the same user\n * succeeds — no-op apart from `last_seen_at`.\n * - **Collision.** If the phone is already verified to a different\n * user, throws an error with `code = \"PHONE_ALREADY_LINKED\"` and\n * `details.conflicting_user_id` populated. The caller decides\n * whether to abort or switch identities via `verifySmsOtp`.\n *\n * Requires an active session — throws `UNAUTHORIZED` otherwise.\n *\n * @returns the updated user record (with `phone` set and\n * `phone_verified = true`).\n */\n linkSmsOtp: async (phone: string, code: string): Promise<User> => {\n return (await coreCall((c) => c.linkSmsOtp(phone, code))) as User;\n },\n\n /**\n * Attach a verified email to the current session's user. Symmetric\n * to `linkSmsOtp` — see that for the full guarantee list. Collision\n * code is `EMAIL_ALREADY_LINKED`.\n */\n linkEmailOtp: async (email: string, code: string): Promise<User> => {\n return (await coreCall((c) => c.linkEmailOtp(email, code))) as User;\n },\n\n /**\n * Detach the SMS-OTP identifier from the current session's user.\n * Refused with `LAST_IDENTIFIER` if this would leave the account\n * with no recoverable identifier (link another first, then unlink).\n * No token rotation.\n */\n unlinkSmsOtp: async (): Promise<User> => {\n return (await coreCall((c) => c.unlinkSmsOtp())) as User;\n },\n\n /** Detach the email-OTP identifier. Same guarantees as `unlinkSmsOtp`. */\n unlinkEmailOtp: async (): Promise<User> => {\n return (await coreCall((c) => c.unlinkEmailOtp())) as User;\n },\n\n /** Detach the Apple social identity from the current session's user. */\n unlinkApple: async (): Promise<User> => {\n return (await coreCall((c) => c.unlinkApple())) as User;\n },\n\n /** Detach the Google social identity from the current session's user. */\n unlinkGoogle: async (): Promise<User> => {\n return (await coreCall((c) => c.unlinkGoogle())) as User;\n },\n\n /**\n * Snapshot the identifier providers attached to the current\n * session's user. Lets a host app gate \"should I show the verify-\n * email prompt\" without a profile round-trip.\n *\n * Identifier values come back **masked** — raw values stay\n * server-side.\n */\n getCurrentIdentifiers: async (): Promise<LinkedIdentifier[]> => {\n return (await coreCall((c) => c.currentIdentifiers())) as LinkedIdentifier[];\n },\n signOut: async (rotateAnonymousId = false): Promise<void> => {\n await coreCall((c) => c.signOut(rotateAnonymousId));\n notifyAuthSubscribers(null);\n },\n refresh: async (): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.refreshSession())) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n me: async (): Promise<User> => {\n return (await coreCall((c) => c.me())) as User;\n },\n\n /**\n * Snapshot the current session, or `null` if no session is live.\n * sessionToken/refreshToken/expiresAt come back as empty strings —\n * they're SDK-managed and not read-back-able from the core. Use\n * `Amba.isAuthenticated` if you only need the boolean.\n */\n getSession: async (): Promise<Session | null> => {\n const core = requireCore();\n if (!core.isAuthenticated()) return null;\n const user = (await coreCall((c) => c.me())) as User;\n return snapshotSession(user);\n },\n\n /**\n * Stable anonymous identifier (kept in memory by the SDK runtime).\n * Sync today, async for parity with the RN/native shape where the\n * platform may need to await a persistence read.\n */\n getAnonymousId: async (): Promise<string> => {\n return requireCore().anonymousId();\n },\n\n /**\n * Subscribe to session changes. Fires after every `signIn*`,\n * `signUp*`, `refresh`, and `signOut` call. Returns an\n * unsubscribe function — call it to remove the callback.\n *\n * Does NOT fire an initial snapshot when subscribed; call\n * `getSession()` once after subscribing if you need the\n * current state up front.\n */\n onAuthStateChange: (\n cb: (session: Session | null) => void,\n ): (() => void) => {\n authSubscribers.add(cb);\n return () => {\n authSubscribers.delete(cb);\n };\n },\n },\n\n /** Profile read/update (SDK 4.0). */\n users: {\n /**\n * Get a user profile. `userId` omitted → current user\n * (`GET /v1/client/users/me`); `userId` set → public-safe profile\n * of the other user (`GET /v1/client/users/{id}`).\n */\n get: async (userId?: string): Promise<User> => {\n return (await coreCall((c) => c.usersGet(\n userId ?? undefined,\n ))) as User;\n },\n /**\n * Update a profile. Two shapes:\n * - `update(patch)` — current user (`PATCH /users/me`).\n * - `update(userId, patch)` — admin-style cross-user update\n * (`PATCH /users/{id}`); the server requires the caller to\n * hold `users:write` and 403s otherwise.\n *\n * Allowed keys (both shapes): `display_name`, `avatar_url`,\n * `properties`, `timezone`.\n */\n update: (((\n arg1: string | Partial<User>,\n arg2?: Partial<User>,\n ): Promise<User> => {\n const isById = typeof arg1 === \"string\";\n const userId = isById ? (arg1 as string) : undefined;\n const patch = isById ? (arg2 ?? {}) : (arg1 as Partial<User>);\n return coreCall((c) => c.usersUpdate(\n userId ?? undefined,\n encodeJson(patch),\n )) as Promise<User>;\n }) as {\n (patch: Partial<User>): Promise<User>;\n (userId: string, patch: Partial<User>): Promise<User>;\n }),\n },\n\n /** List + revoke customer-recorded app sessions (SDK 4.0). */\n sessions: {\n /** `GET /v1/client/sessions` — list the caller's app sessions. */\n list: async (): Promise<AppSession[]> => {\n return (await coreCall((c) => c.sessionsList())) as AppSession[];\n },\n /**\n * `POST /v1/client/sessions/:id/end` — end the session with the\n * given id. The 4.0 `revoke` contract returns unit; customers who\n * need the ended row should use the lower-level `sessions.end`\n * helper on the core (not exposed on the public SDK).\n */\n revoke: async (sessionId: string): Promise<void> => {\n await coreCall((c) => c.sessionsRevoke(sessionId));\n },\n },\n\n /** Typed collection CRUD with auto-RLS. */\n collections: {\n find: async <T = unknown>(\n name: string,\n options: FindOptions = {},\n ): Promise<FindResponse<T>> => {\n return (await coreCall((c) => c.collectionsFind(\n name,\n encodeJson(options),\n ))) as FindResponse<T>;\n },\n findOne: async <T = unknown>(name: string, id: string): Promise<T> => {\n return (await coreCall((c) => c.collectionsFindOne(name, id))) as T;\n },\n insert: async <T = unknown>(\n name: string,\n row: Record<string, unknown>,\n ): Promise<T> => {\n return (await coreCall((c) => c.collectionsInsert(\n name,\n encodeJson(row),\n ))) as T;\n },\n update: async <T = unknown>(\n name: string,\n id: string,\n set: Record<string, unknown>,\n ): Promise<T> => {\n return (await coreCall((c) => c.collectionsUpdate(\n name,\n id,\n encodeJson(set),\n ))) as T;\n },\n delete: async (\n name: string,\n id: string,\n ): Promise<{ data: { deleted: boolean } }> => {\n return (await coreCall((c) => c.collectionsDelete(name, id))) as {\n data: { deleted: boolean };\n };\n },\n /**\n * Vector-search the collection (SDK 4.0). Returns the `k` nearest\n * neighbors of `options.query_vector` against the column named\n * `options.vector_field`. Distance metric and index strategy are\n * server-side; pass `options.filter` to narrow the candidate set\n * before ranking.\n *\n * Spec note: the canonical `findNearest(name, vector, k, filter?)`\n * shape omits the column name; the SDK widens the contract to a\n * single typed options object so `vector_field` is required and\n * unambiguous in TS.\n */\n findNearest: async <T = unknown>(\n name: string,\n options: NearestOptions,\n ): Promise<NearestResponse<T>> => {\n return (await coreCall((c) => c.collectionsFindNearest(\n name,\n encodeJson(options),\n ))) as NearestResponse<T>;\n },\n /**\n * Count rows in the collection (SDK 4.0). Pass an optional filter\n * to scope; omit it for the total. The server's response unwraps to\n * a bare number on the JS side.\n */\n count: async (name: string, filter?: Filter): Promise<number> => {\n return (await coreCall((c) => c.collectionsCount(\n name,\n filter ? encodeJson(filter) : undefined,\n ))) as number;\n },\n /** Filter DSL helpers — pass into `find({ filter: f })`. */\n where: {\n eq: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"eq\",\n value,\n }),\n ne: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"ne\",\n value,\n }),\n gt: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"gt\",\n value,\n }),\n gte: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"gte\",\n value,\n }),\n lt: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"lt\",\n value,\n }),\n lte: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"lte\",\n value,\n }),\n in: (column: string, values: FilterValue[]): Filter => ({\n column,\n op: \"in\",\n value: values,\n }),\n notIn: (column: string, values: FilterValue[]): Filter => ({\n column,\n op: \"not_in\",\n value: values,\n }),\n like: (column: string, pattern: string): Filter => ({\n column,\n op: \"like\",\n value: pattern,\n }),\n ilike: (column: string, pattern: string): Filter => ({\n column,\n op: \"ilike\",\n value: pattern,\n }),\n isNull: (column: string): Filter => ({ column, op: \"is_null\" }),\n isNotNull: (column: string): Filter => ({ column, op: \"is_not_null\" }),\n and: (...filters: Filter[]): Filter => ({ and: filters }),\n or: (...filters: Filter[]): Filter => ({ or: filters }),\n not: (filter: Filter): Filter => ({ not: filter }),\n },\n },\n\n /** Media uploads + CDN URL helpers. */\n storage: {\n presign: async (params: {\n bucket: string;\n filename: string;\n mimeType: string;\n sizeBytes: number;\n retentionDays?: number;\n }): Promise<PresignData> => {\n return (await coreCall((c) => c.storagePresign(\n params.bucket,\n params.filename,\n params.mimeType,\n params.sizeBytes,\n params.retentionDays ?? undefined,\n ))) as PresignData;\n },\n /**\n * Complete-flow upload: presign → PUT to R2 → commit.\n * Returns the finalized MediaAsset.\n */\n upload: async (params: {\n bucket: string;\n file: File | Blob;\n filename?: string;\n retentionDays?: number;\n }): Promise<MediaAsset> => {\n const filename =\n params.filename ??\n (\"name\" in params.file ? params.file.name : \"upload\");\n const mimeType = params.file.type || \"application/octet-stream\";\n const presign = await Amba.storage.presign({\n bucket: params.bucket,\n filename,\n mimeType,\n sizeBytes: params.file.size,\n retentionDays: params.retentionDays,\n });\n\n const uploadHeaders: Record<string, string> = {};\n for (const [k, v] of presign.upload_headers) {\n uploadHeaders[k] = v;\n }\n const putResp = await fetch(presign.upload_url, {\n method: \"PUT\",\n headers: uploadHeaders,\n body: params.file,\n });\n if (!putResp.ok) {\n throw new Error(`upload to R2 failed: status ${putResp.status}`);\n }\n\n return (await coreCall((c) => c.storageCommit(\n presign.upload_id,\n presign.asset_id,\n ))) as MediaAsset;\n },\n /**\n * List media assets (SDK 4.0). Pass `prefix` to scope to a key\n * prefix (filename / path-like). Without it, returns the caller's\n * full list. Server enforces RLS — only the calling user's assets\n * are returned.\n */\n list: async (prefix?: string): Promise<MediaListResponse> => {\n return (await coreCall((c) => c.storageList(\n prefix ?? undefined,\n ))) as MediaListResponse;\n },\n /**\n * Soft-delete the asset (SDK 4.0). Accepts the asset id returned\n * by `presign` / `commit` / `list`. The corresponding R2 object\n * is removed asynchronously on the server.\n */\n delete: async (assetId: string): Promise<void> => {\n await coreCall((c) => c.storageDelete(assetId));\n },\n /**\n * Download an asset's bytes (SDK 4.0). Returns a `Blob` wrapping\n * the Uint8Array returned by the engine, so consumers can\n * call `.text()` / `.arrayBuffer()` / `.stream()` directly or\n * pipe to a `URL.createObjectURL()` for preview. The two-step\n * fetch (asset metadata → CDN GET) is handled server-side on\n * the WASM side; this method is single-call from the consumer.\n */\n download: async (assetId: string): Promise<Blob> => {\n const bytes = (await coreCall((c) => c.storageDownload(\n assetId,\n ))) as Uint8Array;\n // `Blob` is universally available in browsers and Node 18+,\n // so no platform-shim needed. Type defaults to\n // `application/octet-stream` — the caller knows the real type\n // from their original upload metadata if they need it.\n // Cast through `BlobPart` — under newer @types/node typings,\n // `Uint8Array<ArrayBufferLike>` widens to `ArrayBufferLike`\n // which TS refuses to narrow back to `BlobPart`'s\n // `ArrayBufferView<ArrayBuffer>` constituent. The runtime\n // is fine — `Blob` accepts any TypedArray.\n return new Blob([bytes as unknown as BlobPart]);\n },\n },\n\n /** Offline change replay (SDK 4.0). */\n sync: {\n /**\n * Replay a batch of buffered mutations\n * (`POST /v1/client/sync`). The server applies them in order and\n * returns the count of successfully-applied changes plus any\n * per-row conflicts. Conflict resolution in 4.0 is always\n * server-wins; the `SyncConflict.resolution` field is reserved\n * for future strategies.\n */\n pushChanges: async (\n changes: SyncChange[],\n ): Promise<PushChangesResult> => {\n return (await coreCall((c) => c.syncPushChanges(\n encodeJson(changes),\n ))) as PushChangesResult;\n },\n /**\n * Pull remote-origin changes since the supplied cursor\n * (`GET /v1/client/sync`). Pass the `checkpoint_token` from the\n * previous `pushChanges` / `pullChanges` reply, and the\n * `entity_type` to scope to a single collection. On the first\n * call, omit `checkpoint_token` to receive the full backfill.\n */\n pullChanges: async (\n since: PullChangesCursor,\n ): Promise<PullChangesResult> => {\n return (await coreCall((c) => c.syncPullChanges(\n encodeJson(since),\n ))) as PullChangesResult;\n },\n },\n\n /** Push notifications. */\n push: {\n register: async (\n token: string,\n platform: PushPlatform,\n bundleId?: string,\n ): Promise<PushToken> => {\n return (await coreCall((c) => c.pushRegister(\n token,\n platform,\n bundleId ?? undefined,\n ))) as PushToken;\n },\n unregister: async (token: string): Promise<void> => {\n await coreCall((c) => c.pushUnregister(token));\n },\n getTokens: async (): Promise<PushToken[]> => {\n return (await coreCall((c) => c.pushGetTokens())) as PushToken[];\n },\n subscribe: async (topic: string): Promise<void> => {\n await coreCall((c) => c.pushSubscribe(topic));\n },\n unsubscribe: async (topic: string): Promise<void> => {\n await coreCall((c) => c.pushUnsubscribe(topic));\n },\n },\n\n /** RevenueCat/App Store/Stripe entitlements. */\n entitlements: {\n list: async (): Promise<UserEntitlement[]> => {\n return (await coreCall((c) => c.entitlementsList())) as UserEntitlement[];\n },\n has: async (name: string): Promise<boolean> => {\n return (await coreCall((c) => c.entitlementsHas(name))) as boolean;\n },\n },\n\n /** LLM proxy. */\n ai: {\n anthropic: {\n messages: {\n create: async (\n request: AiMessageRequest,\n ): Promise<AiMessageResponse> => {\n return (await coreCall((c) => c.aiAnthropicMessages(\n encodeJson(request),\n ))) as AiMessageResponse;\n },\n },\n },\n },\n\n /** Remote config bundle. */\n config: {\n fetch: async (): Promise<ConfigBundle> => {\n return (await coreCall((c) => c.configFetch())) as ConfigBundle;\n },\n },\n\n /** Server-evaluated feature flags. */\n flags: {\n fetch: async (): Promise<FlagAssignment[]> => {\n return (await coreCall((c) => c.flagsFetch())) as FlagAssignment[];\n },\n /**\n * Single-flag lookup (SDK 4.0). Wraps `GET /v1/client/flags/{key}`.\n * Returns `null` for unknown / disabled keys; other errors\n * (auth, rate-limit, network) propagate.\n */\n get: async (key: string): Promise<FlagAssignment | null> => {\n return (await coreCall((c) => c.flagsGet(key))) as FlagAssignment | null;\n },\n },\n\n /**\n * Wire-verify primitive. Call once after `configure()` to confirm\n * the SDK is talking to the right project with the right key.\n *\n * The response is entirely server-decided — none of the fields are\n * derived from request parameters — so it's trustworthy as a setup\n * check. Common usage:\n *\n * ```ts\n * const ping = await Amba.diagnostics.ping();\n * if (!ping.ok || ping.server_project_id !== expectedProjectId) {\n * throw new Error(`amba misconfigured: ${JSON.stringify(ping)}`);\n * }\n * ```\n */\n diagnostics: {\n ping: async (): Promise<PingResult> => {\n return (await coreCall((c) => c.diagnosticsPing())) as PingResult;\n },\n },\n\n // ── Gamification ──────────────────────────────────────────────────\n\n /** Achievement definitions + per-user progress. */\n achievements: {\n getAll: async (): Promise<Achievement[]> =>\n (await coreCall((c) => c.achievementsGetAll())) as Achievement[],\n getProgress: async (): Promise<AchievementProgress[]> =>\n (await coreCall((c) => c.achievementsGetProgress())) as AchievementProgress[],\n },\n\n /** Time-bounded challenges with rewards. */\n challenges: {\n getActive: async (): Promise<Challenge[]> =>\n (await coreCall((c) => c.challengesGetActive())) as Challenge[],\n get: async (id: string): Promise<Challenge> =>\n (await coreCall((c) => c.challengesGet(id))) as Challenge,\n getProgress: async (id: string): Promise<ChallengeProgress> =>\n (await coreCall((c) => c.challengesGetProgress(id))) as ChallengeProgress,\n claim: async (id: string): Promise<ChallengeProgress> =>\n (await coreCall((c) => c.challengesClaim(id))) as ChallengeProgress,\n },\n\n /** Virtual currency balances + ledger. */\n currencies: {\n getBalance: async (): Promise<CurrencyBalance[]> =>\n (await coreCall((c) => c.currenciesGetBalance())) as CurrencyBalance[],\n getTransactions: async (\n currencyKey: string,\n ): Promise<CurrencyTransaction[]> =>\n (await coreCall((c) => c.currenciesGetTransactions(\n currencyKey,\n ))) as CurrencyTransaction[],\n },\n\n /** User inventory items + purchase/consume. */\n inventory: {\n getItems: async (): Promise<InventoryItem[]> =>\n (await coreCall((c) => c.inventoryGetItems())) as InventoryItem[],\n getItem: async (id: string): Promise<InventoryItem> =>\n (await coreCall((c) => c.inventoryGetItem(id))) as InventoryItem,\n purchase: async (request: PurchaseRequest): Promise<InventoryItem> =>\n (await coreCall((c) => c.inventoryPurchase(\n encodeJson(request),\n ))) as InventoryItem,\n consume: async (request: ConsumeRequest): Promise<InventoryItem> =>\n (await coreCall((c) => c.inventoryConsume(\n encodeJson(request),\n ))) as InventoryItem,\n },\n\n /** Score rankings. */\n leaderboards: {\n get: async (key: string): Promise<Leaderboard> =>\n (await coreCall((c) => c.leaderboardsGet(key))) as Leaderboard,\n getEntries: async (\n key: string,\n limit?: number,\n ): Promise<LeaderboardEntry[]> =>\n (await coreCall((c) => c.leaderboardsGetEntries(\n key,\n limit ?? undefined,\n ))) as LeaderboardEntry[],\n getMyRank: async (key: string): Promise<LeaderboardEntry> =>\n (await coreCall((c) => c.leaderboardsGetMyRank(key))) as LeaderboardEntry,\n },\n\n /**\n * Tiered weekly leaderboard cohorts (SDK 4.0). Each user is bucketed\n * into a small cohort (~25 members) within their league tier; the\n * top scorers each week promote and the bottom scorers demote.\n */\n leagues: {\n /**\n * `GET /v1/client/leagues/me` — the caller's active-cohort\n * standing plus live rank/score and member count.\n */\n me: async (): Promise<LeagueMembership> => {\n return (await coreCall((c) => c.leaguesMe())) as LeagueMembership;\n },\n /**\n * `GET /v1/client/leagues/me/cohort` — the caller's cohort with\n * every member's anonymised standing (display name, score, rank).\n * Notably no user ids — the server strips them so a leaderboard\n * UI can render the cohort without exposing identities.\n */\n cohort: async (): Promise<LeagueCohortView> => {\n return (await coreCall((c) => c.leaguesCohort())) as LeagueCohortView;\n },\n },\n\n /** Purchase storefronts. */\n stores: {\n list: async (): Promise<Store[]> =>\n (await coreCall((c) => c.storesList())) as Store[],\n getPurchaseOptions: async (storeKey: string): Promise<PurchaseOption[]> =>\n (await coreCall((c) => c.storesGetPurchaseOptions(\n storeKey,\n ))) as PurchaseOption[],\n purchase: async (\n storeKey: string,\n purchaseOptionId: string,\n receipt: unknown,\n ): Promise<PurchaseResult> =>\n // `JSON.stringify(undefined)` returns the JS value `undefined`,\n // not a string — passing that to the WASM `storesPurchase` binding\n // crashes. Default the missing-receipt case to an empty object so\n // the server still receives valid JSON (BugBot Low 2026-05-19).\n (await coreCall((c) => c.storesPurchase(\n storeKey,\n purchaseOptionId,\n encodeJson(receipt ?? {}),\n ))) as PurchaseResult,\n },\n\n /** Experience points + level system. */\n xp: {\n getBalance: async (): Promise<XpBalance> =>\n (await coreCall((c) => c.xpGetBalance())) as XpBalance,\n getHistory: async (limit?: number): Promise<XpTransaction[]> =>\n (await coreCall((c) => c.xpGetHistory(\n limit ?? undefined,\n ))) as XpTransaction[],\n claim: async (grantKey: string): Promise<XpTransaction> =>\n (await coreCall((c) => c.xpClaim(grantKey))) as XpTransaction,\n },\n\n /** Daily-engagement streaks. */\n streaks: {\n getAll: async (): Promise<Streak[]> =>\n (await coreCall((c) => c.streaksGetAll())) as Streak[],\n qualify: async (streakKey: string): Promise<Streak> =>\n (await coreCall((c) => c.streaksQualify(streakKey))) as Streak,\n },\n\n // ── Social ─────────────────────────────────────────────────────────\n\n /** Activity feeds. */\n feeds: {\n getActivity: async (\n feed?: string,\n cursor?: string,\n ): Promise<FeedResponse> =>\n (await coreCall((c) => c.feedsGetActivity(\n feed ?? undefined,\n cursor ?? undefined,\n ))) as FeedResponse,\n },\n\n /** Friend graph + block list. */\n friends: {\n getList: async (): Promise<Friendship[]> =>\n (await coreCall((c) => c.friendsGetList())) as Friendship[],\n getFriends: async (): Promise<Friendship[]> =>\n (await coreCall((c) => c.friendsGetFriends())) as Friendship[],\n /**\n * Send a friend request to `userId` (SDK 4.0). Returns the\n * resulting `Friendship` row in `pending` state.\n */\n sendRequest: async (userId: string): Promise<Friendship> =>\n (await coreCall((c) => c.friendsSendRequest(userId))) as Friendship,\n /**\n * Accept a pending incoming friend request (SDK 4.0). Pass the\n * friendship id from `getList()`.\n */\n acceptRequest: async (friendshipId: string): Promise<Friendship> =>\n (await coreCall((c) => c.friendsAcceptRequest(\n friendshipId,\n ))) as Friendship,\n /**\n * Decline a pending incoming friend request (SDK 4.0). Removes\n * the pending row; idempotent.\n */\n declineRequest: async (friendshipId: string): Promise<void> => {\n await coreCall((c) => c.friendsDeclineRequest(friendshipId));\n },\n blockUser: async (userId: string): Promise<Friendship> =>\n (await coreCall((c) => c.friendsBlockUser(userId))) as Friendship,\n unblockUser: async (userId: string): Promise<void> => {\n await coreCall((c) => c.friendsUnblockUser(userId));\n },\n removeBlock: async (friendshipId: string): Promise<void> => {\n await coreCall((c) => c.friendsRemoveBlock(friendshipId));\n },\n /**\n * Unfriend by the other user's id (SDK 4.0). Wraps\n * `DELETE /v1/client/friends/by-user/{userId}`. Server preserves\n * blocked rows; use `unblockUser` to clear those. 404 propagates\n * as `AmbaApiError`.\n */\n removeFriend: async (userId: string): Promise<void> => {\n await coreCall((c) => c.friendsRemoveFriend(userId));\n },\n },\n\n /** Multi-user groups. */\n groups: {\n create: async (params: GroupCreate): Promise<Group> =>\n (await coreCall((c) => c.groupsCreate(encodeJson(params)))) as Group,\n get: async (id: string): Promise<Group> =>\n (await coreCall((c) => c.groupsGet(id))) as Group,\n update: async (id: string, patch: GroupUpdate): Promise<Group> =>\n (await coreCall((c) => c.groupsUpdate(id, encodeJson(patch)))) as Group,\n delete: async (id: string): Promise<void> => {\n await coreCall((c) => c.groupsDelete(id));\n },\n getMembers: async (id: string): Promise<GroupMember[]> =>\n (await coreCall((c) => c.groupsGetMembers(id))) as GroupMember[],\n join: async (id: string): Promise<GroupMember> =>\n (await coreCall((c) => c.groupsJoin(id))) as GroupMember,\n leave: async (id: string): Promise<void> => {\n await coreCall((c) => c.groupsLeave(id));\n },\n invite: async (id: string, userId: string): Promise<GroupMember> =>\n (await coreCall((c) => c.groupsInvite(id, userId))) as GroupMember,\n },\n\n /**\n * User-to-user direct messaging.\n *\n * Paths mirror the API exactly — see `apps/api/src/routes/client/messaging.ts`:\n *\n * | SDK method | API route |\n * | --------------------- | -------------------------------------------------------- |\n * | `createConversation` | POST `/v1/client/messaging/conversations` |\n * | `getConversations` | GET `/v1/client/messaging/conversations` |\n * | `listConversations` | (alias for `getConversations`) |\n * | `sendMessage` | POST `/v1/client/messaging/conversations/:id/messages` |\n * | `listMessages` | GET `/v1/client/messaging/conversations/:id/messages` |\n * | `markRead` | POST `/v1/client/messaging/conversations/:id/read` |\n *\n * Task #62 corrected `sendMessage`'s path (it previously POSTed to\n * `/messaging/messages`, a route that doesn't exist on the API), and\n * added the four missing helpers. The previous `getMessage(id)` helper\n * has been removed — there is no GET-by-id route on the server; the\n * shape consumers actually want is `listMessages(conversationId, opts)`.\n */\n messaging: {\n /**\n * `POST /v1/client/messaging/conversations` — create (or fetch the\n * existing direct) conversation. For `type: \"direct\"` with exactly\n * one other participant, the server returns the existing row if\n * one already exists between these two users — calls are\n * idempotent.\n */\n createConversation: async (\n request: CreateConversationRequest,\n ): Promise<Conversation> =>\n (await coreCall((c) => c.messagingCreateConversation(\n encodeJson(request),\n ))) as Conversation,\n\n /**\n * `GET /v1/client/messaging/conversations` — list the caller's\n * conversations. Canonical 4.0 name; the legacy `getConversations`\n * / `listConversations` are removed in 4.0 per the spec.\n */\n conversations: async (): Promise<Conversation[]> =>\n (await coreCall((c) => c.messagingGetConversations())) as Conversation[],\n\n /**\n * `POST /v1/client/messaging/conversations/:conversationId/messages`\n * — send a message into an existing conversation. The\n * `conversation_id` argument is a path parameter (not a body\n * field) — the previous SDK shape mistakenly placed it in the\n * body, which the API ignored because the route was wrong anyway.\n */\n sendMessage: async (\n conversationId: string,\n request: SendMessageRequest,\n ): Promise<Message> =>\n // The engine ABI takes a single JSON arg with\n // `conversation_id` inline — we provide a cleaner two-positional\n // shape to TS callers and re-fold conversation_id into the\n // payload here. The engine extracts it before posting.\n (await coreCall((c) => c.messagingSendMessage(\n encodeJson({ ...request, conversation_id: conversationId }),\n ))) as Message,\n\n /**\n * `GET /v1/client/messaging/conversations/:conversationId/messages`\n * — list messages in a conversation. Pagination uses `?limit=&offset=`\n * (the server's `parsePagination` clamps both; defaults to 50 / 0).\n */\n listMessages: async (\n conversationId: string,\n opts?: ListMessagesOptions,\n ): Promise<Message[]> =>\n (await coreCall((c) => c.messagingListMessages(\n conversationId,\n opts?.limit ?? undefined,\n opts?.offset ?? undefined,\n ))) as Message[],\n\n /**\n * `GET /v1/client/messaging/conversations/:conversationId/messages/:messageId`\n * — fetch a single message by id. Returns `null` when the message\n * doesn't exist or the caller can't see it. (SDK 4.0: Phase A\n * shipped the missing `amba_messaging_get_message` core symbol the\n * native SDKs were already trying to call.)\n */\n getMessage: async (\n conversationId: string,\n messageId: string,\n ): Promise<Message | null> => {\n return (await coreCall((c) => c.messagingGetMessage(\n conversationId,\n messageId,\n ))) as Message | null;\n },\n\n /**\n * `POST /v1/client/messaging/conversations/:conversationId/read`\n * — bump the caller's `last_read_at` for the conversation. Returns\n * the updated participant row.\n */\n markRead: async (conversationId: string): Promise<MarkReadResult> =>\n (await coreCall((c) => c.messagingMarkRead(\n conversationId,\n ))) as MarkReadResult,\n },\n\n /** Report users / content for moderation. */\n moderation: {\n reportUser: async (request: ReportRequest): Promise<Report> =>\n (await coreCall((c) => c.moderationReportUser(\n encodeJson(request),\n ))) as Report,\n reportContent: async (request: ReportRequest): Promise<Report> =>\n (await coreCall((c) => c.moderationReportContent(\n encodeJson(request),\n ))) as Report,\n getReportStatus: async (id: string): Promise<Report> =>\n (await coreCall((c) => c.moderationGetReportStatus(id))) as Report,\n },\n\n /** User reviews of catalog items or other users. */\n reviews: {\n list: async (targetType: string, targetId: string): Promise<Review[]> =>\n (await coreCall((c) => c.reviewsList(targetType, targetId))) as Review[],\n create: async (params: ReviewCreate): Promise<Review> =>\n (await coreCall((c) => c.reviewsCreate(encodeJson(params)))) as Review,\n update: async (id: string, patch: ReviewUpdate): Promise<Review> =>\n (await coreCall((c) => c.reviewsUpdate(id, encodeJson(patch)))) as Review,\n delete: async (id: string): Promise<void> => {\n await coreCall((c) => c.reviewsDelete(id));\n },\n },\n\n /** RBAC roles + permission checks. */\n roles: {\n getMyRoles: async (): Promise<Role[]> =>\n (await coreCall((c) => c.rolesGetMyRoles())) as Role[],\n hasPermission: async (permission: string): Promise<boolean> =>\n (await coreCall((c) => c.rolesHasPermission(permission))) as boolean,\n },\n\n /** Referral codes + claim flow. */\n referrals: {\n getReferralCode: async (): Promise<ReferralCode> =>\n (await coreCall((c) => c.referralsGetReferralCode())) as ReferralCode,\n claimReferral: async (code: string): Promise<ReferralClaim> =>\n (await coreCall((c) => c.referralsClaimReferral(code))) as ReferralClaim,\n create: async (\n code?: string,\n maxUses?: number,\n ): Promise<ReferralCode> =>\n (await coreCall((c) => c.referralsCreate(\n code ?? undefined,\n maxUses ?? undefined,\n ))) as ReferralCode,\n },\n\n // ── Lifecycle ──────────────────────────────────────────────────────\n\n /** Read-only product catalog. */\n catalog: {\n list: async (): Promise<CatalogItem[]> =>\n (await coreCall((c) => c.catalogList())) as CatalogItem[],\n /**\n * Fetch a single catalog item by id (SDK 4.0).\n * `GET /v1/client/catalog/:id`.\n */\n get: async (id: string): Promise<CatalogItem> =>\n (await coreCall((c) => c.catalogGet(id))) as CatalogItem,\n },\n\n /** Developer-defined content items (daily quotes, lessons, etc.). */\n content: {\n /**\n * Get today's published item for `channel`. Defaults to `\"default\"`\n * so single-channel apps can call `Amba.content.today()` bare.\n * (Canonical 4.0 name; legacy `getToday` is removed.)\n */\n today: async (channel: string = \"default\"): Promise<ContentItem | null> =>\n (await coreCall((c) => c.contentGetToday(channel))) as ContentItem | null,\n /**\n * Paginated library list for `channel`. `options.limit` caps page size\n * (server default applies when omitted); `options.cursor` is the\n * opaque token returned by a prior response's `next_cursor`.\n * (Canonical 4.0 name; legacy `getLibrary` is removed.)\n */\n library: async (\n channel: string = \"default\",\n options?: { limit?: number; cursor?: string },\n ): Promise<ContentItem[]> =>\n (await coreCall((c) => c.contentGetLibrary(\n channel,\n options?.limit ?? undefined,\n options?.cursor ?? undefined,\n ))) as ContentItem[],\n item: async (id: string): Promise<ContentItem> =>\n (await coreCall((c) => c.contentGetItem(id))) as ContentItem,\n updateItem: async (id: string, state: unknown): Promise<ContentItem> =>\n (await coreCall((c) => c.contentUpdateItem(\n id,\n encodeJson(state),\n ))) as ContentItem,\n createItem: async (\n channel: string,\n item: unknown,\n ): Promise<ContentItem> =>\n (await coreCall((c) => c.contentCreateItem(\n channel,\n encodeJson(item),\n ))) as ContentItem,\n },\n\n /** Server-managed deep link records. */\n deepLinks: {\n get: async (shortCode: string): Promise<DeepLink> =>\n (await coreCall((c) => c.deepLinksGet(shortCode))) as DeepLink,\n create: async (params: DeepLinkCreate): Promise<DeepLink> =>\n (await coreCall((c) => c.deepLinksCreate(encodeJson(params)))) as DeepLink,\n },\n\n /** Step-by-step user onboarding flow. */\n onboarding: {\n getStatus: async (): Promise<OnboardingStatus> =>\n (await coreCall((c) => c.onboardingGetStatus())) as OnboardingStatus,\n nextStep: async (payload: unknown): Promise<OnboardingStatus> =>\n (await coreCall((c) => c.onboardingNextStep(\n encodeJson(payload),\n ))) as OnboardingStatus,\n skipStep: async (): Promise<OnboardingStatus> =>\n (await coreCall((c) => c.onboardingSkipStep())) as OnboardingStatus,\n complete: async (): Promise<OnboardingStatus> =>\n (await coreCall((c) => c.onboardingComplete())) as OnboardingStatus,\n },\n\n};\n\n/** Escape hatch — the raw SDK runtime handle, for namespaces not yet wrapped. */\nexport function getCoreWasm(): AmbaCoreWasm {\n return requireCore();\n}\n\n/**\n * Package version stamped at build time. Sent in the\n * `sdk_wrapper_version` header on every customer request.\n *\n * **Must match `package.json#version` exactly** — the\n * `verify-sdk-version-coherence` GH action gates every publish on the\n * pair agreeing (and matching the `web-v<X.Y.Z>` tag when tag-triggered).\n */\nexport const SDK_VERSION = \"4.0.1\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["prefix: string","ctx: RealtimeContext","name: string","controller: AbortController | null","idx: number","dataLines: string[]","conversationId: string","coreInstance: AmbaCoreWasm | null","_configuredProjectId: string | null","_configuredApiUrl: string","_configuredClientKey: string | null","_currentSessionToken: string | null","wasmJsUrl: string","uploadHeaders: Record<string, string>"],"sources":["../src/storage-adapter.ts","../src/json.ts","../src/error.ts","../src/realtime.ts","../src/index.ts"],"sourcesContent":["/**\n * Browser localStorage adapter for SDK identity persistence.\n *\n * The SDK runtime currently re-seeds an `anonymous_id` on every page load.\n * This adapter is the documented home for storage-prefix handling so\n * customers can override the localStorage key prefix used by the\n * (eventual) identity cache.\n */\nexport class LocalStoragePersistence {\n constructor(private readonly prefix: string) {}\n\n /** Read everything we'd want to hydrate at init. No-op until wired through. */\n hydrate(): void {\n // Reserved for v0.2 — the SDK runtime will gain a persistence bridge\n // that calls into JS for read/write/list/delete.\n }\n\n read(key: string): string | null {\n if (typeof localStorage === \"undefined\") return null;\n return localStorage.getItem(`${this.prefix}:${key}`);\n }\n\n write(key: string, value: string): void {\n if (typeof localStorage === \"undefined\") return;\n localStorage.setItem(`${this.prefix}:${key}`, value);\n }\n\n delete(key: string): void {\n if (typeof localStorage === \"undefined\") return;\n localStorage.removeItem(`${this.prefix}:${key}`);\n }\n}\n","/**\n * JSON encode helper — guarantees stable serialization across browser\n * runtimes and provides a single hook for future schema validation.\n */\nexport function encodeJson(value: unknown): string {\n return JSON.stringify(value);\n}\n","/**\n * Typed error class for the amba SDK + helper that converts arbitrary\n * thrown values (native Error, plain objects, runtime-emitted errors)\n * into a stable `AmbaApiError` instance.\n *\n * Callers can `instanceof`-narrow safely, branch on `.code`, and pull\n * extra payload from `.details` (raw HTTP body, validation field paths,\n * etc.). The wrapper methods on `Amba` wrap every async call in\n * `toAmbaApiError`, so consumers see one error shape regardless of\n * which layer (network, runtime, validation) failed.\n */\n\n/**\n * Stable error codes surfaced by the SDK. Strings rather than an enum\n * so customers can extend with custom codes by simply throwing\n * `new AmbaApiError(\"MY_CODE\", \"...\")` without coordinating with this\n * package's TypeScript types.\n */\nexport type AmbaApiErrorCode =\n | \"UNAUTHORIZED\"\n | \"FORBIDDEN\"\n | \"NOT_FOUND\"\n | \"CONFLICT\"\n | \"RATE_LIMITED\"\n | \"VALIDATION_ERROR\"\n | \"NETWORK_ERROR\"\n | \"HTTP_ERROR\"\n | \"CIRCUIT_OPEN\"\n | \"CONSENT_NOT_GRANTED\"\n | \"NOT_INITIALIZED\"\n | \"INVALID_CONFIG\"\n | \"INVALID_ARGUMENT\"\n | \"PUSH_PERMISSION_DENIED\"\n | \"PUSH_REGISTRATION_FAILED\"\n | \"NOT_SANDBOX_TIER\"\n | \"UNKNOWN_ERROR\"\n | (string & {});\n\nexport class AmbaApiError extends Error {\n readonly code: AmbaApiErrorCode;\n readonly details?: unknown;\n constructor(\n code: AmbaApiErrorCode,\n message: string,\n details?: unknown,\n ) {\n super(message);\n this.name = \"AmbaApiError\";\n this.code = code;\n this.details = details;\n // Restore prototype chain when transpiled to ES5 targets — Error\n // subclasses lose their prototype otherwise and `instanceof` breaks.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Best-effort: pull a stable error code out of a Rust `AmbaError`\n * Display string. Used by `toAmbaApiError` when the underlying thrown\n * value is a generic `Error` produced by `wasm-bindgen`'s `JsError::new`.\n *\n * Keep in sync with `sdks/core/src/error.rs::AmbaError`'s `#[error]`\n * format strings — but the parser falls back to UNKNOWN_ERROR for any\n * pattern it doesn't recognize, so a stale match list isn't a footgun,\n * just a quality-of-life regression.\n */\nfunction codeFromMessage(message: string): AmbaApiErrorCode {\n // Cheapest checks first — most production errors are auth or HTTP.\n if (message.startsWith(\"Unauthorized\")) return \"UNAUTHORIZED\";\n if (message.startsWith(\"Forbidden\")) return \"FORBIDDEN\";\n if (message.startsWith(\"Not found\")) return \"NOT_FOUND\";\n if (message.startsWith(\"Conflict\")) return \"CONFLICT\";\n if (message.startsWith(\"Rate limited\")) return \"RATE_LIMITED\";\n if (message.startsWith(\"Validation error\")) return \"VALIDATION_ERROR\";\n if (message.startsWith(\"Network error\")) return \"NETWORK_ERROR\";\n if (message.startsWith(\"HTTP error\")) return \"HTTP_ERROR\";\n if (message.startsWith(\"Circuit breaker\")) return \"CIRCUIT_OPEN\";\n if (message.startsWith(\"Consent not granted\")) return \"CONSENT_NOT_GRANTED\";\n if (message.includes(\"not initialized\")) return \"NOT_INITIALIZED\";\n if (message.startsWith(\"Invalid configuration\")) return \"INVALID_CONFIG\";\n if (message.startsWith(\"Invalid argument\")) return \"INVALID_ARGUMENT\";\n return \"UNKNOWN_ERROR\";\n}\n\n/**\n * Coerce any thrown value into an `AmbaApiError`. Idempotent — passing\n * an existing `AmbaApiError` returns it unchanged so wrappers can stack\n * without re-wrapping.\n *\n * Heuristics:\n * 1. Existing `AmbaApiError` → returned as-is.\n * 2. Object with `.code` → use that code + `.message` + `.details`.\n * 3. `Error` (e.g. runtime-emitted error) → infer code from message prefix.\n * 4. Anything else → stringify and tag UNKNOWN_ERROR.\n */\nexport function toAmbaApiError(err: unknown): AmbaApiError {\n if (err instanceof AmbaApiError) return err;\n if (err && typeof err === \"object\") {\n const obj = err as { code?: unknown; message?: unknown; details?: unknown };\n if (typeof obj.code === \"string\") {\n return new AmbaApiError(\n obj.code,\n typeof obj.message === \"string\" ? obj.message : \"unknown\",\n obj.details,\n );\n }\n }\n if (err instanceof Error) {\n return new AmbaApiError(codeFromMessage(err.message), err.message);\n }\n return new AmbaApiError(\"UNKNOWN_ERROR\", String(err));\n}\n\n/**\n * Wrap a thunk so any thrown value becomes an `AmbaApiError`. The\n * wrapper methods on `Amba` use this to convert runtime-emitted errors\n * uniformly at the SDK boundary.\n */\nexport async function withAmbaError<T>(thunk: () => Promise<T>): Promise<T> {\n try {\n return await thunk();\n } catch (err) {\n throw toAmbaApiError(err);\n }\n}\n","/**\n * Live collection subscriptions for `@layers/amba-web` (PROTOTYPE — T13).\n *\n * Public surface is intentionally tiny and provider-agnostic:\n *\n * const unsub = Amba.collection(\"messages\")\n * .where(\"circle_id\", circleId)\n * .subscribe((change) => {\n * // change.op is \"INSERT\" | \"UPDATE\" | \"DELETE\"\n * // change.row is the affected row\n * });\n * unsub(); // stop listening\n *\n * The transport (a streamed HTTP response) and the server-side fan-out\n * mechanism are deliberately NOT named here — customers only ever see\n * `.subscribe()`. Internally this opens a long-lived streamed GET to the\n * realtime endpoint and reconnects with backoff if the connection drops.\n *\n * Delivery mirrors `Amba.collection.find()` exactly: you receive only rows\n * your session owns, optionally narrowed by `.where(...)` equality filters.\n */\n\nexport type RowChangeOp = \"INSERT\" | \"UPDATE\" | \"DELETE\";\n\nexport interface RealtimeChange<T = unknown> {\n /** Which kind of write happened. */\n op: RowChangeOp;\n /**\n * The affected row. For deletes this is a partial row (at minimum `id`).\n * If the row was too large to deliver inline, `truncated` is `true` and\n * `row` carries just `id` — re-fetch with `Amba.collection.find()` /\n * `findOne()` when you need the full body.\n */\n row: T;\n truncated?: boolean;\n}\n\nexport interface SubscribeOptions {\n /** Called once when the live connection is (re)established. */\n onOpen?: () => void;\n /** Called on a connection error before the SDK retries. */\n onError?: (err: unknown) => void;\n}\n\n/** Unsubscribe handle returned by `.subscribe(...)`. Call it to stop. */\nexport type Unsubscribe = () => void;\n\n/**\n * Resolved at call time so the latest session token is used. Returns the\n * auth headers, or `null` when there's no live session (subscribe throws).\n */\nexport interface RealtimeContext {\n baseUrl: string;\n authHeaders: () => Record<string, string> | null;\n}\n\nconst INITIAL_BACKOFF_MS = 500;\nconst MAX_BACKOFF_MS = 15_000;\n\n/**\n * Builder returned by `Amba.collection(name)`. Chain `.where(...)` to\n * narrow, then `.subscribe(cb)` to start streaming.\n */\nexport class CollectionSubscription<T = unknown> {\n private readonly filters: Record<string, unknown> = {};\n\n constructor(\n private readonly ctx: RealtimeContext,\n private readonly name: string,\n ) {}\n\n /** Add an equality filter. Chainable. All filters must match (AND). */\n where(column: string, value: unknown): this {\n this.filters[column] = value;\n return this;\n }\n\n /**\n * Start listening. `cb` fires once per matching row change. Returns an\n * unsubscribe handle — call it to close the connection.\n */\n subscribe(cb: (change: RealtimeChange<T>) => void, options: SubscribeOptions = {}): Unsubscribe {\n const headers = this.ctx.authHeaders();\n if (!headers) {\n throw new Error(\n \"Amba.collection().subscribe() requires an authenticated session — call Amba.auth.signIn*/verify* first.\",\n );\n }\n const qs =\n Object.keys(this.filters).length > 0\n ? `?where=${encodeURIComponent(JSON.stringify(this.filters))}`\n : \"\";\n const url = `${this.ctx.baseUrl}/v1/client/realtime/collections/${encodeURIComponent(\n this.name,\n )}${qs}`;\n return openStream<T>({\n url,\n authHeaders: this.ctx.authHeaders,\n onChange: cb,\n options,\n });\n }\n}\n\n/**\n * Inputs to a single realtime stream. The collection and conversation paths\n * differ only in how `url` is built; everything downstream (transport, frame\n * parsing, backoff/reconnect) is identical, so they share one implementation.\n */\ninterface StreamArgs<T> {\n url: string;\n authHeaders: () => Record<string, string> | null;\n onChange: (change: RealtimeChange<T>) => void;\n options: SubscribeOptions;\n}\n\n/**\n * Open a streamed GET to a realtime endpoint and dispatch row-change events\n * to `onChange`. Reconnects with exponential backoff until the returned\n * unsubscribe handle is invoked. Shared by both collection and conversation\n * subscriptions — the only thing that differs between them is the URL.\n *\n * Uses `fetch` + a streamed response body (rather than the browser's\n * native `EventSource`) because `EventSource` cannot set request headers —\n * which would force the session token into the URL query string, where it\n * would leak into access logs. Streaming `fetch` keeps auth in headers.\n */\nfunction openStream<T>(args: StreamArgs<T>): Unsubscribe {\n let stopped = false;\n let controller: AbortController | null = null;\n let backoff = INITIAL_BACKOFF_MS;\n\n const run = async (): Promise<void> => {\n while (!stopped) {\n controller = new AbortController();\n try {\n const headers = args.authHeaders();\n if (!headers) throw new Error(\"no active session\");\n const resp = await fetch(args.url, {\n method: \"GET\",\n headers: { ...headers, Accept: \"text/event-stream\" },\n signal: controller.signal,\n });\n if (!resp.ok || !resp.body) {\n throw new Error(`realtime connect failed: HTTP ${resp.status}`);\n }\n // Reset backoff only once the connection proves HEALTHY (first\n // frame received), not merely on a successful connect. A server\n // that accepts the connection then drops it immediately would\n // otherwise reset backoff every loop → a tight reconnect storm\n // with no exponential growth.\n await consume(resp.body, args, () => {\n backoff = INITIAL_BACKOFF_MS;\n args.options.onOpen?.();\n });\n } catch (err) {\n if (stopped) break;\n args.options.onError?.(err);\n }\n if (stopped) break;\n await delay(backoff);\n backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);\n }\n };\n\n void run();\n\n return () => {\n stopped = true;\n controller?.abort();\n };\n}\n\nasync function consume<T>(\n body: ReadableStream<Uint8Array>,\n args: StreamArgs<T>,\n onFirstFrame: () => void,\n): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let sawFrame = false;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) return;\n buffer += decoder.decode(value, { stream: true });\n let idx: number;\n while ((idx = buffer.indexOf(\"\\n\\n\")) !== -1) {\n const frame = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 2);\n if (!sawFrame) {\n sawFrame = true;\n onFirstFrame();\n }\n dispatchFrame<T>(frame, args.onChange);\n }\n }\n}\n\nfunction dispatchFrame<T>(frame: string, onChange: (change: RealtimeChange<T>) => void): void {\n let event = \"\";\n const dataLines: string[] = [];\n for (const line of frame.split(\"\\n\")) {\n if (line.startsWith(\":\")) continue; // keepalive comment\n if (line.startsWith(\"event:\")) event = line.slice(\"event:\".length).trim();\n else if (line.startsWith(\"data:\")) dataLines.push(line.slice(\"data:\".length).trim());\n }\n if (event !== \"change\") return; // ignore ready / error / heartbeat\n try {\n const payload = JSON.parse(dataLines.join(\"\\n\")) as {\n op: RowChangeOp;\n row: T;\n truncated?: boolean;\n };\n onChange({ op: payload.op, row: payload.row, truncated: payload.truncated });\n } catch {\n // malformed frame — skip rather than tear down the stream\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// ── Messaging: live conversation subscriptions ─────────────────────────────\n\n/**\n * A live message change in a conversation. `op` is \"INSERT\" for a new\n * message; moderation removals arrive as \"DELETE\". For a delete (or when a\n * message was too large to deliver inline) `row` may be partial — re-fetch\n * with `Amba.messaging.listMessages(conversationId)` when you need the full\n * body.\n */\nexport type MessageChange<T = unknown> = RealtimeChange<T>;\n\n/**\n * Builder returned by `Amba.messaging.conversation(id)`. Call `.subscribe(cb)`\n * to receive new messages live instead of polling.\n *\n * const unsub = Amba.messaging\n * .conversation(conversationId)\n * .subscribe((change) => {\n * // change.op === \"INSERT\"; change.row is the new message\n * });\n * unsub(); // stop listening\n *\n * Delivery is scoped to conversation participants — you receive messages for\n * a conversation only if your session is a member of it. Reconnects with the\n * same exponential backoff as collection subscriptions.\n */\nexport class ConversationSubscription<T = unknown> {\n constructor(\n private readonly ctx: RealtimeContext,\n private readonly conversationId: string,\n ) {}\n\n subscribe(cb: (change: MessageChange<T>) => void, options: SubscribeOptions = {}): Unsubscribe {\n const headers = this.ctx.authHeaders();\n if (!headers) {\n throw new Error(\n \"Amba.messaging.conversation().subscribe() requires an authenticated session — call Amba.auth.signIn*/verify* first.\",\n );\n }\n const url = `${this.ctx.baseUrl}/v1/client/realtime/conversations/${encodeURIComponent(\n this.conversationId,\n )}`;\n return openStream<T>({\n url,\n authHeaders: this.ctx.authHeaders,\n onChange: cb,\n options,\n });\n }\n}\n","/**\n * @layers/amba-web — browser SDK for the amba platform.\n *\n * Exposes the full SDK 4.0 amba surface (34 modules) as idiomatic\n * TypeScript. All async operations return native Promises.\n *\n * @example\n * ```ts\n * import { Amba } from '@layers/amba-web';\n *\n * await Amba.configure({ projectId: 'proj_...', clientKey: 'amba_ck_...' });\n *\n * const session = await Amba.auth.signInAnonymously();\n * await Amba.events.track('app_opened', { source: 'deep_link' });\n *\n * const todos = await Amba.collections.find('todos', { limit: 20 });\n * await Amba.collections.insert('todos', { title: 'Buy milk' });\n * ```\n */\n\nimport init, { AmbaCoreWasm } from \"@layers/amba-core\";\n\nexport type * from \"./types\";\nimport type {\n AmbaConfig,\n AuthResult,\n User,\n FindOptions,\n FindResponse,\n Filter,\n FilterValue,\n ConfigBundle,\n FlagAssignment,\n PingResult,\n UserEntitlement,\n MediaAsset,\n MediaListResponse,\n PresignData,\n PushPlatform,\n PushToken,\n AiMessageRequest,\n AiMessageResponse,\n Achievement,\n AchievementProgress,\n Challenge,\n ChallengeProgress,\n CurrencyBalance,\n CurrencyTransaction,\n InventoryItem,\n PurchaseRequest,\n ConsumeRequest,\n Leaderboard,\n LeaderboardEntry,\n Store,\n PurchaseOption,\n PurchaseResult,\n XpBalance,\n XpTransaction,\n Streak,\n FeedResponse,\n Friendship,\n Group,\n GroupMember,\n GroupCreate,\n GroupUpdate,\n Conversation,\n Message,\n SendMessageRequest,\n CreateConversationRequest,\n ListMessagesOptions,\n MarkReadResult,\n ConversationParticipant,\n Report,\n ReportRequest,\n ReferralCode,\n ReferralClaim,\n Review,\n ReviewCreate,\n ReviewUpdate,\n Role,\n CatalogItem,\n ContentItem,\n DeepLink,\n DeepLinkCreate,\n OnboardingStatus,\n AppSession,\n SyncChange,\n PushChangesResult,\n PullChangesResult,\n PullChangesCursor,\n LeagueMembership,\n LeagueCohortView,\n NearestOptions,\n NearestResponse,\n LinkedIdentifier,\n} from \"./types\";\n\nimport { LocalStoragePersistence } from \"./storage-adapter\";\nimport { encodeJson } from \"./json\";\nimport { AmbaApiError, toAmbaApiError } from \"./error\";\nimport type { Session } from \"./types\";\nimport { CollectionSubscription, ConversationSubscription } from \"./realtime\";\n\nexport { AmbaApiError } from \"./error\";\nexport type { AmbaApiErrorCode } from \"./error\";\nexport { CollectionSubscription, ConversationSubscription } from \"./realtime\";\nexport type {\n RealtimeChange,\n MessageChange,\n RowChangeOp,\n SubscribeOptions,\n Unsubscribe,\n} from \"./realtime\";\n\nconst DEFAULT_API_URL = \"https://api.amba.dev\";\n\n/**\n * Internal state — one instance per page. Created lazily by `Amba.configure()`.\n */\nlet coreInstance: AmbaCoreWasm | null = null;\n\n/**\n * Stored at configure-time so `Amba.projectId` returns the configured\n * value without going through the engine. Cached only after the\n * core finishes initializing.\n */\nlet _configuredProjectId: string | null = null;\n\n/**\n * Realtime (`Amba.collection(name).subscribe`) needs the API base URL,\n * client key, and current session token in the TS layer to open the\n * streamed connection — the engine doesn't expose them back. We capture\n * the base URL + client key at configure-time and the session token from\n * every auth result (the engine rotates it internally on refresh; the\n * subscribe connection picks up the latest at connect time).\n */\nlet _configuredApiUrl: string = DEFAULT_API_URL;\nlet _configuredClientKey: string | null = null;\nlet _currentSessionToken: string | null = null;\n\nfunction requireCore(): AmbaCoreWasm {\n if (!coreInstance) {\n throw new AmbaApiError(\n \"NOT_INITIALIZED\",\n \"amba SDK not configured. Call Amba.configure({ projectId, clientKey }) at app start before any other API.\",\n );\n }\n return coreInstance;\n}\n\n/**\n * Run a single SDK-runtime call and rewrap any thrown value into a\n * stable `AmbaApiError`. Every method on `Amba` funnels through this\n * so callers see one error shape regardless of which layer failed\n * (network, validation, etc.). Sync `requireCore()` accessors\n * (e.g. the `anonymousId` getter) already throw the typed shape on\n * their own.\n */\nasync function coreCall<T>(fn: (c: AmbaCoreWasm) => Promise<T>): Promise<T> {\n try {\n return await fn(requireCore());\n } catch (err) {\n throw toAmbaApiError(err);\n }\n}\n\n/**\n * In-SDK auth-state pub/sub. `signIn*` / `signUp*` / `signOut` /\n * `refresh` call `notifyAuthSubscribers` after their underlying core\n * call resolves so subscribers always see a consistent `Session | null`\n * snapshot. Subscriber callbacks run synchronously inside the\n * notification path — keep them light; offload heavy work to your own\n * scheduler.\n */\ntype AuthSubscriber = (session: Session | null) => void;\nconst authSubscribers = new Set<AuthSubscriber>();\n\nfunction snapshotSession(user: User | null): Session | null {\n if (!user) return null;\n return {\n sessionToken: \"\",\n refreshToken: \"\",\n user,\n expiresAt: \"\",\n };\n}\n\nfunction notifyAuthSubscribers(session: Session | null): void {\n for (const cb of authSubscribers) {\n try {\n cb(session);\n } catch (err) {\n // Subscriber errors are isolated — one bad callback doesn't\n // block the rest. Surface in debug logs but don't rethrow into\n // the auth call path, which would mask the success result.\n if (typeof console !== \"undefined\") {\n console.error(\"[amba] onAuthStateChange callback threw\", err);\n }\n }\n }\n}\n\nasync function notifyFromAuthResult(result: AuthResult): Promise<void> {\n // Capture the session token for the realtime subscribe path (the engine\n // holds the canonical copy + auto-refreshes; this is the latest snapshot).\n if (result?.session_token) _currentSessionToken = result.session_token;\n notifyAuthSubscribers(snapshotSession(result.user));\n}\n\n/**\n * Build the auth headers for a realtime subscribe connection, or `null`\n * when there's no live session. Read lazily at connect-time so reconnects\n * pick up a rotated session token.\n */\nfunction realtimeAuthHeaders(): Record<string, string> | null {\n if (!_configuredClientKey || !_currentSessionToken) return null;\n return {\n \"X-Api-Key\": _configuredClientKey,\n Authorization: `Bearer ${_currentSessionToken}`,\n };\n}\n\n/**\n * Top-level SDK namespace.\n *\n * Stateless from the JS side — all state lives in the SDK runtime. Calling\n * `Amba.configure()` multiple times replaces the previous instance.\n */\nexport const Amba = {\n /**\n * Initialize the SDK. Must be called once at app start.\n *\n * Seeds an `anonymous_id` from localStorage (if present) or generates a\n * fresh one.\n */\n configure: async (config: AmbaConfig): Promise<void> => {\n if (!config.projectId || config.projectId.trim() === \"\") {\n throw new Error(\"Amba.configure: projectId is required\");\n }\n if (!config.clientKey || config.clientKey.trim() === \"\") {\n throw new Error(\"Amba.configure: clientKey is required\");\n }\n // wasm-pack --target web's auto-loader does `fetch(new URL(\"./amba_core_bg.wasm\", import.meta.url))`.\n // That resolves to a `file://` URL in Node, and Node's undici doesn't\n // support the `file:` scheme — throws `fetch failed: not implemented`.\n // In Node (server-rendering, Jest/Vitest under jsdom, customer-shoes\n // smoke), read the wasm via fs and pass the bytes to init() directly.\n // In browsers, default behavior fetches the wasm from the asset URL.\n const isNode =\n typeof process !== \"undefined\" &&\n !!(process.versions && process.versions.node);\n if (isNode) {\n const [\n { readFile },\n { fileURLToPath, pathToFileURL },\n { createRequire },\n ] = await Promise.all([\n import(\"node:fs/promises\"),\n import(\"node:url\"),\n import(\"node:module\"),\n ]);\n // Resolve the wasm path through @layers/amba-core's package\n // root so we follow the same module resolution as the .js glue\n // — works whether the consumer used a bundler or a raw `node`.\n //\n // Resolution strategy, in order:\n // 1. `import.meta.resolve` (Node ≥20.6, stable in 22). Async or sync\n // depending on Node version — both return a string when awaited.\n // 2. `require.resolve` via `createRequire(import.meta.url)`. Uses\n // Node's standard module resolution which honors pnpm's\n // `.pnpm/<pkg>@<ver>/node_modules/<pkg>` layout. The previous\n // `../node_modules/...` hard-coded fallback failed on pnpm.\n // This mirrors the Node SDK fix at `packages/node/src/index.ts:124`.\n const resolveFn = (\n import.meta as unknown as {\n resolve?: (s: string) => string | Promise<string>;\n }\n ).resolve;\n let wasmJsUrl: string;\n if (resolveFn) {\n wasmJsUrl = await resolveFn(\"@layers/amba-core/wasm\");\n } else {\n const req = createRequire(import.meta.url);\n // `require.resolve` returns a filesystem path; convert to a\n // file:// URL so `fileURLToPath` below works uniformly with the\n // `import.meta.resolve` branch.\n wasmJsUrl = pathToFileURL(\n req.resolve(\"@layers/amba-core/wasm\"),\n ).href;\n }\n const bytes = await readFile(fileURLToPath(wasmJsUrl));\n await init(bytes);\n } else {\n await init();\n }\n const persistence = new LocalStoragePersistence(\n config.storagePrefix ?? \"amba\",\n );\n persistence.hydrate(); // no-op for now; reserved for future identity-cache restoration\n\n // Wrap `AmbaCoreWasm.init`'s throw with `toAmbaApiError` so\n // configure() rejects with an `AmbaApiError` instance — same\n // contract as every method call. Without this, the engine's\n // post-#63 `JsValue` throws would surface to customers as plain\n // objects, breaking `e instanceof Error` checks in\n // configure-failure handlers. (Reported by Cursor BugBot on\n // PR #156, high.)\n try {\n coreInstance = AmbaCoreWasm.init(\n encodeJson({\n api_key: config.clientKey,\n base_url: config.apiUrl,\n project_id: config.projectId,\n sdk_platform: \"web\",\n sdk_wrapper_version: `amba-web/${SDK_VERSION}`,\n consent_required: config.consentRequired,\n debug: config.debug,\n }),\n globalThis.fetch.bind(globalThis),\n );\n } catch (err) {\n throw toAmbaApiError(err);\n }\n\n // Cache the projectId only after WASM init succeeds — leaving the\n // module in a half-initialized state would let `Amba.projectId`\n // return a value while every other method (which checks\n // `coreInstance` via `requireCore()`) correctly throws\n // `NOT_INITIALIZED`.\n _configuredProjectId = config.projectId;\n _configuredApiUrl = config.apiUrl ?? DEFAULT_API_URL;\n _configuredClientKey = config.clientKey;\n },\n\n /** Project id this SDK instance is scoped to. */\n get projectId(): string {\n if (!_configuredProjectId) {\n throw new AmbaApiError(\n \"NOT_INITIALIZED\",\n \"amba SDK not configured. Call Amba.configure({ projectId, clientKey }) at app start before any other API.\",\n );\n }\n return _configuredProjectId;\n },\n\n /** Anonymous id — stable per browser. */\n get anonymousId(): string {\n return requireCore().anonymousId();\n },\n\n /** Authenticated user id, if a session is live. */\n get appUserId(): string | undefined {\n return requireCore().appUserId() ?? undefined;\n },\n\n /** Whether a session token is currently held. */\n get isAuthenticated(): boolean {\n return requireCore().isAuthenticated();\n },\n\n /** Toggle verbose logging at runtime. */\n setDebug: (enabled: boolean): void => {\n requireCore().setDebug(enabled);\n },\n\n // ── Core 9 namespaces ─────────────────────────────────────────────\n\n /** Track engagement events. */\n events: {\n /**\n * Track an event.\n *\n * The default route writes to the engagement meter — events that\n * fan out to segments, workflows, and push. Pass\n * `{ telemetry: true }` for high-volume, fire-and-forget events\n * that DON'T need fan-out: UI button clicks, scroll-depth markers,\n * game-loop telemetry. Telemetry events are billed at $0.10 per 1M\n * overage vs $0.50 per 10K for engagement events — a ~500×\n * difference that mirrors the underlying compute cost.\n *\n * Telemetry events are persisted and queryable via analytics, but\n * skip segment recompute, streak qualification, currency grant\n * rules, and `last_seen_at` updates.\n *\n * @example\n * await Amba.events.track('purchase_completed', { amount: 9.99 });\n * await Amba.events.track('scroll_depth', { px: 1024 }, { telemetry: true });\n */\n track: async (\n event: string,\n properties?: Record<string, unknown>,\n options?: { telemetry?: boolean },\n ): Promise<void> => {\n await coreCall((c) => c.track(\n event,\n properties ? encodeJson(properties) : undefined,\n options?.telemetry,\n ));\n },\n },\n\n /** Authentication flows. */\n auth: {\n signInAnonymously: async (): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signInAnonymously())) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n signInWithEmail: async (\n email: string,\n password: string,\n ): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signInWithEmail(\n email,\n password,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n signUpWithEmail: async (\n email: string,\n password: string,\n ): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signUpWithEmail(\n email,\n password,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Sign in with an Apple identity token (the JWT returned by Sign\n * in with Apple). Replaces the SDK 3.x polymorphic\n * `signInWithSocial('apple', token)` form — that surface is\n * removed in 4.0.\n */\n signInWithApple: async (identityToken: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signInWithSocial(\n \"apple\",\n identityToken,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Sign in with a Google ID token (the JWT returned by Google\n * Sign-In). Replaces the SDK 3.x polymorphic\n * `signInWithSocial('google', token)` form — that surface is\n * removed in 4.0.\n */\n signInWithGoogle: async (idToken: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.signInWithSocial(\n \"google\",\n idToken,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Request a one-time passcode for `email`. The server emails a\n * 6-digit code; the user types it into the app, then call\n * `verifyEmailOtp(email, code)` to exchange for a session. Always\n * resolves successfully regardless of email registration — the\n * server uses uniform responses to prevent account enumeration.\n */\n requestEmailOtp: async (email: string): Promise<void> => {\n await coreCall((c) => c.requestEmailOtp(email));\n },\n /**\n * Exchange `(email, code)` for a session. Returns the same\n * `AuthResult` shape as `signInWithEmail` and persists tokens for\n * subsequent calls. Rejects with a single error code for every\n * failure mode (wrong/expired/exhausted) — the server intentionally\n * does not distinguish them to prevent enumeration.\n */\n verifyEmailOtp: async (email: string, code: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.verifyEmailOtp(email, code))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Request a one-time passcode by SMS. `phone` MUST be E.164\n * (starts with `+`, 8–15 total digits). The SDK rejects\n * anything else with a `VALIDATION_ERROR` before the network\n * call. Server sends a 6-digit code; user types it into the\n * app, then call `verifySmsOtp(phone, code)` to exchange for\n * a session. Always resolves successfully regardless of phone\n * registration — uniform responses prevent enumeration.\n */\n requestSmsOtp: async (phone: string): Promise<void> => {\n await coreCall((c) => c.requestSmsOtp(phone));\n },\n /**\n * Exchange `(phone, code)` for a session. Same shape +\n * failure semantics as `verifyEmailOtp`. Persists tokens for\n * subsequent calls.\n */\n verifySmsOtp: async (phone: string, code: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.verifySmsOtp(phone, code))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Request a magic-link email for `email`. The server emails the\n * link; the user clicks it, which delivers a one-time token back\n * to the app. Exchange that token for a session with\n * `verifyMagicLink(token)`. Always resolves successfully\n * regardless of email registration (uniform responses prevent\n * account enumeration).\n */\n requestMagicLink: async (email: string): Promise<void> => {\n await coreCall((c) => c.requestMagicLink(email));\n },\n /**\n * Exchange a magic-link `token` for a session. Returns the same\n * `AuthResult` shape as `signInWithEmail` and persists tokens for\n * subsequent calls.\n */\n verifyMagicLink: async (token: string): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.verifyMagicLink(token))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n /**\n * Link an additional auth provider to the current session — used to\n * upgrade an anonymous session to an identified one without losing\n * the user's data. `provider` is one of the supported identity\n * strings (e.g. `\"apple\"`, `\"google\"`); `credential` is the\n * provider-issued token (identity-token / id-token / OTP code).\n */\n linkAccount: async (\n provider: string,\n credential: string,\n ): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.linkAccount(\n provider,\n credential,\n ))) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n\n /**\n * Attach a verified phone number to the **current session's user** —\n * without minting new tokens and without changing `user_id`.\n *\n * Flow: call `requestSmsOtp(phone)` first to mail the 6-digit code,\n * then call THIS instead of `verifySmsOtp` when the desired outcome\n * is \"decorate the current (often anonymous) user with this phone\"\n * rather than \"switch to the user who owns this phone\".\n *\n * Guarantees (symmetric to `linkEmailOtp`):\n *\n * - **Same `user_id`** before and after — collections, holds, XP,\n * `anonymous_id` all carry over.\n * - **Session token unchanged.** The existing token stays valid;\n * `onAuthStateChange` does NOT fire (no rotation).\n * - **Idempotent.** Re-linking the same phone to the same user\n * succeeds — no-op apart from `last_seen_at`.\n * - **Collision.** If the phone is already verified to a different\n * user, throws an error with `code = \"PHONE_ALREADY_LINKED\"` and\n * `details.conflicting_user_id` populated. The caller decides\n * whether to abort or switch identities via `verifySmsOtp`.\n *\n * Requires an active session — throws `UNAUTHORIZED` otherwise.\n *\n * @returns the updated user record (with `phone` set and\n * `phone_verified = true`).\n */\n linkSmsOtp: async (phone: string, code: string): Promise<User> => {\n return (await coreCall((c) => c.linkSmsOtp(phone, code))) as User;\n },\n\n /**\n * Attach a verified email to the current session's user. Symmetric\n * to `linkSmsOtp` — see that for the full guarantee list. Collision\n * code is `EMAIL_ALREADY_LINKED`.\n */\n linkEmailOtp: async (email: string, code: string): Promise<User> => {\n return (await coreCall((c) => c.linkEmailOtp(email, code))) as User;\n },\n\n /**\n * Detach the SMS-OTP identifier from the current session's user.\n * Refused with `LAST_IDENTIFIER` if this would leave the account\n * with no recoverable identifier (link another first, then unlink).\n * No token rotation.\n */\n unlinkSmsOtp: async (): Promise<User> => {\n return (await coreCall((c) => c.unlinkSmsOtp())) as User;\n },\n\n /** Detach the email-OTP identifier. Same guarantees as `unlinkSmsOtp`. */\n unlinkEmailOtp: async (): Promise<User> => {\n return (await coreCall((c) => c.unlinkEmailOtp())) as User;\n },\n\n /** Detach the Apple social identity from the current session's user. */\n unlinkApple: async (): Promise<User> => {\n return (await coreCall((c) => c.unlinkApple())) as User;\n },\n\n /** Detach the Google social identity from the current session's user. */\n unlinkGoogle: async (): Promise<User> => {\n return (await coreCall((c) => c.unlinkGoogle())) as User;\n },\n\n /**\n * Snapshot the identifier providers attached to the current\n * session's user. Lets a host app gate \"should I show the verify-\n * email prompt\" without a profile round-trip.\n *\n * Identifier values come back **masked** — raw values stay\n * server-side.\n */\n getCurrentIdentifiers: async (): Promise<LinkedIdentifier[]> => {\n return (await coreCall((c) => c.currentIdentifiers())) as LinkedIdentifier[];\n },\n signOut: async (rotateAnonymousId = false): Promise<void> => {\n await coreCall((c) => c.signOut(rotateAnonymousId));\n _currentSessionToken = null;\n notifyAuthSubscribers(null);\n },\n refresh: async (): Promise<AuthResult> => {\n const r = (await coreCall((c) => c.refreshSession())) as AuthResult;\n await notifyFromAuthResult(r);\n return r;\n },\n me: async (): Promise<User> => {\n return (await coreCall((c) => c.me())) as User;\n },\n\n /**\n * Snapshot the current session, or `null` if no session is live.\n * sessionToken/refreshToken/expiresAt come back as empty strings —\n * they're SDK-managed and not read-back-able from the core. Use\n * `Amba.isAuthenticated` if you only need the boolean.\n */\n getSession: async (): Promise<Session | null> => {\n const core = requireCore();\n if (!core.isAuthenticated()) return null;\n const user = (await coreCall((c) => c.me())) as User;\n return snapshotSession(user);\n },\n\n /**\n * Stable anonymous identifier (kept in memory by the SDK runtime).\n * Sync today, async for parity with the RN/native shape where the\n * platform may need to await a persistence read.\n */\n getAnonymousId: async (): Promise<string> => {\n return requireCore().anonymousId();\n },\n\n /**\n * Subscribe to session changes. Fires after every `signIn*`,\n * `signUp*`, `refresh`, and `signOut` call. Returns an\n * unsubscribe function — call it to remove the callback.\n *\n * Does NOT fire an initial snapshot when subscribed; call\n * `getSession()` once after subscribing if you need the\n * current state up front.\n */\n onAuthStateChange: (\n cb: (session: Session | null) => void,\n ): (() => void) => {\n authSubscribers.add(cb);\n return () => {\n authSubscribers.delete(cb);\n };\n },\n },\n\n /** Profile read/update (SDK 4.0). */\n users: {\n /**\n * Get a user profile. `userId` omitted → current user\n * (`GET /v1/client/users/me`); `userId` set → public-safe profile\n * of the other user (`GET /v1/client/users/{id}`).\n */\n get: async (userId?: string): Promise<User> => {\n return (await coreCall((c) => c.usersGet(\n userId ?? undefined,\n ))) as User;\n },\n /**\n * Update a profile. Two shapes:\n * - `update(patch)` — current user (`PATCH /users/me`).\n * - `update(userId, patch)` — admin-style cross-user update\n * (`PATCH /users/{id}`); the server requires the caller to\n * hold `users:write` and 403s otherwise.\n *\n * Allowed keys (both shapes): `display_name`, `avatar_url`,\n * `properties`, `timezone`.\n */\n update: (((\n arg1: string | Partial<User>,\n arg2?: Partial<User>,\n ): Promise<User> => {\n const isById = typeof arg1 === \"string\";\n const userId = isById ? (arg1 as string) : undefined;\n const patch = isById ? (arg2 ?? {}) : (arg1 as Partial<User>);\n return coreCall((c) => c.usersUpdate(\n userId ?? undefined,\n encodeJson(patch),\n )) as Promise<User>;\n }) as {\n (patch: Partial<User>): Promise<User>;\n (userId: string, patch: Partial<User>): Promise<User>;\n }),\n },\n\n /** List + revoke customer-recorded app sessions (SDK 4.0). */\n sessions: {\n /** `GET /v1/client/sessions` — list the caller's app sessions. */\n list: async (): Promise<AppSession[]> => {\n return (await coreCall((c) => c.sessionsList())) as AppSession[];\n },\n /**\n * `POST /v1/client/sessions/:id/end` — end the session with the\n * given id. The 4.0 `revoke` contract returns unit; customers who\n * need the ended row should use the lower-level `sessions.end`\n * helper on the core (not exposed on the public SDK).\n */\n revoke: async (sessionId: string): Promise<void> => {\n await coreCall((c) => c.sessionsRevoke(sessionId));\n },\n },\n\n /**\n * Live collection subscriptions (SDK 4.0). Returns a builder — chain\n * `.where(column, value)` to narrow, then `.subscribe(cb)` to start\n * receiving row changes. `subscribe` returns an unsubscribe handle.\n *\n * @example\n * const unsub = Amba.collection(\"messages\")\n * .where(\"circle_id\", circleId)\n * .subscribe((change) => {\n * // change.op: \"INSERT\" | \"UPDATE\" | \"DELETE\"; change.row: the row\n * });\n * // later: unsub();\n *\n * Delivery mirrors `Amba.collections.find()` — you only receive rows your\n * session owns. Requires an authenticated session.\n */\n collection: <T = unknown>(name: string): CollectionSubscription<T> =>\n new CollectionSubscription<T>(\n { baseUrl: _configuredApiUrl, authHeaders: realtimeAuthHeaders },\n name,\n ),\n\n /** Typed collection CRUD with auto-RLS. */\n collections: {\n find: async <T = unknown>(\n name: string,\n options: FindOptions = {},\n ): Promise<FindResponse<T>> => {\n return (await coreCall((c) => c.collectionsFind(\n name,\n encodeJson(options),\n ))) as FindResponse<T>;\n },\n findOne: async <T = unknown>(name: string, id: string): Promise<T> => {\n return (await coreCall((c) => c.collectionsFindOne(name, id))) as T;\n },\n insert: async <T = unknown>(\n name: string,\n row: Record<string, unknown>,\n ): Promise<T> => {\n return (await coreCall((c) => c.collectionsInsert(\n name,\n encodeJson(row),\n ))) as T;\n },\n update: async <T = unknown>(\n name: string,\n id: string,\n set: Record<string, unknown>,\n ): Promise<T> => {\n return (await coreCall((c) => c.collectionsUpdate(\n name,\n id,\n encodeJson(set),\n ))) as T;\n },\n delete: async (\n name: string,\n id: string,\n ): Promise<{ data: { deleted: boolean } }> => {\n return (await coreCall((c) => c.collectionsDelete(name, id))) as {\n data: { deleted: boolean };\n };\n },\n /**\n * Vector-search the collection (SDK 4.0). Returns the `k` nearest\n * neighbors of `options.query_vector` against the column named\n * `options.vector_field`. Distance metric and index strategy are\n * server-side; pass `options.filter` to narrow the candidate set\n * before ranking.\n *\n * Spec note: the canonical `findNearest(name, vector, k, filter?)`\n * shape omits the column name; the SDK widens the contract to a\n * single typed options object so `vector_field` is required and\n * unambiguous in TS.\n */\n findNearest: async <T = unknown>(\n name: string,\n options: NearestOptions,\n ): Promise<NearestResponse<T>> => {\n return (await coreCall((c) => c.collectionsFindNearest(\n name,\n encodeJson(options),\n ))) as NearestResponse<T>;\n },\n /**\n * Count rows in the collection (SDK 4.0). Pass an optional filter\n * to scope; omit it for the total. The server's response unwraps to\n * a bare number on the JS side.\n */\n count: async (name: string, filter?: Filter): Promise<number> => {\n return (await coreCall((c) => c.collectionsCount(\n name,\n filter ? encodeJson(filter) : undefined,\n ))) as number;\n },\n /** Filter DSL helpers — pass into `find({ filter: f })`. */\n where: {\n eq: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"eq\",\n value,\n }),\n ne: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"ne\",\n value,\n }),\n gt: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"gt\",\n value,\n }),\n gte: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"gte\",\n value,\n }),\n lt: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"lt\",\n value,\n }),\n lte: (column: string, value: FilterValue): Filter => ({\n column,\n op: \"lte\",\n value,\n }),\n in: (column: string, values: FilterValue[]): Filter => ({\n column,\n op: \"in\",\n value: values,\n }),\n notIn: (column: string, values: FilterValue[]): Filter => ({\n column,\n op: \"not_in\",\n value: values,\n }),\n like: (column: string, pattern: string): Filter => ({\n column,\n op: \"like\",\n value: pattern,\n }),\n ilike: (column: string, pattern: string): Filter => ({\n column,\n op: \"ilike\",\n value: pattern,\n }),\n isNull: (column: string): Filter => ({ column, op: \"is_null\" }),\n isNotNull: (column: string): Filter => ({ column, op: \"is_not_null\" }),\n and: (...filters: Filter[]): Filter => ({ and: filters }),\n or: (...filters: Filter[]): Filter => ({ or: filters }),\n not: (filter: Filter): Filter => ({ not: filter }),\n },\n },\n\n /** Media uploads + CDN URL helpers. */\n storage: {\n presign: async (params: {\n bucket: string;\n filename: string;\n mimeType: string;\n sizeBytes: number;\n retentionDays?: number;\n }): Promise<PresignData> => {\n return (await coreCall((c) => c.storagePresign(\n params.bucket,\n params.filename,\n params.mimeType,\n params.sizeBytes,\n params.retentionDays ?? undefined,\n ))) as PresignData;\n },\n /**\n * Complete-flow upload: presign → PUT to R2 → commit.\n * Returns the finalized MediaAsset.\n */\n upload: async (params: {\n bucket: string;\n file: File | Blob;\n filename?: string;\n retentionDays?: number;\n }): Promise<MediaAsset> => {\n const filename =\n params.filename ??\n (\"name\" in params.file ? params.file.name : \"upload\");\n const mimeType = params.file.type || \"application/octet-stream\";\n const presign = await Amba.storage.presign({\n bucket: params.bucket,\n filename,\n mimeType,\n sizeBytes: params.file.size,\n retentionDays: params.retentionDays,\n });\n\n const uploadHeaders: Record<string, string> = {};\n for (const [k, v] of presign.upload_headers) {\n uploadHeaders[k] = v;\n }\n const putResp = await fetch(presign.upload_url, {\n method: \"PUT\",\n headers: uploadHeaders,\n body: params.file,\n });\n if (!putResp.ok) {\n throw new Error(`upload to R2 failed: status ${putResp.status}`);\n }\n\n return (await coreCall((c) => c.storageCommit(\n presign.upload_id,\n presign.asset_id,\n ))) as MediaAsset;\n },\n /**\n * List media assets (SDK 4.0). Pass `prefix` to scope to a key\n * prefix (filename / path-like). Without it, returns the caller's\n * full list. Server enforces RLS — only the calling user's assets\n * are returned.\n */\n list: async (prefix?: string): Promise<MediaListResponse> => {\n return (await coreCall((c) => c.storageList(\n prefix ?? undefined,\n ))) as MediaListResponse;\n },\n /**\n * Soft-delete the asset (SDK 4.0). Accepts the asset id returned\n * by `presign` / `commit` / `list`. The corresponding R2 object\n * is removed asynchronously on the server.\n */\n delete: async (assetId: string): Promise<void> => {\n await coreCall((c) => c.storageDelete(assetId));\n },\n /**\n * Download an asset's bytes (SDK 4.0). Returns a `Blob` wrapping\n * the Uint8Array returned by the engine, so consumers can\n * call `.text()` / `.arrayBuffer()` / `.stream()` directly or\n * pipe to a `URL.createObjectURL()` for preview. The two-step\n * fetch (asset metadata → CDN GET) is handled server-side on\n * the WASM side; this method is single-call from the consumer.\n */\n download: async (assetId: string): Promise<Blob> => {\n const bytes = (await coreCall((c) => c.storageDownload(\n assetId,\n ))) as Uint8Array;\n // `Blob` is universally available in browsers and Node 18+,\n // so no platform-shim needed. Type defaults to\n // `application/octet-stream` — the caller knows the real type\n // from their original upload metadata if they need it.\n // Cast through `BlobPart` — under newer @types/node typings,\n // `Uint8Array<ArrayBufferLike>` widens to `ArrayBufferLike`\n // which TS refuses to narrow back to `BlobPart`'s\n // `ArrayBufferView<ArrayBuffer>` constituent. The runtime\n // is fine — `Blob` accepts any TypedArray.\n return new Blob([bytes as unknown as BlobPart]);\n },\n },\n\n /** Offline change replay (SDK 4.0). */\n sync: {\n /**\n * Replay a batch of buffered mutations\n * (`POST /v1/client/sync`). The server applies them in order and\n * returns the count of successfully-applied changes plus any\n * per-row conflicts. Conflict resolution in 4.0 is always\n * server-wins; the `SyncConflict.resolution` field is reserved\n * for future strategies.\n */\n pushChanges: async (\n changes: SyncChange[],\n ): Promise<PushChangesResult> => {\n return (await coreCall((c) => c.syncPushChanges(\n encodeJson(changes),\n ))) as PushChangesResult;\n },\n /**\n * Pull remote-origin changes since the supplied cursor\n * (`GET /v1/client/sync`). Pass the `checkpoint_token` from the\n * previous `pushChanges` / `pullChanges` reply, and the\n * `entity_type` to scope to a single collection. On the first\n * call, omit `checkpoint_token` to receive the full backfill.\n */\n pullChanges: async (\n since: PullChangesCursor,\n ): Promise<PullChangesResult> => {\n return (await coreCall((c) => c.syncPullChanges(\n encodeJson(since),\n ))) as PullChangesResult;\n },\n },\n\n /** Push notifications. */\n push: {\n register: async (\n token: string,\n platform: PushPlatform,\n bundleId?: string,\n ): Promise<PushToken> => {\n return (await coreCall((c) => c.pushRegister(\n token,\n platform,\n bundleId ?? undefined,\n ))) as PushToken;\n },\n unregister: async (token: string): Promise<void> => {\n await coreCall((c) => c.pushUnregister(token));\n },\n getTokens: async (): Promise<PushToken[]> => {\n return (await coreCall((c) => c.pushGetTokens())) as PushToken[];\n },\n subscribe: async (topic: string): Promise<void> => {\n await coreCall((c) => c.pushSubscribe(topic));\n },\n unsubscribe: async (topic: string): Promise<void> => {\n await coreCall((c) => c.pushUnsubscribe(topic));\n },\n },\n\n /** RevenueCat/App Store/Stripe entitlements. */\n entitlements: {\n list: async (): Promise<UserEntitlement[]> => {\n return (await coreCall((c) => c.entitlementsList())) as UserEntitlement[];\n },\n has: async (name: string): Promise<boolean> => {\n return (await coreCall((c) => c.entitlementsHas(name))) as boolean;\n },\n },\n\n /** LLM proxy. */\n ai: {\n anthropic: {\n messages: {\n create: async (\n request: AiMessageRequest,\n ): Promise<AiMessageResponse> => {\n return (await coreCall((c) => c.aiAnthropicMessages(\n encodeJson(request),\n ))) as AiMessageResponse;\n },\n },\n },\n },\n\n /** Remote config bundle. */\n config: {\n fetch: async (): Promise<ConfigBundle> => {\n return (await coreCall((c) => c.configFetch())) as ConfigBundle;\n },\n },\n\n /** Server-evaluated feature flags. */\n flags: {\n fetch: async (): Promise<FlagAssignment[]> => {\n return (await coreCall((c) => c.flagsFetch())) as FlagAssignment[];\n },\n /**\n * Single-flag lookup (SDK 4.0). Wraps `GET /v1/client/flags/{key}`.\n * Returns `null` for unknown / disabled keys; other errors\n * (auth, rate-limit, network) propagate.\n */\n get: async (key: string): Promise<FlagAssignment | null> => {\n return (await coreCall((c) => c.flagsGet(key))) as FlagAssignment | null;\n },\n },\n\n /**\n * Wire-verify primitive. Call once after `configure()` to confirm\n * the SDK is talking to the right project with the right key.\n *\n * The response is entirely server-decided — none of the fields are\n * derived from request parameters — so it's trustworthy as a setup\n * check. Common usage:\n *\n * ```ts\n * const ping = await Amba.diagnostics.ping();\n * if (!ping.ok || ping.server_project_id !== expectedProjectId) {\n * throw new Error(`amba misconfigured: ${JSON.stringify(ping)}`);\n * }\n * ```\n */\n diagnostics: {\n ping: async (): Promise<PingResult> => {\n return (await coreCall((c) => c.diagnosticsPing())) as PingResult;\n },\n },\n\n // ── Gamification ──────────────────────────────────────────────────\n\n /** Achievement definitions + per-user progress. */\n achievements: {\n getAll: async (): Promise<Achievement[]> =>\n (await coreCall((c) => c.achievementsGetAll())) as Achievement[],\n getProgress: async (): Promise<AchievementProgress[]> =>\n (await coreCall((c) => c.achievementsGetProgress())) as AchievementProgress[],\n },\n\n /** Time-bounded challenges with rewards. */\n challenges: {\n getActive: async (): Promise<Challenge[]> =>\n (await coreCall((c) => c.challengesGetActive())) as Challenge[],\n get: async (id: string): Promise<Challenge> =>\n (await coreCall((c) => c.challengesGet(id))) as Challenge,\n getProgress: async (id: string): Promise<ChallengeProgress> =>\n (await coreCall((c) => c.challengesGetProgress(id))) as ChallengeProgress,\n claim: async (id: string): Promise<ChallengeProgress> =>\n (await coreCall((c) => c.challengesClaim(id))) as ChallengeProgress,\n },\n\n /** Virtual currency balances + ledger. */\n currencies: {\n getBalance: async (): Promise<CurrencyBalance[]> =>\n (await coreCall((c) => c.currenciesGetBalance())) as CurrencyBalance[],\n getTransactions: async (\n currencyKey: string,\n ): Promise<CurrencyTransaction[]> =>\n (await coreCall((c) => c.currenciesGetTransactions(\n currencyKey,\n ))) as CurrencyTransaction[],\n },\n\n /** User inventory items + purchase/consume. */\n inventory: {\n getItems: async (): Promise<InventoryItem[]> =>\n (await coreCall((c) => c.inventoryGetItems())) as InventoryItem[],\n getItem: async (id: string): Promise<InventoryItem> =>\n (await coreCall((c) => c.inventoryGetItem(id))) as InventoryItem,\n purchase: async (request: PurchaseRequest): Promise<InventoryItem> =>\n (await coreCall((c) => c.inventoryPurchase(\n encodeJson(request),\n ))) as InventoryItem,\n consume: async (request: ConsumeRequest): Promise<InventoryItem> =>\n (await coreCall((c) => c.inventoryConsume(\n encodeJson(request),\n ))) as InventoryItem,\n },\n\n /** Score rankings. */\n leaderboards: {\n get: async (key: string): Promise<Leaderboard> =>\n (await coreCall((c) => c.leaderboardsGet(key))) as Leaderboard,\n getEntries: async (\n key: string,\n limit?: number,\n ): Promise<LeaderboardEntry[]> =>\n (await coreCall((c) => c.leaderboardsGetEntries(\n key,\n limit ?? undefined,\n ))) as LeaderboardEntry[],\n getMyRank: async (key: string): Promise<LeaderboardEntry> =>\n (await coreCall((c) => c.leaderboardsGetMyRank(key))) as LeaderboardEntry,\n },\n\n /**\n * Tiered weekly leaderboard cohorts (SDK 4.0). Each user is bucketed\n * into a small cohort (~25 members) within their league tier; the\n * top scorers each week promote and the bottom scorers demote.\n */\n leagues: {\n /**\n * `GET /v1/client/leagues/me` — the caller's active-cohort\n * standing plus live rank/score and member count.\n */\n me: async (): Promise<LeagueMembership> => {\n return (await coreCall((c) => c.leaguesMe())) as LeagueMembership;\n },\n /**\n * `GET /v1/client/leagues/me/cohort` — the caller's cohort with\n * every member's anonymised standing (display name, score, rank).\n * Notably no user ids — the server strips them so a leaderboard\n * UI can render the cohort without exposing identities.\n */\n cohort: async (): Promise<LeagueCohortView> => {\n return (await coreCall((c) => c.leaguesCohort())) as LeagueCohortView;\n },\n },\n\n /** Purchase storefronts. */\n stores: {\n list: async (): Promise<Store[]> =>\n (await coreCall((c) => c.storesList())) as Store[],\n getPurchaseOptions: async (storeKey: string): Promise<PurchaseOption[]> =>\n (await coreCall((c) => c.storesGetPurchaseOptions(\n storeKey,\n ))) as PurchaseOption[],\n purchase: async (\n storeKey: string,\n purchaseOptionId: string,\n receipt: unknown,\n ): Promise<PurchaseResult> =>\n // `JSON.stringify(undefined)` returns the JS value `undefined`,\n // not a string — passing that to the WASM `storesPurchase` binding\n // crashes. Default the missing-receipt case to an empty object so\n // the server still receives valid JSON (BugBot Low 2026-05-19).\n (await coreCall((c) => c.storesPurchase(\n storeKey,\n purchaseOptionId,\n encodeJson(receipt ?? {}),\n ))) as PurchaseResult,\n },\n\n /** Experience points + level system. */\n xp: {\n getBalance: async (): Promise<XpBalance> =>\n (await coreCall((c) => c.xpGetBalance())) as XpBalance,\n getHistory: async (limit?: number): Promise<XpTransaction[]> =>\n (await coreCall((c) => c.xpGetHistory(\n limit ?? undefined,\n ))) as XpTransaction[],\n claim: async (grantKey: string): Promise<XpTransaction> =>\n (await coreCall((c) => c.xpClaim(grantKey))) as XpTransaction,\n },\n\n /** Daily-engagement streaks. */\n streaks: {\n getAll: async (): Promise<Streak[]> =>\n (await coreCall((c) => c.streaksGetAll())) as Streak[],\n qualify: async (streakKey: string): Promise<Streak> =>\n (await coreCall((c) => c.streaksQualify(streakKey))) as Streak,\n },\n\n // ── Social ─────────────────────────────────────────────────────────\n\n /** Activity feeds. */\n feeds: {\n getActivity: async (\n feed?: string,\n cursor?: string,\n ): Promise<FeedResponse> =>\n (await coreCall((c) => c.feedsGetActivity(\n feed ?? undefined,\n cursor ?? undefined,\n ))) as FeedResponse,\n },\n\n /** Friend graph + block list. */\n friends: {\n getList: async (): Promise<Friendship[]> =>\n (await coreCall((c) => c.friendsGetList())) as Friendship[],\n getFriends: async (): Promise<Friendship[]> =>\n (await coreCall((c) => c.friendsGetFriends())) as Friendship[],\n /**\n * Send a friend request to `userId` (SDK 4.0). Returns the\n * resulting `Friendship` row in `pending` state.\n */\n sendRequest: async (userId: string): Promise<Friendship> =>\n (await coreCall((c) => c.friendsSendRequest(userId))) as Friendship,\n /**\n * Accept a pending incoming friend request (SDK 4.0). Pass the\n * friendship id from `getList()`.\n */\n acceptRequest: async (friendshipId: string): Promise<Friendship> =>\n (await coreCall((c) => c.friendsAcceptRequest(\n friendshipId,\n ))) as Friendship,\n /**\n * Decline a pending incoming friend request (SDK 4.0). Removes\n * the pending row; idempotent.\n */\n declineRequest: async (friendshipId: string): Promise<void> => {\n await coreCall((c) => c.friendsDeclineRequest(friendshipId));\n },\n blockUser: async (userId: string): Promise<Friendship> =>\n (await coreCall((c) => c.friendsBlockUser(userId))) as Friendship,\n unblockUser: async (userId: string): Promise<void> => {\n await coreCall((c) => c.friendsUnblockUser(userId));\n },\n removeBlock: async (friendshipId: string): Promise<void> => {\n await coreCall((c) => c.friendsRemoveBlock(friendshipId));\n },\n /**\n * Unfriend by the other user's id (SDK 4.0). Wraps\n * `DELETE /v1/client/friends/by-user/{userId}`. Server preserves\n * blocked rows; use `unblockUser` to clear those. 404 propagates\n * as `AmbaApiError`.\n */\n removeFriend: async (userId: string): Promise<void> => {\n await coreCall((c) => c.friendsRemoveFriend(userId));\n },\n },\n\n /** Multi-user groups. */\n groups: {\n create: async (params: GroupCreate): Promise<Group> =>\n (await coreCall((c) => c.groupsCreate(encodeJson(params)))) as Group,\n get: async (id: string): Promise<Group> =>\n (await coreCall((c) => c.groupsGet(id))) as Group,\n update: async (id: string, patch: GroupUpdate): Promise<Group> =>\n (await coreCall((c) => c.groupsUpdate(id, encodeJson(patch)))) as Group,\n delete: async (id: string): Promise<void> => {\n await coreCall((c) => c.groupsDelete(id));\n },\n getMembers: async (id: string): Promise<GroupMember[]> =>\n (await coreCall((c) => c.groupsGetMembers(id))) as GroupMember[],\n join: async (id: string): Promise<GroupMember> =>\n (await coreCall((c) => c.groupsJoin(id))) as GroupMember,\n leave: async (id: string): Promise<void> => {\n await coreCall((c) => c.groupsLeave(id));\n },\n invite: async (id: string, userId: string): Promise<GroupMember> =>\n (await coreCall((c) => c.groupsInvite(id, userId))) as GroupMember,\n },\n\n /**\n * User-to-user direct messaging.\n *\n * Paths mirror the API exactly — see `apps/api/src/routes/client/messaging.ts`:\n *\n * | SDK method | API route |\n * | --------------------- | -------------------------------------------------------- |\n * | `createConversation` | POST `/v1/client/messaging/conversations` |\n * | `getConversations` | GET `/v1/client/messaging/conversations` |\n * | `listConversations` | (alias for `getConversations`) |\n * | `sendMessage` | POST `/v1/client/messaging/conversations/:id/messages` |\n * | `listMessages` | GET `/v1/client/messaging/conversations/:id/messages` |\n * | `markRead` | POST `/v1/client/messaging/conversations/:id/read` |\n *\n * Task #62 corrected `sendMessage`'s path (it previously POSTed to\n * `/messaging/messages`, a route that doesn't exist on the API), and\n * added the four missing helpers. The previous `getMessage(id)` helper\n * has been removed — there is no GET-by-id route on the server; the\n * shape consumers actually want is `listMessages(conversationId, opts)`.\n */\n messaging: {\n /**\n * `POST /v1/client/messaging/conversations` — create (or fetch the\n * existing direct) conversation. For `type: \"direct\"` with exactly\n * one other participant, the server returns the existing row if\n * one already exists between these two users — calls are\n * idempotent.\n */\n createConversation: async (\n request: CreateConversationRequest,\n ): Promise<Conversation> =>\n (await coreCall((c) => c.messagingCreateConversation(\n encodeJson(request),\n ))) as Conversation,\n\n /**\n * `GET /v1/client/messaging/conversations` — list the caller's\n * conversations. Canonical 4.0 name; the legacy `getConversations`\n * / `listConversations` are removed in 4.0 per the spec.\n */\n conversations: async (): Promise<Conversation[]> =>\n (await coreCall((c) => c.messagingGetConversations())) as Conversation[],\n\n /**\n * `POST /v1/client/messaging/conversations/:conversationId/messages`\n * — send a message into an existing conversation. The\n * `conversation_id` argument is a path parameter (not a body\n * field) — the previous SDK shape mistakenly placed it in the\n * body, which the API ignored because the route was wrong anyway.\n */\n sendMessage: async (\n conversationId: string,\n request: SendMessageRequest,\n ): Promise<Message> =>\n // The engine ABI takes a single JSON arg with\n // `conversation_id` inline — we provide a cleaner two-positional\n // shape to TS callers and re-fold conversation_id into the\n // payload here. The engine extracts it before posting.\n (await coreCall((c) => c.messagingSendMessage(\n encodeJson({ ...request, conversation_id: conversationId }),\n ))) as Message,\n\n /**\n * `GET /v1/client/messaging/conversations/:conversationId/messages`\n * — list messages in a conversation. Pagination uses `?limit=&offset=`\n * (the server's `parsePagination` clamps both; defaults to 50 / 0).\n */\n listMessages: async (\n conversationId: string,\n opts?: ListMessagesOptions,\n ): Promise<Message[]> =>\n (await coreCall((c) => c.messagingListMessages(\n conversationId,\n opts?.limit ?? undefined,\n opts?.offset ?? undefined,\n ))) as Message[],\n\n /**\n * `GET /v1/client/messaging/conversations/:conversationId/messages/:messageId`\n * — fetch a single message by id. Returns `null` when the message\n * doesn't exist or the caller can't see it. (SDK 4.0: Phase A\n * shipped the missing `amba_messaging_get_message` core symbol the\n * native SDKs were already trying to call.)\n */\n getMessage: async (\n conversationId: string,\n messageId: string,\n ): Promise<Message | null> => {\n return (await coreCall((c) => c.messagingGetMessage(\n conversationId,\n messageId,\n ))) as Message | null;\n },\n\n /**\n * `POST /v1/client/messaging/conversations/:conversationId/participants`\n * — add a participant to an existing conversation. The caller must\n * already be a participant (the server returns `403\n * NOT_A_PARTICIPANT` otherwise) — this is the peer-invite path.\n * Idempotent: re-adding an existing member returns the existing\n * participant row, not an error. Enables dynamic membership growth\n * (e.g. a circle whose members qualify over time). Server-side\n * membership management (admin/matchmaker) uses the admin\n * add-participant endpoint instead.\n */\n addParticipant: async (\n conversationId: string,\n userId: string,\n ): Promise<ConversationParticipant> =>\n (await coreCall((c) => c.messagingAddParticipant(\n conversationId,\n userId,\n ))) as ConversationParticipant,\n\n /**\n * `POST /v1/client/messaging/conversations/:conversationId/read`\n * — bump the caller's `last_read_at` for the conversation. Returns\n * the updated participant row.\n */\n markRead: async (conversationId: string): Promise<MarkReadResult> =>\n (await coreCall((c) => c.messagingMarkRead(\n conversationId,\n ))) as MarkReadResult,\n\n /**\n * Live message subscriptions (SDK 4.0). Returns a builder — call\n * `.subscribe(cb)` to receive new messages in a conversation live\n * instead of polling `listMessages`. `subscribe` returns an\n * unsubscribe handle.\n *\n * @example\n * const unsub = Amba.messaging\n * .conversation(conversationId)\n * .subscribe((change) => {\n * // change.op === \"INSERT\"; change.row is the new message\n * appendMessageToThread(change.row);\n * });\n * // later: unsub();\n *\n * Delivery is scoped to conversation participants — you receive a\n * conversation's messages only if your session is a member of it.\n * Requires an authenticated session.\n */\n conversation: <T = Message>(conversationId: string): ConversationSubscription<T> =>\n new ConversationSubscription<T>(\n { baseUrl: _configuredApiUrl, authHeaders: realtimeAuthHeaders },\n conversationId,\n ),\n },\n\n /** Report users / content for moderation. */\n moderation: {\n reportUser: async (request: ReportRequest): Promise<Report> =>\n (await coreCall((c) => c.moderationReportUser(\n encodeJson(request),\n ))) as Report,\n reportContent: async (request: ReportRequest): Promise<Report> =>\n (await coreCall((c) => c.moderationReportContent(\n encodeJson(request),\n ))) as Report,\n getReportStatus: async (id: string): Promise<Report> =>\n (await coreCall((c) => c.moderationGetReportStatus(id))) as Report,\n },\n\n /** User reviews of catalog items or other users. */\n reviews: {\n list: async (targetType: string, targetId: string): Promise<Review[]> =>\n (await coreCall((c) => c.reviewsList(targetType, targetId))) as Review[],\n create: async (params: ReviewCreate): Promise<Review> =>\n (await coreCall((c) => c.reviewsCreate(encodeJson(params)))) as Review,\n update: async (id: string, patch: ReviewUpdate): Promise<Review> =>\n (await coreCall((c) => c.reviewsUpdate(id, encodeJson(patch)))) as Review,\n delete: async (id: string): Promise<void> => {\n await coreCall((c) => c.reviewsDelete(id));\n },\n },\n\n /** RBAC roles + permission checks. */\n roles: {\n getMyRoles: async (): Promise<Role[]> =>\n (await coreCall((c) => c.rolesGetMyRoles())) as Role[],\n hasPermission: async (permission: string): Promise<boolean> =>\n (await coreCall((c) => c.rolesHasPermission(permission))) as boolean,\n },\n\n /** Referral codes + claim flow. */\n referrals: {\n getReferralCode: async (): Promise<ReferralCode> =>\n (await coreCall((c) => c.referralsGetReferralCode())) as ReferralCode,\n claimReferral: async (code: string): Promise<ReferralClaim> =>\n (await coreCall((c) => c.referralsClaimReferral(code))) as ReferralClaim,\n create: async (\n code?: string,\n maxUses?: number,\n ): Promise<ReferralCode> =>\n (await coreCall((c) => c.referralsCreate(\n code ?? undefined,\n maxUses ?? undefined,\n ))) as ReferralCode,\n },\n\n // ── Lifecycle ──────────────────────────────────────────────────────\n\n /** Read-only product catalog. */\n catalog: {\n list: async (): Promise<CatalogItem[]> =>\n (await coreCall((c) => c.catalogList())) as CatalogItem[],\n /**\n * Fetch a single catalog item by id (SDK 4.0).\n * `GET /v1/client/catalog/:id`.\n */\n get: async (id: string): Promise<CatalogItem> =>\n (await coreCall((c) => c.catalogGet(id))) as CatalogItem,\n },\n\n /** Developer-defined content items (daily quotes, lessons, etc.). */\n content: {\n /**\n * Get today's published item for `channel`. Defaults to `\"default\"`\n * so single-channel apps can call `Amba.content.today()` bare.\n * (Canonical 4.0 name; legacy `getToday` is removed.)\n */\n today: async (channel: string = \"default\"): Promise<ContentItem | null> =>\n (await coreCall((c) => c.contentGetToday(channel))) as ContentItem | null,\n /**\n * Paginated library list for `channel`. `options.limit` caps page size\n * (server default applies when omitted); `options.cursor` is the\n * opaque token returned by a prior response's `next_cursor`.\n * (Canonical 4.0 name; legacy `getLibrary` is removed.)\n */\n library: async (\n channel: string = \"default\",\n options?: { limit?: number; cursor?: string },\n ): Promise<ContentItem[]> =>\n (await coreCall((c) => c.contentGetLibrary(\n channel,\n options?.limit ?? undefined,\n options?.cursor ?? undefined,\n ))) as ContentItem[],\n item: async (id: string): Promise<ContentItem> =>\n (await coreCall((c) => c.contentGetItem(id))) as ContentItem,\n updateItem: async (id: string, state: unknown): Promise<ContentItem> =>\n (await coreCall((c) => c.contentUpdateItem(\n id,\n encodeJson(state),\n ))) as ContentItem,\n createItem: async (\n channel: string,\n item: unknown,\n ): Promise<ContentItem> =>\n (await coreCall((c) => c.contentCreateItem(\n channel,\n encodeJson(item),\n ))) as ContentItem,\n },\n\n /** Server-managed deep link records. */\n deepLinks: {\n get: async (shortCode: string): Promise<DeepLink> =>\n (await coreCall((c) => c.deepLinksGet(shortCode))) as DeepLink,\n create: async (params: DeepLinkCreate): Promise<DeepLink> =>\n (await coreCall((c) => c.deepLinksCreate(encodeJson(params)))) as DeepLink,\n },\n\n /** Step-by-step user onboarding flow. */\n onboarding: {\n getStatus: async (): Promise<OnboardingStatus> =>\n (await coreCall((c) => c.onboardingGetStatus())) as OnboardingStatus,\n nextStep: async (payload: unknown): Promise<OnboardingStatus> =>\n (await coreCall((c) => c.onboardingNextStep(\n encodeJson(payload),\n ))) as OnboardingStatus,\n skipStep: async (): Promise<OnboardingStatus> =>\n (await coreCall((c) => c.onboardingSkipStep())) as OnboardingStatus,\n complete: async (): Promise<OnboardingStatus> =>\n (await coreCall((c) => c.onboardingComplete())) as OnboardingStatus,\n },\n\n};\n\n/** Escape hatch — the raw SDK runtime handle, for namespaces not yet wrapped. */\nexport function getCoreWasm(): AmbaCoreWasm {\n return requireCore();\n}\n\n/**\n * Package version stamped at build time. Sent in the\n * `sdk_wrapper_version` header on every customer request.\n *\n * **Must match `package.json#version` exactly** — the\n * `verify-sdk-version-coherence` GH action gates every publish on the\n * pair agreeing (and matching the `web-v<X.Y.Z>` tag when tag-triggered).\n */\nexport const SDK_VERSION = \"4.0.3\";\n"],"mappings":"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"}
|