@layers/amba-web 4.0.4 → 4.0.5

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 CHANGED
@@ -114,6 +114,38 @@ interface OrderBy {
114
114
  column: string;
115
115
  direction: "asc" | "desc";
116
116
  }
117
+ /**
118
+ * Eager-load related rows from another collection in the same `find` call,
119
+ * avoiding an N+1 round-trip per base row. Single-level (MVP).
120
+ *
121
+ * belongs-to — each base row's `localKey` column points at the related row:
122
+ * { collection: "novels", localKey: "novel_id", as: "novel", single: true }
123
+ * → row.novel = the matching novels row (or null)
124
+ *
125
+ * has-many — the related collection's `foreignKey` column points back at the
126
+ * base row's id:
127
+ * { collection: "chapters", foreignKey: "novel_id", as: "chapters" }
128
+ * → row.chapters = the matching chapters rows (array)
129
+ *
130
+ * The included collection's own read policy + soft-delete are honored.
131
+ */
132
+ interface IncludeClause {
133
+ /** Target collection to eager-load from. */
134
+ collection: string;
135
+ /** belongs-to: FK column on the base row pointing at the target. */
136
+ localKey?: string;
137
+ /**
138
+ * Join column on the target. belongs-to: defaults to `id`. has-many:
139
+ * required — the FK column on the target pointing back at the base id.
140
+ */
141
+ foreignKey?: string;
142
+ /** Result key the nested data lands under on each base row. */
143
+ as: string;
144
+ /** belongs-to only: nest a single object instead of an array. */
145
+ single?: boolean;
146
+ /** has-many only: cap related rows per base row (default 100, max 1000). */
147
+ limit?: number;
148
+ }
117
149
  interface FindOptions {
118
150
  filter?: Filter;
119
151
  order?: OrderBy[];
@@ -121,12 +153,61 @@ interface FindOptions {
121
153
  cursor?: string;
122
154
  select?: string[];
123
155
  include_deleted?: boolean;
156
+ /** Eager-load related rows from other collections (kills N+1). */
157
+ include?: IncludeClause[];
124
158
  }
125
159
  interface FindResponse<T> {
126
160
  data: T[];
127
161
  next_cursor?: string | null;
128
162
  has_more: boolean;
129
163
  }
164
+ /**
165
+ * Options for {@link Amba.collections.upsert}.
166
+ *
167
+ * `conflictTarget` is the set of columns covered by the unique index the
168
+ * upsert arbitrates on (e.g. `["user_id", "kind"]`). Every column must be
169
+ * present in the inserted row. `onConflict: "ignore"` keeps the existing
170
+ * row and returns it; `"update"` merges the supplied columns into it.
171
+ */
172
+ interface UpsertOptions {
173
+ onConflict: "ignore" | "update";
174
+ conflictTarget: string[];
175
+ }
176
+ /** Result of {@link Amba.collections.deleteWhere} — the soft-deleted row count. */
177
+ interface DeleteManyResult {
178
+ data: {
179
+ deleted: number;
180
+ };
181
+ }
182
+ /**
183
+ * One operation in an atomic multi-collection transaction
184
+ * ({@link Amba.collections.transaction}). Mirrors the single-row methods:
185
+ * `insert` carries `row` (+ optional upsert controls); `update` carries `id` +
186
+ * `set` (+ optional `expected` compare-and-set); `delete` carries `id` (+
187
+ * optional `expected`). `where` is an extra guard predicate AND'd onto the
188
+ * owner scope.
189
+ */
190
+ interface TransactionOp {
191
+ collection: string;
192
+ op: "insert" | "update" | "delete";
193
+ id?: string;
194
+ row?: Record<string, unknown>;
195
+ set?: Record<string, unknown>;
196
+ where?: Record<string, unknown>;
197
+ expected?: Record<string, unknown>;
198
+ onConflict?: "ignore" | "update";
199
+ conflictTarget?: string[];
200
+ }
201
+ /** One per-op result returned by a committed transaction. */
202
+ interface TransactionOpResult {
203
+ index: number;
204
+ op: "insert" | "update" | "delete";
205
+ collection: string;
206
+ id: string | null;
207
+ created?: boolean;
208
+ deleted?: boolean;
209
+ row?: Record<string, unknown>;
210
+ }
130
211
  interface MediaAsset {
131
212
  id: string;
132
213
  bucket: string;
@@ -152,27 +233,120 @@ interface PushToken {
152
233
  bundle_id?: string | null;
153
234
  created_at: string;
154
235
  }
155
- type EntitlementSource = "revenue_cat" | "app_store" | "play_store" | "stripe" | "promo_code" | "manual";
236
+ /**
237
+ * Store an entitlement's purchase resolved from. `"web"` is the neutral bucket
238
+ * for any non-native checkout (it replaced the former `"stripe"` value).
239
+ */
240
+ type EntitlementStore = "app_store" | "play_store" | "web";
241
+ /** Lifecycle phase of the subscription period backing the entitlement. */
242
+ type EntitlementPeriodType = "trial" | "intro" | "normal";
243
+ /**
244
+ * A server-evaluated entitlement grant, mirroring the
245
+ * `GET /v1/client/entitlements` response field-for-field. `store` and
246
+ * `period_type` are nullable, CHECK-constrained text columns, typed
247
+ * loosely (`… | (string & {}) | null`) so an unexpected value from a newer
248
+ * server never breaks decoding while still autocompleting the known set.
249
+ */
156
250
  interface UserEntitlement {
157
- id: string;
158
- name: string;
251
+ /** Project-defined entitlement key (e.g. `"pro"`) — what `has()` checks. */
252
+ entitlement_id: string;
159
253
  is_active: boolean;
160
- source: EntitlementSource;
161
- expires_at?: string | null;
162
- granted_at?: string | null;
254
+ product_id?: string | null;
255
+ store?: EntitlementStore | (string & {}) | null;
256
+ purchase_date?: string | null;
257
+ expiration_date?: string | null;
258
+ period_type?: EntitlementPeriodType | (string & {}) | null;
259
+ }
260
+ /** Result of `entitlements.restore()` — the active set after a server re-sync. */
261
+ interface RestoreResult {
262
+ restored_count: number;
263
+ entitlements: UserEntitlement[];
264
+ }
265
+ /** A product behind an offering package (provider-neutral). */
266
+ interface OfferingProduct {
267
+ product_id: string;
268
+ display_name?: string | null;
269
+ description?: string | null;
270
+ product_type?: string | null;
271
+ /** Map of neutral store id → that store's product identifier. */
272
+ store_product_refs: Record<string, string>;
273
+ grants_entitlement_id?: string | null;
274
+ trial_period_days?: number | null;
275
+ /** ISO-8601 duration display hint (e.g. "P1M", "P1Y"). */
276
+ duration?: string | null;
277
+ }
278
+ /** A package — one product at a position within an offering. */
279
+ interface OfferingPackage {
280
+ package_id: string;
281
+ position: number;
282
+ metadata: Record<string, unknown>;
283
+ product: OfferingProduct | null;
284
+ }
285
+ interface Offering {
286
+ offering_id: string;
287
+ display_name?: string | null;
288
+ description?: string | null;
289
+ /** Whether this is the default offering to show. */
290
+ current: boolean;
163
291
  metadata: Record<string, unknown>;
292
+ packages: OfferingPackage[];
293
+ }
294
+ /** The shape `offerings()` returns. */
295
+ interface OfferingsResult {
296
+ offerings: Offering[];
297
+ current_offering_id: string | null;
164
298
  }
165
299
  interface AiMessage {
166
300
  role: string;
167
301
  content: unknown;
168
302
  }
303
+ /**
304
+ * A single vendor-neutral image for vision (multimodal) prompts. Provide a
305
+ * remote `url` OR base64 `data` (+ optional `mime`). Amba maps it to the
306
+ * model's native image format — you never touch provider-specific shapes.
307
+ */
308
+ interface AiImageInput {
309
+ /** Remote image URL. Use this OR `data`, not both. */
310
+ url?: string;
311
+ /** Base64-encoded image bytes (no `data:` prefix). */
312
+ data?: string;
313
+ /** MIME type for a base64 image (e.g. `"image/png"`). Defaults to image/png. */
314
+ mime?: string;
315
+ }
316
+ /** A vendor-neutral content block inside a message's `content` array. */
317
+ type AiContentBlock = {
318
+ type: "text";
319
+ text: string;
320
+ } | {
321
+ type: "image";
322
+ url?: string;
323
+ data?: string;
324
+ mime?: string;
325
+ };
169
326
  interface AiMessageRequest {
170
327
  prompt_slug: string;
171
328
  variables?: Record<string, unknown>;
172
329
  messages?: AiMessage[];
330
+ /**
331
+ * Image(s) to send to a vision-capable prompt. They attach to the last user
332
+ * message as vendor-neutral content blocks; the backend maps them to the
333
+ * model's native image format. The prompt's model must be vision-capable, or
334
+ * the call returns `ai_model_not_multimodal`. Omit for text-only prompts.
335
+ */
336
+ images?: AiImageInput[];
173
337
  max_tokens?: number;
174
338
  temperature?: number;
175
339
  enable_prompt_cache?: boolean;
340
+ /**
341
+ * Opt into a streamed (SSE) response from the backend. NOTE: the buffered
342
+ * `ai.anthropic.messages.create()` decodes a single JSON envelope, so it
343
+ * ignores this flag — to consume streamed tokens use the dedicated
344
+ * `ai.anthropic.messages.stream()` / `ai.openai.chat.completions.stream()`
345
+ * methods, which set `stream: true` for you and yield text deltas as they
346
+ * arrive plus a final usage event. The field exists so the request type
347
+ * matches the backend contract.
348
+ */
349
+ stream?: boolean;
176
350
  }
177
351
  interface AiUsage {
178
352
  input_tokens: number;
@@ -185,6 +359,13 @@ interface AiMessageResponse {
185
359
  usage: AiUsage;
186
360
  stop_reason?: string | null;
187
361
  model: string;
362
+ /**
363
+ * Computed USD cost of this call (input + output + cache token rates,
364
+ * summed server-side). `null` when the model isn't in the cost table — the
365
+ * call still succeeds; the cost is just unattributed. Read it to surface
366
+ * per-call spend without a separate analytics round-trip.
367
+ */
368
+ cost_usd?: number | null;
188
369
  }
189
370
  /**
190
371
  * Resolved remote config returned by `config.fetch()`.
@@ -723,6 +904,60 @@ interface MediaListResponse {
723
904
  data: MediaAsset[];
724
905
  next_cursor?: string | null;
725
906
  }
907
+ /** A single asset within a media catalog, resolved to a public URL. */
908
+ interface MediaCatalogItem {
909
+ media_id: string;
910
+ position: number;
911
+ caption?: string | null;
912
+ metadata: Record<string, unknown>;
913
+ filename: string;
914
+ mime_type: string;
915
+ /** Stable, long-cacheable public URL for the asset. */
916
+ url: string;
917
+ thumbnail_url?: string | null;
918
+ alt_text?: string | null;
919
+ blurhash?: string | null;
920
+ }
921
+ /**
922
+ * A curated, slug-addressable bundle of media assets fetched in one call.
923
+ * Items are returned in their configured order.
924
+ */
925
+ interface MediaCatalog {
926
+ slug: string;
927
+ name: string;
928
+ description?: string | null;
929
+ metadata: Record<string, unknown>;
930
+ updated_at: string;
931
+ items: MediaCatalogItem[];
932
+ }
933
+ /**
934
+ * One rule a candidate event would trigger, as returned by
935
+ * `Amba.events.explain`. `would` describes the effect that WOULD be produced
936
+ * if the event were tracked for real; `note` (when present) flags a per-user
937
+ * gate (daily limit, cooldown, balance cap) that would suppress or reduce it.
938
+ */
939
+ interface ExplainMatchedRule {
940
+ rule_type: "xp" | "currency_grant" | "feed" | "streak" | "webhook";
941
+ rule_id: string;
942
+ name: string;
943
+ would: Record<string, unknown>;
944
+ note?: string;
945
+ }
946
+ /**
947
+ * Result of a read-only event rule dry-run (`Amba.events.explain`). Producing
948
+ * this commits no side effect — it is a preview of what tracking the event
949
+ * would do across XP, currency grants, feed items, streaks, and webhooks.
950
+ */
951
+ interface EventExplainResult {
952
+ event: {
953
+ name: string;
954
+ properties: Record<string, unknown>;
955
+ user_id: string | null;
956
+ };
957
+ matched: ExplainMatchedRule[];
958
+ evaluated_surfaces: string[];
959
+ unmatched_reason_samples?: string[];
960
+ }
726
961
  /**
727
962
  * Options for `Amba.collections.findNearest`.
728
963
  *
@@ -745,6 +980,46 @@ interface NearestOptions {
745
980
  interface NearestResponse<T> {
746
981
  data: T[];
747
982
  }
983
+ /**
984
+ * When a local notification should fire. Exactly one shape:
985
+ *
986
+ * - `{ at: Date }` — fire once at an absolute time.
987
+ * - `{ inSeconds, repeats? }` — fire after a relative delay.
988
+ *
989
+ * Local notifications are scheduled and fired by the device itself, with
990
+ * no server involvement — distinct from remote push (`Amba.push.*`).
991
+ * Browser scheduling is partial; see `notifications.scheduleLocal`.
992
+ */
993
+ type LocalNotificationTrigger = {
994
+ at: Date | string;
995
+ } | {
996
+ inSeconds: number;
997
+ repeats?: boolean;
998
+ };
999
+ /** Input to `Amba.notifications.scheduleLocal`. */
1000
+ interface ScheduleLocalNotificationInput {
1001
+ /** Optional stable id; omit to let the platform mint one. */
1002
+ id?: string;
1003
+ /** Notification title (required, non-empty). */
1004
+ title: string;
1005
+ /** Notification body text. */
1006
+ body: string;
1007
+ /** Arbitrary payload delivered to the app when the notification is tapped. */
1008
+ data?: Record<string, unknown>;
1009
+ /** When to fire it. */
1010
+ trigger: LocalNotificationTrigger;
1011
+ }
1012
+ /** Handle returned by `scheduleLocal`; `id` is accepted by `cancelLocal`. */
1013
+ interface LocalNotificationHandle {
1014
+ id: string;
1015
+ }
1016
+ /** A pending local notification, as reported by `listScheduledLocal`. */
1017
+ interface ScheduledLocalNotification {
1018
+ id: string;
1019
+ title: string;
1020
+ body: string;
1021
+ data?: Record<string, unknown>;
1022
+ }
748
1023
  //#endregion
749
1024
  //#region src/realtime.d.ts
750
1025
  /**
@@ -843,6 +1118,184 @@ declare class ConversationSubscription<T = unknown> {
843
1118
  constructor(ctx: RealtimeContext, conversationId: string);
844
1119
  subscribe(cb: (change: MessageChange<T>) => void, options?: SubscribeOptions): Unsubscribe;
845
1120
  }
1121
+ /** Which slice of the signed-in user's gamification state changed. */
1122
+ type GamificationKind = "xp" | "level" | "achievement" | "streak";
1123
+ /**
1124
+ * A live change to the signed-in user's gamification state. `kind` says which
1125
+ * slice moved; `data` carries the new state inline so you can update without a
1126
+ * re-fetch:
1127
+ * - `xp` — `{ total_xp, level, delta }`
1128
+ * - `level` — `{ level, total_xp }`
1129
+ * - `achievement` — `{ achievement_id, unlocked }`
1130
+ * - `streak` — `{ streak_id, count, status, ... }`
1131
+ *
1132
+ * If a payload was too large to deliver inline, `truncated` is `true` and `data`
1133
+ * is empty — re-fetch with `Amba.xp.getBalance()` / `Amba.streaks.getAll()` etc.
1134
+ */
1135
+ interface GamificationChange<T = Record<string, unknown>> {
1136
+ kind: GamificationKind;
1137
+ data: T;
1138
+ truncated?: boolean;
1139
+ }
1140
+ /**
1141
+ * Builder returned by `Amba.gamification`. Call `.subscribe(cb)` to receive the
1142
+ * signed-in user's xp / level / achievement / streak changes live instead of
1143
+ * polling.
1144
+ *
1145
+ * const unsub = Amba.gamification.subscribe((change) => {
1146
+ * // change.kind: "xp" | "level" | "achievement" | "streak"
1147
+ * // change.data: the new state
1148
+ * });
1149
+ * unsub(); // stop listening
1150
+ *
1151
+ * Delivery is scoped to the signed-in user — you only ever receive your own
1152
+ * gamification changes, never another user's. Reconnects with the same
1153
+ * exponential backoff as collection subscriptions.
1154
+ */
1155
+ declare class GamificationSubscription {
1156
+ private readonly ctx;
1157
+ constructor(ctx: RealtimeContext);
1158
+ subscribe(cb: (change: GamificationChange) => void, options?: SubscribeOptions): Unsubscribe;
1159
+ }
1160
+ //#endregion
1161
+ //#region src/ai-stream.d.ts
1162
+ /** A streamed token delta — append `text` to your running output buffer. */
1163
+ interface AiStreamDelta {
1164
+ type: "delta";
1165
+ /** The incremental text the model just produced. */
1166
+ text: string;
1167
+ }
1168
+ /**
1169
+ * Terminal event. Emitted once when the stream completes cleanly. `usage`
1170
+ * carries the token accounting accumulated across the stream (zeroed fields
1171
+ * when the vendor didn't report a given counter); `model` / `stopReason` are
1172
+ * populated when the vendor surfaced them.
1173
+ */
1174
+ interface AiStreamDone {
1175
+ type: "done";
1176
+ usage: AiUsage;
1177
+ model?: string;
1178
+ stopReason?: string | null;
1179
+ }
1180
+ /** Vendor-neutral event yielded by the streaming AI methods. */
1181
+ type AiStreamEvent = AiStreamDelta | AiStreamDone;
1182
+ /** Options accepted by the streaming AI methods. */
1183
+ interface AiStreamOptions {
1184
+ /**
1185
+ * Optional callback invoked for every text delta as it arrives — a
1186
+ * convenience over iterating, useful when you only care about appending
1187
+ * tokens to the UI. Fires in addition to the yielded `delta` events.
1188
+ */
1189
+ onChunk?: (text: string) => void;
1190
+ }
1191
+ //#endregion
1192
+ //#region src/resilience.d.ts
1193
+ /**
1194
+ * Offline mutation queue + optimistic-update helpers — framework-agnostic
1195
+ * orchestration that sits ABOVE the collection / event write methods.
1196
+ *
1197
+ * Nothing here touches the SDK runtime directly: the queue is handed a
1198
+ * small `KvStore` (durable key/value persistence) and a `WriteExecutor`
1199
+ * (the function that actually performs a queued mutation against the API).
1200
+ * That keeps the same code identical across every JS SDK target — only the
1201
+ * adapters that supply storage + the executor differ per platform.
1202
+ *
1203
+ * Design:
1204
+ * - A write that fails because the device is offline (a transport-level
1205
+ * network error, or `navigator.onLine === false`) is appended to a
1206
+ * durable outbox instead of throwing all the way up.
1207
+ * - Each queued op carries a stable idempotency key. On replay the key is
1208
+ * forwarded to the API's collection-write idempotency support so a
1209
+ * mutation that actually reached the server before the connection
1210
+ * dropped is never applied twice.
1211
+ * - On reconnect (`online` event) the outbox is flushed in FIFO order;
1212
+ * each op is removed only after it succeeds, so a mid-flush failure
1213
+ * leaves the remainder intact for the next attempt.
1214
+ */
1215
+ /**
1216
+ * Minimal durable key/value contract the outbox persists through. Both the
1217
+ * browser `localStorage` adapter and the React Native AsyncStorage adapter
1218
+ * satisfy this — the queue never assumes anything else.
1219
+ */
1220
+ interface KvStore {
1221
+ get(key: string): Promise<string | null> | string | null;
1222
+ set(key: string, value: string): Promise<void> | void;
1223
+ delete(key: string): Promise<void> | void;
1224
+ }
1225
+ /** The kinds of mutation the outbox can durably replay. */
1226
+ type OutboxOpKind = "collection.insert" | "collection.update" | "collection.delete" | "track";
1227
+ /**
1228
+ * A single durably-queued mutation. `idempotencyKey` is reused verbatim on
1229
+ * every replay attempt so the server dedupes a COLLECTION write that landed
1230
+ * before the connection dropped (the events `track` API has no idempotency
1231
+ * channel, so `track` replays are at-least-once — a rare reconnect duplicate
1232
+ * is acceptable for fire-and-forget analytics). `enqueuedAt` is an ISO
1233
+ * timestamp for inspection.
1234
+ */
1235
+ interface OutboxOp {
1236
+ /** Stable per-op id (the idempotency key for collection writes). */
1237
+ idempotencyKey: string;
1238
+ kind: OutboxOpKind;
1239
+ /** Target collection name (absent for `track`). */
1240
+ collection?: string;
1241
+ /** Row id for update / delete. */
1242
+ id?: string;
1243
+ /** Insert row / update set payload. */
1244
+ payload?: Record<string, unknown>;
1245
+ /** Event name for `track`. */
1246
+ event?: string;
1247
+ /** Event properties for `track`. */
1248
+ properties?: Record<string, unknown>;
1249
+ /** Whether the tracked event was telemetry-tier. */
1250
+ telemetry?: boolean;
1251
+ /**
1252
+ * ISO timestamp the `track` originally OCCURRED, captured at enqueue. Replayed
1253
+ * as the events body `timestamp` (→ `occurred_at`) so a buffered event keeps
1254
+ * its real time instead of being re-stamped at flush. (Attribution is by the
1255
+ * session user at replay time — the events route has no body-id channel.)
1256
+ */
1257
+ occurredAt?: string;
1258
+ enqueuedAt: string;
1259
+ }
1260
+ /** Result of a {@link OfflineQueue.flush}. */
1261
+ interface FlushResult {
1262
+ /** Ops successfully replayed and removed from the outbox. */
1263
+ flushed: number;
1264
+ /**
1265
+ * Ops dropped because their replay failed deterministically (a coded server
1266
+ * rejection like `VALIDATION_ERROR` / `NOT_FOUND` that would fail identically
1267
+ * forever). Dropping them prevents one poisoned op from wedging the queue;
1268
+ * the drain continues past it.
1269
+ */
1270
+ dropped: number;
1271
+ /** Ops still pending after the flush (a replay failed and stopped it). */
1272
+ remaining: number;
1273
+ }
1274
+ /**
1275
+ * Apply a local change immediately, fire the real mutation, and roll the
1276
+ * local change back if the mutation fails. Framework-agnostic: `apply` and
1277
+ * `rollback` operate on whatever local view you hand them (a React state
1278
+ * setter, a store, an in-memory cache).
1279
+ *
1280
+ * Resolves with the mutation's result on success. On failure it invokes
1281
+ * `rollback` (with the value `apply` returned, so you can restore a captured
1282
+ * snapshot) and rethrows the original error.
1283
+ *
1284
+ * @example
1285
+ * await withOptimistic({
1286
+ * apply: () => { const prev = todos; setTodos([...todos, draft]); return prev; },
1287
+ * mutate: () => Amba.collections.insert("todos", draft),
1288
+ * rollback: (prev) => setTodos(prev),
1289
+ * });
1290
+ */
1291
+ declare function withOptimistic<TApply, TResult>(spec: {
1292
+ /** Mutate the local view now. Return a snapshot for `rollback` to restore. */
1293
+ apply: () => TApply;
1294
+ /** The real async mutation against the API. */
1295
+ mutate: () => Promise<TResult>;
1296
+ /** Undo the local change. Receives whatever `apply` returned. */
1297
+ rollback: (applied: TApply) => void;
1298
+ }): Promise<TResult>;
846
1299
  //#endregion
847
1300
  //#region src/error.d.ts
848
1301
  /**
@@ -862,13 +1315,38 @@ declare class ConversationSubscription<T = unknown> {
862
1315
  * `new AmbaApiError("MY_CODE", "...")` without coordinating with this
863
1316
  * package's TypeScript types.
864
1317
  */
865
- type AmbaApiErrorCode = "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "CONFLICT" | "RATE_LIMITED" | "VALIDATION_ERROR" | "NETWORK_ERROR" | "HTTP_ERROR" | "CIRCUIT_OPEN" | "CONSENT_NOT_GRANTED" | "NOT_INITIALIZED" | "INVALID_CONFIG" | "INVALID_ARGUMENT" | "PUSH_PERMISSION_DENIED" | "PUSH_REGISTRATION_FAILED" | "NOT_SANDBOX_TIER" | "UNKNOWN_ERROR" | (string & {});
1318
+ type AmbaApiErrorCode = "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "CONFLICT" | "RATE_LIMITED" | "VALIDATION_ERROR" | "NETWORK_ERROR" | "HTTP_ERROR" | "CIRCUIT_OPEN" | "CONSENT_NOT_GRANTED" | "NOT_INITIALIZED" | "INVALID_CONFIG" | "INVALID_ARGUMENT" | "PUSH_PERMISSION_DENIED" | "PUSH_REGISTRATION_FAILED" | "LOCAL_NOTIFICATIONS_UNAVAILABLE" | "LOCAL_NOTIFICATIONS_PERMISSION_DENIED" | "NOT_SANDBOX_TIER" | "UNKNOWN_ERROR" | (string & {});
866
1319
  declare class AmbaApiError extends Error {
867
1320
  readonly code: AmbaApiErrorCode;
868
1321
  readonly details?: unknown;
1322
+ /**
1323
+ * Server-side request / trace id (the `X-Amba-Request-Id` response
1324
+ * header, falling back to the `request_id` field in the standard error
1325
+ * envelope). Present on errors thrown by `Amba.functions.invoke()` so a
1326
+ * failed run can be correlated with server logs
1327
+ * (`functions logs --request-id <traceId>`). `undefined` when the failure
1328
+ * happened before a response was received (e.g. a transport error).
1329
+ */
1330
+ traceId?: string;
869
1331
  constructor(code: AmbaApiErrorCode, message: string, details?: unknown);
870
1332
  }
871
1333
  //#endregion
1334
+ //#region src/local-notifications.d.ts
1335
+ /**
1336
+ * The web `notifications` namespace. Web capability is partial — see the
1337
+ * module-level doc. The returned handle includes `scheduledVia` so apps
1338
+ * can detect whether the notification was handed to the OS
1339
+ * (`"os-trigger"`) or relies on an in-page timer (`"timer"`).
1340
+ */
1341
+ declare const notifications: {
1342
+ scheduleLocal(input: ScheduleLocalNotificationInput): Promise<LocalNotificationHandle & {
1343
+ scheduledVia: "os-trigger" | "timer";
1344
+ }>;
1345
+ cancelLocal(id: string): Promise<void>;
1346
+ listScheduledLocal(): Promise<ScheduledLocalNotification[]>;
1347
+ };
1348
+ type LocalNotificationsNamespace = typeof notifications;
1349
+ //#endregion
872
1350
  //#region src/index.d.ts
873
1351
  /** Options for `Amba.functions.invoke`. */
874
1352
  interface InvokeOptions {
@@ -876,6 +1354,18 @@ interface InvokeOptions {
876
1354
  method?: "POST" | "GET" | "PUT" | "PATCH" | "DELETE";
877
1355
  /** Extra headers merged on top of the injected auth headers. */
878
1356
  headers?: Record<string, string>;
1357
+ /**
1358
+ * Called with the server-side request / trace id (the
1359
+ * `X-Amba-Request-Id` response header) as soon as a response is
1360
+ * received — on both success and failure. Use it to correlate a run with
1361
+ * server logs (`functions logs --request-id <traceId>`). `null` when the
1362
+ * server returned no trace id (e.g. a pre-auth rejection that doesn't
1363
+ * stamp the header).
1364
+ *
1365
+ * The same id is also attached to any thrown `AmbaApiError` as
1366
+ * `error.traceId`, so error-path correlation works without a callback.
1367
+ */
1368
+ onTraceId?: (traceId: string | null) => void;
879
1369
  }
880
1370
  /**
881
1371
  * Top-level SDK namespace.
@@ -925,6 +1415,23 @@ declare const Amba: {
925
1415
  track: (event: string, properties?: Record<string, unknown>, options?: {
926
1416
  telemetry?: boolean;
927
1417
  }) => Promise<void>;
1418
+ /**
1419
+ * Dry-run an event against the rule engine WITHOUT firing it. Returns
1420
+ * which rules would match and what each WOULD produce — XP awards,
1421
+ * currency grants, feed items, streak qualification, and webhook
1422
+ * deliveries — so you can predict the consequences of a `track` call
1423
+ * before committing any side effect. Nothing is written.
1424
+ *
1425
+ * Pass `{ userId }` to also preview per-user gating (daily limits,
1426
+ * cooldowns, balance caps); omit it for the user-independent base match.
1427
+ *
1428
+ * @example
1429
+ * const plan = await Amba.events.explain('lesson_completed', { score: 90 });
1430
+ * // plan.matched → [{ rule_type: 'xp', would: { xp_delta: 25 }, ... }, ...]
1431
+ */
1432
+ explain: (event: string, properties?: Record<string, unknown>, options?: {
1433
+ userId?: string | null;
1434
+ }) => Promise<EventExplainResult>;
928
1435
  };
929
1436
  /** Authentication flows. */
930
1437
  auth: {
@@ -1172,6 +1679,54 @@ declare const Amba: {
1172
1679
  deleted: boolean;
1173
1680
  };
1174
1681
  }>;
1682
+ /**
1683
+ * Insert a row, resolving a unique-index conflict instead of failing.
1684
+ *
1685
+ * With `options.onConflict: "ignore"` a conflicting row is left
1686
+ * untouched and returned; with `"update"` the supplied columns are
1687
+ * merged into the existing row. `options.conflictTarget` names the
1688
+ * unique-index columns to arbitrate on (e.g. `["user_id", "kind"]`) and
1689
+ * every one must be present in `row`. Auto-RLS still applies — the
1690
+ * ignore-fallback / merge is scoped to the caller's own rows.
1691
+ *
1692
+ * @example
1693
+ * await Amba.collections.upsert("prefs",
1694
+ * { kind: "theme", value: "dark" },
1695
+ * { onConflict: "update", conflictTarget: ["kind"] });
1696
+ */
1697
+ upsert: <T = unknown>(name: string, row: Record<string, unknown>, options: UpsertOptions) => Promise<T>;
1698
+ /**
1699
+ * Bulk soft-delete every row matching `filter`. Returns the count of
1700
+ * rows deleted. Auto-RLS scopes the delete to the caller's own rows;
1701
+ * soft-deleted rows can be brought back with {@link restore}.
1702
+ *
1703
+ * @example
1704
+ * const { data } = await Amba.collections.deleteWhere(
1705
+ * "todos", Amba.collections.where.eq("status", "done"));
1706
+ * console.log(`${data.deleted} removed`);
1707
+ */
1708
+ deleteWhere: (name: string, filter: Filter) => Promise<DeleteManyResult>;
1709
+ /**
1710
+ * Restore a previously soft-deleted row by id (clears `deleted_at`).
1711
+ * Returns the restored row. Only rows currently soft-deleted and owned
1712
+ * by the caller can be restored; anything else resolves as not-found.
1713
+ */
1714
+ restore: <T = unknown>(name: string, id: string) => Promise<T>;
1715
+ /**
1716
+ * Run an ordered list of writes (insert / update / delete, across any
1717
+ * collections) as ONE atomic transaction. The whole batch commits, or — if
1718
+ * any op fails — rolls back entirely; a partial multi-write can never
1719
+ * persist. Resolves to the per-op results; throws naming the failing op
1720
+ * index (`details.opIndex`) on rollback. Each op honors the same auto-RLS /
1721
+ * owner-scoping / compare-and-set rules as the single-row methods.
1722
+ *
1723
+ * @example
1724
+ * await Amba.collections.transaction([
1725
+ * { collection: "carts", op: "insert", row: { sku: "widget", qty: 2 } },
1726
+ * { collection: "inventory", op: "update", id: invId, set: { reserved: 2 } },
1727
+ * ]);
1728
+ */
1729
+ transaction: (operations: TransactionOp[]) => Promise<TransactionOpResult[]>;
1175
1730
  /**
1176
1731
  * Vector-search the collection (SDK 4.0). Returns the `k` nearest
1177
1732
  * neighbors of `options.query_vector` against the column named
@@ -1191,6 +1746,45 @@ declare const Amba: {
1191
1746
  * a bare number on the JS side.
1192
1747
  */
1193
1748
  count: (name: string, filter?: Filter) => Promise<number>;
1749
+ /**
1750
+ * Optimistic insert — update a local view immediately, fire the real
1751
+ * insert, and roll the local view back if it fails. The reconcile is your
1752
+ * own (replace the temporary local row with the server's authoritative
1753
+ * row in your `apply`/`rollback` handlers). Thin convenience over the
1754
+ * exported {@link withOptimistic} so the common single-write case reads
1755
+ * clean; for multi-step flows use `withOptimistic` directly.
1756
+ *
1757
+ * Optimistic writes always hit the network directly — they are NOT
1758
+ * diverted to the offline outbox even when `Amba.offline` is enabled.
1759
+ * Optimistic UI needs an unambiguous outcome: this resolves only on a
1760
+ * confirmed server write, and rejects (running your `rollback`) on any
1761
+ * failure including being offline. To buffer-and-replay instead, use the
1762
+ * plain `insert`/`update`/`delete` with the outbox on.
1763
+ *
1764
+ * @example
1765
+ * await Amba.collections.optimisticInsert("todos", draft, {
1766
+ * apply: () => { const prev = todos; setTodos([...todos, draft]); return prev; },
1767
+ * rollback: (prev) => setTodos(prev),
1768
+ * });
1769
+ */
1770
+ optimisticInsert: <T = unknown, TApply = unknown>(name: string, row: Record<string, unknown>, view: {
1771
+ apply: () => TApply;
1772
+ rollback: (applied: TApply) => void;
1773
+ }) => Promise<T>;
1774
+ /** Optimistic update — see {@link optimisticInsert}. */
1775
+ optimisticUpdate: <T = unknown, TApply = unknown>(name: string, id: string, set: Record<string, unknown>, view: {
1776
+ apply: () => TApply;
1777
+ rollback: (applied: TApply) => void;
1778
+ }) => Promise<T>;
1779
+ /** Optimistic delete — see {@link optimisticInsert}. */
1780
+ optimisticDelete: <TApply = unknown>(name: string, id: string, view: {
1781
+ apply: () => TApply;
1782
+ rollback: (applied: TApply) => void;
1783
+ }) => Promise<{
1784
+ data: {
1785
+ deleted: boolean;
1786
+ };
1787
+ }>;
1194
1788
  /** Filter DSL helpers — pass into `find({ filter: f })`. */
1195
1789
  where: {
1196
1790
  eq: (column: string, value: FilterValue) => Filter;
@@ -1220,7 +1814,7 @@ declare const Amba: {
1220
1814
  retentionDays?: number;
1221
1815
  }) => Promise<PresignData>;
1222
1816
  /**
1223
- * Complete-flow upload: presign → PUT to R2 → commit.
1817
+ * Complete-flow upload: presign → PUT to object storage → commit.
1224
1818
  * Returns the finalized MediaAsset.
1225
1819
  */
1226
1820
  upload: (params: {
@@ -1238,7 +1832,7 @@ declare const Amba: {
1238
1832
  list: (prefix?: string) => Promise<MediaListResponse>;
1239
1833
  /**
1240
1834
  * Soft-delete the asset (SDK 4.0). Accepts the asset id returned
1241
- * by `presign` / `commit` / `list`. The corresponding R2 object
1835
+ * by `presign` / `commit` / `list`. The corresponding storage object
1242
1836
  * is removed asynchronously on the server.
1243
1837
  */
1244
1838
  delete: (assetId: string) => Promise<void>;
@@ -1247,11 +1841,23 @@ declare const Amba: {
1247
1841
  * the Uint8Array returned by the engine, so consumers can
1248
1842
  * call `.text()` / `.arrayBuffer()` / `.stream()` directly or
1249
1843
  * pipe to a `URL.createObjectURL()` for preview. The two-step
1250
- * fetch (asset metadata → CDN GET) is handled server-side on
1251
- * the WASM side; this method is single-call from the consumer.
1844
+ * fetch (asset metadata → CDN GET) is handled inside the SDK
1845
+ * core; this method is single-call from the consumer.
1252
1846
  */
1253
1847
  download: (assetId: string) => Promise<Blob>;
1254
1848
  };
1849
+ /** Curated public-asset catalogs. */
1850
+ media: {
1851
+ /**
1852
+ * Fetch a public media catalog by slug
1853
+ * (`GET /v1/client/media/catalogs/:slug`). A catalog is a named,
1854
+ * curated bundle of assets your app loads in one call — each item
1855
+ * resolves to a stable, long-cacheable public URL, returned in the
1856
+ * order configured for the catalog. Only catalogs published as public
1857
+ * are readable; the call needs the client key but no signed-in user.
1858
+ */
1859
+ catalog: (slug: string) => Promise<MediaCatalog>;
1860
+ };
1255
1861
  /** Offline change replay (SDK 4.0). */
1256
1862
  sync: {
1257
1863
  /**
@@ -1272,6 +1878,53 @@ declare const Amba: {
1272
1878
  */
1273
1879
  pullChanges: (since: PullChangesCursor) => Promise<PullChangesResult>;
1274
1880
  };
1881
+ /**
1882
+ * Automatic offline mutation queue (opt-in).
1883
+ *
1884
+ * Once enabled, a collection write (`insert` / `update` / `delete`) or a
1885
+ * `track` that fails because the device is offline is buffered to a durable
1886
+ * local outbox instead of throwing — then replayed in order the moment
1887
+ * connectivity returns. Replays reuse a per-op idempotency key so a write
1888
+ * that actually reached the server before the connection dropped is never
1889
+ * applied twice.
1890
+ *
1891
+ * This is distinct from `Amba.sync` (manual change replay): `offline` is
1892
+ * the automatic, fire-and-forget safety net for ordinary writes.
1893
+ *
1894
+ * @example
1895
+ * Amba.offline.enable(); // call once after configure()
1896
+ * await Amba.collections.insert("todos", { title: "Buy milk" }); // queues if offline
1897
+ * // ...reconnect...
1898
+ * console.log(await Amba.offline.pendingCount()); // drains automatically
1899
+ */
1900
+ offline: {
1901
+ /**
1902
+ * Turn the outbox on and start auto-flushing on reconnect. Idempotent —
1903
+ * a repeat call detaches the prior `online` listener before re-attaching,
1904
+ * so it never stacks listeners. Immediately attempts a flush in case ops
1905
+ * were persisted in a prior session. Returns a disable function that
1906
+ * detaches the reconnect listener (queued ops are NOT dropped — call
1907
+ * `clear()` for that).
1908
+ *
1909
+ * The disabler is tied to THIS activation: once a later `enable()` (or a
1910
+ * `configure()`) supersedes it, calling it is a no-op — so a stale disabler
1911
+ * can never turn a freshly re-enabled outbox off.
1912
+ */
1913
+ enable: () => (() => void);
1914
+ /** Whether the outbox is currently enabled. */
1915
+ isEnabled: () => boolean;
1916
+ /** Count of writes awaiting replay. */
1917
+ pendingCount: () => Promise<number>;
1918
+ /** Snapshot the pending ops (a copy — safe to inspect). */
1919
+ pending: () => Promise<OutboxOp[]>;
1920
+ /**
1921
+ * Force a replay attempt now (also runs automatically on reconnect).
1922
+ * Resolves with `{ flushed, dropped, remaining }` (dropped = ops the server rejected deterministically on replay, removed so they cannot wedge the queue).
1923
+ */
1924
+ flush: () => Promise<FlushResult>;
1925
+ /** Drop every queued write without replaying. */
1926
+ clear: () => Promise<void>;
1927
+ };
1275
1928
  /** Push notifications. */
1276
1929
  push: {
1277
1930
  register: (token: string, platform: PushPlatform, bundleId?: string) => Promise<PushToken>;
@@ -1279,17 +1932,97 @@ declare const Amba: {
1279
1932
  getTokens: () => Promise<PushToken[]>;
1280
1933
  subscribe: (topic: string) => Promise<void>;
1281
1934
  unsubscribe: (topic: string) => Promise<void>;
1935
+ /**
1936
+ * Auto re-register the device's Web Push subscription when the browser
1937
+ * rotates it.
1938
+ *
1939
+ * The browser can silently roll a push subscription (key rollover,
1940
+ * permission re-grant); when it does, the service worker fires
1941
+ * `pushsubscriptionchange` and the old endpoint stops delivering. Call
1942
+ * this from your service worker (where that event fires) and the SDK
1943
+ * re-registers the fresh endpoint through the idempotent
1944
+ * {@link register} path automatically.
1945
+ *
1946
+ * No-op (returns a no-op detacher) in runtimes without service-worker /
1947
+ * push support, so it's safe to call unconditionally. Returns an
1948
+ * unsubscribe function.
1949
+ *
1950
+ * @example
1951
+ * // in your service worker
1952
+ * Amba.push.enableAutoRotation();
1953
+ */
1954
+ enableAutoRotation: () => (() => void);
1955
+ };
1956
+ /**
1957
+ * On-device local notifications — `scheduleLocal` / `cancelLocal` /
1958
+ * `listScheduledLocal`. Fire from the device without a server
1959
+ * round-trip (reminders, streak nudges), distinct from remote push
1960
+ * (`Amba.push.*`). Browser scheduling is partial: the OS-backed path
1961
+ * needs the experimental Notification Triggers API + an active Service
1962
+ * Worker (Chromium today); without it the SDK falls back to an in-page
1963
+ * timer and reports `scheduledVia: "timer"` so the degradation is
1964
+ * visible — never a silent no-op. See `./local-notifications.ts`.
1965
+ */
1966
+ notifications: {
1967
+ scheduleLocal(input: ScheduleLocalNotificationInput): Promise<LocalNotificationHandle & {
1968
+ scheduledVia: "os-trigger" | "timer";
1969
+ }>;
1970
+ cancelLocal(id: string): Promise<void>;
1971
+ listScheduledLocal(): Promise<ScheduledLocalNotification[]>;
1282
1972
  };
1283
- /** RevenueCat/App Store/Stripe entitlements. */
1973
+ /** Subscription entitlements — feature gates resolved server-side. */
1284
1974
  entitlements: {
1285
1975
  list: () => Promise<UserEntitlement[]>;
1286
1976
  has: (name: string) => Promise<boolean>;
1977
+ /**
1978
+ * Restore purchases — re-sync the user's owned entitlements from the
1979
+ * server and return the active set. Required for App Store review (3.1.1);
1980
+ * wire it to a "Restore Purchases" button. Rejects (access unchanged) if
1981
+ * the server can't reach the validation engine — show a retry message.
1982
+ */
1983
+ restore: () => Promise<RestoreResult>;
1287
1984
  };
1985
+ /**
1986
+ * Subscription offerings — the packages your paywall renders, provider-
1987
+ * neutral. Pass an `offeringId` to fetch one offering; omit it for all.
1988
+ */
1989
+ offerings: (offeringId?: string) => Promise<OfferingsResult>;
1288
1990
  /** LLM proxy. */
1289
1991
  ai: {
1290
1992
  anthropic: {
1291
1993
  messages: {
1292
1994
  create: (request: AiMessageRequest) => Promise<AiMessageResponse>;
1995
+ /**
1996
+ * Stream the response token-by-token instead of waiting for the full
1997
+ * buffered reply. Returns an async iterable of vendor-neutral events:
1998
+ * zero or more `{type:'delta', text}` as tokens arrive, then exactly
1999
+ * one `{type:'done', usage, model, stopReason}` when the stream ends.
2000
+ *
2001
+ * ```ts
2002
+ * let answer = "";
2003
+ * for await (const ev of Amba.ai.anthropic.messages.stream({ prompt_slug: "chat" })) {
2004
+ * if (ev.type === "delta") answer += ev.text;
2005
+ * else console.log("tokens:", ev.usage.output_tokens);
2006
+ * }
2007
+ * ```
2008
+ *
2009
+ * Pass `{ onChunk }` to also receive each delta via callback. Throws
2010
+ * an `AmbaApiError` on a transport failure or a non-2xx response.
2011
+ */
2012
+ stream: (request: AiMessageRequest, options?: AiStreamOptions) => AsyncGenerator<AiStreamEvent, void, unknown>;
2013
+ };
2014
+ };
2015
+ openai: {
2016
+ chat: {
2017
+ completions: {
2018
+ /**
2019
+ * Stream an OpenAI-routed prompt token-by-token. Same event shape
2020
+ * as `Amba.ai.anthropic.messages.stream` — the vendor split is just
2021
+ * a stable wire path; the server resolves the real provider from the
2022
+ * prompt's registered configuration.
2023
+ */
2024
+ stream: (request: AiMessageRequest, options?: AiStreamOptions) => AsyncGenerator<AiStreamEvent, void, unknown>;
2025
+ };
1293
2026
  };
1294
2027
  };
1295
2028
  };
@@ -1301,19 +2034,37 @@ declare const Amba: {
1301
2034
  * hand-rolling `fetch` against a function URL, which leaves the call
1302
2035
  * unauthenticated (a footgun when the function holds secrets).
1303
2036
  *
2037
+ * The return value is unchanged (the parsed body, typed `T`). To
2038
+ * correlate a run with server logs, read the trace id additively:
2039
+ * pass `options.onTraceId` to receive the `X-Amba-Request-Id` on every
2040
+ * response, and on failure read `error.traceId` off the thrown
2041
+ * `AmbaApiError`. Then `functions logs --request-id <traceId>` pulls the
2042
+ * matching server log.
2043
+ *
1304
2044
  * @example
1305
2045
  * const result = await Amba.functions.invoke<{ ok: boolean }>(
1306
2046
  * 'send_welcome_email',
1307
2047
  * { to: 'user@example.com' },
2048
+ * { onTraceId: (id) => console.log('trace', id) },
1308
2049
  * );
1309
2050
  *
2051
+ * @example
2052
+ * try {
2053
+ * await Amba.functions.invoke('charge', { amount: 100 });
2054
+ * } catch (err) {
2055
+ * if (err instanceof AmbaApiError) {
2056
+ * console.error(`failed (trace ${err.traceId}): ${err.message}`);
2057
+ * }
2058
+ * }
2059
+ *
1310
2060
  * @param name The deployed function name.
1311
2061
  * @param body JSON-serializable request body (omitted for GET).
1312
- * @param options Method + extra headers.
2062
+ * @param options Method, extra headers, and an `onTraceId` callback.
1313
2063
  * @returns The parsed JSON response (or the raw text if not JSON).
1314
2064
  * @throws AmbaApiError on a network failure or a non-2xx response. When
1315
2065
  * the function / router returns the standard `{ error: { code, message } }`
1316
- * envelope, those surface as the thrown error's `code` + `message`.
2066
+ * envelope, those surface as the thrown error's `code` + `message`; the
2067
+ * server trace id (when present) is attached as `error.traceId`.
1317
2068
  */
1318
2069
  functions: {
1319
2070
  invoke: <T = unknown>(name: string, body?: unknown, options?: InvokeOptions) => Promise<T>;
@@ -1416,6 +2167,22 @@ declare const Amba: {
1416
2167
  getAll: () => Promise<Streak[]>;
1417
2168
  qualify: (streakKey: string) => Promise<Streak>;
1418
2169
  };
2170
+ /**
2171
+ * Live gamification updates for the signed-in user. Call `.subscribe(cb)` to
2172
+ * receive xp / level / achievement / streak changes the instant they happen,
2173
+ * instead of polling `xp.getBalance()` / `streaks.getAll()` on a timer.
2174
+ *
2175
+ * @example
2176
+ * const unsub = Amba.gamification.subscribe((change) => {
2177
+ * // change.kind: "xp" | "level" | "achievement" | "streak"
2178
+ * if (change.kind === "level") showLevelUp(change.data.level);
2179
+ * });
2180
+ * // later: unsub();
2181
+ *
2182
+ * You only ever receive your own gamification changes — never another user's.
2183
+ * Requires an authenticated session.
2184
+ */
2185
+ readonly gamification: GamificationSubscription;
1419
2186
  /** Activity feeds. */
1420
2187
  feeds: {
1421
2188
  getActivity: (feed?: string, cursor?: string) => Promise<FeedResponse>;
@@ -1635,7 +2402,7 @@ declare function getCoreWasm(): AmbaCoreWasm;
1635
2402
  * `verify-sdk-version-coherence` GH action gates every publish on the
1636
2403
  * pair agreeing (and matching the `web-v<X.Y.Z>` tag when tag-triggered).
1637
2404
  */
1638
- declare const SDK_VERSION = "4.0.4";
2405
+ declare const SDK_VERSION = "4.0.5";
1639
2406
  //#endregion
1640
- export { Achievement, AchievementProgress, AiMessage, AiMessageRequest, AiMessageResponse, AiUsage, Amba, AmbaApiError, type AmbaApiErrorCode, AmbaConfig, AndFilter, AppSession, AuthResult, CatalogItem, Challenge, ChallengeProgress, CollectionSubscription, ConditionFilter, ConfigBundle, ConsumeRequest, ContentItem, Conversation, ConversationParticipant, ConversationSubscription, ConversationType, CreateConversationRequest, CurrencyBalance, CurrencyTransaction, DeepLink, DeepLinkCreate, DiagnosticsEnvironment, EntitlementSource, FeedItem, FeedResponse, Filter, FilterValue, FindOptions, FindResponse, FlagAssignment, Friendship, FriendshipState, Group, GroupCreate, GroupMember, GroupUpdate, InventoryItem, InvokeOptions, Leaderboard, LeaderboardEntry, LeagueCohort, LeagueCohortMember, LeagueCohortView, LeagueMembership, LeagueTier, LinkedIdentifier, ListMessagesOptions, MarkReadResult, MediaAsset, MediaListResponse, Message, type MessageChange, MessageType, NearestOptions, NearestResponse, NotFilter, OnboardingStatus, OrFilter, OrderBy, PingResult, PresignData, PullChangesCursor, PullChangesResult, PurchaseOption, PurchaseRequest, PurchaseResult, PushChangesResult, PushPlatform, PushToken, type RealtimeChange, ReferralClaim, ReferralCode, Report, ReportRequest, Review, ReviewCreate, ReviewUpdate, Role, type RowChangeOp, SDK_VERSION, SendMessageRequest, Session, SocialProvider, Store, Streak, type SubscribeOptions, SyncChange, SyncConflict, type Unsubscribe, User, UserEntitlement, XpBalance, XpTransaction, getCoreWasm };
2407
+ export { Achievement, AchievementProgress, AiContentBlock, AiImageInput, AiMessage, AiMessageRequest, AiMessageResponse, type AiStreamDelta, type AiStreamDone, type AiStreamEvent, type AiStreamOptions, AiUsage, Amba, AmbaApiError, type AmbaApiErrorCode, AmbaConfig, AndFilter, AppSession, AuthResult, CatalogItem, Challenge, ChallengeProgress, CollectionSubscription, ConditionFilter, ConfigBundle, ConsumeRequest, ContentItem, Conversation, ConversationParticipant, ConversationSubscription, ConversationType, CreateConversationRequest, CurrencyBalance, CurrencyTransaction, DeepLink, DeepLinkCreate, DeleteManyResult, DiagnosticsEnvironment, EntitlementPeriodType, EntitlementStore, EventExplainResult, ExplainMatchedRule, FeedItem, FeedResponse, Filter, FilterValue, FindOptions, FindResponse, FlagAssignment, type FlushResult, Friendship, FriendshipState, type GamificationChange, type GamificationKind, GamificationSubscription, Group, GroupCreate, GroupMember, GroupUpdate, IncludeClause, InventoryItem, InvokeOptions, type KvStore, Leaderboard, LeaderboardEntry, LeagueCohort, LeagueCohortMember, LeagueCohortView, LeagueMembership, LeagueTier, LinkedIdentifier, ListMessagesOptions, LocalNotificationHandle, LocalNotificationTrigger, type LocalNotificationsNamespace, MarkReadResult, MediaAsset, MediaCatalog, MediaCatalogItem, MediaListResponse, Message, type MessageChange, MessageType, NearestOptions, NearestResponse, NotFilter, Offering, OfferingPackage, OfferingProduct, OfferingsResult, OnboardingStatus, OrFilter, OrderBy, type OutboxOp, type OutboxOpKind, PingResult, PresignData, PullChangesCursor, PullChangesResult, PurchaseOption, PurchaseRequest, PurchaseResult, PushChangesResult, PushPlatform, PushToken, type RealtimeChange, ReferralClaim, ReferralCode, Report, ReportRequest, RestoreResult, Review, ReviewCreate, ReviewUpdate, Role, type RowChangeOp, SDK_VERSION, ScheduleLocalNotificationInput, ScheduledLocalNotification, SendMessageRequest, Session, SocialProvider, Store, Streak, type SubscribeOptions, SyncChange, SyncConflict, TransactionOp, TransactionOpResult, type Unsubscribe, UpsertOptions, User, UserEntitlement, XpBalance, XpTransaction, getCoreWasm, withOptimistic };
1641
2408
  //# sourceMappingURL=index.d.ts.map