@wix/himalaya-cli 0.1142.0 → 0.1144.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.
Files changed (47) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/delivery-contract.d.ts +104 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/delivery.d.ts +33 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/index.d.ts +5 -0
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +509 -3
  5. package/dist/cli.mjs +31387 -30592
  6. package/dist/preview-assets.generated.bin +0 -0
  7. package/guides/getting-started.md +29 -11
  8. package/guides/himi-skill.md +29 -11
  9. package/guides/sdk-reference.json +132 -0
  10. package/guides/templates.md +33 -0
  11. package/guides/trim-a-template.md +13 -0
  12. package/package.json +2 -2
  13. package/templates/beauty-salon/dev/index.ts +2 -0
  14. package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +2 -2
  15. package/templates/beauty-salon/tier5-src/himi-store-account/index.ts +7 -1
  16. package/templates/branded-lite/dev/index.ts +3 -1
  17. package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +2 -2
  18. package/templates/branded-lite/tier5-src/himi-events-rsvp/index.ts +2 -2
  19. package/templates/branded-lite/tier5-src/himi-store-account/index.ts +7 -1
  20. package/templates/community-club/dev/index.ts +2 -1
  21. package/templates/community-club/tier5-src/himi-events-rsvp/index.ts +2 -2
  22. package/templates/community-club/tier5-src/himi-store-account/index.ts +7 -1
  23. package/templates/events-meetups/dev/index.ts +2 -1
  24. package/templates/events-meetups/tier5-src/himi-events-rsvp/index.ts +2 -2
  25. package/templates/events-meetups/tier5-src/himi-store-account/index.ts +7 -1
  26. package/templates/gym-fitness/dev/index.ts +3 -1
  27. package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +2 -2
  28. package/templates/gym-fitness/tier5-src/himi-events-rsvp/index.ts +2 -2
  29. package/templates/gym-fitness/tier5-src/himi-store-account/index.ts +7 -1
  30. package/templates/nonprofit-cause/dev/index.ts +2 -1
  31. package/templates/nonprofit-cause/tier5-src/himi-events-rsvp/index.ts +2 -2
  32. package/templates/nonprofit-cause/tier5-src/himi-store-account/index.ts +7 -1
  33. package/templates/podcast-creator/dev/index.ts +2 -1
  34. package/templates/podcast-creator/tier5-src/himi-events-rsvp/index.ts +2 -2
  35. package/templates/podcast-creator/tier5-src/himi-store-account/index.ts +7 -1
  36. package/templates/portfolio-creative/dev/index.ts +2 -1
  37. package/templates/portfolio-creative/tier5-src/himi-events-rsvp/index.ts +2 -2
  38. package/templates/portfolio-creative/tier5-src/himi-store-account/index.ts +7 -1
  39. package/templates/restaurant/dev/index.ts +2 -1
  40. package/templates/restaurant/tier5-src/himi-events-rsvp/index.ts +2 -2
  41. package/templates/restaurant/tier5-src/himi-store-account/index.ts +7 -1
  42. package/templates/retail-store/dev/index.ts +1 -0
  43. package/templates/retail-store/tier5-src/himi-store-account/index.ts +7 -1
  44. package/templates/yoga-studio/dev/index.ts +3 -1
  45. package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +2 -2
  46. package/templates/yoga-studio/tier5-src/himi-events-rsvp/index.ts +2 -2
  47. package/templates/yoga-studio/tier5-src/himi-store-account/index.ts +7 -1
@@ -13,6 +13,507 @@ function dispatch(handlerId, params, _options) {
13
13
  return himalaya.dispatch(handlerId, stringParams);
14
14
  }
15
15
 
16
+ // ../../core/sdk/iap/src/delivery.ts
17
+ var MAX_AUTOMATIC_ATTEMPTS = 5;
18
+ var MAX_RETRY_DELAY_MS = 6e4;
19
+ var BASE_RETRY_DELAY_MS = 1e3;
20
+ var UNAVAILABLE_CODES = /* @__PURE__ */ new Set(["unsupported", "unavailable", "notEnabled"]);
21
+ function createPurchaseCoordinator(deps) {
22
+ const items = /* @__PURE__ */ new Map();
23
+ const queue = createSerialQueue();
24
+ const store = guardStore(deps.store);
25
+ let outcome = "idle";
26
+ let purchasing = false;
27
+ let signInPrompt = false;
28
+ let unavailable = null;
29
+ let pendingApproval = null;
30
+ let errorCode = null;
31
+ let errorFromReconcile = false;
32
+ let unfinishedCount = null;
33
+ let generation = deps.session.current().generation;
34
+ let staleSignal = createSignal();
35
+ let started = false;
36
+ let disposed = false;
37
+ const unsubscribe = deps.session.subscribe(onSessionNotified);
38
+ function start() {
39
+ started = true;
40
+ return reconcile();
41
+ }
42
+ function purchase2(catalogRef) {
43
+ onSessionNotified();
44
+ const requestedBy = deps.session.current();
45
+ const name = `purchase:${requestedBy.generation}:${catalogRef}`;
46
+ return runJob(name, () => runPurchase(requestedBy, catalogRef), { joinRunning: true }).then(([dropped, state]) => dropped ? { ...state, errorCode: "sessionChanged" } : state);
47
+ }
48
+ function reconcile() {
49
+ resetIfSessionChanged();
50
+ return enqueue("reconcile", runReconcile);
51
+ }
52
+ function retry() {
53
+ resetIfSessionChanged();
54
+ return enqueue("retry", runRetry);
55
+ }
56
+ function tick() {
57
+ if (resetIfSessionChanged() && started) return reconcile();
58
+ return enqueue("tick", runDue);
59
+ }
60
+ function getState() {
61
+ if (disposed || !sessionMatches()) return { phase: "idle", errorCode: null, items: [], unfinishedCount: null, nextWakeAt: null };
62
+ const snapshot = [...items.values()].map((item) => ({ ...item.state }));
63
+ const due = snapshot.map((item) => item.nextAttemptAt).filter((at) => at !== null);
64
+ return { phase: currentPhase(), errorCode: errorCode ?? unavailable?.code ?? null, items: snapshot, unfinishedCount, nextWakeAt: due.length > 0 ? Math.min(...due) : null };
65
+ }
66
+ function dispose() {
67
+ disposed = true;
68
+ unsubscribe();
69
+ staleSignal.fire();
70
+ }
71
+ async function runPurchase(session, catalogRef) {
72
+ if (!isCurrent(session)) return !disposed;
73
+ setError(null, false);
74
+ outcome = "idle";
75
+ pendingApproval = null;
76
+ unavailable = null;
77
+ releaseSignIn();
78
+ if (session.kind !== "member") {
79
+ requireSignIn();
80
+ return false;
81
+ }
82
+ const context = await purchaseContext(session, catalogRef);
83
+ if (!isCurrent(session)) return !disposed;
84
+ if (!context) return false;
85
+ purchasing = true;
86
+ publish();
87
+ const { productId, appAccountToken } = context;
88
+ const result = await store.purchaseForVerification({ productId, appAccountToken });
89
+ purchasing = false;
90
+ if (!isCurrent(session)) return !disposed;
91
+ if (result.status === "purchased") await deliverPurchase(session, result.transaction, context);
92
+ else if (result.status === "failed") failStore(result.code, false);
93
+ else if (result.status === "pending") {
94
+ if (!await awaitApproval(session, context)) return !disposed;
95
+ } else setOutcome("cancelled");
96
+ return false;
97
+ }
98
+ async function deliverPurchase(session, transaction, context) {
99
+ const item = upsert(transaction, null);
100
+ applyDelivered(await deliver(session, [item], context));
101
+ await enumerate(session);
102
+ publish();
103
+ }
104
+ async function runReconcile() {
105
+ resetIfSessionChanged();
106
+ const session = deps.session.current();
107
+ const listing = await enumerate(session);
108
+ if (listing === "stale") return;
109
+ if (session.kind !== "member") return requireSignIn();
110
+ if (listing === "listed") clearReconcileProblem();
111
+ const now = deps.clock.now();
112
+ const eligible = itemsWhere((state) => isAwaitingDelivery(state) && (state.nextAttemptAt === null || state.nextAttemptAt <= now));
113
+ eligible.forEach(restartAttemptBudget);
114
+ await settleDelivery(session, await deliver(session, eligible));
115
+ }
116
+ async function settleDelivery(session, delivered) {
117
+ applyDelivered(delivered);
118
+ if (delivered.finished) await enumerate(session);
119
+ publish();
120
+ }
121
+ function applyDelivered(delivered) {
122
+ if (delivered.confirmedProducts.length === 0) return;
123
+ if (outcome === "cancelled") outcome = "idle";
124
+ if (!delivered.signInLost) releaseSignIn();
125
+ }
126
+ function releaseSignIn() {
127
+ if (!signInPrompt) return;
128
+ signInPrompt = false;
129
+ const now = deps.clock.now();
130
+ for (const item of items.values()) {
131
+ if (item.state.access === "signInRequired") Object.assign(item.state, { access: "waitingToRetry", attempts: 0, nextAttemptAt: now });
132
+ }
133
+ }
134
+ function clearReconcileProblem() {
135
+ if (unavailable?.from === "reconcile") unavailable = null;
136
+ if (errorFromReconcile) setError(null, false);
137
+ }
138
+ async function runRetry() {
139
+ releaseSignIn();
140
+ for (const item of items.values()) unblock(item.state);
141
+ await runReconcile();
142
+ }
143
+ async function runDue() {
144
+ if (resetIfSessionChanged()) return started ? runReconcile() : void 0;
145
+ const session = memberSession();
146
+ const now = deps.clock.now();
147
+ const due = itemsWhere((state) => state.nextAttemptAt !== null && state.nextAttemptAt <= now);
148
+ if (!session || due.length === 0) return;
149
+ await settleDelivery(session, await deliver(session, due));
150
+ }
151
+ async function deliver(session, batch, known) {
152
+ const needProof = batch.filter((item) => item.state.access !== "confirmed");
153
+ const context = known ?? (needProof.length > 0 ? await memberContext(session, needProof) : void 0);
154
+ const delivered = noDelivery();
155
+ for (const item of batch) {
156
+ if (!isCurrent(session)) return noDelivery();
157
+ const wasConfirmed = item.state.access === "confirmed";
158
+ if (delivered.signInLost && !wasConfirmed) {
159
+ blockWithoutSession(item, context);
160
+ continue;
161
+ }
162
+ if (await deliverItem(session, item, context)) delivered.finished = true;
163
+ if (!wasConfirmed && item.state.access === "confirmed") delivered.confirmedProducts.push(item.state.productId);
164
+ if (item.state.access === "signInRequired") delivered.signInLost = true;
165
+ }
166
+ return delivered;
167
+ }
168
+ function blockWithoutSession(item, context) {
169
+ const foreign = context !== void 0 && !sameAccount(item.transaction.appAccountToken, context.appAccountToken);
170
+ block(item.state, foreign ? "ownershipConflict" : "signInRequired", null);
171
+ }
172
+ async function deliverItem(session, item, context) {
173
+ if (item.state.access !== "confirmed") {
174
+ if (!context || !await confirmAccess(session, item, context)) return false;
175
+ }
176
+ return complete(session, item);
177
+ }
178
+ async function confirmAccess(session, item, context) {
179
+ if (!sameAccount(item.transaction.appAccountToken, context.appAccountToken)) {
180
+ block(item.state, "ownershipConflict", null);
181
+ return false;
182
+ }
183
+ updateItem(item, { access: "confirming", nextAttemptAt: null });
184
+ const settled = await settle(session, () => deps.backend.submitProof(session, item.transaction));
185
+ if (settled.kind === "stale") return false;
186
+ if (settled.kind === "error") return recordFailedAttempt(item, void 0);
187
+ return applySubmission(item, settled.value, context.scopeKey);
188
+ }
189
+ function applySubmission(item, raw, scopeKey) {
190
+ if (!isObject(raw)) return block(item.state, "rejected", "invalidResponse");
191
+ switch (raw.status) {
192
+ case "processed":
193
+ case "alreadyProcessed":
194
+ if (!acknowledges(raw.acknowledgement, item.transaction, scopeKey)) return block(item.state, "rejected", "invalidResponse");
195
+ Object.assign(item.state, { access: "confirmed", nextAttemptAt: null, errorCode: null });
196
+ return true;
197
+ case "retryable":
198
+ return recordFailedAttempt(item, retryAfter(raw.retryAfterMs));
199
+ case "authRequired":
200
+ signInPrompt = true;
201
+ return block(item.state, "signInRequired", null);
202
+ case "ownershipConflict":
203
+ return block(item.state, "ownershipConflict", null);
204
+ case "rejected":
205
+ return block(item.state, "rejected", "proofRejected");
206
+ default:
207
+ return block(item.state, "rejected", "invalidResponse");
208
+ }
209
+ }
210
+ async function complete(session, item) {
211
+ if (!isCurrent(session)) return false;
212
+ const result = await store.finishTransaction({ transactionId: item.transaction.transactionId });
213
+ if (!isCurrent(session)) return false;
214
+ if (result.status === "failed") {
215
+ item.state.completion = "retryRequired";
216
+ recordFailedAttempt(item, void 0);
217
+ return false;
218
+ }
219
+ Object.assign(item.state, { completion: result.status, held: false, nextAttemptAt: null });
220
+ return result.status === "finished";
221
+ }
222
+ function recordFailedAttempt(item, retryAfterMs) {
223
+ const state = item.state;
224
+ state.attempts += 1;
225
+ if (state.access !== "confirmed") state.access = "waitingToRetry";
226
+ state.nextAttemptAt = state.attempts >= MAX_AUTOMATIC_ATTEMPTS ? null : deps.clock.now() + retryDelay(state.attempts, retryAfterMs);
227
+ return false;
228
+ }
229
+ function retryDelay(attempts, retryAfterMs) {
230
+ if (retryAfterMs !== void 0) return Math.min(retryAfterMs, MAX_RETRY_DELAY_MS);
231
+ const base = Math.min(BASE_RETRY_DELAY_MS * 2 ** (attempts - 1), MAX_RETRY_DELAY_MS);
232
+ return base + Math.max(0, deps.jitter?.(base) ?? 0);
233
+ }
234
+ async function purchaseContext(session, catalogRef) {
235
+ const settled = await settle(session, () => deps.backend.getPurchaseContext(session, catalogRef));
236
+ if (settled.kind === "stale") return null;
237
+ const decoded = decodeContext(settled, isPurchaseContext);
238
+ if (decoded.kind === "ok") return decoded.context;
239
+ if (decoded.kind === "signInRequired") requireSignIn();
240
+ else failContext(decoded.kind);
241
+ return null;
242
+ }
243
+ async function memberContext(session, waiting) {
244
+ const settled = await settle(session, () => deps.backend.getMemberContext(session));
245
+ if (settled.kind === "stale") return void 0;
246
+ const decoded = decodeContext(settled, isMemberContext);
247
+ if (decoded.kind === "ok") return decoded.context;
248
+ if (decoded.kind === "rejected") setError("contextRejected", true);
249
+ if (decoded.kind === "signInRequired") signInPrompt = true;
250
+ for (const item of waiting) {
251
+ if (decoded.kind === "unavailable") recordFailedAttempt(item, decoded.retryAfterMs);
252
+ else if (decoded.kind === "rejected") block(item.state, "waitingToRetry", "contextRejected");
253
+ else block(item.state, "signInRequired", null);
254
+ }
255
+ return void 0;
256
+ }
257
+ async function enumerate(session, { quiet = false } = {}) {
258
+ if (!isCurrent(session)) return "stale";
259
+ const result = await store.getUnfinishedTransactions();
260
+ if (!isCurrent(session)) return "stale";
261
+ if (result.status !== "ok") {
262
+ unfinishedCount = null;
263
+ if (!quiet) failStore(result.code, true);
264
+ return "failed";
265
+ }
266
+ const held = new Set(result.transactions.map((transaction) => upsert(transaction, true)));
267
+ for (const item of items.values()) if (!held.has(item)) item.state.held = false;
268
+ unfinishedCount = result.transactions.length;
269
+ return "listed";
270
+ }
271
+ function upsert(transaction, held) {
272
+ const key = identityOf(transaction);
273
+ const existing = items.get(key);
274
+ if (existing) {
275
+ existing.transaction = transaction;
276
+ if (held !== null) existing.state.held = held;
277
+ return existing;
278
+ }
279
+ if (pendingApproval?.productId === transaction.productId && !pendingApproval.known.has(key) && sameAccount(transaction.appAccountToken, pendingApproval.token)) {
280
+ pendingApproval = null;
281
+ if (outcome === "awaitingApproval") outcome = "idle";
282
+ }
283
+ const item = { transaction, state: newItemState(transaction, held) };
284
+ items.set(key, item);
285
+ return item;
286
+ }
287
+ function onSessionNotified() {
288
+ if (resetIfSessionChanged() && started) void reconcile();
289
+ }
290
+ function resetIfSessionChanged() {
291
+ const next = deps.session.current().generation;
292
+ if (disposed || next === generation) return false;
293
+ generation = next;
294
+ staleSignal.fire();
295
+ staleSignal = createSignal();
296
+ items.clear();
297
+ outcome = "idle";
298
+ purchasing = false;
299
+ signInPrompt = false;
300
+ unavailable = null;
301
+ pendingApproval = null;
302
+ unfinishedCount = null;
303
+ setError(null, false);
304
+ publish();
305
+ return true;
306
+ }
307
+ function memberSession() {
308
+ const session = deps.session.current();
309
+ return session.kind === "member" ? session : null;
310
+ }
311
+ function sessionMatches() {
312
+ return deps.session.current().generation === generation;
313
+ }
314
+ function isCurrent(session) {
315
+ return !disposed && session.generation === generation && sessionMatches();
316
+ }
317
+ async function settle(session, call) {
318
+ const stale = staleSignal.waiter();
319
+ try {
320
+ const pending = Promise.resolve().then(() => {
321
+ if (!isCurrent(session)) throw ABANDONED;
322
+ return call();
323
+ });
324
+ const settled = await Promise.race([pending.then((value) => ({ kind: "value", value })), stale.fired.then(() => STALE)]);
325
+ return isCurrent(session) ? settled : STALE;
326
+ } catch {
327
+ return isCurrent(session) ? { kind: "error" } : STALE;
328
+ } finally {
329
+ stale.cancel();
330
+ }
331
+ }
332
+ function runJob(name, run, options = {}) {
333
+ return queue.run(name, () => disposed ? Promise.resolve(void 0) : run(), options).then((result) => [result, getState()]);
334
+ }
335
+ function enqueue(name, run) {
336
+ return runJob(name, run).then(([, state]) => state);
337
+ }
338
+ function itemsWhere(predicate) {
339
+ return [...items.values()].filter((item) => predicate(item.state));
340
+ }
341
+ function updateItem(item, patch) {
342
+ Object.assign(item.state, patch);
343
+ publish();
344
+ }
345
+ function requireSignIn() {
346
+ for (const item of items.values()) {
347
+ if (isAwaitingDelivery(item.state) && item.state.access !== "confirmed") block(item.state, "signInRequired", null);
348
+ }
349
+ signInPrompt = true;
350
+ publish();
351
+ }
352
+ function failContext(reason) {
353
+ setError(reason === "rejected" ? "contextRejected" : "contextUnavailable", false);
354
+ publish();
355
+ }
356
+ function failStore(code, fromReconcile) {
357
+ setError(code, fromReconcile);
358
+ if (UNAVAILABLE_CODES.has(code) && unavailable?.from !== "purchase") {
359
+ unavailable = { from: fromReconcile ? "reconcile" : "purchase", code };
360
+ }
361
+ publish();
362
+ }
363
+ async function awaitApproval(session, context) {
364
+ if (await enumerate(session, { quiet: true }) === "stale") return false;
365
+ const known = new Set([...items.keys()].filter((key) => items.get(key).state.productId === context.productId));
366
+ pendingApproval = { productId: context.productId, token: context.appAccountToken, known };
367
+ setOutcome("awaitingApproval");
368
+ return true;
369
+ }
370
+ function setOutcome(next) {
371
+ outcome = next;
372
+ publish();
373
+ }
374
+ function currentPhase() {
375
+ if (purchasing) return "purchasing";
376
+ if (unavailable?.from === "purchase") return "unavailable";
377
+ if (signInPrompt) return "signInRequired";
378
+ if (unavailable?.from === "reconcile") return "unavailable";
379
+ return outcome;
380
+ }
381
+ function setError(code, fromReconcile) {
382
+ errorCode = code;
383
+ errorFromReconcile = code !== null && fromReconcile;
384
+ }
385
+ function publish() {
386
+ if (!disposed && sessionMatches()) deps.onState?.(getState());
387
+ }
388
+ return { start, purchase: purchase2, reconcile, retry, tick, getState, dispose };
389
+ }
390
+ var noDelivery = () => ({ finished: false, confirmedProducts: [], signInLost: false });
391
+ var STALE = { kind: "stale" };
392
+ var ABANDONED = { abandoned: true };
393
+ async function storeCall(call) {
394
+ try {
395
+ return await call();
396
+ } catch {
397
+ return { status: "failed", code: "storeError" };
398
+ }
399
+ }
400
+ function guardStore(store) {
401
+ return {
402
+ purchaseForVerification: (input) => storeCall(() => store.purchaseForVerification(input)),
403
+ getUnfinishedTransactions: () => storeCall(() => store.getUnfinishedTransactions()),
404
+ finishTransaction: (input) => storeCall(() => store.finishTransaction(input))
405
+ };
406
+ }
407
+ function identityOf(transaction) {
408
+ return `${transaction.store}:${transaction.environment}:${transaction.transactionId}`;
409
+ }
410
+ function newItemState(transaction, held) {
411
+ return {
412
+ productId: transaction.productId,
413
+ environment: transaction.environment,
414
+ held,
415
+ access: "pending",
416
+ completion: "pending",
417
+ attempts: 0,
418
+ nextAttemptAt: null,
419
+ errorCode: null
420
+ };
421
+ }
422
+ function isAwaitingDelivery(state) {
423
+ if (state.access === "confirmed") return state.completion === "pending" || state.completion === "retryRequired";
424
+ return state.access === "pending" || state.access === "waitingToRetry" || state.access === "signInRequired";
425
+ }
426
+ function restartAttemptBudget(item) {
427
+ item.state.attempts = 0;
428
+ }
429
+ function unblock(state) {
430
+ if (state.access !== "confirmed") Object.assign(state, { access: "pending", errorCode: null });
431
+ Object.assign(state, { attempts: 0, nextAttemptAt: null });
432
+ }
433
+ function block(state, access, errorCode) {
434
+ Object.assign(state, { access, errorCode, nextAttemptAt: null });
435
+ return false;
436
+ }
437
+ function sameAccount(transactionToken, memberToken) {
438
+ return transactionToken !== null && transactionToken.toLowerCase() === memberToken.toLowerCase();
439
+ }
440
+ function acknowledges(acknowledgement, transaction, scopeKey) {
441
+ return isObject(acknowledgement) && acknowledgement.transactionId === transaction.transactionId && acknowledgement.productId === transaction.productId && acknowledgement.environment === transaction.environment && acknowledgement.scopeKey === scopeKey;
442
+ }
443
+ function decodeContext(settled, isContext) {
444
+ const raw = settled.kind === "value" ? settled.value : null;
445
+ if (!isObject(raw)) return { kind: "unavailable" };
446
+ if (raw.status === "ok" && isContext(raw.context)) return { kind: "ok", context: raw.context };
447
+ if (raw.status === "authRequired") return { kind: "signInRequired" };
448
+ if (raw.status === "rejected") return { kind: "rejected" };
449
+ return { kind: "unavailable", retryAfterMs: retryAfter(raw.retryAfterMs) };
450
+ }
451
+ function isPurchaseContext(value) {
452
+ return isMemberContext(value) && isObject(value) && isNonEmpty(value.productId);
453
+ }
454
+ function isMemberContext(value) {
455
+ return isObject(value) && isNonEmpty(value.appAccountToken) && isNonEmpty(value.scopeKey);
456
+ }
457
+ function retryAfter(value) {
458
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
459
+ }
460
+ function isNonEmpty(value) {
461
+ return typeof value === "string" && value.length > 0;
462
+ }
463
+ function isObject(value) {
464
+ return value !== null && typeof value === "object" && !Array.isArray(value);
465
+ }
466
+ function createSignal() {
467
+ const listeners = /* @__PURE__ */ new Set();
468
+ let hasFired = false;
469
+ return {
470
+ fire() {
471
+ hasFired = true;
472
+ for (const listener of listeners) listener();
473
+ listeners.clear();
474
+ },
475
+ waiter() {
476
+ let listener = () => {
477
+ };
478
+ const fired = new Promise((resolve) => {
479
+ listener = resolve;
480
+ });
481
+ if (hasFired) listener();
482
+ else listeners.add(listener);
483
+ return { fired, cancel: () => {
484
+ listeners.delete(listener);
485
+ } };
486
+ }
487
+ };
488
+ }
489
+ function createSerialQueue() {
490
+ let tail = Promise.resolve();
491
+ const waiting = /* @__PURE__ */ new Map();
492
+ const running = /* @__PURE__ */ new Map();
493
+ async function execute(name, self, job) {
494
+ waiting.delete(name);
495
+ running.set(name, self);
496
+ try {
497
+ return await job();
498
+ } catch {
499
+ return void 0;
500
+ } finally {
501
+ running.delete(name);
502
+ }
503
+ }
504
+ return {
505
+ /** Callers joined onto a shared job all receive that job's result. */
506
+ run(name, job, { joinRunning = false }) {
507
+ const shared = waiting.get(name) ?? (joinRunning ? running.get(name) : void 0);
508
+ if (shared) return shared;
509
+ const scheduled = tail.then(() => execute(name, scheduled, job));
510
+ waiting.set(name, scheduled);
511
+ tail = scheduled;
512
+ return scheduled;
513
+ }
514
+ };
515
+ }
516
+
16
517
  // ../../core/sdk/iap/src/index.ts
17
518
  async function getPaywallConfig() {
18
519
  const r = await dispatch("capability.iap.getPaywallConfig");
@@ -81,15 +582,16 @@ async function finishTransaction(input) {
81
582
  if (result?.status === "finished" || result?.status === "notFound") return { status: result.status };
82
583
  return decodeFailure(result);
83
584
  }
585
+ var appleManagedStore = { purchaseForVerification, getUnfinishedTransactions, finishTransaction };
84
586
  var transactionErrors = /* @__PURE__ */ new Set(["unsupported", "unavailable", "invalidArgument", "invalidResponse", "notEnabled", "unsupportedProductType", "unknownProduct", "verificationFailed", "persistenceFailed", "ownershipConflict", "storeError", "busy"]);
85
587
  var failure = (code) => ({ status: "failed", code });
86
588
  var nonempty = (value) => typeof value === "string" && value.trim().length > 0;
87
589
  var isUUID = (value) => typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value) && value.length === 36;
88
- var isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
590
+ var isObject2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
89
591
  async function managedDispatch(invoke) {
90
592
  try {
91
593
  const value = await invoke();
92
- return isObject(value) ? value : null;
594
+ return isObject2(value) ? value : null;
93
595
  } catch {
94
596
  return failure("unavailable");
95
597
  }
@@ -98,7 +600,7 @@ function decodeFailure(value) {
98
600
  return value?.status === "failed" && transactionErrors.has(value.code) ? failure(value.code) : failure("invalidResponse");
99
601
  }
100
602
  function isAppleTransaction(value) {
101
- if (!isObject(value)) return false;
603
+ if (!isObject2(value)) return false;
102
604
  return value.store === "apple" && typeof value.signedTransaction === "string" && /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.signedTransaction) && nonempty(value.transactionId) && nonempty(value.originalTransactionId) && nonempty(value.productId) && (value.appAccountToken === null || isUUID(value.appAccountToken)) && ["production", "sandbox", "xcode", "unknown"].includes(value.environment);
103
605
  }
104
606
  function decodeTransaction(value) {
@@ -106,7 +608,11 @@ function decodeTransaction(value) {
106
608
  return { store, signedTransaction, transactionId, originalTransactionId, productId, appAccountToken, environment };
107
609
  }
108
610
  export {
611
+ MAX_AUTOMATIC_ATTEMPTS,
612
+ MAX_RETRY_DELAY_MS,
613
+ appleManagedStore,
109
614
  consume,
615
+ createPurchaseCoordinator,
110
616
  entitlements,
111
617
  finishTransaction,
112
618
  getPaywallConfig,