@layers/amba-react-native 1.0.0 → 2.0.0
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/README.md +16 -18
- package/dist/index.cjs +691 -178
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -33
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +13 -33
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +691 -178
- package/dist/index.js.map +1 -1
- package/package.json +3 -6
package/dist/index.js
CHANGED
|
@@ -52,70 +52,278 @@ var AmbaApiError = class extends Error {
|
|
|
52
52
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
53
53
|
}
|
|
54
54
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/http-client.ts
|
|
58
|
+
/** Default amba API endpoint. */
|
|
59
|
+
const DEFAULT_BASE_URL = "https://api.amba.dev";
|
|
60
|
+
var AmbaHttpClient = class {
|
|
61
|
+
apiKey;
|
|
62
|
+
baseUrl;
|
|
63
|
+
sdkPlatform;
|
|
64
|
+
sdkVersionHeader;
|
|
65
|
+
identity;
|
|
66
|
+
fetchImpl;
|
|
67
|
+
constructor(opts) {
|
|
68
|
+
this.apiKey = opts.apiKey;
|
|
69
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
70
|
+
this.sdkPlatform = opts.sdkPlatform;
|
|
71
|
+
this.sdkVersionHeader = opts.sdkVersionHeader;
|
|
72
|
+
this.identity = opts.identity;
|
|
73
|
+
this.fetchImpl = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
74
|
+
}
|
|
75
|
+
/** Build the absolute URL for an API path, optionally with a query string. */
|
|
76
|
+
url(path, query) {
|
|
77
|
+
const base = this.baseUrl + path;
|
|
78
|
+
if (!query) return base;
|
|
79
|
+
const parts = [];
|
|
80
|
+
for (const k of Object.keys(query)) {
|
|
81
|
+
const v = query[k];
|
|
82
|
+
if (v === void 0 || v === null) continue;
|
|
83
|
+
parts.push(`${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);
|
|
84
|
+
}
|
|
85
|
+
if (parts.length === 0) return base;
|
|
86
|
+
return `${base}?${parts.join("&")}`;
|
|
87
|
+
}
|
|
88
|
+
/** Build the standard request headers for the current identity state. */
|
|
89
|
+
buildHeaders(extra) {
|
|
90
|
+
const h = {
|
|
91
|
+
"X-Api-Key": this.apiKey,
|
|
92
|
+
"X-SDK-Platform": this.sdkPlatform,
|
|
93
|
+
"X-SDK-Version": this.sdkVersionHeader,
|
|
94
|
+
"Content-Type": "application/json",
|
|
95
|
+
Accept: "application/json",
|
|
96
|
+
...extra
|
|
97
|
+
};
|
|
98
|
+
const tok = this.identity.getSessionToken();
|
|
99
|
+
if (tok) h.Authorization = `Bearer ${tok}`;
|
|
100
|
+
return h;
|
|
101
|
+
}
|
|
102
|
+
async get(path, query) {
|
|
103
|
+
return this.request("GET", path, void 0, query);
|
|
104
|
+
}
|
|
105
|
+
async post(path, body, query) {
|
|
106
|
+
return this.request("POST", path, body, query);
|
|
107
|
+
}
|
|
108
|
+
async patch(path, body) {
|
|
109
|
+
return this.request("PATCH", path, body);
|
|
110
|
+
}
|
|
111
|
+
async delete(path) {
|
|
112
|
+
return this.request("DELETE", path);
|
|
113
|
+
}
|
|
114
|
+
async request(method, path, body, query) {
|
|
115
|
+
const url = this.url(path, query);
|
|
116
|
+
const init = {
|
|
117
|
+
method,
|
|
118
|
+
headers: this.buildHeaders(),
|
|
119
|
+
body: body === void 0 ? void 0 : JSON.stringify(body ?? {})
|
|
120
|
+
};
|
|
121
|
+
let response;
|
|
122
|
+
try {
|
|
123
|
+
response = await this.fetchImpl(url, init);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
throw new AmbaApiError("NETWORK_ERROR", `Network error: ${err instanceof Error ? err.message : typeof err === "string" ? err : "fetch failed"}`, err);
|
|
126
|
+
}
|
|
127
|
+
return parseResponse(response);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
async function parseResponse(response) {
|
|
131
|
+
if (response.status === 204) return null;
|
|
132
|
+
const text = await response.text();
|
|
133
|
+
const isJson = (response.headers.get("content-type") ?? "").includes("application/json");
|
|
134
|
+
if (!response.ok) throw mapHttpError(response, text, isJson);
|
|
135
|
+
if (text === "") return null;
|
|
136
|
+
if (isJson) try {
|
|
137
|
+
return JSON.parse(text);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
throw new AmbaApiError("HTTP_ERROR", `Failed to parse JSON response: ${err instanceof Error ? err.message : String(err)}`, { body: text });
|
|
140
|
+
}
|
|
141
|
+
return text;
|
|
142
|
+
}
|
|
143
|
+
function mapHttpError(response, rawBody, isJson) {
|
|
144
|
+
let parsed = void 0;
|
|
145
|
+
let message = rawBody || `HTTP ${response.status}`;
|
|
146
|
+
let code;
|
|
147
|
+
if (isJson && rawBody) {
|
|
148
|
+
try {
|
|
149
|
+
parsed = JSON.parse(rawBody);
|
|
150
|
+
} catch {
|
|
151
|
+
parsed = void 0;
|
|
152
|
+
}
|
|
153
|
+
const innerErr = parsed?.error;
|
|
154
|
+
if (innerErr && typeof innerErr === "object") {
|
|
155
|
+
if (typeof innerErr.code === "string") code = innerErr.code;
|
|
156
|
+
if (typeof innerErr.message === "string") message = innerErr.message;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
switch (response.status) {
|
|
160
|
+
case 401: return new AmbaApiError(code ?? "UNAUTHORIZED", message, parsed);
|
|
161
|
+
case 403: return new AmbaApiError(code ?? "FORBIDDEN", message, parsed);
|
|
162
|
+
case 404: return new AmbaApiError(code ?? "NOT_FOUND", message, parsed);
|
|
163
|
+
case 409: return new AmbaApiError(code ?? "CONFLICT", message, parsed);
|
|
164
|
+
case 422: return new AmbaApiError(code ?? "VALIDATION_ERROR", message, parsed);
|
|
165
|
+
case 429: {
|
|
166
|
+
const retryAfter = response.headers.get("retry-after") ?? "unspecified";
|
|
167
|
+
const serverGaveMessage = message !== rawBody && message !== `HTTP ${response.status}`;
|
|
168
|
+
return new AmbaApiError(code ?? "RATE_LIMITED", serverGaveMessage ? message : `Rate limited (retry after ${retryAfter})`, parsed);
|
|
169
|
+
}
|
|
170
|
+
default: return new AmbaApiError(code ?? "HTTP_ERROR", message, parsed ?? {
|
|
171
|
+
status: response.status,
|
|
172
|
+
body: rawBody
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/uuid.ts
|
|
179
|
+
function getRandomBytes(n) {
|
|
180
|
+
const bytes = new Uint8Array(n);
|
|
181
|
+
if (typeof globalThis.crypto?.getRandomValues === "function") {
|
|
182
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
183
|
+
return bytes;
|
|
184
|
+
}
|
|
185
|
+
for (let i = 0; i < n; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
186
|
+
return bytes;
|
|
80
187
|
}
|
|
81
188
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* without re-wrapping.
|
|
85
|
-
*
|
|
86
|
-
* Heuristics:
|
|
87
|
-
* 1. Existing `AmbaApiError` → returned as-is.
|
|
88
|
-
* 2. Object with `.code` → use that code + `.message` + `.details`.
|
|
89
|
-
* 3. `Error` (e.g. WASM JsError) → infer code from message prefix.
|
|
90
|
-
* 4. Anything else → stringify and tag UNKNOWN_ERROR.
|
|
189
|
+
* Generate a UUID v4 (random) per RFC 4122. Wire shape:
|
|
190
|
+
* `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` where `y ∈ {8,9,a,b}`.
|
|
91
191
|
*/
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (err instanceof Error) return new AmbaApiError(codeFromMessage(err.message), err.message);
|
|
99
|
-
return new AmbaApiError("UNKNOWN_ERROR", String(err));
|
|
192
|
+
function uuidv4() {
|
|
193
|
+
const b = getRandomBytes(16);
|
|
194
|
+
b[6] = b[6] & 15 | 64;
|
|
195
|
+
b[8] = b[8] & 63 | 128;
|
|
196
|
+
const h = Array.from(b, (v) => v.toString(16).padStart(2, "0"));
|
|
197
|
+
return h.slice(0, 4).join("") + "-" + h.slice(4, 6).join("") + "-" + h.slice(6, 8).join("") + "-" + h.slice(8, 10).join("") + "-" + h.slice(10, 16).join("");
|
|
100
198
|
}
|
|
101
199
|
|
|
102
200
|
//#endregion
|
|
103
|
-
//#region src/
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return
|
|
201
|
+
//#region src/identity.ts
|
|
202
|
+
/** Storage key under the configured prefix. Bumped when shape changes. */
|
|
203
|
+
const IDENTITY_KEY = "identity_v1";
|
|
204
|
+
function isExpired(expiresAt) {
|
|
205
|
+
if (!expiresAt) return false;
|
|
206
|
+
const t = Date.parse(expiresAt);
|
|
207
|
+
if (Number.isNaN(t)) return false;
|
|
208
|
+
return t <= Date.now();
|
|
108
209
|
}
|
|
109
210
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
211
|
+
* The SDK's identity state — held in memory after hydration, persisted
|
|
212
|
+
* to AsyncStorage on every mutation. All methods are sync after
|
|
213
|
+
* `hydrate()` resolves.
|
|
112
214
|
*/
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
215
|
+
var IdentityStore = class IdentityStore {
|
|
216
|
+
anonymousId;
|
|
217
|
+
appUserId = null;
|
|
218
|
+
sessionToken = null;
|
|
219
|
+
refreshToken = null;
|
|
220
|
+
expiresAt = null;
|
|
221
|
+
constructor(persistence, seed) {
|
|
222
|
+
this.persistence = persistence;
|
|
223
|
+
this.anonymousId = seed.anonymous_id;
|
|
224
|
+
this.appUserId = seed.app_user_id;
|
|
225
|
+
this.sessionToken = seed.session_token;
|
|
226
|
+
this.refreshToken = seed.refresh_token;
|
|
227
|
+
this.expiresAt = seed.expires_at;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Build a store, hydrating any prior identity from AsyncStorage.
|
|
231
|
+
* If no prior identity exists, a fresh `anonymous_id` is minted.
|
|
232
|
+
* Expired session tokens are dropped at hydration (the refresh token
|
|
233
|
+
* survives so callers can `auth.refresh()` to mint a new pair).
|
|
234
|
+
*/
|
|
235
|
+
static async create(persistence) {
|
|
236
|
+
const raw = await persistence.read(IDENTITY_KEY);
|
|
237
|
+
let seed;
|
|
238
|
+
if (raw) try {
|
|
239
|
+
const parsed = JSON.parse(raw);
|
|
240
|
+
seed = {
|
|
241
|
+
anonymous_id: parsed.anonymous_id ?? uuidv4(),
|
|
242
|
+
app_user_id: parsed.app_user_id ?? null,
|
|
243
|
+
session_token: parsed.session_token ?? null,
|
|
244
|
+
refresh_token: parsed.refresh_token ?? null,
|
|
245
|
+
expires_at: parsed.expires_at ?? null
|
|
246
|
+
};
|
|
247
|
+
} catch {
|
|
248
|
+
seed = freshSeed();
|
|
249
|
+
}
|
|
250
|
+
else seed = freshSeed();
|
|
251
|
+
if (isExpired(seed.expires_at)) {
|
|
252
|
+
seed.session_token = null;
|
|
253
|
+
seed.expires_at = null;
|
|
254
|
+
}
|
|
255
|
+
const store = new IdentityStore(persistence, seed);
|
|
256
|
+
await store.flush();
|
|
257
|
+
return store;
|
|
118
258
|
}
|
|
259
|
+
snapshot() {
|
|
260
|
+
return {
|
|
261
|
+
anonymousId: this.anonymousId,
|
|
262
|
+
appUserId: this.appUserId,
|
|
263
|
+
sessionToken: this.sessionToken,
|
|
264
|
+
refreshToken: this.refreshToken,
|
|
265
|
+
expiresAt: this.expiresAt
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
getAnonymousId() {
|
|
269
|
+
return this.anonymousId;
|
|
270
|
+
}
|
|
271
|
+
getAppUserId() {
|
|
272
|
+
return this.appUserId;
|
|
273
|
+
}
|
|
274
|
+
getSessionToken() {
|
|
275
|
+
return this.sessionToken;
|
|
276
|
+
}
|
|
277
|
+
getRefreshToken() {
|
|
278
|
+
return this.refreshToken;
|
|
279
|
+
}
|
|
280
|
+
isAuthenticated() {
|
|
281
|
+
return this.sessionToken !== null;
|
|
282
|
+
}
|
|
283
|
+
async setSession(args) {
|
|
284
|
+
this.appUserId = args.appUserId;
|
|
285
|
+
this.sessionToken = args.sessionToken;
|
|
286
|
+
this.refreshToken = args.refreshToken;
|
|
287
|
+
this.expiresAt = args.expiresAt;
|
|
288
|
+
await this.flush();
|
|
289
|
+
}
|
|
290
|
+
async clearSession(rotateAnonymousId) {
|
|
291
|
+
this.appUserId = null;
|
|
292
|
+
this.sessionToken = null;
|
|
293
|
+
this.refreshToken = null;
|
|
294
|
+
this.expiresAt = null;
|
|
295
|
+
if (rotateAnonymousId) this.anonymousId = uuidv4();
|
|
296
|
+
await this.flush();
|
|
297
|
+
}
|
|
298
|
+
async flush() {
|
|
299
|
+
const payload = {
|
|
300
|
+
anonymous_id: this.anonymousId,
|
|
301
|
+
app_user_id: this.appUserId,
|
|
302
|
+
session_token: this.sessionToken,
|
|
303
|
+
refresh_token: this.refreshToken,
|
|
304
|
+
expires_at: this.expiresAt
|
|
305
|
+
};
|
|
306
|
+
await this.persistence.write(IDENTITY_KEY, JSON.stringify(payload));
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
function freshSeed() {
|
|
310
|
+
return {
|
|
311
|
+
anonymous_id: uuidv4(),
|
|
312
|
+
app_user_id: null,
|
|
313
|
+
session_token: null,
|
|
314
|
+
refresh_token: null,
|
|
315
|
+
expires_at: null
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region src/index.ts
|
|
321
|
+
/** SDK semver — burned in at build time. Bump alongside package.json. */
|
|
322
|
+
const SDK_VERSION = "2.0.0";
|
|
323
|
+
let state = null;
|
|
324
|
+
function getState() {
|
|
325
|
+
if (!state) throw new AmbaApiError("NOT_INITIALIZED", "@layers/amba-react-native: SDK not configured. Call Amba.configure({ apiKey }) at app start.");
|
|
326
|
+
return state;
|
|
119
327
|
}
|
|
120
328
|
const authSubscribers = /* @__PURE__ */ new Set();
|
|
121
329
|
function snapshotSession(user) {
|
|
@@ -137,82 +345,183 @@ function notifyAuthSubscribers(session) {
|
|
|
137
345
|
async function notifyFromAuthResult(result) {
|
|
138
346
|
notifyAuthSubscribers(snapshotSession(result.user));
|
|
139
347
|
}
|
|
348
|
+
function expiresAtFromResult(result) {
|
|
349
|
+
if (result.expires_at && typeof result.expires_at === "string") return result.expires_at;
|
|
350
|
+
return new Date(Date.now() + 3600 * 1e3).toISOString();
|
|
351
|
+
}
|
|
352
|
+
async function persistAuthResult(state_, result) {
|
|
353
|
+
await state_.identity.setSession({
|
|
354
|
+
appUserId: result.user.id,
|
|
355
|
+
sessionToken: result.session_token,
|
|
356
|
+
refreshToken: result.refresh_token,
|
|
357
|
+
expiresAt: expiresAtFromResult(result)
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
async function postAuth(state_, path, body) {
|
|
361
|
+
const result = (await state_.http.post(path, body)).data;
|
|
362
|
+
await persistAuthResult(state_, result);
|
|
363
|
+
await notifyFromAuthResult(result);
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
function requireEmail(email) {
|
|
367
|
+
const trimmed = email.trim();
|
|
368
|
+
if (trimmed === "") throw new AmbaApiError("VALIDATION_ERROR", "email must not be empty");
|
|
369
|
+
if (!trimmed.includes("@") || !trimmed.includes(".")) throw new AmbaApiError("VALIDATION_ERROR", `email '${email}' is not a valid email address`);
|
|
370
|
+
}
|
|
371
|
+
function requirePassword(password) {
|
|
372
|
+
if (password.length < 8) throw new AmbaApiError("VALIDATION_ERROR", "password must be at least 8 characters");
|
|
373
|
+
}
|
|
374
|
+
const P = {
|
|
375
|
+
authAnonymous: "/v1/client/auth/anonymous",
|
|
376
|
+
authEmailLogin: "/v1/client/auth/email/login",
|
|
377
|
+
authEmailSignup: "/v1/client/auth/email/signup",
|
|
378
|
+
authSocial: "/v1/client/auth/social",
|
|
379
|
+
authRefresh: "/v1/client/auth/refresh",
|
|
380
|
+
authLogout: "/v1/client/auth/logout",
|
|
381
|
+
authMe: "/v1/client/auth/me",
|
|
382
|
+
events: "/v1/client/events",
|
|
383
|
+
collections: "/v1/client/collections",
|
|
384
|
+
storage: "/v1/client/media",
|
|
385
|
+
storagePresign: "/v1/client/media/presign",
|
|
386
|
+
storageCommit: "/v1/client/media/commit",
|
|
387
|
+
push: "/v1/client/push",
|
|
388
|
+
pushRegister: "/v1/client/push/register",
|
|
389
|
+
pushUnregister: "/v1/client/push/unregister",
|
|
390
|
+
pushTokens: "/v1/client/push/tokens",
|
|
391
|
+
pushSubscribe: "/v1/client/push/subscribe",
|
|
392
|
+
pushUnsubscribe: "/v1/client/push/unsubscribe",
|
|
393
|
+
entitlements: "/v1/client/entitlements",
|
|
394
|
+
aiAnthropic: "/v1/client/ai/anthropic/messages",
|
|
395
|
+
config: "/v1/client/config",
|
|
396
|
+
flags: "/v1/client/flags",
|
|
397
|
+
achievements: "/v1/client/achievements",
|
|
398
|
+
challenges: "/v1/client/challenges",
|
|
399
|
+
catalog: "/v1/client/catalog",
|
|
400
|
+
currencies: "/v1/client/currencies",
|
|
401
|
+
inventory: "/v1/client/inventory",
|
|
402
|
+
leaderboards: "/v1/client/leaderboards",
|
|
403
|
+
stores: "/v1/client/stores",
|
|
404
|
+
xp: "/v1/client/xp",
|
|
405
|
+
streaks: "/v1/client/streaks",
|
|
406
|
+
feeds: "/v1/client/feeds",
|
|
407
|
+
friends: "/v1/client/friends",
|
|
408
|
+
groups: "/v1/client/groups",
|
|
409
|
+
messaging: "/v1/client/messaging",
|
|
410
|
+
moderation: "/v1/client/moderation",
|
|
411
|
+
reviews: "/v1/client/reviews",
|
|
412
|
+
roles: "/v1/client/roles",
|
|
413
|
+
referrals: "/v1/client/referrals",
|
|
414
|
+
content: "/v1/client/content",
|
|
415
|
+
deepLinks: "/v1/client/deeplinks",
|
|
416
|
+
onboarding: "/v1/client/onboarding"
|
|
417
|
+
};
|
|
418
|
+
function encodePathSegment(s) {
|
|
419
|
+
return encodeURIComponent(s);
|
|
420
|
+
}
|
|
140
421
|
/**
|
|
141
422
|
* Top-level SDK namespace for React Native.
|
|
142
|
-
*
|
|
143
|
-
* Differences from `@layers/amba-web`:
|
|
144
|
-
* - `configure` is async (waits for WASM init AND AsyncStorage hydration).
|
|
145
|
-
* - Persistence is AsyncStorage-backed — identity survives app restarts.
|
|
146
423
|
*/
|
|
147
424
|
const Amba = {
|
|
148
425
|
configure: async (config) => {
|
|
149
426
|
if (!config.apiKey || config.apiKey.trim() === "") throw new Error("Amba.configure: apiKey is required");
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
427
|
+
const persistence = new AsyncStoragePersistence(config.storagePrefix ?? "amba");
|
|
428
|
+
await persistence.hydrate();
|
|
429
|
+
const identity = await IdentityStore.create(persistence);
|
|
430
|
+
const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
431
|
+
const sdkVersionHeader = `amba-sdk/${SDK_VERSION} ${`amba-react-native/${SDK_VERSION}`}`;
|
|
432
|
+
state = {
|
|
433
|
+
http: new AmbaHttpClient({
|
|
434
|
+
apiKey: config.apiKey,
|
|
435
|
+
baseUrl,
|
|
436
|
+
sdkPlatform: "react-native",
|
|
437
|
+
sdkVersionHeader,
|
|
438
|
+
identity
|
|
439
|
+
}),
|
|
440
|
+
identity,
|
|
441
|
+
debug: config.debug ?? false
|
|
442
|
+
};
|
|
443
|
+
},
|
|
444
|
+
_reset: () => {
|
|
445
|
+
state = null;
|
|
446
|
+
authSubscribers.clear();
|
|
163
447
|
},
|
|
164
448
|
get anonymousId() {
|
|
165
|
-
return
|
|
449
|
+
return getState().identity.getAnonymousId();
|
|
166
450
|
},
|
|
167
451
|
get appUserId() {
|
|
168
|
-
return
|
|
452
|
+
return getState().identity.getAppUserId() ?? void 0;
|
|
169
453
|
},
|
|
170
454
|
get isAuthenticated() {
|
|
171
|
-
return
|
|
455
|
+
return getState().identity.isAuthenticated();
|
|
172
456
|
},
|
|
173
457
|
setDebug: (enabled) => {
|
|
174
|
-
|
|
458
|
+
getState().debug = enabled;
|
|
175
459
|
},
|
|
176
460
|
events: { track: async (event, properties) => {
|
|
177
|
-
|
|
461
|
+
const s = getState();
|
|
462
|
+
await s.http.post(P.events, {
|
|
463
|
+
name: event,
|
|
464
|
+
properties: properties ?? void 0,
|
|
465
|
+
anonymous_id: s.identity.getAnonymousId(),
|
|
466
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
467
|
+
});
|
|
178
468
|
} },
|
|
179
469
|
auth: {
|
|
180
470
|
signInAnonymously: async () => {
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
return r;
|
|
471
|
+
const s = getState();
|
|
472
|
+
return postAuth(s, P.authAnonymous, { anonymous_id: s.identity.getAnonymousId() });
|
|
184
473
|
},
|
|
185
474
|
signInWithEmail: async (email, password) => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return
|
|
475
|
+
requireEmail(email);
|
|
476
|
+
if (password === "") throw new AmbaApiError("VALIDATION_ERROR", "password must not be empty");
|
|
477
|
+
return postAuth(getState(), P.authEmailLogin, {
|
|
478
|
+
email,
|
|
479
|
+
password
|
|
480
|
+
});
|
|
189
481
|
},
|
|
190
482
|
signUpWithEmail: async (email, password) => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return
|
|
483
|
+
requireEmail(email);
|
|
484
|
+
requirePassword(password);
|
|
485
|
+
return postAuth(getState(), P.authEmailSignup, {
|
|
486
|
+
email,
|
|
487
|
+
password
|
|
488
|
+
});
|
|
194
489
|
},
|
|
195
490
|
signInWithSocial: async (provider, idToken) => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
491
|
+
if (idToken.trim() === "") throw new AmbaApiError("VALIDATION_ERROR", "id_token must not be empty");
|
|
492
|
+
return postAuth(getState(), P.authSocial, {
|
|
493
|
+
provider,
|
|
494
|
+
id_token: idToken
|
|
495
|
+
});
|
|
199
496
|
},
|
|
200
497
|
signOut: async (rotateAnonymousId = false) => {
|
|
201
|
-
|
|
498
|
+
const s = getState();
|
|
499
|
+
if (s.identity.getSessionToken()) try {
|
|
500
|
+
await s.http.post(P.authLogout, {});
|
|
501
|
+
} catch (err) {
|
|
502
|
+
if (typeof console !== "undefined") console.warn("[amba] signOut server call failed", err);
|
|
503
|
+
}
|
|
504
|
+
await s.identity.clearSession(rotateAnonymousId);
|
|
202
505
|
notifyAuthSubscribers(null);
|
|
203
506
|
},
|
|
204
507
|
refresh: async () => {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
508
|
+
const s = getState();
|
|
509
|
+
const refreshToken = s.identity.getRefreshToken();
|
|
510
|
+
if (!refreshToken) throw new AmbaApiError("UNAUTHORIZED", "no refresh token available — call signIn* first");
|
|
511
|
+
return postAuth(s, P.authRefresh, { refresh_token: refreshToken });
|
|
512
|
+
},
|
|
513
|
+
me: async () => {
|
|
514
|
+
const s = getState();
|
|
515
|
+
if (!s.identity.getSessionToken()) throw new AmbaApiError("UNAUTHORIZED", "no active session — call signIn* first");
|
|
516
|
+
return (await s.http.get(P.authMe)).data;
|
|
208
517
|
},
|
|
209
|
-
me: async () => await coreCall((c) => c.me()),
|
|
210
518
|
getSession: async () => {
|
|
211
|
-
|
|
212
|
-
|
|
519
|
+
const s = getState();
|
|
520
|
+
if (!s.identity.isAuthenticated()) return null;
|
|
521
|
+
return snapshotSession((await s.http.get(P.authMe)).data);
|
|
213
522
|
},
|
|
214
523
|
getAnonymousId: async () => {
|
|
215
|
-
return
|
|
524
|
+
return getState().identity.getAnonymousId();
|
|
216
525
|
},
|
|
217
526
|
onAuthStateChange: (cb) => {
|
|
218
527
|
authSubscribers.add(cb);
|
|
@@ -222,11 +531,21 @@ const Amba = {
|
|
|
222
531
|
}
|
|
223
532
|
},
|
|
224
533
|
collections: {
|
|
225
|
-
find: async (name, options = {}) =>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
534
|
+
find: async (name, options = {}) => {
|
|
535
|
+
return getState().http.post(`${P.collections}/${encodePathSegment(name)}/find`, options);
|
|
536
|
+
},
|
|
537
|
+
findOne: async (name, id) => {
|
|
538
|
+
return (await getState().http.get(`${P.collections}/${encodePathSegment(name)}/${encodePathSegment(id)}`)).data;
|
|
539
|
+
},
|
|
540
|
+
insert: async (name, row) => {
|
|
541
|
+
return (await getState().http.post(`${P.collections}/${encodePathSegment(name)}`, row)).data;
|
|
542
|
+
},
|
|
543
|
+
update: async (name, id, set) => {
|
|
544
|
+
return (await getState().http.patch(`${P.collections}/${encodePathSegment(name)}/${encodePathSegment(id)}`, { set })).data;
|
|
545
|
+
},
|
|
546
|
+
delete: async (name, id) => {
|
|
547
|
+
return await getState().http.delete(`${P.collections}/${encodePathSegment(name)}/${encodePathSegment(id)}`) ?? { data: { deleted: true } };
|
|
548
|
+
},
|
|
230
549
|
where: {
|
|
231
550
|
eq: (column, value) => ({
|
|
232
551
|
column,
|
|
@@ -292,141 +611,335 @@ const Amba = {
|
|
|
292
611
|
}
|
|
293
612
|
},
|
|
294
613
|
storage: {
|
|
295
|
-
presign: async (params) =>
|
|
296
|
-
|
|
614
|
+
presign: async (params) => {
|
|
615
|
+
return (await getState().http.post(P.storagePresign, {
|
|
616
|
+
bucket: params.bucket,
|
|
617
|
+
filename: params.filename,
|
|
618
|
+
mime_type: params.mimeType,
|
|
619
|
+
size_bytes: params.sizeBytes,
|
|
620
|
+
retention_days: params.retentionDays
|
|
621
|
+
})).data;
|
|
622
|
+
},
|
|
623
|
+
commit: async (uploadId, assetId) => {
|
|
624
|
+
return (await getState().http.post(P.storageCommit, {
|
|
625
|
+
upload_id: uploadId,
|
|
626
|
+
asset_id: assetId
|
|
627
|
+
})).data;
|
|
628
|
+
}
|
|
297
629
|
},
|
|
298
630
|
push: {
|
|
299
|
-
register: async (token, platform, bundleId) =>
|
|
631
|
+
register: async (token, platform, bundleId) => {
|
|
632
|
+
return (await getState().http.post(P.pushRegister, {
|
|
633
|
+
token,
|
|
634
|
+
platform,
|
|
635
|
+
bundle_id: bundleId
|
|
636
|
+
})).data;
|
|
637
|
+
},
|
|
300
638
|
unregister: async (token) => {
|
|
301
|
-
await
|
|
639
|
+
await getState().http.post(P.pushUnregister, { token });
|
|
640
|
+
},
|
|
641
|
+
getTokens: async () => {
|
|
642
|
+
return (await getState().http.get(P.pushTokens)).data;
|
|
302
643
|
},
|
|
303
|
-
getTokens: async () => await coreCall((c) => c.pushGetTokens()),
|
|
304
644
|
subscribe: async (topic) => {
|
|
305
|
-
await
|
|
645
|
+
await getState().http.post(P.pushSubscribe, { topic });
|
|
306
646
|
},
|
|
307
647
|
unsubscribe: async (topic) => {
|
|
308
|
-
await
|
|
648
|
+
await getState().http.post(P.pushUnsubscribe, { topic });
|
|
309
649
|
}
|
|
310
650
|
},
|
|
311
651
|
entitlements: {
|
|
312
|
-
list: async () =>
|
|
313
|
-
|
|
652
|
+
list: async () => {
|
|
653
|
+
return (await getState().http.get(P.entitlements)).data;
|
|
654
|
+
},
|
|
655
|
+
has: async (name) => {
|
|
656
|
+
return (await getState().http.get(P.entitlements, { active_only: "true" })).data.some((e) => e.name === name && e.is_active);
|
|
657
|
+
}
|
|
314
658
|
},
|
|
315
|
-
ai: { anthropic: { messages: { create: async (request) =>
|
|
316
|
-
|
|
317
|
-
|
|
659
|
+
ai: { anthropic: { messages: { create: async (request) => {
|
|
660
|
+
return (await getState().http.post(P.aiAnthropic, request)).data;
|
|
661
|
+
} } } },
|
|
662
|
+
config: { fetch: async () => {
|
|
663
|
+
const s = getState();
|
|
664
|
+
const url = s.http.url(P.config);
|
|
665
|
+
const headers = s.http.buildHeaders();
|
|
666
|
+
let response;
|
|
667
|
+
try {
|
|
668
|
+
response = await (globalThis.fetch ?? fetch)(url, {
|
|
669
|
+
method: "GET",
|
|
670
|
+
headers
|
|
671
|
+
});
|
|
672
|
+
} catch (err) {
|
|
673
|
+
throw new AmbaApiError("NETWORK_ERROR", `Network error: ${err instanceof Error ? err.message : String(err)}`, err);
|
|
674
|
+
}
|
|
675
|
+
const text = await response.text();
|
|
676
|
+
if (!response.ok) {
|
|
677
|
+
const ct = response.headers.get("content-type") ?? "";
|
|
678
|
+
throw mapHttpError(response, text, ct.includes("application/json"));
|
|
679
|
+
}
|
|
680
|
+
let parsed = {};
|
|
681
|
+
if (text) try {
|
|
682
|
+
parsed = JSON.parse(text);
|
|
683
|
+
} catch {
|
|
684
|
+
parsed = {};
|
|
685
|
+
}
|
|
686
|
+
const etag = response.headers.get("etag");
|
|
687
|
+
let version = null;
|
|
688
|
+
if (etag) {
|
|
689
|
+
const cleaned = etag.replace(/^"|"$/g, "");
|
|
690
|
+
const m = cleaned.match(/^(v\d+)/);
|
|
691
|
+
version = m ? m[1] ?? null : cleaned || null;
|
|
692
|
+
}
|
|
693
|
+
return {
|
|
694
|
+
version,
|
|
695
|
+
values: parsed.data ?? {}
|
|
696
|
+
};
|
|
697
|
+
} },
|
|
698
|
+
flags: { fetch: async () => {
|
|
699
|
+
return (await getState().http.get(P.flags)).data;
|
|
700
|
+
} },
|
|
318
701
|
achievements: {
|
|
319
|
-
getAll: async () =>
|
|
320
|
-
|
|
702
|
+
getAll: async () => {
|
|
703
|
+
return (await getState().http.get(P.achievements)).data;
|
|
704
|
+
},
|
|
705
|
+
getProgress: async () => {
|
|
706
|
+
return (await getState().http.get(`${P.achievements}/progress`)).data;
|
|
707
|
+
}
|
|
321
708
|
},
|
|
322
709
|
challenges: {
|
|
323
|
-
getActive: async () =>
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
710
|
+
getActive: async () => {
|
|
711
|
+
return (await getState().http.get(`${P.challenges}/active`)).data;
|
|
712
|
+
},
|
|
713
|
+
get: async (id) => {
|
|
714
|
+
return (await getState().http.get(`${P.challenges}/${encodePathSegment(id)}`)).data;
|
|
715
|
+
},
|
|
716
|
+
getProgress: async (id) => {
|
|
717
|
+
return (await getState().http.get(`${P.challenges}/${encodePathSegment(id)}/progress`)).data;
|
|
718
|
+
},
|
|
719
|
+
claim: async (id) => {
|
|
720
|
+
return (await getState().http.post(`${P.challenges}/${encodePathSegment(id)}/claim`, {})).data;
|
|
721
|
+
}
|
|
327
722
|
},
|
|
328
723
|
currencies: {
|
|
329
|
-
getBalance: async () =>
|
|
330
|
-
|
|
724
|
+
getBalance: async () => {
|
|
725
|
+
return (await getState().http.get(P.currencies)).data;
|
|
726
|
+
},
|
|
727
|
+
getTransactions: async (currencyKey) => {
|
|
728
|
+
return (await getState().http.get(`${P.currencies}/${encodePathSegment(currencyKey)}/transactions`)).data;
|
|
729
|
+
}
|
|
331
730
|
},
|
|
332
731
|
inventory: {
|
|
333
|
-
getItems: async () =>
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
732
|
+
getItems: async () => {
|
|
733
|
+
return (await getState().http.get(P.inventory)).data;
|
|
734
|
+
},
|
|
735
|
+
getItem: async (id) => {
|
|
736
|
+
return (await getState().http.get(`${P.inventory}/${encodePathSegment(id)}`)).data;
|
|
737
|
+
},
|
|
738
|
+
purchase: async (request) => {
|
|
739
|
+
return (await getState().http.post(`${P.inventory}/purchase`, request)).data;
|
|
740
|
+
},
|
|
741
|
+
consume: async (request) => {
|
|
742
|
+
return (await getState().http.post(`${P.inventory}/consume`, request)).data;
|
|
743
|
+
}
|
|
337
744
|
},
|
|
338
745
|
leaderboards: {
|
|
339
|
-
get: async (key) =>
|
|
340
|
-
|
|
341
|
-
|
|
746
|
+
get: async (key) => {
|
|
747
|
+
return (await getState().http.get(`${P.leaderboards}/${encodePathSegment(key)}`)).data;
|
|
748
|
+
},
|
|
749
|
+
getEntries: async (key, limit) => {
|
|
750
|
+
return (await getState().http.get(`${P.leaderboards}/${encodePathSegment(key)}/entries`, limit !== void 0 ? { limit } : void 0)).data;
|
|
751
|
+
},
|
|
752
|
+
getMyRank: async (key) => {
|
|
753
|
+
return (await getState().http.get(`${P.leaderboards}/${encodePathSegment(key)}/me`)).data;
|
|
754
|
+
}
|
|
342
755
|
},
|
|
343
756
|
stores: {
|
|
344
|
-
list: async () =>
|
|
345
|
-
|
|
346
|
-
|
|
757
|
+
list: async () => {
|
|
758
|
+
return (await getState().http.get(P.stores)).data;
|
|
759
|
+
},
|
|
760
|
+
getPurchaseOptions: async (storeKey) => {
|
|
761
|
+
return (await getState().http.get(`${P.stores}/${encodePathSegment(storeKey)}/options`)).data;
|
|
762
|
+
},
|
|
763
|
+
purchase: async (storeKey, purchaseOptionId, receipt) => {
|
|
764
|
+
return (await getState().http.post(`${P.stores}/${encodePathSegment(storeKey)}/purchase`, {
|
|
765
|
+
purchase_option_id: purchaseOptionId,
|
|
766
|
+
receipt
|
|
767
|
+
})).data;
|
|
768
|
+
}
|
|
347
769
|
},
|
|
348
770
|
xp: {
|
|
349
|
-
getBalance: async () =>
|
|
350
|
-
|
|
351
|
-
|
|
771
|
+
getBalance: async () => {
|
|
772
|
+
return (await getState().http.get(P.xp)).data;
|
|
773
|
+
},
|
|
774
|
+
getHistory: async (limit) => {
|
|
775
|
+
return (await getState().http.get(`${P.xp}/history`, limit !== void 0 ? { limit } : void 0)).data;
|
|
776
|
+
},
|
|
777
|
+
claim: async (grantKey) => {
|
|
778
|
+
return (await getState().http.post(`${P.xp}/claim`, { grant_key: grantKey })).data;
|
|
779
|
+
}
|
|
352
780
|
},
|
|
353
781
|
streaks: {
|
|
354
|
-
getAll: async () =>
|
|
355
|
-
|
|
782
|
+
getAll: async () => {
|
|
783
|
+
return (await getState().http.get(P.streaks)).data;
|
|
784
|
+
},
|
|
785
|
+
qualify: async (streakKey) => {
|
|
786
|
+
return (await getState().http.post(`${P.streaks}/${encodePathSegment(streakKey)}/qualify`, {})).data;
|
|
787
|
+
}
|
|
356
788
|
},
|
|
357
|
-
feeds: { getActivity: async (feed, cursor) =>
|
|
789
|
+
feeds: { getActivity: async (feed, cursor) => {
|
|
790
|
+
const f = feed ?? "default";
|
|
791
|
+
return getState().http.get(`${P.feeds}/${encodePathSegment(f)}`, cursor ? { cursor } : void 0);
|
|
792
|
+
} },
|
|
358
793
|
friends: {
|
|
359
|
-
getList: async () =>
|
|
360
|
-
|
|
361
|
-
|
|
794
|
+
getList: async () => {
|
|
795
|
+
return (await getState().http.get(P.friends)).data;
|
|
796
|
+
},
|
|
797
|
+
getFriends: async () => {
|
|
798
|
+
return (await getState().http.get(P.friends, { state: "accepted" })).data;
|
|
799
|
+
},
|
|
800
|
+
blockUser: async (userId) => {
|
|
801
|
+
return (await getState().http.post(`${P.friends}/block`, { user_id: userId })).data;
|
|
802
|
+
},
|
|
362
803
|
unblockUser: async (userId) => {
|
|
363
|
-
await
|
|
804
|
+
await getState().http.post(`${P.friends}/unblock`, { user_id: userId });
|
|
364
805
|
},
|
|
365
806
|
removeBlock: async (friendshipId) => {
|
|
366
|
-
await
|
|
807
|
+
await getState().http.delete(`${P.friends}/${encodePathSegment(friendshipId)}`);
|
|
367
808
|
}
|
|
368
809
|
},
|
|
369
810
|
groups: {
|
|
370
|
-
create: async (params) =>
|
|
371
|
-
|
|
372
|
-
|
|
811
|
+
create: async (params) => {
|
|
812
|
+
return (await getState().http.post(P.groups, params)).data;
|
|
813
|
+
},
|
|
814
|
+
get: async (id) => {
|
|
815
|
+
return (await getState().http.get(`${P.groups}/${encodePathSegment(id)}`)).data;
|
|
816
|
+
},
|
|
817
|
+
update: async (id, patch) => {
|
|
818
|
+
return (await getState().http.patch(`${P.groups}/${encodePathSegment(id)}`, patch)).data;
|
|
819
|
+
},
|
|
373
820
|
delete: async (id) => {
|
|
374
|
-
await
|
|
821
|
+
await getState().http.delete(`${P.groups}/${encodePathSegment(id)}`);
|
|
822
|
+
},
|
|
823
|
+
getMembers: async (id) => {
|
|
824
|
+
return (await getState().http.get(`${P.groups}/${encodePathSegment(id)}/members`)).data;
|
|
825
|
+
},
|
|
826
|
+
join: async (id) => {
|
|
827
|
+
return (await getState().http.post(`${P.groups}/${encodePathSegment(id)}/join`, {})).data;
|
|
375
828
|
},
|
|
376
|
-
getMembers: async (id) => await coreCall((c) => c.groupsGetMembers(id)),
|
|
377
|
-
join: async (id) => await coreCall((c) => c.groupsJoin(id)),
|
|
378
829
|
leave: async (id) => {
|
|
379
|
-
await
|
|
830
|
+
await getState().http.post(`${P.groups}/${encodePathSegment(id)}/leave`, {});
|
|
380
831
|
},
|
|
381
|
-
invite: async (id, userId) =>
|
|
832
|
+
invite: async (id, userId) => {
|
|
833
|
+
return (await getState().http.post(`${P.groups}/${encodePathSegment(id)}/invite`, { user_id: userId })).data;
|
|
834
|
+
}
|
|
382
835
|
},
|
|
383
836
|
messaging: {
|
|
384
|
-
getConversations: async () =>
|
|
385
|
-
|
|
386
|
-
|
|
837
|
+
getConversations: async () => {
|
|
838
|
+
return (await getState().http.get(`${P.messaging}/conversations`)).data;
|
|
839
|
+
},
|
|
840
|
+
getMessage: async (id) => {
|
|
841
|
+
return (await getState().http.get(`${P.messaging}/messages/${encodePathSegment(id)}`)).data;
|
|
842
|
+
},
|
|
843
|
+
sendMessage: async (request) => {
|
|
844
|
+
return (await getState().http.post(`${P.messaging}/messages`, request)).data;
|
|
845
|
+
}
|
|
387
846
|
},
|
|
388
847
|
moderation: {
|
|
389
|
-
reportUser: async (request) =>
|
|
390
|
-
|
|
391
|
-
|
|
848
|
+
reportUser: async (request) => {
|
|
849
|
+
return (await getState().http.post(`${P.moderation}/reports/users`, request)).data;
|
|
850
|
+
},
|
|
851
|
+
reportContent: async (request) => {
|
|
852
|
+
return (await getState().http.post(`${P.moderation}/reports/content`, request)).data;
|
|
853
|
+
},
|
|
854
|
+
getReportStatus: async (id) => {
|
|
855
|
+
return (await getState().http.get(`${P.moderation}/reports/${encodePathSegment(id)}`)).data;
|
|
856
|
+
}
|
|
392
857
|
},
|
|
393
858
|
reviews: {
|
|
394
|
-
list: async (targetType, targetId) =>
|
|
395
|
-
|
|
396
|
-
|
|
859
|
+
list: async (targetType, targetId) => {
|
|
860
|
+
return (await getState().http.get(P.reviews, {
|
|
861
|
+
target_type: targetType,
|
|
862
|
+
target_id: targetId
|
|
863
|
+
})).data;
|
|
864
|
+
},
|
|
865
|
+
create: async (params) => {
|
|
866
|
+
return (await getState().http.post(P.reviews, params)).data;
|
|
867
|
+
},
|
|
868
|
+
update: async (id, patch) => {
|
|
869
|
+
return (await getState().http.patch(`${P.reviews}/${encodePathSegment(id)}`, patch)).data;
|
|
870
|
+
},
|
|
397
871
|
delete: async (id) => {
|
|
398
|
-
await
|
|
872
|
+
await getState().http.delete(`${P.reviews}/${encodePathSegment(id)}`);
|
|
399
873
|
}
|
|
400
874
|
},
|
|
401
875
|
roles: {
|
|
402
|
-
getMyRoles: async () =>
|
|
403
|
-
|
|
876
|
+
getMyRoles: async () => {
|
|
877
|
+
return (await getState().http.get(`${P.roles}/me`)).data;
|
|
878
|
+
},
|
|
879
|
+
hasPermission: async (permission) => {
|
|
880
|
+
return (await getState().http.get(`${P.roles}/check`, { permission })).data.allowed === true;
|
|
881
|
+
}
|
|
404
882
|
},
|
|
405
883
|
referrals: {
|
|
406
|
-
getReferralCode: async () =>
|
|
407
|
-
|
|
408
|
-
|
|
884
|
+
getReferralCode: async () => {
|
|
885
|
+
return (await getState().http.get(`${P.referrals}/me`)).data;
|
|
886
|
+
},
|
|
887
|
+
claimReferral: async (code) => {
|
|
888
|
+
return (await getState().http.post(`${P.referrals}/claim`, { code })).data;
|
|
889
|
+
},
|
|
890
|
+
create: async (code, maxUses) => {
|
|
891
|
+
const body = {};
|
|
892
|
+
if (code !== void 0) body.code = code;
|
|
893
|
+
if (maxUses !== void 0) body.max_uses = maxUses;
|
|
894
|
+
return (await getState().http.post(P.referrals, body)).data;
|
|
895
|
+
}
|
|
409
896
|
},
|
|
410
|
-
catalog: { list: async () =>
|
|
897
|
+
catalog: { list: async () => {
|
|
898
|
+
return (await getState().http.get(P.catalog)).data;
|
|
899
|
+
} },
|
|
411
900
|
content: {
|
|
412
|
-
getToday: async (channel = "default") =>
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
901
|
+
getToday: async (channel = "default") => {
|
|
902
|
+
return (await getState().http.get(`${P.content}/today/${encodePathSegment(channel)}`)).data ?? null;
|
|
903
|
+
},
|
|
904
|
+
getLibrary: async (channel = "default", options) => {
|
|
905
|
+
return (await getState().http.get(`${P.content}/library/${encodePathSegment(channel)}`, {
|
|
906
|
+
limit: options?.limit,
|
|
907
|
+
cursor: options?.cursor
|
|
908
|
+
})).data;
|
|
909
|
+
},
|
|
910
|
+
getItem: async (id) => {
|
|
911
|
+
return (await getState().http.get(`${P.content}/${encodePathSegment(id)}`)).data;
|
|
912
|
+
},
|
|
913
|
+
updateItem: async (id, state_) => {
|
|
914
|
+
return (await getState().http.post(`${P.content}/${encodePathSegment(id)}/state`, state_)).data;
|
|
915
|
+
},
|
|
916
|
+
createItem: async (channel, item) => {
|
|
917
|
+
return (await getState().http.post(`${P.content}/${encodePathSegment(channel)}`, item)).data;
|
|
918
|
+
}
|
|
417
919
|
},
|
|
418
920
|
deepLinks: {
|
|
419
|
-
get: async (shortCode) =>
|
|
420
|
-
|
|
921
|
+
get: async (shortCode) => {
|
|
922
|
+
return (await getState().http.get(`${P.deepLinks}/${encodePathSegment(shortCode)}`)).data;
|
|
923
|
+
},
|
|
924
|
+
create: async (params) => {
|
|
925
|
+
return (await getState().http.post(P.deepLinks, params)).data;
|
|
926
|
+
}
|
|
421
927
|
},
|
|
422
928
|
onboarding: {
|
|
423
|
-
getStatus: async () =>
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
929
|
+
getStatus: async () => {
|
|
930
|
+
return (await getState().http.get(P.onboarding)).data;
|
|
931
|
+
},
|
|
932
|
+
nextStep: async (payload) => {
|
|
933
|
+
return (await getState().http.post(`${P.onboarding}/next`, payload)).data;
|
|
934
|
+
},
|
|
935
|
+
skipStep: async () => {
|
|
936
|
+
return (await getState().http.post(`${P.onboarding}/skip`, {})).data;
|
|
937
|
+
},
|
|
938
|
+
complete: async () => {
|
|
939
|
+
return (await getState().http.post(`${P.onboarding}/complete`, {})).data;
|
|
940
|
+
}
|
|
427
941
|
}
|
|
428
942
|
};
|
|
429
|
-
const SDK_VERSION = "0.1.0";
|
|
430
943
|
|
|
431
944
|
//#endregion
|
|
432
945
|
export { Amba, AmbaApiError, SDK_VERSION };
|