@layers/amba-web 4.0.4 → 4.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +783 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1514 -22
- package/dist/index.js.map +1 -1
- package/dist-rn/index.d.ts +783 -16
- package/dist-rn/index.js +1514 -22
- package/package.json +2 -2
package/dist-rn/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
|
-
|
|
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
|
-
|
|
158
|
-
|
|
251
|
+
/** Project-defined entitlement key (e.g. `"pro"`) — what `has()` checks. */
|
|
252
|
+
entitlement_id: string;
|
|
159
253
|
is_active: boolean;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
|
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
|
|
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
|
|
1251
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
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.
|
|
2405
|
+
declare const SDK_VERSION = "4.0.6";
|
|
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,
|
|
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
|