glitch-javascript-sdk 3.10.8 → 3.15.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/dist/esm/index.js CHANGED
@@ -5862,7 +5862,7 @@ class Requests {
5862
5862
  }
5863
5863
  return Requests.request('DELETE', url);
5864
5864
  }
5865
- static uploadFile(url, filename, file, data, params, onUploadProgress) {
5865
+ static uploadFile(url, filename, file, data, params, onUploadProgress, options) {
5866
5866
  // Process URL and params
5867
5867
  if (params && Object.keys(params).length > 0) {
5868
5868
  const queryString = Object.entries(params)
@@ -5893,6 +5893,8 @@ class Requests {
5893
5893
  data: formData,
5894
5894
  headers,
5895
5895
  onUploadProgress,
5896
+ signal: options === null || options === void 0 ? void 0 : options.signal,
5897
+ timeout: options === null || options === void 0 ? void 0 : options.timeout,
5896
5898
  });
5897
5899
  }
5898
5900
  static postFormData(url, formData, params, onUploadProgress) {
@@ -6006,13 +6008,21 @@ class Requests {
6006
6008
  }
6007
6009
  });
6008
6010
  }
6009
- static processRoute(route, data, routeReplace, params) {
6011
+ static processRoute(route, data, routeReplace, params, options) {
6010
6012
  let url = route.url;
6011
6013
  if (routeReplace) {
6012
6014
  for (let key in routeReplace) {
6013
6015
  url = url.replace("{" + key + "}", routeReplace[key]);
6014
6016
  }
6015
6017
  }
6018
+ if (options) {
6019
+ const query = Object.assign(Object.assign({}, params), (Requests.community_id && !options.excludeCommunityContext ? { community_id: Requests.community_id } : {}));
6020
+ return axios({
6021
+ method: route.method, url: Requests.buildUrl(url, query), data,
6022
+ headers: Object.assign(Object.assign({ 'Content-Type': 'application/json' }, (Requests.authToken ? { Authorization: `Bearer ${Requests.authToken}` } : {})), options.headers),
6023
+ signal: options.signal, timeout: options.timeout,
6024
+ });
6025
+ }
6016
6026
  if (route.method == HTTP_METHODS.GET) {
6017
6027
  return Requests.get(url, params);
6018
6028
  }
@@ -14774,7 +14784,10 @@ class Messages {
14774
14784
  return Requests.processRoute(MessagesRoute.routes.listMessageThreads, undefined, undefined, params);
14775
14785
  }
14776
14786
  /**
14777
- * Send a new message that will be added to a thread
14787
+ * Send a new message that will be added to a thread. Festival-scoped threads
14788
+ * enforce current admission, blocking and read-only state server-side.
14789
+ * Include an optional client_message_id UUID and reuse it when retrying a
14790
+ * timed-out request to prevent duplicate messages and notifications.
14778
14791
  *
14779
14792
  * @see https://api.glitch.fun/api/documentation#/Messages/storeMessage
14780
14793
  *
@@ -21588,6 +21601,748 @@ class GameDesign {
21588
21601
  }
21589
21602
  }
21590
21603
 
21604
+ /** Participant-only festival networking; all access checks are enforced by the API. */
21605
+ class FestivalNetworkingRoute {
21606
+ }
21607
+ FestivalNetworkingRoute.routes = {
21608
+ settings: { url: '/gameshows/{show_id}/networking/settings', method: HTTP_METHODS.GET },
21609
+ updateSettings: { url: '/gameshows/{show_id}/networking/settings', method: HTTP_METHODS.PUT },
21610
+ listPosts: { url: '/gameshows/{show_id}/networking/posts', method: HTTP_METHODS.GET },
21611
+ createPost: { url: '/gameshows/{show_id}/networking/posts', method: HTTP_METHODS.POST },
21612
+ getPost: { url: '/gameshows/{show_id}/networking/posts/{post_id}', method: HTTP_METHODS.GET },
21613
+ updatePost: { url: '/gameshows/{show_id}/networking/posts/{post_id}', method: HTTP_METHODS.PUT },
21614
+ listComments: { url: '/gameshows/{show_id}/networking/posts/{post_id}/comments', method: HTTP_METHODS.GET },
21615
+ createComment: { url: '/gameshows/{show_id}/networking/posts/{post_id}/comments', method: HTTP_METHODS.POST },
21616
+ setInteraction: { url: '/gameshows/{show_id}/networking/posts/{post_id}/interaction', method: HTTP_METHODS.PUT },
21617
+ apply: { url: '/gameshows/{show_id}/networking/posts/{post_id}/apply', method: HTTP_METHODS.POST },
21618
+ matches: { url: '/gameshows/{show_id}/networking/posts/{post_id}/matches', method: HTTP_METHODS.GET },
21619
+ report: { url: '/gameshows/{show_id}/networking/posts/{post_id}/report', method: HTTP_METHODS.POST },
21620
+ applications: { url: '/gameshows/{show_id}/networking/applications', method: HTTP_METHODS.GET },
21621
+ updateApplication: { url: '/gameshows/{show_id}/networking/applications/{application_id}', method: HTTP_METHODS.PUT },
21622
+ conversation: { url: '/gameshows/{show_id}/networking/applications/{application_id}/conversation', method: HTTP_METHODS.POST },
21623
+ moderation: { url: '/gameshows/{show_id}/networking/moderation', method: HTTP_METHODS.GET },
21624
+ moderatePost: { url: '/gameshows/{show_id}/networking/moderation/posts/{post_id}', method: HTTP_METHODS.PUT },
21625
+ resolveReport: { url: '/gameshows/{show_id}/networking/moderation/{report_id}', method: HTTP_METHODS.PUT },
21626
+ restrictMember: { url: '/gameshows/{show_id}/networking/members/{user_id}', method: HTTP_METHODS.PUT },
21627
+ preferences: { url: '/gameshows/{show_id}/networking/preferences', method: HTTP_METHODS.GET },
21628
+ updatePreferences: { url: '/gameshows/{show_id}/networking/preferences', method: HTTP_METHODS.PUT },
21629
+ media: { url: '/gameshows/{show_id}/networking/media', method: HTTP_METHODS.GET },
21630
+ uploadMedia: { url: '/gameshows/{show_id}/networking/media', method: HTTP_METHODS.POST },
21631
+ organizations: { url: '/gameshows/{show_id}/networking/organizations', method: HTTP_METHODS.GET },
21632
+ analytics: { url: '/gameshows/{show_id}/networking/analytics', method: HTTP_METHODS.GET },
21633
+ };
21634
+
21635
+ /** Festival-scoped discussions, talent, jobs, moderation and new owned media uploads. */
21636
+ class FestivalNetworking {
21637
+ static request(name, show_id, data, ids = {}, params, options) {
21638
+ const replacements = Object.fromEntries(Object.entries(Object.assign({ show_id }, ids)).map(([key, id]) => [key, encodeURIComponent(id)]));
21639
+ return Requests.processRoute(FestivalNetworkingRoute.routes[name], data, replacements, params, options);
21640
+ }
21641
+ /** Read enabled tools and the current account's registration/ticket access. */
21642
+ static settings(id, options) { return this.request('settings', id, undefined, {}, undefined, options); }
21643
+ /** Organizer-only settings update; admission remains mandatory. */
21644
+ static updateSettings(id, data) { return this.request('updateSettings', id, data); }
21645
+ /** Search posts; compensation comparisons require currency and period. */
21646
+ static listPosts(id, params, options) { return this.request('listPosts', id, undefined, {}, params, options); }
21647
+ /** Create a post with rich HTML and optional newly uploaded UserMedia IDs. */
21648
+ static createPost(id, data) { return this.request('createPost', id, data); }
21649
+ /** Direct links still require admission and content visibility permission. */
21650
+ static getPost(id, post_id, options) { return this.request('getPost', id, undefined, { post_id }, undefined, options); }
21651
+ /** Edit or soft-delete via state; omit media_ids to preserve current attachments. */
21652
+ static updatePost(id, post_id, data) { return this.request('updatePost', id, data, { post_id }); }
21653
+ /** Paginated direct replies; fetch children to expand a thread. */
21654
+ static listComments(id, post_id, params, options) { return this.request('listComments', id, undefined, { post_id }, params, options); }
21655
+ /** Add a rich-text reply, subject to locking and five-level nesting. */
21656
+ static createComment(id, post_id, data) { return this.request('createComment', id, data, { post_id }); }
21657
+ /** Set, replace, or remove a vote/save/hide idempotently. */
21658
+ static setInteraction(id, post_id, data) { return this.request('setInteraction', id, data, { post_id }); }
21659
+ /** Apply or express interest once; the original listing is snapshotted. */
21660
+ static apply(id, post_id, data) { return this.request('apply', id, data, { post_id }); }
21661
+ /** Discovery matches for the current user's own job/talent listing. */
21662
+ static matches(id, post_id, params, options) { return this.request('matches', id, undefined, { post_id }, params, options); }
21663
+ /** Report suspicious content privately to festival moderators. */
21664
+ static report(id, post_id, data) { return this.request('report', id, data, { post_id }); }
21665
+ /** Only the applicant and listing owner receive application records. */
21666
+ static applications(id, params, options) { return this.request('applications', id, undefined, {}, params, options); }
21667
+ /** Applicant withdrawal or owner-managed status changes. */
21668
+ static updateApplication(id, application_id, data) { return this.request('updateApplication', id, data, { application_id }); }
21669
+ /** Open the application/talent inquiry's private shared-inbox conversation, creating it once for legacy applications. Only the applicant and original listing owner may call this. Use Messages.getThread/sendMessage for subsequent conversation activity. */
21670
+ static conversation(id, application_id) { return this.request('conversation', id, {}, { application_id }); }
21671
+ /** Moderator-only report queue and audit history. */
21672
+ static moderation(id, params, options) { return this.request('moderation', id, undefined, {}, params, options); }
21673
+ /** Moderation remains available even while the board is disabled. */
21674
+ static moderatePost(id, post_id, data) { return this.request('moderatePost', id, data, { post_id }); }
21675
+ /** Resolve, dismiss or begin reviewing a report. */
21676
+ static resolveReport(id, report_id, data) { return this.request('resolveReport', id, data, { report_id }); }
21677
+ /** Moderator-only participant restrictions. */
21678
+ static restrictMember(id, user_id, data) { return this.request('restrictMember', id, data, { user_id }); }
21679
+ /** Current user's privacy and notification preferences. */
21680
+ static preferences(id, options) { return this.request('preferences', id, undefined, {}, undefined, options); }
21681
+ /** Set notification opt-out and blocked participants/companies. */
21682
+ static updatePreferences(id, data) { return this.request('updatePreferences', id, data); }
21683
+ /** Uploaded festival attachments only; not the gameplay clip library. */
21684
+ static media(id, params, options) { return this.request('media', id, undefined, {}, params, options); }
21685
+ /**
21686
+ * Upload a new image (10 MB max) or video (100 MB max), using the existing media pipeline.
21687
+ * The response ID is an owned UserMedia ID for createPost/updatePost media_ids.
21688
+ * @param file New file selected by the attendee; supported images exclude SVG.
21689
+ * @param data Which enabled board the upload is for.
21690
+ * @param onUploadProgress Transfer progress; 100% may still require conversion before completion.
21691
+ */
21692
+ static uploadMedia(id, file, data, onUploadProgress, options) {
21693
+ return Requests.uploadFile(FestivalNetworkingRoute.routes.uploadMedia.url.replace('{show_id}', encodeURIComponent(id)), 'media', file, data, undefined, onUploadProgress, options);
21694
+ }
21695
+ /** Organizations the authenticated user is authorized to represent. */
21696
+ static organizations(id, options) { return this.request('organizations', id, undefined, {}, undefined, options); }
21697
+ /** Organizer-only aggregate participation metrics. */
21698
+ static analytics(id, options) { return this.request('analytics', id, undefined, {}, undefined, options); }
21699
+ }
21700
+
21701
+ /** Consumer-facing commerce routes. Signed provider webhooks are deliberately not client APIs. */
21702
+ class MicrotransactionsRoute {
21703
+ }
21704
+ MicrotransactionsRoute.routes = {
21705
+ uploadMedia: { url: '/titles/{title_id}/microtransactions/media', method: HTTP_METHODS.POST },
21706
+ mcpUploadMedia: { url: '/mcp/v1/titles/{title_id}/microtransactions/media', method: HTTP_METHODS.POST },
21707
+ settings: { url: '/titles/{title_id}/microtransactions/settings', method: HTTP_METHODS.GET },
21708
+ updateSettings: { url: '/titles/{title_id}/microtransactions/settings', method: HTTP_METHODS.PUT },
21709
+ readiness: { url: '/titles/{title_id}/microtransactions/readiness', method: HTTP_METHODS.GET },
21710
+ products: { url: '/titles/{title_id}/microtransactions/products', method: HTTP_METHODS.GET },
21711
+ createProduct: { url: '/titles/{title_id}/microtransactions/products', method: HTTP_METHODS.POST },
21712
+ updateProduct: { url: '/titles/{title_id}/microtransactions/products/{product_id}', method: HTTP_METHODS.PUT },
21713
+ archiveProduct: { url: '/titles/{title_id}/microtransactions/products/{product_id}/archive', method: HTTP_METHODS.POST },
21714
+ providers: { url: '/titles/{title_id}/microtransactions/providers', method: HTTP_METHODS.GET },
21715
+ earnings: { url: '/titles/{title_id}/microtransactions/earnings', method: HTTP_METHODS.GET },
21716
+ orders: { url: '/titles/{title_id}/microtransactions/orders', method: HTTP_METHODS.GET },
21717
+ order: { url: '/titles/{title_id}/microtransactions/orders/{order_id}', method: HTTP_METHODS.GET },
21718
+ refund: { url: '/titles/{title_id}/microtransactions/orders/{order_id}/refund', method: HTTP_METHODS.POST },
21719
+ replayDelivery: { url: '/titles/{title_id}/microtransactions/deliveries/{delivery_id}/replay', method: HTTP_METHODS.POST },
21720
+ catalog: { url: '/titles/{title_id}/microtransactions/catalog', method: HTTP_METHODS.GET },
21721
+ createQuote: { url: '/titles/{title_id}/microtransactions/quotes', method: HTTP_METHODS.POST },
21722
+ createCheckoutSession: { url: '/titles/{title_id}/microtransactions/checkout-sessions', method: HTTP_METHODS.POST },
21723
+ createRestoreSession: { url: '/titles/{title_id}/microtransactions/restore-sessions', method: HTTP_METHODS.POST },
21724
+ checkoutSession: { url: '/titles/{title_id}/microtransactions/checkout-sessions/{session_id}', method: HTTP_METHODS.GET },
21725
+ checkoutFramePolicy: { url: '/titles/{title_id}/microtransactions/checkout-sessions/{session_id}/frame-policy', method: HTTP_METHODS.GET },
21726
+ framePolicy: { url: '/titles/{title_id}/microtransactions/frame-policy', method: HTTP_METHODS.GET },
21727
+ authenticateCheckoutSession: { url: '/titles/{title_id}/microtransactions/checkout-sessions/{session_id}/authenticate', method: HTTP_METHODS.POST },
21728
+ checkout: { url: '/titles/{title_id}/microtransactions/checkout-sessions/{session_id}/checkout', method: HTTP_METHODS.POST },
21729
+ reconcileCheckout: { url: '/titles/{title_id}/microtransactions/checkout-sessions/{session_id}/reconcile', method: HTTP_METHODS.POST },
21730
+ createHandoff: { url: '/titles/{title_id}/microtransactions/checkout-sessions/{session_id}/handoff', method: HTTP_METHODS.POST },
21731
+ claimHandoff: { url: '/titles/{title_id}/microtransactions/handoffs/claim', method: HTTP_METHODS.POST },
21732
+ restoreHandoff: { url: '/titles/{title_id}/microtransactions/handoffs/restore', method: HTTP_METHODS.POST },
21733
+ verifyIntegration: { url: '/titles/{title_id}/microtransactions/integration/verify', method: HTTP_METHODS.POST },
21734
+ entitlements: { url: '/titles/{title_id}/microtransactions/entitlements', method: HTTP_METHODS.GET },
21735
+ myPurchases: { url: '/titles/{title_id}/microtransactions/me/purchases', method: HTTP_METHODS.GET },
21736
+ consume: { url: '/titles/{title_id}/microtransactions/consume', method: HTTP_METHODS.POST },
21737
+ requestRefund: { url: '/titles/{title_id}/microtransactions/refund-requests', method: HTTP_METHODS.POST },
21738
+ acknowledgeDelivery: { url: '/titles/{title_id}/microtransactions/deliveries/{delivery_id}/acknowledge', method: HTTP_METHODS.POST },
21739
+ mcpCapabilities: { url: '/mcp/v1/titles/{title_id}/microtransactions/capabilities', method: HTTP_METHODS.GET },
21740
+ mcpOperation: { url: '/mcp/v1/titles/{title_id}/microtransactions/operations/{operation}', method: HTTP_METHODS.POST },
21741
+ };
21742
+
21743
+ /**
21744
+ * Provider-neutral, title-scoped commerce. Configure with user JWT; purchases
21745
+ * use a recoverable user account and limited checkout capability. Install/title
21746
+ * tokens cannot authorize money, ownership, refunds, or catalog changes.
21747
+ *
21748
+ * Each result preserves payment versus fulfillment versus settlement. Redirects
21749
+ * and postMessage events only trigger an authoritative refresh. A timeout is
21750
+ * unknown; reconcile the original attempt instead of charging another provider.
21751
+ */
21752
+ class Microtransactions {
21753
+ /**
21754
+ * Upload an image/video through existing Glitch Media processing with title
21755
+ * and actor ownership. Attach its returned Media ID to products/branding.
21756
+ * Does not create a social-library post, scheduler, or new payment product.
21757
+ */
21758
+ static uploadMedia(title_id, media, onUploadProgress, options) {
21759
+ if (!/^[A-Za-z0-9_:-]+$/.test(title_id))
21760
+ throw new Error('Invalid commerce title identifier.');
21761
+ return Requests.uploadFile(MicrotransactionsRoute.routes.uploadMedia.url.replace('{title_id}', encodeURIComponent(title_id)), 'media', media, {}, undefined, onUploadProgress, options);
21762
+ }
21763
+ /** Same title-authorized Media pipeline using the caller's MCP credential and commerce:write ability. */
21764
+ static mcpUploadMedia(title_id, media, onUploadProgress, options) {
21765
+ if (!/^[A-Za-z0-9_:-]+$/.test(title_id))
21766
+ throw new Error('Invalid commerce title identifier.');
21767
+ return Requests.uploadFile(MicrotransactionsRoute.routes.mcpUploadMedia.url.replace('{title_id}', encodeURIComponent(title_id)), 'media', media, {}, undefined, onUploadProgress, options);
21768
+ }
21769
+ /** Admin settings, including immutable 1200bp commission and readiness blockers. */
21770
+ static settings(title_id, options) { return this.call('settings', title_id, undefined, {}, undefined, options); }
21771
+ /** Atomic policy update. Sandbox/off by default. Cannot disable the final working revenue model. */
21772
+ static updateSettings(title_id, data, options) { return this.call('updateSettings', title_id, data, {}, undefined, options); }
21773
+ /** Read-only country/provider/approval readiness; never enables a provider. */
21774
+ static readiness(title_id, options) { return this.call('readiness', title_id, undefined, {}, undefined, options); }
21775
+ /** Admin list includes drafts and archives. Player clients should use catalog(). */
21776
+ static listProducts(title_id, options) { return this.call('products', title_id, undefined, {}, undefined, options); }
21777
+ /** Save a catalog product. Prices use integer minor units and attached media must belong to the title. */
21778
+ static createProduct(title_id, data, options) { return this.call('createProduct', title_id, data, {}, undefined, options); }
21779
+ /** Update a product version. Existing order snapshots remain unchanged. */
21780
+ static updateProduct(title_id, product_id, data, options) { return this.call('updateProduct', title_id, data, { product_id }, undefined, options); }
21781
+ /** Archive, never delete financial history. Requires explicit confirmation. */
21782
+ static archiveProduct(title_id, product_id, data, options) { return this.call('archiveProduct', title_id, data, { product_id }, undefined, options); }
21783
+ /** Public provider metadata only. Credentials and commercial approvals are platform-managed. */
21784
+ static providers(title_id, options) { return this.call('providers', title_id, undefined, {}, undefined, options); }
21785
+ /** Admin read of separate-currency balances; pending is not withdrawable revenue. */
21786
+ static earnings(title_id, params, options) { return this.call('earnings', title_id, undefined, {}, params, options); }
21787
+ /** Admin list, bounded to the server's most recent 100 redacted orders. */
21788
+ static listOrders(title_id, params, options) { return this.call('orders', title_id, undefined, {}, params, options); }
21789
+ /** Owner JWT/scoped player token or title admin. An arbitrary order UUID grants no access. */
21790
+ static getOrder(title_id, order_id, options) { return this.call('order', title_id, undefined, { order_id }, undefined, options); }
21791
+ /** Financial admin only; original provider and human approval. Omit amount_minor for remaining full refund; partial amounts are bounded and allocated pro rata. */
21792
+ static refundOrder(title_id, order_id, data, options) { return this.call('refund', title_id, data, { order_id }, undefined, options); }
21793
+ /** Replay the same immutable event. Receiver must deduplicate event_id. This cannot mint goods. */
21794
+ static replayDelivery(title_id, delivery_id, data, options) { return this.call('replayDelivery', title_id, data, { delivery_id }, undefined, options); }
21795
+ /** Public eligible catalog. Sandbox is restricted by backend environment/admin policy. */
21796
+ static catalog(title_id, params, options) { return this.call('catalog', title_id, undefined, {}, params, options); }
21797
+ /** User-authenticated quote. Clients select product/quantity, never monetary values or seller accounts. */
21798
+ static createQuote(title_id, data, options) { return this.call('createQuote', title_id, data, {}, undefined, options); }
21799
+ /** Anonymous-safe opening step only. The hosted UI creates/logs into an account before payment. */
21800
+ static createCheckoutSession(title_id, data, options) { return this.call('createCheckoutSession', title_id, data, {}, undefined, options); }
21801
+ /** Anonymous-safe inventory recovery. Opens an in-game hosted sign-in overlay, never creates a charge or requires the game's account JWT. */
21802
+ static createRestoreSession(title_id, data, options) { return this.call('createRestoreSession', title_id, data, {}, undefined, options); }
21803
+ /** Read the session using its limited capability. Cannot mutate user identity or declare payment. */
21804
+ static getCheckoutSession(title_id, session_id, options) { return this.call('checkoutSession', title_id, undefined, { session_id }, undefined, options); }
21805
+ /** Anonymous, read-only embedding policy: server-approved frame ancestors only, no player/session capability data. */
21806
+ static getCheckoutFramePolicy(title_id, session_id, options) { return this.call('checkoutFramePolicy', title_id, undefined, { session_id }, undefined, options); }
21807
+ /** Anonymous title-wide approved embedding policy for trusted hosted account pages; no player data. */
21808
+ static getFramePolicy(title_id, options) { return this.call('framePolicy', title_id, undefined, {}, undefined, options); }
21809
+ /** Bind once to the existing authenticated account. Cannot reassign another player's purchase. */
21810
+ static authenticateCheckoutSession(title_id, session_id, options) { return this.call('authenticateCheckoutSession', title_id, {}, { session_id }, undefined, options); }
21811
+ /** Bound-user JWT + session capability. Reuse the idempotency key after a network timeout. */
21812
+ static checkout(title_id, session_id, data, options) { return this.call('checkout', title_id, data, { session_id }, undefined, options); }
21813
+ /** Query original provider; never creates another charge. Pending/unknown remains non-terminal. */
21814
+ static reconcileCheckoutSession(title_id, session_id, options) { return this.call('reconcileCheckout', title_id, {}, { session_id }, undefined, options); }
21815
+ /** Hosted checkout only. Server issues an expiring one-time game handoff after verified fulfillment. */
21816
+ static createHandoff(title_id, session_id, options) { return this.call('createHandoff', title_id, {}, { session_id }, undefined, options); }
21817
+ /** Game exchanges a verified popup code. Browser Origin must match return_origin; code is consumed once. */
21818
+ static claimHandoff(title_id, data, options) { return this.call('claimHandoff', title_id, data, {}, undefined, options); }
21819
+ /**
21820
+ * Authenticated hosted Glitch account only: restore a previous purchase into a
21821
+ * NEW nonce-bound session/handoff after the game's 15-minute token expires or
21822
+ * storage is cleared. Does not create another payment. Return to the game via
21823
+ * verified source/origin and a new bridge bound to event.checkout_session_id.
21824
+ */
21825
+ static restoreHandoff(title_id, data, options) { return this.call('restoreHandoff', title_id, data, {}, undefined, options); }
21826
+ /** Record integration proof from a genuinely paid, fulfilled sandbox order with a claimed game handoff. */
21827
+ static verifyIntegration(title_id, data, options) { return this.call('verifyIntegration', title_id, data, {}, undefined, options); }
21828
+ /** Restore authoritative durable ownership/current consumable balances, never mutable cloud-save balances. */
21829
+ static listEntitlements(title_id, params, options) { return this.call('entitlements', title_id, undefined, {}, params, options); }
21830
+ /**
21831
+ * Optional self-only purchase/usage history. A user JWT selects that user; a
21832
+ * scoped playerToken selects its bound title/player/environment and requires
21833
+ * the exact approved game Origin. No MCP/install token or caller-selected
21834
+ * user_id/player_id is accepted. JWT environment defaults to live; scoped
21835
+ * tokens default to their bound environment. Admin listOrders stays separate.
21836
+ *
21837
+ * Read response.data.data.purchases and .pagination. Use grant_usage for lot
21838
+ * consumption/refund/expiry status, listEntitlements for current aggregate
21839
+ * inventory, and consume for explicit gameplay spending. History never grants
21840
+ * inventory and durable/pass is_used is null rather than a guessed boolean.
21841
+ */
21842
+ static listMyPurchases(title_id, filters = {}, options) {
21843
+ const allowed = ['environment', 'page', 'per_page'];
21844
+ if (Object.keys(filters).some(key => !allowed.includes(key)))
21845
+ throw new Error('Own purchase history supports only environment, page and per_page; identity cannot be selected.');
21846
+ if (filters.environment !== undefined && !['sandbox', 'live'].includes(filters.environment))
21847
+ throw new Error('Invalid purchase-history environment.');
21848
+ if (filters.page !== undefined && (!Number.isInteger(filters.page) || filters.page < 1 || filters.page > 10000))
21849
+ throw new Error('Purchase-history page must be an integer from 1 to 10000.');
21850
+ if (filters.per_page !== undefined && (!Number.isInteger(filters.per_page) || filters.per_page < 1 || filters.per_page > 100))
21851
+ throw new Error('Purchase-history per_page must be an integer from 1 to 100.');
21852
+ return this.call('myPurchases', title_id, undefined, {}, filters, options);
21853
+ }
21854
+ /** Atomic tracked spending. Reuse action_id for retries; a new gameplay action needs a new ID. */
21855
+ static consume(title_id, data, options) { return this.call('consume', title_id, data, {}, undefined, options); }
21856
+ /** Owning user asks support to review a refund. This does not execute payment reversal. */
21857
+ static requestRefund(title_id, data, options) { return this.call('requestRefund', title_id, data, {}, undefined, options); }
21858
+ /** Trusted title server with commerce:fulfill or admin JWT acknowledges the immutable event. */
21859
+ static acknowledgeDelivery(title_id, delivery_id, data, options) { return this.call('acknowledgeDelivery', title_id, data, { delivery_id }, undefined, options); }
21860
+ /** Title MCP token, never a runtime install token. Describes every argument/schema/ability/approval gate. */
21861
+ static mcpCapabilities(title_id, options) { return this.call('mcpCapabilities', title_id, undefined, {}, undefined, options); }
21862
+ /** Execute only an operation discovered in mcpCapabilities. confirm is not financial approval. */
21863
+ static mcpOperation(title_id, operation, data, options) { return this.call('mcpOperation', title_id, data, { operation }, undefined, options); }
21864
+ static call(route, title_id, data, ids = {}, params, options) {
21865
+ const replacements = {};
21866
+ for (const [key, value] of Object.entries(Object.assign({ title_id }, ids))) {
21867
+ if (!value || !/^[A-Za-z0-9_.:-]+$/.test(value) || value === '.' || value === '..')
21868
+ throw new Error(`Invalid commerce route identifier: ${key}`);
21869
+ replacements[key] = encodeURIComponent(value);
21870
+ }
21871
+ const headers = {};
21872
+ if (options === null || options === void 0 ? void 0 : options.playerToken)
21873
+ headers.Authorization = `Bearer ${options.playerToken}`;
21874
+ if (options && 'checkoutToken' in options) {
21875
+ if (!options.checkoutToken)
21876
+ throw new Error('A checkout capability is required.');
21877
+ headers['X-Checkout-Token'] = options.checkoutToken;
21878
+ }
21879
+ return Requests.processRoute(MicrotransactionsRoute.routes[route], data, replacements, params, {
21880
+ signal: options === null || options === void 0 ? void 0 : options.signal, timeout: options === null || options === void 0 ? void 0 : options.timeout, headers,
21881
+ // Self-history accepts only its explicit filters, not global community scope.
21882
+ excludeCommunityContext: route === 'myPurchases',
21883
+ });
21884
+ }
21885
+ }
21886
+
21887
+ /** Generate a 256-bit browser nonce. Fails closed without secure Web Crypto. */
21888
+ function createMicrotransactionNonce() {
21889
+ var _a;
21890
+ if (typeof ((_a = globalThis.crypto) === null || _a === void 0 ? void 0 : _a.getRandomValues) !== 'function') {
21891
+ throw new Error('Secure Web Crypto is required for a checkout nonce.');
21892
+ }
21893
+ const bytes = new Uint8Array(32);
21894
+ globalThis.crypto.getRandomValues(bytes);
21895
+ return Array.from(bytes, value => value.toString(16).padStart(2, '0')).join('');
21896
+ }
21897
+ /**
21898
+ * Listen for Glitch-hosted, game-branded checkout changes with strict origin,
21899
+ * source, title, session, and nonce binding. Message data cannot grant an item.
21900
+ * The caller always verifies the session at Glitch before updating inventory.
21901
+ *
21902
+ * Prefer openMicrotransactionOverlay with the exact server-returned URL. The
21903
+ * game stays mounted; no top-level navigation fallback is permitted. If an
21904
+ * embedded flow is unavailable, show retry/close and preserve the game state.
21905
+ * refresh() requires an already verified claim. Keep
21906
+ * secrets in memory/session storage or a URL fragment, never query parameters.
21907
+ * Dispose on game unmount/account change. Reconnect restores ownership through
21908
+ * the authenticated entitlement API, not a saved "purchase successful" flag.
21909
+ */
21910
+ function createMicrotransactionBridge(options) {
21911
+ if (!options.checkoutSessionId)
21912
+ throw new Error('The original checkout session is required.');
21913
+ return createBridge(options, options.checkoutSessionId);
21914
+ }
21915
+ /**
21916
+ * Restore-only bridge for /games/:titleId/purchases/restore. Pin the prior order,
21917
+ * fresh nonce, exact Glitch origin and opened window. The hosted signed-in page
21918
+ * creates a NEW session; the server-verified claim must match that new session
21919
+ * and the pinned order. This does not relax purchase-session binding.
21920
+ *
21921
+ * Open the hosted restore page, never request the account JWT in the game.
21922
+ * verify(message) exchanges the code using message.checkout_session_id. All
21923
+ * duplicate-code, expiry and same-player refresh safeguards still apply.
21924
+ */
21925
+ function createMicrotransactionRestoreBridge(options) {
21926
+ if (!/^[A-Za-z0-9_:-]{1,160}$/.test(options.orderId))
21927
+ throw new Error('The original verified order is required for restore.');
21928
+ return createBridge(options, undefined, options.orderId);
21929
+ }
21930
+ function createBridge(options, checkoutSessionId, expectedOrderId) {
21931
+ var _a;
21932
+ const origin = new URL(options.checkoutOrigin);
21933
+ const local = ['localhost', '127.0.0.1', '[::1]'].includes(origin.hostname) || origin.hostname.endsWith('.test') || (origin.hostname === 'www.glitch.local' && origin.port === '3000');
21934
+ if (origin.origin !== options.checkoutOrigin || origin.username || origin.password ||
21935
+ (origin.protocol !== 'https:' && !(options.allowLocalDevelopment && local && origin.protocol === 'http:'))) {
21936
+ throw new Error('Checkout requires an exact trusted HTTPS origin.');
21937
+ }
21938
+ if (!options.checkoutWindow || !options.titleId ||
21939
+ !/^[A-Za-z0-9_-]{22,128}$/.test(options.nonce)) {
21940
+ throw new Error('Checkout window, title, session, and secure nonce are required.');
21941
+ }
21942
+ const target = (_a = options.eventTarget) !== null && _a !== void 0 ? _a : window;
21943
+ let disposed = false;
21944
+ let inFlight;
21945
+ let verified;
21946
+ const attemptedCodes = new Set();
21947
+ const accept = (result, orderId, sessionId) => __awaiter(this, void 0, void 0, function* () {
21948
+ if (disposed)
21949
+ return;
21950
+ if (result.title_id !== options.titleId || result.checkout_session_id !== sessionId || result.order_id !== orderId ||
21951
+ (verified && verified.player_id !== result.player_id) ||
21952
+ typeof result.player_id !== 'string' || !result.player_id || typeof result.player_token !== 'string' || !result.player_token ||
21953
+ !Array.isArray(result.entitlements) || !Number.isFinite(Date.parse(result.expires_at)) || Date.parse(result.expires_at) <= Date.now()) {
21954
+ throw new Error('Checkout verification returned an invalid or differently bound claim.');
21955
+ }
21956
+ verified = result;
21957
+ yield options.onVerified(result);
21958
+ });
21959
+ const refresh = () => {
21960
+ if (disposed)
21961
+ return Promise.resolve();
21962
+ if (inFlight)
21963
+ return inFlight;
21964
+ if (!verified || !options.refresh)
21965
+ return Promise.reject(new Error('A verified claim and scoped-token refresh callback are required.'));
21966
+ const previous = verified;
21967
+ inFlight = Promise.resolve().then(() => options.refresh(previous)).then(result => accept(result, previous.order_id, previous.checkout_session_id)).finally(() => { inFlight = undefined; });
21968
+ return inFlight;
21969
+ };
21970
+ const listener = (event) => {
21971
+ if (disposed || event.origin !== options.checkoutOrigin || event.source !== options.checkoutWindow)
21972
+ return;
21973
+ const value = event.data;
21974
+ if (!value || typeof value !== 'object')
21975
+ return;
21976
+ const message = value;
21977
+ if (message.type !== 'glitch.microtransaction.updated' || message.version !== 1 || message.title_id !== options.titleId ||
21978
+ (checkoutSessionId && message.checkout_session_id !== checkoutSessionId) || message.nonce !== options.nonce ||
21979
+ typeof message.checkout_session_id !== 'string' || !/^[A-Za-z0-9_:-]{1,160}$/.test(message.checkout_session_id) ||
21980
+ (expectedOrderId && message.order_id !== expectedOrderId) ||
21981
+ typeof message.order_id !== 'string' || !/^[A-Za-z0-9_:-]{1,160}$/.test(message.order_id) ||
21982
+ typeof message.claim_code !== 'string' || !/^[A-Za-z0-9_-]{40,128}$/.test(message.claim_code))
21983
+ return;
21984
+ if (inFlight || attemptedCodes.has(message.claim_code) || attemptedCodes.size >= 8)
21985
+ return;
21986
+ if (verified && (verified.order_id !== message.order_id || verified.checkout_session_id !== message.checkout_session_id))
21987
+ return;
21988
+ // Mark BEFORE network I/O. Even a timeout can mean the server consumed it.
21989
+ attemptedCodes.add(message.claim_code);
21990
+ const handoff = message;
21991
+ inFlight = Promise.resolve().then(() => options.verify(handoff)).then(result => accept(result, handoff.order_id, handoff.checkout_session_id)).finally(() => { inFlight = undefined; });
21992
+ void inFlight.catch(error => {
21993
+ var _a;
21994
+ if (!disposed)
21995
+ (_a = options.onError) === null || _a === void 0 ? void 0 : _a.call(options, error);
21996
+ });
21997
+ };
21998
+ target.addEventListener('message', listener);
21999
+ return {
22000
+ refresh,
22001
+ dispose: () => {
22002
+ disposed = true;
22003
+ verified = undefined;
22004
+ attemptedCodes.clear();
22005
+ target.removeEventListener('message', listener);
22006
+ },
22007
+ };
22008
+ }
22009
+
22010
+ let overlaySequence = 0;
22011
+ const activeOverlays = new WeakMap();
22012
+ /**
22013
+ * Mount Glitch checkout IN the running game. The game document, URL and session
22014
+ * stay intact. Uses a modal dialog with focus restore and a sandboxed payment
22015
+ * iframe. No top-navigation permission or top-level/popup-blocked fallback exists.
22016
+ * Only bank/OAuth verification may open a controlled provider window from inside
22017
+ * the frame. If embedding is unavailable, show retry/close instead of navigating.
22018
+ *
22019
+ * Receipt messages must originate from this exact iframe.contentWindow and pass
22020
+ * origin/title/session/nonce checks. The SDK redeems the one-time claim at Glitch
22021
+ * and uses the returned scoped player token only on commerce requests. Closing
22022
+ * does not cancel an uncertain payment, grant goods, or discard the game state.
22023
+ */
22024
+ function openMicrotransactionOverlay(options) {
22025
+ var _a, _b, _c, _d;
22026
+ const doc = (_a = options.document) !== null && _a !== void 0 ? _a : document;
22027
+ const win = doc.defaultView;
22028
+ if (!win || !doc.body)
22029
+ throw new Error('A mounted game document is required.');
22030
+ if (activeOverlays.has(doc))
22031
+ throw new Error('A checkout is already open. Resume or close that same purchase first.');
22032
+ const session = options.session;
22033
+ const parsed = new URL(session.hosted_url);
22034
+ const path = `/games/${encodeURIComponent(options.titleId)}/checkout/${encodeURIComponent(session.id)}`;
22035
+ if (parsed.origin !== options.checkoutOrigin || parsed.pathname !== path || parsed.search || parsed.username || parsed.password ||
22036
+ new URLSearchParams(parsed.hash.slice(1)).get('token') !== session.session_token || !session.session_token ||
22037
+ (session.checkout_session_id && session.checkout_session_id !== session.id)) {
22038
+ throw new Error('The hosted checkout URL does not match its title, session and capability.');
22039
+ }
22040
+ const timeout = Math.min(60000, Math.max(1000, (_b = options.timeoutMs) !== null && _b !== void 0 ? _b : 15000));
22041
+ const requestedFrameTimeout = (_c = options.frameLoadTimeoutMs) !== null && _c !== void 0 ? _c : 20000;
22042
+ const frameTimeout = Number.isFinite(requestedFrameTimeout) ? Math.min(60000, Math.max(1000, requestedFrameTimeout)) : 20000;
22043
+ const beforeFocus = doc.activeElement;
22044
+ const beforeOverflow = doc.body.style.overflow;
22045
+ const dialog = doc.createElement('dialog');
22046
+ const id = `glitch-commerce-modal-${++overlaySequence}`;
22047
+ dialog.id = id;
22048
+ dialog.setAttribute('aria-modal', 'true');
22049
+ dialog.setAttribute('aria-labelledby', `${id}-title`);
22050
+ dialog.setAttribute('role', 'dialog');
22051
+ dialog.style.cssText = 'position:fixed;inset:16px;margin:auto;padding:0;border:1px solid #cbd5e1;border-radius:16px;width:min(1100px,calc(100vw - 32px));height:min(850px,calc(100dvh - 32px));max-width:none;max-height:none;background:#fff;color:#172033;box-shadow:0 24px 90px #0008;z-index:2147483647;overflow:hidden;';
22052
+ const style = doc.createElement('style');
22053
+ style.textContent = `#${id}::backdrop{background:rgba(8,16,32,.72)}#${id} button:focus-visible{outline:3px solid #4263eb;outline-offset:3px}@media(max-width:600px){#${id}{inset:0!important;width:100vw!important;height:100dvh!important;border-radius:0!important}}`;
22054
+ const header = doc.createElement('div');
22055
+ header.style.cssText = 'display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 16px;border-bottom:1px solid #e2e8f0;height:56px;box-sizing:border-box;';
22056
+ const heading = doc.createElement('h2');
22057
+ heading.id = `${id}-title`;
22058
+ heading.textContent = options.label || (session.intent === 'restore' ? 'Restore game purchases' : 'Secure game checkout');
22059
+ heading.style.cssText = 'margin:0;font:600 17px/1.3 system-ui,sans-serif;color:#172033;';
22060
+ const closeButton = doc.createElement('button');
22061
+ closeButton.type = 'button';
22062
+ closeButton.textContent = 'Close';
22063
+ closeButton.setAttribute('aria-label', 'Close checkout and return to game');
22064
+ closeButton.style.cssText = 'border:1px solid #cbd5e1;border-radius:8px;padding:7px 14px;background:#fff;color:#172033;font:600 14px system-ui,sans-serif;cursor:pointer;';
22065
+ const retryButton = doc.createElement('button');
22066
+ retryButton.type = 'button';
22067
+ retryButton.textContent = 'Retry';
22068
+ retryButton.setAttribute('aria-label', 'Reload this same checkout without starting another purchase');
22069
+ retryButton.style.cssText = closeButton.style.cssText;
22070
+ const controls = doc.createElement('div');
22071
+ controls.style.cssText = 'display:flex;gap:8px;';
22072
+ controls.append(retryButton, closeButton);
22073
+ header.append(heading, controls);
22074
+ const status = doc.createElement('div');
22075
+ status.setAttribute('role', 'status');
22076
+ status.style.cssText = 'padding:6px 16px;font:12px/1.4 system-ui,sans-serif;background:#f1f5f9;color:#172033;min-height:28px;box-sizing:border-box;';
22077
+ status.textContent = 'Your game stays open. Loading secure checkout…';
22078
+ const iframe = doc.createElement('iframe');
22079
+ iframe.title = heading.textContent;
22080
+ iframe.setAttribute('allow', 'payment');
22081
+ iframe.setAttribute('sandbox', 'allow-scripts allow-forms allow-same-origin allow-popups allow-popups-to-escape-sandbox');
22082
+ iframe.referrerPolicy = 'no-referrer';
22083
+ iframe.style.cssText = 'display:block;width:100%;height:calc(100% - 84px);border:0;background:#fff;';
22084
+ iframe.src = session.hosted_url;
22085
+ dialog.append(style, header, status, iframe);
22086
+ doc.body.append(dialog);
22087
+ const frameWindow = iframe.contentWindow;
22088
+ if (!frameWindow) {
22089
+ dialog.remove();
22090
+ throw new Error('In-game checkout embedding is unavailable. Your game has not navigated.');
22091
+ }
22092
+ let closed = false;
22093
+ let closing;
22094
+ let verified;
22095
+ let bridge;
22096
+ let frameLoadTimer;
22097
+ let appReadyTimer;
22098
+ let applicationReady = false;
22099
+ const blocked = [];
22100
+ const report = (error) => { var _a; try {
22101
+ (_a = options.onError) === null || _a === void 0 ? void 0 : _a.call(options, error);
22102
+ }
22103
+ catch ( /* Consumer error handlers cannot prevent modal cleanup. */_b) { /* Consumer error handlers cannot prevent modal cleanup. */ } };
22104
+ const clearWatchdogs = () => {
22105
+ if (frameLoadTimer !== undefined)
22106
+ win.clearTimeout(frameLoadTimer);
22107
+ if (appReadyTimer !== undefined)
22108
+ win.clearTimeout(appReadyTimer);
22109
+ frameLoadTimer = undefined;
22110
+ appReadyTimer = undefined;
22111
+ };
22112
+ const unavailable = (reason) => {
22113
+ if (closed)
22114
+ return;
22115
+ clearWatchdogs();
22116
+ status.setAttribute('role', 'alert');
22117
+ status.textContent = reason === 'ready'
22118
+ ? 'Checkout did not become ready. Retry this same checkout or Close; your game remains open.'
22119
+ : 'Checkout could not load here. Retry this same checkout or Close; your game remains open.';
22120
+ report(new Error(reason === 'ready'
22121
+ ? 'Embedded checkout readiness timed out; no navigation or new payment was attempted.'
22122
+ : 'Embedded checkout loading unavailable; no navigation or new payment was attempted.'));
22123
+ };
22124
+ const markApplicationReady = () => {
22125
+ if (closed)
22126
+ return;
22127
+ applicationReady = true;
22128
+ clearWatchdogs();
22129
+ status.setAttribute('role', 'status');
22130
+ status.textContent = 'Checkout is ready. Your game remains open underneath.';
22131
+ };
22132
+ const armLoadWatchdog = () => {
22133
+ clearWatchdogs();
22134
+ applicationReady = false;
22135
+ frameLoadTimer = win.setTimeout(() => unavailable('load'), frameTimeout);
22136
+ };
22137
+ const receipt = () => __awaiter(this, void 0, void 0, function* () {
22138
+ var _e;
22139
+ const response = yield Microtransactions.getCheckoutSession(options.titleId, session.id, { checkoutToken: session.session_token, timeout });
22140
+ const current = response.data.data;
22141
+ if (current.id !== session.id || current.title.id !== options.titleId)
22142
+ throw new Error('Checkout status returned a different title or session.');
22143
+ yield ((_e = options.onOrderUpdate) === null || _e === void 0 ? void 0 : _e.call(options, current.order));
22144
+ });
22145
+ try {
22146
+ bridge = createMicrotransactionBridge({
22147
+ titleId: options.titleId, checkoutSessionId: session.id, checkoutOrigin: options.checkoutOrigin,
22148
+ checkoutWindow: frameWindow, nonce: session.nonce, eventTarget: win,
22149
+ allowLocalDevelopment: options.allowLocalDevelopment,
22150
+ verify: (message) => __awaiter(this, void 0, void 0, function* () {
22151
+ return (yield Microtransactions.claimHandoff(options.titleId, {
22152
+ claim_code: message.claim_code, checkout_session_id: session.id, nonce: session.nonce, return_origin: win.location.origin,
22153
+ }, { timeout })).data.data;
22154
+ }),
22155
+ refresh: (previous) => __awaiter(this, void 0, void 0, function* () {
22156
+ var _f;
22157
+ const auth = { playerToken: previous.player_token, timeout };
22158
+ const order = (yield Microtransactions.getOrder(options.titleId, previous.order_id, auth)).data.data;
22159
+ if (order.id !== previous.order_id || order.title_id !== options.titleId)
22160
+ throw new Error('Restored order identity mismatch.');
22161
+ const inventory = (yield Microtransactions.listEntitlements(options.titleId, undefined, auth)).data.data;
22162
+ yield ((_f = options.onOrderUpdate) === null || _f === void 0 ? void 0 : _f.call(options, order));
22163
+ return Object.assign(Object.assign({}, previous), { entitlements: inventory.entitlements });
22164
+ }),
22165
+ onVerified: (result) => __awaiter(this, void 0, void 0, function* () { markApplicationReady(); verified = result; yield options.onVerified(result); }),
22166
+ onError: report,
22167
+ });
22168
+ }
22169
+ catch (error) {
22170
+ dialog.remove();
22171
+ throw error;
22172
+ }
22173
+ const refresh = () => __awaiter(this, void 0, void 0, function* () {
22174
+ if (verified)
22175
+ yield bridge.refresh();
22176
+ else
22177
+ yield receipt();
22178
+ });
22179
+ const onKey = (event) => {
22180
+ if (event.key === 'Escape') {
22181
+ event.preventDefault();
22182
+ void overlay.close();
22183
+ }
22184
+ if (event.key === 'Tab' && !closed) {
22185
+ if (event.shiftKey && doc.activeElement === retryButton) {
22186
+ event.preventDefault();
22187
+ iframe.focus();
22188
+ }
22189
+ else if (!event.shiftKey && doc.activeElement === iframe) {
22190
+ event.preventDefault();
22191
+ retryButton.focus();
22192
+ }
22193
+ }
22194
+ };
22195
+ const onCancel = (event) => { event.preventDefault(); void overlay.close(); };
22196
+ const onCloseMessage = (event) => {
22197
+ if (closed || event.origin !== options.checkoutOrigin || event.source !== frameWindow || !event.data || typeof event.data !== 'object')
22198
+ return;
22199
+ const message = event.data;
22200
+ if (message.version !== 1 || message.title_id !== options.titleId ||
22201
+ message.checkout_session_id !== session.id || message.nonce !== session.nonce)
22202
+ return;
22203
+ if (message.type === 'glitch.microtransaction.ready') {
22204
+ markApplicationReady();
22205
+ return;
22206
+ }
22207
+ if (message.type !== 'glitch.microtransaction.close')
22208
+ return;
22209
+ void overlay.close(verified ? 'completed' : 'dismissed');
22210
+ };
22211
+ const onFrameError = () => { unavailable('error'); };
22212
+ const onFrameLoad = () => {
22213
+ if (closed)
22214
+ return;
22215
+ if (frameLoadTimer !== undefined)
22216
+ win.clearTimeout(frameLoadTimer);
22217
+ frameLoadTimer = undefined;
22218
+ if (applicationReady)
22219
+ return;
22220
+ status.setAttribute('role', 'status');
22221
+ status.textContent = 'Checkout document loaded. Waiting for the secure checkout interface…';
22222
+ // A document load is not proof the app rendered. Repeated loads cannot
22223
+ // indefinitely extend this bounded wait; only explicit Retry resets it.
22224
+ if (appReadyTimer === undefined)
22225
+ appReadyTimer = win.setTimeout(() => unavailable('ready'), frameTimeout);
22226
+ };
22227
+ const overlay = {
22228
+ element: dialog, iframe, refresh,
22229
+ retry: () => {
22230
+ if (closed)
22231
+ return;
22232
+ status.textContent = 'Retrying the same secure checkout. Your game stays open.';
22233
+ status.setAttribute('role', 'status');
22234
+ armLoadWatchdog();
22235
+ iframe.src = session.hosted_url;
22236
+ },
22237
+ close: (reason = 'dismissed') => {
22238
+ if (closing)
22239
+ return closing;
22240
+ if (closed)
22241
+ return Promise.resolve();
22242
+ closed = true;
22243
+ clearWatchdogs();
22244
+ status.textContent = 'Finishing secure purchase verification. Your game stays open.';
22245
+ closing = (() => __awaiter(this, void 0, void 0, function* () {
22246
+ var _a;
22247
+ try {
22248
+ // The dialog remains mounted until in-flight claim AND inventory callback finish.
22249
+ try {
22250
+ yield bridge.refresh();
22251
+ }
22252
+ catch (error) {
22253
+ if (verified)
22254
+ throw error;
22255
+ }
22256
+ }
22257
+ catch (error) {
22258
+ report(error);
22259
+ }
22260
+ finally {
22261
+ win.removeEventListener('keydown', onKey, true);
22262
+ win.removeEventListener('message', onCloseMessage);
22263
+ dialog.removeEventListener('cancel', onCancel);
22264
+ iframe.removeEventListener('load', onFrameLoad);
22265
+ iframe.removeEventListener('error', onFrameError);
22266
+ dialog.remove();
22267
+ doc.body.style.overflow = beforeOverflow;
22268
+ for (const item of blocked) {
22269
+ item.element.inert = item.inert;
22270
+ if (item.ariaHidden === null)
22271
+ item.element.removeAttribute('aria-hidden');
22272
+ else
22273
+ item.element.setAttribute('aria-hidden', item.ariaHidden);
22274
+ }
22275
+ activeOverlays.delete(doc);
22276
+ (beforeFocus === null || beforeFocus === void 0 ? void 0 : beforeFocus.isConnected) && beforeFocus.focus();
22277
+ try {
22278
+ (_a = options.onClose) === null || _a === void 0 ? void 0 : _a.call(options, reason);
22279
+ }
22280
+ catch (error) {
22281
+ report(error);
22282
+ }
22283
+ // No claimed player token means status-only recovery, never a grant.
22284
+ if (!verified) {
22285
+ try {
22286
+ yield receipt();
22287
+ }
22288
+ catch (error) {
22289
+ report(error);
22290
+ }
22291
+ }
22292
+ bridge.dispose();
22293
+ }
22294
+ }))();
22295
+ return closing;
22296
+ },
22297
+ };
22298
+ closeButton.addEventListener('click', () => { void overlay.close(); });
22299
+ retryButton.addEventListener('click', overlay.retry);
22300
+ iframe.addEventListener('error', onFrameError);
22301
+ iframe.addEventListener('load', onFrameLoad);
22302
+ dialog.addEventListener('cancel', onCancel);
22303
+ win.addEventListener('keydown', onKey, true);
22304
+ win.addEventListener('message', onCloseMessage);
22305
+ doc.body.style.overflow = 'hidden';
22306
+ if (typeof dialog.showModal === 'function') {
22307
+ try {
22308
+ dialog.showModal();
22309
+ }
22310
+ catch (error) {
22311
+ void overlay.close('unavailable');
22312
+ throw error;
22313
+ }
22314
+ }
22315
+ else {
22316
+ dialog.setAttribute('open', '');
22317
+ for (const child of Array.from(doc.body.children)) {
22318
+ if (child !== dialog && child instanceof win.HTMLElement) {
22319
+ const element = child;
22320
+ blocked.push({ element, inert: element.inert, ariaHidden: element.getAttribute('aria-hidden') });
22321
+ element.inert = true;
22322
+ element.setAttribute('aria-hidden', 'true');
22323
+ }
22324
+ }
22325
+ }
22326
+ activeOverlays.set(doc, overlay);
22327
+ closeButton.focus();
22328
+ try {
22329
+ (_d = options.onOpen) === null || _d === void 0 ? void 0 : _d.call(options);
22330
+ }
22331
+ catch (error) {
22332
+ void overlay.close('unavailable');
22333
+ throw error;
22334
+ }
22335
+ if (!closed)
22336
+ armLoadWatchdog();
22337
+ return overlay;
22338
+ }
22339
+ /** Same in-game modal for anonymous-safe restore sessions; never opens a new payment. */
22340
+ function openMicrotransactionRestoreOverlay(options) {
22341
+ if (options.session.intent !== 'restore')
22342
+ throw new Error('Create a restore session before opening purchase recovery.');
22343
+ return openMicrotransactionOverlay(options);
22344
+ }
22345
+
21591
22346
  class Parser {
21592
22347
  /**
21593
22348
  * To be used inside a catch close, this function will parse out any JSON in a error response from the api.
@@ -22102,6 +22857,7 @@ Glitch.api = {
22102
22857
  Newsletters: Newsletters,
22103
22858
  PlayTests: PlayTests,
22104
22859
  Media: Media,
22860
+ FestivalNetworking: FestivalNetworking,
22105
22861
  Scheduler: Scheduler,
22106
22862
  RedditSubreddits: RedditSubreddits,
22107
22863
  Funnel: Funnel,
@@ -22127,6 +22883,7 @@ Glitch.api = {
22127
22883
  GameAdvertising: GameAdvertising,
22128
22884
  Hosting: Hosting,
22129
22885
  GameDesign: GameDesign,
22886
+ Microtransactions: Microtransactions,
22130
22887
  };
22131
22888
  Glitch.util = {
22132
22889
  Requests: Requests,
@@ -22154,5 +22911,5 @@ Glitch.constants = {
22154
22911
  VenueType: VenueType
22155
22912
  };
22156
22913
 
22157
- export { Glitch as default };
22914
+ export { createMicrotransactionBridge, createMicrotransactionNonce, createMicrotransactionRestoreBridge, Glitch as default, openMicrotransactionOverlay, openMicrotransactionRestoreOverlay };
22158
22915
  //# sourceMappingURL=index.js.map