@lockerverse/sdk 0.1.0-alpha.1
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 +184 -0
- package/dist/checkout.d.ts +6 -0
- package/dist/checkout.d.ts.map +1 -0
- package/dist/checkout.js +2 -0
- package/dist/checkout.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/signup.d.ts +90 -0
- package/dist/signup.d.ts.map +1 -0
- package/dist/signup.js +2 -0
- package/dist/signup.js.map +1 -0
- package/dist/telemetry.js +8 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/transport.js +2 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +247 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +90 -0
package/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Lockerverse SDK
|
|
2
|
+
|
|
3
|
+
Framework-free browser SDK for building native Lockerverse checkout and signup
|
|
4
|
+
experiences.
|
|
5
|
+
|
|
6
|
+
This package provides independent workflow entries. Checkout loads a public
|
|
7
|
+
Product catalog, maintains a headless selection, calculates an authoritative
|
|
8
|
+
total, and submits a Stripe confirmation token. Signup loads configured fields
|
|
9
|
+
and submits a registration. The SDK does not render UI, initialize React,
|
|
10
|
+
collect analytics, or include auction behavior.
|
|
11
|
+
|
|
12
|
+
## Checkout
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { createLockerverseCheckout } from "@lockerverse/sdk/checkout";
|
|
16
|
+
|
|
17
|
+
const checkout = createLockerverseCheckout({
|
|
18
|
+
communitySlug: "auburn",
|
|
19
|
+
widgetSlug: "auburn-tailgate-party",
|
|
20
|
+
onError(error) {
|
|
21
|
+
// Optional host notification. Reportable failures are also sent directly
|
|
22
|
+
// to Lockerverse's Sentry project by an isolated SDK client.
|
|
23
|
+
console.error(error.code, error.operation);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const { products, widget } = await checkout.load();
|
|
28
|
+
|
|
29
|
+
// Render `products` and `widget.customFields` with any DOM or UI framework.
|
|
30
|
+
checkout.setQuantity("adult", 2);
|
|
31
|
+
checkout.setAmount("donation", 1000);
|
|
32
|
+
|
|
33
|
+
const selection = checkout.getSelection();
|
|
34
|
+
const pricing = {
|
|
35
|
+
email: "customer@example.com",
|
|
36
|
+
includeServiceFee: true,
|
|
37
|
+
tipCents: 500,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Synchronous host feedback. Discounts remain null until Lockerverse verifies
|
|
41
|
+
// the same input on the backend.
|
|
42
|
+
const preview = checkout.previewTotal(pricing);
|
|
43
|
+
|
|
44
|
+
// Subscribe once to drive any host UI from immutable public snapshots.
|
|
45
|
+
const unsubscribe = checkout.subscribe((state) => {
|
|
46
|
+
renderCheckoutState(state);
|
|
47
|
+
});
|
|
48
|
+
const total = await checkout.calculateTotal(pricing);
|
|
49
|
+
|
|
50
|
+
// Initialize Stripe.js in the host with total.payment.publishableKey and
|
|
51
|
+
// total.payment.connectedAccountId. Persist total.paymentReference if the host
|
|
52
|
+
// wants to recover this payment after a refresh.
|
|
53
|
+
|
|
54
|
+
// Collect payment details with Stripe Elements, then pass its short-lived
|
|
55
|
+
// confirmation token to Lockerverse.
|
|
56
|
+
const payment = await checkout.submitPayment({
|
|
57
|
+
confirmationToken: "ctoken_...",
|
|
58
|
+
customFieldAnswers: [
|
|
59
|
+
{ fieldId: "guest-name", value: "Ada Lovelace" },
|
|
60
|
+
{ fieldId: "interests", value: ["meetups", "merch"] },
|
|
61
|
+
],
|
|
62
|
+
email: "customer@example.com",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Safe after a refresh or an interrupted response.
|
|
66
|
+
const recoveredPayment = await checkout.getPaymentStatus(
|
|
67
|
+
total.paymentReference,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
unsubscribe();
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`getState()` returns the current immutable snapshot immediately. `subscribe()`
|
|
74
|
+
immediately receives that snapshot, then receives each observable phase change:
|
|
75
|
+
`idle`, `loading`, `ready`, `quoting`, `quoted`, `submitting`, `recovering`,
|
|
76
|
+
`payment`, or `error`. Its unsubscribe function is safe to call more than once.
|
|
77
|
+
Hosts should enable payment only in `quoted`, and freeze catalog, selection, and
|
|
78
|
+
pricing controls in `submitting`.
|
|
79
|
+
|
|
80
|
+
The default endpoint is production. A custom endpoint must always name its
|
|
81
|
+
environment so a staging or proxy hostname can never silently select live
|
|
82
|
+
Stripe configuration. Custom endpoints must be HTTP(S) URLs without embedded
|
|
83
|
+
credentials, query strings, or fragments. HTTPS is required except for literal
|
|
84
|
+
`localhost`, `127.0.0.1`, and `[::1]` endpoints in the development environment:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const checkout = createLockerverseCheckout({
|
|
88
|
+
apiBaseUrl: "https://portal-dev.lockerverse.com/api",
|
|
89
|
+
communitySlug: "auburn",
|
|
90
|
+
environment: "development",
|
|
91
|
+
widgetSlug: "auburn-tailgate-party",
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`widget.customFields` is a discriminated union covering `text`, `textarea`,
|
|
96
|
+
`select`, `multi_select`, `radio`, and `checkboxes`. Archived fields and options
|
|
97
|
+
are omitted. Hosts own rendering and client-side required-field feedback:
|
|
98
|
+
single-value fields submit a string, while `multi_select` and `checkboxes`
|
|
99
|
+
submit a string array. Lockerverse validates the answers again when the payment
|
|
100
|
+
is submitted.
|
|
101
|
+
|
|
102
|
+
Fixed prices are display data only. `calculateTotal()` sends Product IDs and
|
|
103
|
+
selections to Lockerverse, which resolves the authoritative price,
|
|
104
|
+
availability, discount eligibility, and subtotal. Changing the selection
|
|
105
|
+
invalidates that total, so `submitPayment()` requires recalculation first.
|
|
106
|
+
The email submitted for payment must be the normalized email used for the
|
|
107
|
+
accepted quote, because email-list eligibility is part of the payable amount.
|
|
108
|
+
Repeated submissions of one calculated total carry the same payment reference;
|
|
109
|
+
Lockerverse uses it to prevent duplicate checkout creation. Payment references
|
|
110
|
+
are generated internally with `crypto.randomUUID()` and exposed on the
|
|
111
|
+
calculated total for recovery.
|
|
112
|
+
|
|
113
|
+
## Signup
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { createLockerverseSignup } from "@lockerverse/sdk/signup";
|
|
117
|
+
|
|
118
|
+
const signup = createLockerverseSignup({
|
|
119
|
+
communitySlug: "auburn",
|
|
120
|
+
signupSlug: "tailgate-guests",
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const definition = await signup.load();
|
|
124
|
+
|
|
125
|
+
// Render definition.fields and definition.customFields with any DOM or UI
|
|
126
|
+
// framework, then submit the collected values.
|
|
127
|
+
const submission = await signup.submit({
|
|
128
|
+
answers: [{ fieldId: "guest-type", value: "student" }],
|
|
129
|
+
email: "customer@example.com",
|
|
130
|
+
name: "Ada Lovelace",
|
|
131
|
+
participantCount: 2,
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`subscribe()` observes `idle`, `loading`, `ready`, `submitting`, `submitted`,
|
|
136
|
+
and `error`. Definitions and submission results are immutable snapshots.
|
|
137
|
+
Lockerverse validates enabled and required built-in fields, custom-field
|
|
138
|
+
answers, and signup availability authoritatively when submitted. A host may
|
|
139
|
+
pass a hidden bot-trap value as `honeypot`; a legitimate user should never
|
|
140
|
+
populate it.
|
|
141
|
+
|
|
142
|
+
## Commands
|
|
143
|
+
|
|
144
|
+
Run these from the repository root:
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
pnpm demo
|
|
148
|
+
pnpm typecheck
|
|
149
|
+
pnpm test
|
|
150
|
+
pnpm build
|
|
151
|
+
pnpm --filter @lockerverse/sdk pack:check
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`pnpm demo` starts a throwaway browser playground at
|
|
155
|
+
`http://127.0.0.1:4173`. It loads a public dev widget and completes an end-to-end
|
|
156
|
+
Stripe test-mode payment with plain host HTML and Stripe Elements. It cannot
|
|
157
|
+
create a live charge.
|
|
158
|
+
|
|
159
|
+
## Security and observability
|
|
160
|
+
|
|
161
|
+
- No Stripe or Lockerverse secret is accepted by the public API.
|
|
162
|
+
- Runtime options require non-empty community and workflow slugs, a known
|
|
163
|
+
environment, and a secure custom endpoint.
|
|
164
|
+
- Backend response bodies are not included in SDK errors.
|
|
165
|
+
- Every successful catalog, quote, confirmation, and status response is
|
|
166
|
+
structurally validated before it enters SDK state or is returned to the host.
|
|
167
|
+
A successful HTTP status alone is insufficient; invalid JSON or response
|
|
168
|
+
shapes become sanitized, reportable `LockerverseSdkError` failures.
|
|
169
|
+
- Expected selection errors are marked `reportable: false`.
|
|
170
|
+
- Unexpected network/server failures are marked `reportable: true`.
|
|
171
|
+
- Reportable failures are sent directly to Sentry with only allowlisted SDK and
|
|
172
|
+
workflow context; request data, users, and breadcrumbs are removed.
|
|
173
|
+
- The Sentry runtime is a private failure-only chunk. It is not loaded by the
|
|
174
|
+
successful checkout path, and `sentryDsn: null` prevents both loading and
|
|
175
|
+
sending.
|
|
176
|
+
- The SDK does not initialize a global Sentry client in the host application.
|
|
177
|
+
- Hosts with a restrictive Content Security Policy must allow the configured
|
|
178
|
+
Sentry ingest origin in `connect-src`, or disable SDK reporting with
|
|
179
|
+
`sentryDsn: null`.
|
|
180
|
+
- Stripe's shared publishable key is selected by environment; the community's
|
|
181
|
+
connected account comes from the authoritative checkout quote. The backend
|
|
182
|
+
builds that quote with the same charge-target resolver used to create
|
|
183
|
+
payments.
|
|
184
|
+
- Analytics are intentionally out of scope for v0.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { A as LockerverseSingleOptionCustomField, C as LockerversePaymentSubmission, D as LockerverseSdkOperation, E as LockerverseSdkErrorCode, F as LockerverseWidgetState, M as LockerverseWidget, N as LockerverseWidgetConfiguration, O as LockerverseSelection, P as LockerverseWidgetFields, S as LockerversePaymentStatus, T as LockerverseSdkError, _ as LockerverseEnvironment, a as LockerverseCheckoutAmounts, b as LockerversePaymentOption, c as LockerverseCheckoutPreview, d as LockerverseCheckoutQuote, f as LockerverseCheckoutTotal, g as LockerverseCustomFieldOption, h as LockerverseCustomFieldAnswerValue, i as LockerverseCatalog, j as LockerverseTextCustomField, k as LockerverseSelectionItem, l as LockerverseCheckoutPricingInput, m as LockerverseCustomFieldAnswer, n as LOCKERVERSE_SDK_VERSION, o as LockerverseCheckoutLineItem, p as LockerverseCustomField, r as LockerverseAppliedDiscount, s as LockerverseCheckoutPaymentConfiguration, t as CreateLockerverseWidgetOptions, u as LockerverseCheckoutPricingPolicy, v as LockerverseMultiOptionCustomField, w as LockerverseProduct, x as LockerversePaymentResult, y as LockerversePaymentConfiguration } from "./types.js";
|
|
2
|
+
//#region src/checkout.d.ts
|
|
3
|
+
declare function createLockerverseCheckout(options: CreateLockerverseWidgetOptions): LockerverseWidget;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { CreateLockerverseWidgetOptions, LOCKERVERSE_SDK_VERSION, LockerverseAppliedDiscount, LockerverseCatalog, LockerverseCheckoutAmounts, LockerverseCheckoutLineItem, LockerverseCheckoutPaymentConfiguration, LockerverseCheckoutPreview, LockerverseCheckoutPricingInput, LockerverseCheckoutPricingPolicy, LockerverseCheckoutQuote, LockerverseCheckoutTotal, LockerverseCustomField, LockerverseCustomFieldAnswer, LockerverseCustomFieldAnswerValue, LockerverseCustomFieldOption, LockerverseEnvironment, LockerverseMultiOptionCustomField, LockerversePaymentConfiguration, LockerversePaymentOption, LockerversePaymentResult, LockerversePaymentStatus, LockerversePaymentSubmission, LockerverseProduct, LockerverseSdkError, LockerverseSdkErrorCode, LockerverseSdkOperation, LockerverseSelection, LockerverseSelectionItem, LockerverseSingleOptionCustomField, LockerverseTextCustomField, LockerverseWidget, LockerverseWidgetConfiguration, LockerverseWidgetFields, LockerverseWidgetState, createLockerverseCheckout };
|
|
6
|
+
//# sourceMappingURL=checkout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout.d.ts","names":[],"sources":["../src/checkout.ts"],"mappings":";;iBA+BgB,0BACd,SAAS,iCACR"}
|
package/dist/checkout.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as e,c as t,d as n,f as r,i,l as a,n as o,o as s,p as c,r as l,s as u,t as d,u as f}from"./transport.js";import{n as p,t as m}from"./types.js";const h={development:`pk_test_51O7FkjDHAhgRuLtFHdkXdIe8T5i7rOVaG9PCtDetK3UUVKojVUEKHmQacGzigf9mOX1wz3zSOKoYwFjRcTfML9PU00OjJko2lk`,production:`pk_live_51O7FkjDHAhgRuLtFlzLdxJrwo7F09WCKTlzT9lnBePjOGizWnuijkH9oCkoAddkmBT8ngIuqAPkDiHlPEAH4KXbz00Tm0DaPT4`};function g(e){let t=c(e,`widgetSlug`);return{...t,stripePublishableKey:h[t.environment],widgetSlug:t.resourceSlug,widgetSlugValue:t.resourceSlugValue}}function _(e,t){if(!Number.isSafeInteger(e)||e<t)throw TypeError(`Expected a safe integer.`);return e}function v(e,t,n){if(typeof e!=`number`||!Number.isFinite(e)||e<t||e>n)throw TypeError(`Expected a bounded finite number.`);return e}function y(e,t){return e===null?null:_(e,t)}function b(e){if(e===`one-time`||e===`monthly`||e===`annually`)return e;throw TypeError(`Expected a supported payment option.`)}function x(e){if(e===`fixed`||e===`custom`)return e;throw TypeError(`Expected a supported pricing mode.`)}function S(e){if(e===`action_required`||e===`failed`||e===`pending`||e===`success`)return e;throw TypeError(`Expected a supported payment status.`)}function C(e){if(e===null)return null;let t=f(e);if(t.source!==`email_list`&&t.source!==`promo_code`)throw TypeError(`Expected a supported discount source.`);let n=t.source;return{percentageOff:v(t.percentageOff,0,100),source:n}}function w(e){let t=e===void 0?{}:f(e);return{memberId:u(t.memberId,!1),merchSize:u(t.merchSize,!1),phone:u(t.phone,!1),promoCode:u(t.promoCode,!1),serviceFee:u(t.serviceFee,!1),shipping:u(t.shipping,!1),tipping:u(t.tipping,!1)}}function T(n){let r=f(n);return{amountCents:y(r.amountCents,0),description:t(r.description,null),id:e(r.id),inventoryQuantity:y(r.inventoryQuantity,0),maxQuantity:y(r.maxQuantity,0),minimumAmountCents:y(r.minimumAmountCents,0),minQuantity:y(r.minQuantity,0),name:e(r.name),paymentOption:b(r.paymentOption),pricingMode:x(r.pricingMode)}}function E(t){let n=f(t);return{acceptsDiscounts:u(n.acceptsDiscounts,!1),id:e(n.id),product:T(n.product),productId:e(n.productId),slug:e(n.slug)}}function D(e){let n=f(e),r=n.config===void 0?{}:f(n.config),o=n.pricingPolicy===void 0?{currency:`usd`,serviceFeeRateBasisPoints:0}:f(n.pricingPolicy),s=n.products===void 0?[]:n.products;if(!Array.isArray(s))throw TypeError(`Expected a Product array.`);if(o.currency!==`usd`)throw TypeError(`Expected USD checkout pricing policy.`);return{config:{customFields:i(r.customFields),fields:w(r.fields)},description:t(n.description,null),id:a(n.id,``),name:a(n.name,`Lockerverse widget`),pricingPolicy:{currency:`usd`,serviceFeeRateBasisPoints:_(o.serviceFeeRateBasisPoints,0)},products:s.map(E),showCommunityBranding:u(n.showCommunityBranding,!0),title:t(n.title,null)}}function O(t){let n=f(t);return{acceptsDiscounts:l(n.acceptsDiscounts),listingId:e(n.listingId),listingSlug:e(n.listingSlug),paymentOption:b(n.paymentOption),pricingMode:x(n.pricingMode),productId:e(n.productId),productName:e(n.productName),quantity:_(n.quantity,1),subtotalCents:_(n.subtotalCents,0),unitAmountCents:_(n.unitAmountCents,0)}}function k(t){let n=f(t);if(!Array.isArray(n.lineItems))throw TypeError(`Expected a line item array.`);return{amountCents:_(n.amountCents,0),appliedDiscount:C(n.appliedDiscount),connectedAccountId:n.connectedAccountId===null?null:e(n.connectedAccountId),discountableSubtotalCents:_(n.discountableSubtotalCents,0),discountCents:_(n.discountCents,0),lineItems:n.lineItems.map(O),paymentOption:b(n.paymentOption),serviceFeeCents:_(n.serviceFeeCents,0),subtotalCents:_(n.subtotalCents,0),tipCents:_(n.tipCents,0),totalCents:_(n.totalCents,0)}}function A(t){let n=f(t);return{checkoutId:e(n.checkoutId),checkoutStatus:S(n.checkoutStatus),clientSecret:s(n.clientSecret),paymentReference:e(n.paymentReference),requiresAction:l(n.requiresAction),status:s(n.status)}}const j=1e4;function M(e,t){if(!Number.isSafeInteger(e)||e<0)throw TypeError(t);return e}function N(e,t){return M(e+t,`The selected checkout total is too large.`)}function P(e,t){return M(e*t,`The selected Product quantity produces an unsafe total.`)}function F(e,t){let n=(BigInt(e)*BigInt(t)+BigInt(j/2))/BigInt(j);if(n>BigInt(2**53-1))throw TypeError(`The selected checkout total is too large.`);return Number(n)}function I(e,t,n){let r=0,i=0;for(let n of t.items){let t=e.products.find(({id:e,slug:t})=>e===n.productId&&t===n.productSlug);if(!t)throw TypeError(`The selected Product is no longer available.`);if(t.paymentOption!==`one-time`)throw TypeError(`Recurring Products are not supported by this SDK checkout yet.`);let a=`quantity`in n?P(t.amountCents??0,n.quantity):n.amountCents;r=N(r,a),t.acceptsDiscounts&&(i=N(i,a))}let a=n.includeServiceFee?F(r,e.pricingPolicy.serviceFeeRateBasisPoints):0,o=n.tipCents??0,s=N(r,a);return{amountCents:s,appliedDiscount:null,authoritative:!1,discountableSubtotalCents:i,discountCents:0,serviceFeeCents:a,subtotalCents:r,tipCents:o,totalCents:N(s,o)}}function L(e){let{product:t}=e;return{acceptsDiscounts:e.acceptsDiscounts??!1,amountCents:t.amountCents,description:t.description??null,id:t.id,inventoryQuantity:t.inventoryQuantity,listingId:e.id,maximumQuantity:t.maxQuantity,minimumAmountCents:t.minimumAmountCents,minimumQuantity:t.minQuantity,name:t.name,paymentOption:t.paymentOption,pricingMode:t.pricingMode,slug:e.slug}}function R(e,t){let n=e.config?.fields??{};return{payment:{currency:`usd`,publishableKey:t},pricingPolicy:{currency:`usd`,serviceFeeRateBasisPoints:e.pricingPolicy?.serviceFeeRateBasisPoints??0},products:(e.products??[]).map(L),widget:{customFields:e.config?.customFields??[],description:e.description??null,fields:{memberId:n.memberId??!1,merchSize:n.merchSize??!1,phone:n.phone??!1,promoCode:n.promoCode??!1,serviceFee:n.serviceFee??!1,shipping:n.shipping??!1,tipping:n.tipping??!1},id:e.id??``,name:e.name??`Lockerverse widget`,showCommunityBranding:e.showCommunityBranding??!0,title:e.title??null}}}function z(e){return r({payment:{...e.payment},pricingPolicy:{...e.pricingPolicy},products:e.products.map(e=>({...e})),widget:{...e.widget,customFields:e.widget.customFields.map(e=>`options`in e?{...e,options:e.options.map(e=>({...e}))}:{...e}),fields:{...e.widget.fields}}})}function B(e){return r({...e,appliedDiscount:e.appliedDiscount?{...e.appliedDiscount}:null,lineItems:e.lineItems.map(e=>({...e})),payment:{...e.payment}})}function V(e){return r({...e})}function H(e){let{apiBaseUrl:t,communitySlug:i,communitySlugValue:a,environment:s,fetchImplementation:c,onError:l,sentryDsn:u,stripePublishableKey:f,widgetSlug:m,widgetSlugValue:h}=g(e),_=null,v=null,y=null,b=null,x=null,S=0,C=0,w=!1,T=new Map,E=o({phase:`idle`,selection:r({items:[]})});function O(e){let t=_,n=t?t.products.find(({slug:t})=>t===e):void 0;if(!n)throw Error(`Lockerverse Product "${e}" is unavailable.`);return n}let j=n({communitySlug:a,environment:s,getContext:()=>({paymentReference:b,widgetSlug:h}),onError:l,resourceContextName:`lockerverse_widget`,sentryDsn:u});function M(e,t=`update_selection`){throw j(new p({code:`invalid_selection`,message:e,operation:t,reportable:!1}))}let{fetchResponse:N,parseResponseJson:P}=d(c,j);function F(){let e=_;return r({items:(e?e.products:[]).flatMap(e=>{let t=T.get(e.slug);return t?[{productId:e.id,productSlug:e.slug,...t}]:[]})})}function L(){v=null,y=null,b=null,x=null}function H(){w&&M(`Selection cannot change while a payment is being submitted.`)}function U(e){w&&M(`This operation cannot run while a payment is being submitted.`,e)}function W(){C+=1,L()}function G(e=null){_&&E.commit({catalog:_,phase:`ready`,preview:e,selection:F()})}function K(e,t=null){E.commit({catalog:_,error:e,phase:`error`,recoverablePaymentReference:t,selection:F()})}function q(e,t){if(e!==C||t!==S)throw j(new p({code:`total_calculation_failed`,message:`This Lockerverse checkout total was superseded. Calculate the total again for the current selection.`,operation:`calculate_total`,reportable:!1}))}function J(e={}){if(U(`calculate_total`),!_)throw Error(`Load the Lockerverse widget before previewing the total.`);T.size===0&&M(`Select at least one Product before previewing.`);let t=Y(_,e);W();try{let e=r(I(_,F(),t));return x=e,G(e),e}catch(e){M(e instanceof Error?e.message:`Unable to preview checkout.`)}}function Y(e,t){X(e,t);let n=t.tipCents??0,r=t.email?.trim().toLowerCase(),i=t.promoCode?.trim();return{...r?{email:r}:{},...t.includeServiceFee===void 0?{}:{includeServiceFee:t.includeServiceFee},...i?{promoCode:i}:{},...t.tipCents===void 0?{}:{tipCents:n}}}function X(e,t){let n=t.tipCents??0;(!Number.isSafeInteger(n)||n<0)&&M(`Tip must be a non-negative whole number of cents.`),t.includeServiceFee&&!e.widget.fields.serviceFee&&M(`Service fee is not enabled for this widget.`),t.includeServiceFee&&e.pricingPolicy.serviceFeeRateBasisPoints===0&&M(`Service fee pricing is unavailable. Reload the widget and try again.`),n>0&&!e.widget.fields.tipping&&M(`Tipping is not enabled for this widget.`)}async function Z(e={}){if(U(`calculate_total`),!_)throw Error(`Load the Lockerverse widget before calculating the total.`);let n=Y(_,e);T.size===0&&M(`Select at least one Product before calculating the total.`,`calculate_total`);let a=F(),o=r(I(_,a,n));x=o,E.commit({catalog:_,phase:`quoting`,preview:o,selection:a});let s=a.items.map(({productSlug:e,...t})=>t),c=C,l=S+1;S=l,v=null,b=null;let u;try{u=await N(`${t}/v2/community/${i}/payment-widgets/${m}/checkout/quote`,{body:JSON.stringify({...n,items:s}),headers:{"Content-Type":`application/json`},method:`POST`},{code:`total_calculation_failed`,message:`Unable to calculate the Lockerverse checkout total because the request failed.`,operation:`calculate_total`,report:!1})}catch(e){throw q(c,l),e instanceof p?(K(e),j(e)):e}if(q(c,l),!u.ok){let e=new p({code:`total_calculation_failed`,message:`Unable to calculate the Lockerverse checkout total (${u.status}).`,operation:`calculate_total`,reportable:u.status>=500,status:u.status});throw K(e),j(e)}let d;try{if(d=await P(u,k,{code:`total_calculation_failed`,message:`Lockerverse returned an invalid checkout total.`,operation:`calculate_total`,report:!1}),d.paymentOption!==`one-time`)throw new p({code:`total_calculation_failed`,message:`Lockerverse returned an unsupported checkout cadence.`,operation:`calculate_total`,reportable:!0})}catch(e){throw q(c,l),e instanceof p?(K(e),j(e)):e}q(c,l);let f=globalThis.crypto.randomUUID(),{connectedAccountId:h,paymentOption:g,...w}=d,D=r({...w,authoritative:!0,payment:{..._.payment,connectedAccountId:h},paymentOption:`one-time`,paymentReference:f});return v=D,y=r({...n}),b=f,E.commit({catalog:_,phase:`quoted`,preview:o,quote:D,selection:a}),B(D)}return{calculateTotal:Z,clear(){H(),T.clear(),W(),G()},async getPaymentStatus(e=b??``){U(`get_payment_status`),e||M(`Provide a payment reference to recover its status.`,`get_payment_status`),b=e;let n=F();E.commit({catalog:_,paymentReference:e,phase:`recovering`,selection:n});try{let r=await N(`${t}/v2/community/${i}/payment-widgets/${m}/checkout/${encodeURIComponent(e)}/status`,void 0,{code:`payment_status_failed`,message:`Unable to recover the Lockerverse payment status because the request failed.`,operation:`get_payment_status`});if(!r.ok)throw j(new p({code:`payment_status_failed`,message:`Unable to recover the Lockerverse payment status (${r.status}).`,operation:`get_payment_status`,reportable:r.status>=500,status:r.status}));let a=V(await P(r,A,{code:`payment_status_failed`,message:`Lockerverse returned an invalid payment status.`,operation:`get_payment_status`}));return E.commit({catalog:_,payment:a,phase:`payment`,quote:v?.paymentReference===e?v:null,selection:n}),V(a)}catch(t){throw t instanceof p&&K(t,e),t}},getSelection:F,getState:E.getState,async load(){U(`load_widget`),W(),E.commit({phase:`loading`,selection:F()});let e={code:`widget_load_failed`,message:`Unable to load Lockerverse widget because the request failed.`,operation:`load_widget`,report:!1},n;try{n=await N(`${t}/v2/community/${i}/payment-widgets/${m}`,void 0,e)}catch(e){throw e instanceof p?(K(e),j(e)):e}if(!n.ok){let e=new p({code:`widget_load_failed`,message:`Unable to load Lockerverse widget (${n.status}).`,operation:`load_widget`,reportable:n.status>=500,status:n.status});throw K(e),j(e)}let a=await P(n,D,{code:`widget_load_failed`,message:`Lockerverse returned an invalid widget catalog.`,operation:`load_widget`});return T.clear(),_=r(R(a,f)),G(),z(_)},previewTotal:J,remove(e){H(),T.delete(e),W(),G()},setAmount(e,t){H();let n=O(e);n.pricingMode!==`custom`&&M(`Fixed-price Products do not accept custom amounts.`),(!Number.isSafeInteger(t)||t<=0)&&M(`Product amount must be a positive integer in cents.`),n.minimumAmountCents!==null&&t<n.minimumAmountCents&&M(`Product amount must be at least ${n.minimumAmountCents} cents.`),T.set(e,{amountCents:t}),W(),G()},setQuantity(e,t){H();let n=O(e);n.pricingMode!==`fixed`&&M(`Custom-amount Products do not accept quantities.`),(!Number.isSafeInteger(t)||t<=0)&&M(`Product quantity must be a positive integer.`),n.minimumQuantity!==null&&t<n.minimumQuantity&&M(`Product quantity must be at least ${n.minimumQuantity}.`),n.maximumQuantity!==null&&t>n.maximumQuantity&&M(`Product quantity must not exceed ${n.maximumQuantity}.`),n.inventoryQuantity!==null&&t>n.inventoryQuantity&&M(`Requested Product quantity is unavailable.`),T.set(e,{quantity:t}),W(),G()},async submitPayment(e){_&&v&&y||M(`Calculate the current total before submitting a payment.`,`submit_payment`),w&&M(`A Lockerverse payment is already being submitted.`,`submit_payment`);let n=_,r=v,a=y,o=F(),s=x??I(n,o,a),c=e.email.trim().toLowerCase();(!c||c!==a.email)&&M(`Payment email must match the current checkout quote.`,`submit_payment`);let l=o.items.map(({productSlug:e,...t})=>t);w=!0,E.commit({catalog:n,phase:`submitting`,preview:s,quote:r,selection:o});try{let s=await N(`${t}/v2/community/${i}/payment-widgets/${m}/checkout/confirm`,{body:JSON.stringify({confirmationToken:e.confirmationToken,customFieldAnswers:e.customFieldAnswers,email:c,expectedAmountCents:r.amountCents,expectedAppliedDiscount:r.appliedDiscount,expectedConnectedAccountId:r.payment.connectedAccountId,expectedDiscountableSubtotalCents:r.discountableSubtotalCents,expectedDiscountCents:r.discountCents,expectedServiceFeeCents:r.serviceFeeCents,expectedSubtotalCents:r.subtotalCents,expectedTipCents:r.tipCents,expectedTotalCents:r.totalCents,...a,items:l,memberId:e.memberId,merchSize:e.merchSize,metadata:e.metadata,paymentReference:r.paymentReference,phone:e.phone,quoteContractVersion:1}),headers:{"Content-Type":`application/json`},method:`POST`},{code:`payment_submit_failed`,message:`Unable to submit the Lockerverse payment because the request failed.`,operation:`submit_payment`});if(!s.ok)throw j(new p({code:`payment_submit_failed`,message:`Unable to submit the Lockerverse payment (${s.status}).`,operation:`submit_payment`,reportable:s.status>=500,status:s.status}));let u=V(await P(s,A,{code:`payment_submit_failed`,message:`Lockerverse returned an invalid payment confirmation.`,operation:`submit_payment`}));return E.commit({catalog:n,payment:u,phase:`payment`,quote:r,selection:o}),V(u)}catch(e){throw e instanceof p&&K(e,r.paymentReference),e}finally{w=!1}},subscribe:E.subscribe}}export{m as LOCKERVERSE_SDK_VERSION,p as LockerverseSdkError,H as createLockerverseCheckout};
|
|
2
|
+
//# sourceMappingURL=checkout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout.js","names":[],"sources":["../src/checkout-environment.ts","../src/parsers.ts","../src/pricing.ts","../src/snapshots.ts","../src/checkout.ts"],"sourcesContent":["import { resolveResourceEnvironment } from \"./environment.ts\";\nimport type {\n CreateLockerverseWidgetOptions,\n LockerverseEnvironment,\n} from \"./types.ts\";\n\nconst STRIPE_PUBLISHABLE_KEYS: Record<LockerverseEnvironment, string> = {\n development:\n \"pk_test_51O7FkjDHAhgRuLtFHdkXdIe8T5i7rOVaG9PCtDetK3UUVKojVUEKHmQacGzigf9mOX1wz3zSOKoYwFjRcTfML9PU00OjJko2lk\",\n production:\n \"pk_live_51O7FkjDHAhgRuLtFlzLdxJrwo7F09WCKTlzT9lnBePjOGizWnuijkH9oCkoAddkmBT8ngIuqAPkDiHlPEAH4KXbz00Tm0DaPT4\",\n};\n\nexport function resolveWidgetEnvironment(\n options: CreateLockerverseWidgetOptions\n) {\n const runtime = resolveResourceEnvironment(options, \"widgetSlug\");\n return {\n ...runtime,\n stripePublishableKey: STRIPE_PUBLISHABLE_KEYS[runtime.environment],\n widgetSlug: runtime.resourceSlug,\n widgetSlugValue: runtime.resourceSlugValue,\n };\n}\n","import type {\n PublicCheckoutQuote,\n PublicProduct,\n PublicProductListing,\n PublicWidget,\n} from \"./contracts.ts\";\nimport {\n parseBoolean,\n parseCustomFields,\n parseNonEmptyString,\n parseNullableString,\n parseOptionalBoolean,\n parseOptionalNullableString,\n parseOptionalString,\n parseRecord,\n} from \"./parsing.ts\";\nimport type {\n LockerverseAppliedDiscount,\n LockerverseCheckoutLineItem,\n LockerversePaymentOption,\n LockerversePaymentResult,\n LockerversePaymentStatus,\n LockerverseWidgetFields,\n} from \"./types.ts\";\n\nfunction parseSafeInteger(value: unknown, minimum: number): number {\n if (!Number.isSafeInteger(value) || (value as number) < minimum) {\n throw new TypeError(\"Expected a safe integer.\");\n }\n\n return value as number;\n}\n\nfunction parseFiniteNumber(\n value: unknown,\n minimum: number,\n maximum: number\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value < minimum ||\n value > maximum\n ) {\n throw new TypeError(\"Expected a bounded finite number.\");\n }\n return value;\n}\n\nfunction parseNullableSafeInteger(\n value: unknown,\n minimum: number\n): number | null {\n return value === null ? null : parseSafeInteger(value, minimum);\n}\n\nfunction parsePaymentOption(value: unknown): LockerversePaymentOption {\n if (value === \"one-time\" || value === \"monthly\" || value === \"annually\") {\n return value;\n }\n\n throw new TypeError(\"Expected a supported payment option.\");\n}\n\nfunction parsePricingMode(value: unknown): \"fixed\" | \"custom\" {\n if (value === \"fixed\" || value === \"custom\") {\n return value;\n }\n\n throw new TypeError(\"Expected a supported pricing mode.\");\n}\n\nfunction parsePaymentStatus(value: unknown): LockerversePaymentStatus {\n if (\n value === \"action_required\" ||\n value === \"failed\" ||\n value === \"pending\" ||\n value === \"success\"\n ) {\n return value;\n }\n\n throw new TypeError(\"Expected a supported payment status.\");\n}\n\nfunction parseAppliedDiscount(\n value: unknown\n): LockerverseAppliedDiscount | null {\n if (value === null) {\n return null;\n }\n const discount = parseRecord(value);\n if (discount.source !== \"email_list\" && discount.source !== \"promo_code\") {\n throw new TypeError(\"Expected a supported discount source.\");\n }\n const source = discount.source as LockerverseAppliedDiscount[\"source\"];\n return {\n percentageOff: parseFiniteNumber(discount.percentageOff, 0, 100),\n source,\n };\n}\n\nfunction parseWidgetFields(value: unknown): LockerverseWidgetFields {\n const fields = value === undefined ? {} : parseRecord(value);\n\n return {\n memberId: parseOptionalBoolean(fields.memberId, false),\n merchSize: parseOptionalBoolean(fields.merchSize, false),\n phone: parseOptionalBoolean(fields.phone, false),\n promoCode: parseOptionalBoolean(fields.promoCode, false),\n serviceFee: parseOptionalBoolean(fields.serviceFee, false),\n shipping: parseOptionalBoolean(fields.shipping, false),\n tipping: parseOptionalBoolean(fields.tipping, false),\n };\n}\n\nfunction parsePublicProduct(value: unknown): PublicProduct {\n const product = parseRecord(value);\n\n return {\n amountCents: parseNullableSafeInteger(product.amountCents, 0),\n description: parseOptionalNullableString(product.description, null),\n id: parseNonEmptyString(product.id),\n inventoryQuantity: parseNullableSafeInteger(product.inventoryQuantity, 0),\n maxQuantity: parseNullableSafeInteger(product.maxQuantity, 0),\n minimumAmountCents: parseNullableSafeInteger(product.minimumAmountCents, 0),\n minQuantity: parseNullableSafeInteger(product.minQuantity, 0),\n name: parseNonEmptyString(product.name),\n paymentOption: parsePaymentOption(product.paymentOption),\n pricingMode: parsePricingMode(product.pricingMode),\n };\n}\n\nfunction parseProductListing(value: unknown): PublicProductListing {\n const listing = parseRecord(value);\n\n return {\n acceptsDiscounts: parseOptionalBoolean(listing.acceptsDiscounts, false),\n id: parseNonEmptyString(listing.id),\n product: parsePublicProduct(listing.product),\n productId: parseNonEmptyString(listing.productId),\n slug: parseNonEmptyString(listing.slug),\n };\n}\n\nexport function parsePublicWidget(value: unknown): PublicWidget {\n const widget = parseRecord(value);\n const config = widget.config === undefined ? {} : parseRecord(widget.config);\n const pricingPolicy =\n widget.pricingPolicy === undefined\n ? { currency: \"usd\", serviceFeeRateBasisPoints: 0 }\n : parseRecord(widget.pricingPolicy);\n const products = widget.products === undefined ? [] : widget.products;\n if (!Array.isArray(products)) {\n throw new TypeError(\"Expected a Product array.\");\n }\n if (pricingPolicy.currency !== \"usd\") {\n throw new TypeError(\"Expected USD checkout pricing policy.\");\n }\n\n return {\n config: {\n customFields: parseCustomFields(config.customFields),\n fields: parseWidgetFields(config.fields),\n },\n description: parseOptionalNullableString(widget.description, null),\n id: parseOptionalString(widget.id, \"\"),\n name: parseOptionalString(widget.name, \"Lockerverse widget\"),\n pricingPolicy: {\n currency: \"usd\",\n serviceFeeRateBasisPoints: parseSafeInteger(\n pricingPolicy.serviceFeeRateBasisPoints,\n 0\n ),\n },\n products: products.map(parseProductListing),\n showCommunityBranding: parseOptionalBoolean(\n widget.showCommunityBranding,\n true\n ),\n title: parseOptionalNullableString(widget.title, null),\n };\n}\n\nfunction parseCheckoutLineItem(value: unknown): LockerverseCheckoutLineItem {\n const lineItem = parseRecord(value);\n\n return {\n acceptsDiscounts: parseBoolean(lineItem.acceptsDiscounts),\n listingId: parseNonEmptyString(lineItem.listingId),\n listingSlug: parseNonEmptyString(lineItem.listingSlug),\n paymentOption: parsePaymentOption(lineItem.paymentOption),\n pricingMode: parsePricingMode(lineItem.pricingMode),\n productId: parseNonEmptyString(lineItem.productId),\n productName: parseNonEmptyString(lineItem.productName),\n quantity: parseSafeInteger(lineItem.quantity, 1),\n subtotalCents: parseSafeInteger(lineItem.subtotalCents, 0),\n unitAmountCents: parseSafeInteger(lineItem.unitAmountCents, 0),\n };\n}\n\nexport function parseCheckoutQuote(value: unknown): PublicCheckoutQuote {\n const quote = parseRecord(value);\n if (!Array.isArray(quote.lineItems)) {\n throw new TypeError(\"Expected a line item array.\");\n }\n\n return {\n amountCents: parseSafeInteger(quote.amountCents, 0),\n appliedDiscount: parseAppliedDiscount(quote.appliedDiscount),\n connectedAccountId:\n quote.connectedAccountId === null\n ? null\n : parseNonEmptyString(quote.connectedAccountId),\n discountableSubtotalCents: parseSafeInteger(\n quote.discountableSubtotalCents,\n 0\n ),\n discountCents: parseSafeInteger(quote.discountCents, 0),\n lineItems: quote.lineItems.map(parseCheckoutLineItem),\n paymentOption: parsePaymentOption(quote.paymentOption),\n serviceFeeCents: parseSafeInteger(quote.serviceFeeCents, 0),\n subtotalCents: parseSafeInteger(quote.subtotalCents, 0),\n tipCents: parseSafeInteger(quote.tipCents, 0),\n totalCents: parseSafeInteger(quote.totalCents, 0),\n };\n}\n\nexport function parsePaymentResult(value: unknown): LockerversePaymentResult {\n const paymentResult = parseRecord(value);\n\n return {\n checkoutId: parseNonEmptyString(paymentResult.checkoutId),\n checkoutStatus: parsePaymentStatus(paymentResult.checkoutStatus),\n clientSecret: parseNullableString(paymentResult.clientSecret),\n paymentReference: parseNonEmptyString(paymentResult.paymentReference),\n requiresAction: parseBoolean(paymentResult.requiresAction),\n status: parseNullableString(paymentResult.status),\n };\n}\n","import type {\n LockerverseCatalog,\n LockerverseCheckoutPreview,\n LockerverseCheckoutPricingInput,\n LockerverseSelection,\n} from \"./types.ts\";\n\nconst BASIS_POINTS_PER_WHOLE = 10_000;\n\nfunction assertSafeCents(value: number, message: string) {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new TypeError(message);\n }\n return value;\n}\n\nfunction addCents(left: number, right: number) {\n return assertSafeCents(\n left + right,\n \"The selected checkout total is too large.\"\n );\n}\n\nfunction multiplyCents(value: number, quantity: number) {\n return assertSafeCents(\n value * quantity,\n \"The selected Product quantity produces an unsafe total.\"\n );\n}\n\nfunction calculateBasisPoints(value: number, basisPoints: number) {\n const rounded =\n (BigInt(value) * BigInt(basisPoints) + BigInt(BASIS_POINTS_PER_WHOLE / 2)) /\n BigInt(BASIS_POINTS_PER_WHOLE);\n if (rounded > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new TypeError(\"The selected checkout total is too large.\");\n }\n return Number(rounded);\n}\n\nexport function calculateCheckoutPreview(\n catalog: LockerverseCatalog,\n selection: LockerverseSelection,\n input: LockerverseCheckoutPricingInput\n): LockerverseCheckoutPreview {\n let subtotalCents = 0;\n let discountableSubtotalCents = 0;\n\n for (const item of selection.items) {\n const product = catalog.products.find(\n ({ id, slug }) => id === item.productId && slug === item.productSlug\n );\n if (!product) {\n throw new TypeError(\"The selected Product is no longer available.\");\n }\n if (product.paymentOption !== \"one-time\") {\n throw new TypeError(\n \"Recurring Products are not supported by this SDK checkout yet.\"\n );\n }\n const itemSubtotal =\n \"quantity\" in item\n ? multiplyCents(product.amountCents ?? 0, item.quantity)\n : item.amountCents;\n subtotalCents = addCents(subtotalCents, itemSubtotal);\n if (product.acceptsDiscounts) {\n discountableSubtotalCents = addCents(\n discountableSubtotalCents,\n itemSubtotal\n );\n }\n }\n\n const serviceFeeCents = input.includeServiceFee\n ? calculateBasisPoints(\n subtotalCents,\n catalog.pricingPolicy.serviceFeeRateBasisPoints\n )\n : 0;\n const tipCents = input.tipCents ?? 0;\n const amountCents = addCents(subtotalCents, serviceFeeCents);\n\n return {\n amountCents,\n appliedDiscount: null,\n authoritative: false,\n discountableSubtotalCents,\n discountCents: 0,\n serviceFeeCents,\n subtotalCents,\n tipCents,\n totalCents: addCents(amountCents, tipCents),\n };\n}\n","import type { PublicProductListing, PublicWidget } from \"./contracts.ts\";\nimport { deepFreeze } from \"./deep-freeze.ts\";\nimport type {\n LockerverseCatalog,\n LockerverseCheckoutTotal,\n LockerversePaymentResult,\n LockerverseProduct,\n} from \"./types.ts\";\n\nfunction mapProduct(listing: PublicProductListing): LockerverseProduct {\n const { product } = listing;\n\n return {\n acceptsDiscounts: listing.acceptsDiscounts ?? false,\n amountCents: product.amountCents,\n description: product.description ?? null,\n id: product.id,\n inventoryQuantity: product.inventoryQuantity,\n listingId: listing.id,\n maximumQuantity: product.maxQuantity,\n minimumAmountCents: product.minimumAmountCents,\n minimumQuantity: product.minQuantity,\n name: product.name,\n paymentOption: product.paymentOption,\n pricingMode: product.pricingMode,\n slug: listing.slug,\n };\n}\n\nexport function createCatalog(\n widget: PublicWidget,\n publishableKey: string\n): LockerverseCatalog {\n const fields = widget.config?.fields ?? {};\n\n return {\n payment: {\n currency: \"usd\",\n publishableKey,\n },\n pricingPolicy: {\n currency: \"usd\",\n serviceFeeRateBasisPoints:\n widget.pricingPolicy?.serviceFeeRateBasisPoints ?? 0,\n },\n products: (widget.products ?? []).map(mapProduct),\n widget: {\n customFields: widget.config?.customFields ?? [],\n description: widget.description ?? null,\n fields: {\n memberId: fields.memberId ?? false,\n merchSize: fields.merchSize ?? false,\n phone: fields.phone ?? false,\n promoCode: fields.promoCode ?? false,\n serviceFee: fields.serviceFee ?? false,\n shipping: fields.shipping ?? false,\n tipping: fields.tipping ?? false,\n },\n id: widget.id ?? \"\",\n name: widget.name ?? \"Lockerverse widget\",\n showCommunityBranding: widget.showCommunityBranding ?? true,\n title: widget.title ?? null,\n },\n };\n}\n\nexport function cloneCatalog(catalog: LockerverseCatalog): LockerverseCatalog {\n return deepFreeze({\n payment: { ...catalog.payment },\n pricingPolicy: { ...catalog.pricingPolicy },\n products: catalog.products.map((product) => ({ ...product })),\n widget: {\n ...catalog.widget,\n customFields: catalog.widget.customFields.map((field) =>\n \"options\" in field\n ? {\n ...field,\n options: field.options.map((option) => ({ ...option })),\n }\n : { ...field }\n ),\n fields: { ...catalog.widget.fields },\n },\n });\n}\n\nexport function cloneCheckoutTotal(\n total: LockerverseCheckoutTotal\n): LockerverseCheckoutTotal {\n return deepFreeze({\n ...total,\n appliedDiscount: total.appliedDiscount\n ? { ...total.appliedDiscount }\n : null,\n lineItems: total.lineItems.map((lineItem) => ({ ...lineItem })),\n payment: { ...total.payment },\n });\n}\n\nexport function clonePaymentResult(\n paymentResult: LockerversePaymentResult\n): LockerversePaymentResult {\n return deepFreeze({ ...paymentResult });\n}\n","import { resolveWidgetEnvironment } from \"./checkout-environment.ts\";\nimport type { PublicCheckoutQuote } from \"./contracts.ts\";\nimport { deepFreeze } from \"./deep-freeze.ts\";\nimport { createSdkErrorReporter } from \"./error-reporting.ts\";\nimport {\n parseCheckoutQuote,\n parsePaymentResult,\n parsePublicWidget,\n} from \"./parsers.ts\";\nimport { calculateCheckoutPreview } from \"./pricing.ts\";\nimport {\n cloneCatalog,\n cloneCheckoutTotal,\n clonePaymentResult,\n createCatalog,\n} from \"./snapshots.ts\";\nimport { createStateStore } from \"./state.ts\";\nimport { createTransport } from \"./transport.ts\";\nimport {\n type CreateLockerverseWidgetOptions,\n type LockerverseCatalog,\n type LockerverseCheckoutPreview,\n type LockerverseCheckoutPricingInput,\n type LockerverseCheckoutTotal,\n LockerverseSdkError,\n type LockerverseSdkOperation,\n type LockerverseSelection,\n type LockerverseWidget,\n type LockerverseWidgetState,\n} from \"./types.ts\";\n\nexport function createLockerverseCheckout(\n options: CreateLockerverseWidgetOptions\n): LockerverseWidget {\n const {\n apiBaseUrl,\n communitySlug,\n communitySlugValue,\n environment,\n fetchImplementation,\n onError,\n sentryDsn,\n stripePublishableKey,\n widgetSlug,\n widgetSlugValue,\n } = resolveWidgetEnvironment(options);\n let catalog: LockerverseCatalog | null = null;\n let calculatedTotal: LockerverseCheckoutTotal | null = null;\n let calculatedPricingInput: LockerverseCheckoutPricingInput | null = null;\n let latestPaymentReference: string | null = null;\n let latestPreview: LockerverseCheckoutPreview | null = null;\n let quoteGeneration = 0;\n let stateRevision = 0;\n let submitting = false;\n const selection = new Map<\n string,\n { amountCents: number } | { quantity: number }\n >();\n const stateStore = createStateStore<LockerverseWidgetState>({\n phase: \"idle\",\n selection: deepFreeze({ items: [] }),\n });\n\n function getProduct(productSlug: string) {\n const currentCatalog = catalog;\n const product = currentCatalog\n ? currentCatalog.products.find(({ slug }) => slug === productSlug)\n : undefined;\n\n if (!product) {\n throw new Error(`Lockerverse Product \"${productSlug}\" is unavailable.`);\n }\n\n return product;\n }\n\n const reportError = createSdkErrorReporter({\n communitySlug: communitySlugValue,\n environment,\n getContext: () => ({\n paymentReference: latestPaymentReference,\n widgetSlug: widgetSlugValue,\n }),\n onError,\n resourceContextName: \"lockerverse_widget\",\n sentryDsn,\n });\n\n function invalidSelection(\n message: string,\n operation: LockerverseSdkOperation = \"update_selection\"\n ): never {\n throw reportError(\n new LockerverseSdkError({\n code: \"invalid_selection\",\n message,\n operation,\n reportable: false,\n })\n );\n }\n\n const { fetchResponse, parseResponseJson } = createTransport(\n fetchImplementation,\n reportError\n );\n\n function getSelection(): LockerverseSelection {\n const currentCatalog = catalog;\n return deepFreeze({\n items: (currentCatalog ? currentCatalog.products : []).flatMap(\n (product) => {\n const selected = selection.get(product.slug);\n return selected\n ? [\n {\n productId: product.id,\n productSlug: product.slug,\n ...selected,\n },\n ]\n : [];\n }\n ),\n });\n }\n\n function invalidateCalculatedTotal() {\n calculatedTotal = null;\n calculatedPricingInput = null;\n latestPaymentReference = null;\n latestPreview = null;\n }\n\n function ensureSelectionMutable() {\n if (submitting) {\n invalidSelection(\n \"Selection cannot change while a payment is being submitted.\"\n );\n }\n }\n\n function ensureOperationAvailable(operation: LockerverseSdkOperation) {\n if (submitting) {\n invalidSelection(\n \"This operation cannot run while a payment is being submitted.\",\n operation\n );\n }\n }\n\n function reviseState() {\n stateRevision += 1;\n invalidateCalculatedTotal();\n }\n\n function commitReady(preview: LockerverseCheckoutPreview | null = null) {\n if (!catalog) {\n return;\n }\n stateStore.commit({\n catalog,\n phase: \"ready\",\n preview,\n selection: getSelection(),\n });\n }\n\n function commitError(\n error: LockerverseSdkError,\n recoverablePaymentReference: string | null = null\n ) {\n stateStore.commit({\n catalog,\n error,\n phase: \"error\",\n recoverablePaymentReference,\n selection: getSelection(),\n });\n }\n\n function rejectSupersededQuote(\n requestedStateRevision: number,\n requestedQuoteGeneration: number\n ) {\n if (\n requestedStateRevision === stateRevision &&\n requestedQuoteGeneration === quoteGeneration\n ) {\n return;\n }\n\n throw reportError(\n new LockerverseSdkError({\n code: \"total_calculation_failed\",\n message:\n \"This Lockerverse checkout total was superseded. Calculate the total again for the current selection.\",\n operation: \"calculate_total\",\n reportable: false,\n })\n );\n }\n\n function previewTotal(input: LockerverseCheckoutPricingInput = {}) {\n ensureOperationAvailable(\"calculate_total\");\n if (!catalog) {\n throw new Error(\n \"Load the Lockerverse widget before previewing the total.\"\n );\n }\n if (selection.size === 0) {\n invalidSelection(\"Select at least one Product before previewing.\");\n }\n const normalizedInput = normalizePricingInput(catalog, input);\n reviseState();\n\n try {\n const preview = deepFreeze(\n calculateCheckoutPreview(catalog, getSelection(), normalizedInput)\n );\n latestPreview = preview;\n commitReady(preview);\n return preview;\n } catch (error) {\n invalidSelection(\n error instanceof Error ? error.message : \"Unable to preview checkout.\"\n );\n }\n }\n\n function normalizePricingInput(\n currentCatalog: LockerverseCatalog,\n input: LockerverseCheckoutPricingInput\n ): LockerverseCheckoutPricingInput {\n validatePricingInput(currentCatalog, input);\n const tipCents = input.tipCents ?? 0;\n const email = input.email?.trim().toLowerCase();\n const promoCode = input.promoCode?.trim();\n return {\n ...(email ? { email } : {}),\n ...(input.includeServiceFee === undefined\n ? {}\n : { includeServiceFee: input.includeServiceFee }),\n ...(promoCode ? { promoCode } : {}),\n ...(input.tipCents === undefined ? {} : { tipCents }),\n };\n }\n\n function validatePricingInput(\n currentCatalog: LockerverseCatalog,\n input: LockerverseCheckoutPricingInput\n ) {\n const tipCents = input.tipCents ?? 0;\n if (!Number.isSafeInteger(tipCents) || tipCents < 0) {\n invalidSelection(\"Tip must be a non-negative whole number of cents.\");\n }\n if (input.includeServiceFee && !currentCatalog.widget.fields.serviceFee) {\n invalidSelection(\"Service fee is not enabled for this widget.\");\n }\n if (\n input.includeServiceFee &&\n currentCatalog.pricingPolicy.serviceFeeRateBasisPoints === 0\n ) {\n invalidSelection(\n \"Service fee pricing is unavailable. Reload the widget and try again.\"\n );\n }\n if (tipCents > 0 && !currentCatalog.widget.fields.tipping) {\n invalidSelection(\"Tipping is not enabled for this widget.\");\n }\n }\n\n async function calculateTotal(input: LockerverseCheckoutPricingInput = {}) {\n ensureOperationAvailable(\"calculate_total\");\n if (!catalog) {\n throw new Error(\n \"Load the Lockerverse widget before calculating the total.\"\n );\n }\n\n const normalizedInput = normalizePricingInput(catalog, input);\n if (selection.size === 0) {\n invalidSelection(\n \"Select at least one Product before calculating the total.\",\n \"calculate_total\"\n );\n }\n const currentSelection = getSelection();\n const preview = deepFreeze(\n calculateCheckoutPreview(catalog, currentSelection, normalizedInput)\n );\n latestPreview = preview;\n stateStore.commit({\n catalog,\n phase: \"quoting\",\n preview,\n selection: currentSelection,\n });\n const items = currentSelection.items.map(\n ({ productSlug: _productSlug, ...item }) => item\n );\n const requestedStateRevision = stateRevision;\n const requestedQuoteGeneration = quoteGeneration + 1;\n quoteGeneration = requestedQuoteGeneration;\n calculatedTotal = null;\n latestPaymentReference = null;\n let response: Response;\n\n try {\n response = await fetchResponse(\n `${apiBaseUrl}/v2/community/${communitySlug}/payment-widgets/${widgetSlug}/checkout/quote`,\n {\n body: JSON.stringify({ ...normalizedInput, items }),\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n },\n {\n code: \"total_calculation_failed\",\n message:\n \"Unable to calculate the Lockerverse checkout total because the request failed.\",\n operation: \"calculate_total\",\n report: false,\n }\n );\n } catch (error) {\n rejectSupersededQuote(requestedStateRevision, requestedQuoteGeneration);\n if (error instanceof LockerverseSdkError) {\n commitError(error);\n throw reportError(error);\n }\n throw error;\n }\n\n rejectSupersededQuote(requestedStateRevision, requestedQuoteGeneration);\n\n if (!response.ok) {\n const error = new LockerverseSdkError({\n code: \"total_calculation_failed\",\n message: `Unable to calculate the Lockerverse checkout total (${response.status}).`,\n operation: \"calculate_total\",\n reportable: response.status >= 500,\n status: response.status,\n });\n commitError(error);\n throw reportError(error);\n }\n\n let serverTotal: PublicCheckoutQuote;\n try {\n serverTotal = await parseResponseJson(response, parseCheckoutQuote, {\n code: \"total_calculation_failed\",\n message: \"Lockerverse returned an invalid checkout total.\",\n operation: \"calculate_total\",\n report: false,\n });\n if (serverTotal.paymentOption !== \"one-time\") {\n throw new LockerverseSdkError({\n code: \"total_calculation_failed\",\n message: \"Lockerverse returned an unsupported checkout cadence.\",\n operation: \"calculate_total\",\n reportable: true,\n });\n }\n } catch (error) {\n rejectSupersededQuote(requestedStateRevision, requestedQuoteGeneration);\n if (error instanceof LockerverseSdkError) {\n commitError(error);\n throw reportError(error);\n }\n throw error;\n }\n rejectSupersededQuote(requestedStateRevision, requestedQuoteGeneration);\n const paymentReference = globalThis.crypto.randomUUID();\n const {\n connectedAccountId,\n paymentOption: _paymentOption,\n ...total\n } = serverTotal;\n const nextCalculatedTotal = deepFreeze({\n ...total,\n authoritative: true as const,\n payment: {\n ...catalog.payment,\n connectedAccountId,\n },\n paymentOption: \"one-time\" as const,\n paymentReference,\n });\n calculatedTotal = nextCalculatedTotal;\n calculatedPricingInput = deepFreeze({ ...normalizedInput });\n latestPaymentReference = paymentReference;\n stateStore.commit({\n catalog,\n phase: \"quoted\",\n preview,\n quote: nextCalculatedTotal,\n selection: currentSelection,\n });\n return cloneCheckoutTotal(nextCalculatedTotal);\n }\n\n return {\n calculateTotal,\n clear() {\n ensureSelectionMutable();\n selection.clear();\n reviseState();\n commitReady();\n },\n async getPaymentStatus(paymentReference = latestPaymentReference ?? \"\") {\n ensureOperationAvailable(\"get_payment_status\");\n if (!paymentReference) {\n invalidSelection(\n \"Provide a payment reference to recover its status.\",\n \"get_payment_status\"\n );\n }\n latestPaymentReference = paymentReference;\n const currentSelection = getSelection();\n stateStore.commit({\n catalog,\n paymentReference,\n phase: \"recovering\",\n selection: currentSelection,\n });\n try {\n const response = await fetchResponse(\n `${apiBaseUrl}/v2/community/${communitySlug}/payment-widgets/${widgetSlug}/checkout/${encodeURIComponent(paymentReference)}/status`,\n undefined,\n {\n code: \"payment_status_failed\",\n message:\n \"Unable to recover the Lockerverse payment status because the request failed.\",\n operation: \"get_payment_status\",\n }\n );\n\n if (!response.ok) {\n throw reportError(\n new LockerverseSdkError({\n code: \"payment_status_failed\",\n message: `Unable to recover the Lockerverse payment status (${response.status}).`,\n operation: \"get_payment_status\",\n reportable: response.status >= 500,\n status: response.status,\n })\n );\n }\n\n const payment = clonePaymentResult(\n await parseResponseJson(response, parsePaymentResult, {\n code: \"payment_status_failed\",\n message: \"Lockerverse returned an invalid payment status.\",\n operation: \"get_payment_status\",\n })\n );\n stateStore.commit({\n catalog,\n payment,\n phase: \"payment\",\n quote:\n calculatedTotal?.paymentReference === paymentReference\n ? calculatedTotal\n : null,\n selection: currentSelection,\n });\n return clonePaymentResult(payment);\n } catch (error) {\n if (error instanceof LockerverseSdkError) {\n commitError(error, paymentReference);\n }\n throw error;\n }\n },\n getSelection,\n getState: stateStore.getState,\n async load() {\n ensureOperationAvailable(\"load_widget\");\n reviseState();\n stateStore.commit({ phase: \"loading\", selection: getSelection() });\n const requestContext = {\n code: \"widget_load_failed\" as const,\n message:\n \"Unable to load Lockerverse widget because the request failed.\",\n operation: \"load_widget\" as const,\n report: false,\n };\n let widgetResponse: Response;\n\n try {\n widgetResponse = await fetchResponse(\n `${apiBaseUrl}/v2/community/${communitySlug}/payment-widgets/${widgetSlug}`,\n undefined,\n requestContext\n );\n } catch (error) {\n if (error instanceof LockerverseSdkError) {\n commitError(error);\n throw reportError(error);\n }\n throw error;\n }\n\n if (!widgetResponse.ok) {\n const error = new LockerverseSdkError({\n code: \"widget_load_failed\",\n message: `Unable to load Lockerverse widget (${widgetResponse.status}).`,\n operation: \"load_widget\",\n reportable: widgetResponse.status >= 500,\n status: widgetResponse.status,\n });\n commitError(error);\n throw reportError(error);\n }\n\n const widget = await parseResponseJson(\n widgetResponse,\n parsePublicWidget,\n {\n code: \"widget_load_failed\",\n message: \"Lockerverse returned an invalid widget catalog.\",\n operation: \"load_widget\",\n }\n );\n\n selection.clear();\n catalog = deepFreeze(createCatalog(widget, stripePublishableKey));\n commitReady();\n\n return cloneCatalog(catalog);\n },\n previewTotal,\n remove(productSlug) {\n ensureSelectionMutable();\n selection.delete(productSlug);\n reviseState();\n commitReady();\n },\n setAmount(productSlug, amountCents) {\n ensureSelectionMutable();\n const product = getProduct(productSlug);\n\n if (product.pricingMode !== \"custom\") {\n invalidSelection(\"Fixed-price Products do not accept custom amounts.\");\n }\n if (!Number.isSafeInteger(amountCents) || amountCents <= 0) {\n invalidSelection(\"Product amount must be a positive integer in cents.\");\n }\n if (\n product.minimumAmountCents !== null &&\n amountCents < product.minimumAmountCents\n ) {\n invalidSelection(\n `Product amount must be at least ${product.minimumAmountCents} cents.`\n );\n }\n\n selection.set(productSlug, { amountCents });\n reviseState();\n commitReady();\n },\n setQuantity(productSlug, quantity) {\n ensureSelectionMutable();\n const product = getProduct(productSlug);\n\n if (product.pricingMode !== \"fixed\") {\n invalidSelection(\"Custom-amount Products do not accept quantities.\");\n }\n if (!Number.isSafeInteger(quantity) || quantity <= 0) {\n invalidSelection(\"Product quantity must be a positive integer.\");\n }\n if (\n product.minimumQuantity !== null &&\n quantity < product.minimumQuantity\n ) {\n invalidSelection(\n `Product quantity must be at least ${product.minimumQuantity}.`\n );\n }\n if (\n product.maximumQuantity !== null &&\n quantity > product.maximumQuantity\n ) {\n invalidSelection(\n `Product quantity must not exceed ${product.maximumQuantity}.`\n );\n }\n if (\n product.inventoryQuantity !== null &&\n quantity > product.inventoryQuantity\n ) {\n invalidSelection(\"Requested Product quantity is unavailable.\");\n }\n\n selection.set(productSlug, { quantity });\n reviseState();\n commitReady();\n },\n async submitPayment(submission) {\n if (!(catalog && calculatedTotal && calculatedPricingInput)) {\n invalidSelection(\n \"Calculate the current total before submitting a payment.\",\n \"submit_payment\"\n );\n }\n if (submitting) {\n invalidSelection(\n \"A Lockerverse payment is already being submitted.\",\n \"submit_payment\"\n );\n }\n\n const transactionCatalog = catalog;\n const transactionQuote = calculatedTotal;\n const transactionPricingInput = calculatedPricingInput;\n const transactionSelection = getSelection();\n const transactionPreview =\n latestPreview ??\n calculateCheckoutPreview(\n transactionCatalog,\n transactionSelection,\n transactionPricingInput\n );\n const normalizedEmail = submission.email.trim().toLowerCase();\n if (\n !normalizedEmail ||\n normalizedEmail !== transactionPricingInput.email\n ) {\n invalidSelection(\n \"Payment email must match the current checkout quote.\",\n \"submit_payment\"\n );\n }\n\n const items = transactionSelection.items.map(\n ({ productSlug: _productSlug, ...item }) => item\n );\n submitting = true;\n stateStore.commit({\n catalog: transactionCatalog,\n phase: \"submitting\",\n preview: transactionPreview,\n quote: transactionQuote,\n selection: transactionSelection,\n });\n try {\n const response = await fetchResponse(\n `${apiBaseUrl}/v2/community/${communitySlug}/payment-widgets/${widgetSlug}/checkout/confirm`,\n {\n body: JSON.stringify({\n confirmationToken: submission.confirmationToken,\n customFieldAnswers: submission.customFieldAnswers,\n email: normalizedEmail,\n expectedAmountCents: transactionQuote.amountCents,\n expectedAppliedDiscount: transactionQuote.appliedDiscount,\n expectedConnectedAccountId:\n transactionQuote.payment.connectedAccountId,\n expectedDiscountableSubtotalCents:\n transactionQuote.discountableSubtotalCents,\n expectedDiscountCents: transactionQuote.discountCents,\n expectedServiceFeeCents: transactionQuote.serviceFeeCents,\n expectedSubtotalCents: transactionQuote.subtotalCents,\n expectedTipCents: transactionQuote.tipCents,\n expectedTotalCents: transactionQuote.totalCents,\n ...transactionPricingInput,\n items,\n memberId: submission.memberId,\n merchSize: submission.merchSize,\n metadata: submission.metadata,\n paymentReference: transactionQuote.paymentReference,\n phone: submission.phone,\n quoteContractVersion: 1,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n },\n {\n code: \"payment_submit_failed\",\n message:\n \"Unable to submit the Lockerverse payment because the request failed.\",\n operation: \"submit_payment\",\n }\n );\n\n if (!response.ok) {\n throw reportError(\n new LockerverseSdkError({\n code: \"payment_submit_failed\",\n message: `Unable to submit the Lockerverse payment (${response.status}).`,\n operation: \"submit_payment\",\n reportable: response.status >= 500,\n status: response.status,\n })\n );\n }\n\n const payment = clonePaymentResult(\n await parseResponseJson(response, parsePaymentResult, {\n code: \"payment_submit_failed\",\n message: \"Lockerverse returned an invalid payment confirmation.\",\n operation: \"submit_payment\",\n })\n );\n stateStore.commit({\n catalog: transactionCatalog,\n payment,\n phase: \"payment\",\n quote: transactionQuote,\n selection: transactionSelection,\n });\n return clonePaymentResult(payment);\n } catch (error) {\n if (error instanceof LockerverseSdkError) {\n commitError(error, transactionQuote.paymentReference);\n }\n throw error;\n } finally {\n submitting = false;\n }\n },\n subscribe: stateStore.subscribe,\n };\n}\n"],"mappings":"wJAMA,MAAM,EAAkE,CACtE,YACE,8GACF,WACE,6GACJ,EAEA,SAAgB,EACd,EACA,CACA,IAAM,EAAU,EAA2B,EAAS,YAAY,EAChE,MAAO,CACL,GAAG,EACH,qBAAsB,EAAwB,EAAQ,aACtD,WAAY,EAAQ,aACpB,gBAAiB,EAAQ,iBAC3B,CACF,CCEA,SAAS,EAAiB,EAAgB,EAAyB,CACjE,GAAI,CAAC,OAAO,cAAc,CAAK,GAAM,EAAmB,EACtD,MAAU,UAAU,0BAA0B,EAGhD,OAAO,CACT,CAEA,SAAS,EACP,EACA,EACA,EACQ,CACR,GACE,OAAO,GAAU,UACjB,CAAC,OAAO,SAAS,CAAK,GACtB,EAAQ,GACR,EAAQ,EAER,MAAU,UAAU,mCAAmC,EAEzD,OAAO,CACT,CAEA,SAAS,EACP,EACA,EACe,CACf,OAAO,IAAU,KAAO,KAAO,EAAiB,EAAO,CAAO,CAChE,CAEA,SAAS,EAAmB,EAA0C,CACpE,GAAI,IAAU,YAAc,IAAU,WAAa,IAAU,WAC3D,OAAO,EAGT,MAAU,UAAU,sCAAsC,CAC5D,CAEA,SAAS,EAAiB,EAAoC,CAC5D,GAAI,IAAU,SAAW,IAAU,SACjC,OAAO,EAGT,MAAU,UAAU,oCAAoC,CAC1D,CAEA,SAAS,EAAmB,EAA0C,CACpE,GACE,IAAU,mBACV,IAAU,UACV,IAAU,WACV,IAAU,UAEV,OAAO,EAGT,MAAU,UAAU,sCAAsC,CAC5D,CAEA,SAAS,EACP,EACmC,CACnC,GAAI,IAAU,KACZ,OAAO,KAET,IAAM,EAAW,EAAY,CAAK,EAClC,GAAI,EAAS,SAAW,cAAgB,EAAS,SAAW,aAC1D,MAAU,UAAU,uCAAuC,EAE7D,IAAM,EAAS,EAAS,OACxB,MAAO,CACL,cAAe,EAAkB,EAAS,cAAe,EAAG,GAAG,EAC/D,QACF,CACF,CAEA,SAAS,EAAkB,EAAyC,CAClE,IAAM,EAAS,IAAU,IAAA,GAAY,CAAC,EAAI,EAAY,CAAK,EAE3D,MAAO,CACL,SAAU,EAAqB,EAAO,SAAU,EAAK,EACrD,UAAW,EAAqB,EAAO,UAAW,EAAK,EACvD,MAAO,EAAqB,EAAO,MAAO,EAAK,EAC/C,UAAW,EAAqB,EAAO,UAAW,EAAK,EACvD,WAAY,EAAqB,EAAO,WAAY,EAAK,EACzD,SAAU,EAAqB,EAAO,SAAU,EAAK,EACrD,QAAS,EAAqB,EAAO,QAAS,EAAK,CACrD,CACF,CAEA,SAAS,EAAmB,EAA+B,CACzD,IAAM,EAAU,EAAY,CAAK,EAEjC,MAAO,CACL,YAAa,EAAyB,EAAQ,YAAa,CAAC,EAC5D,YAAa,EAA4B,EAAQ,YAAa,IAAI,EAClE,GAAI,EAAoB,EAAQ,EAAE,EAClC,kBAAmB,EAAyB,EAAQ,kBAAmB,CAAC,EACxE,YAAa,EAAyB,EAAQ,YAAa,CAAC,EAC5D,mBAAoB,EAAyB,EAAQ,mBAAoB,CAAC,EAC1E,YAAa,EAAyB,EAAQ,YAAa,CAAC,EAC5D,KAAM,EAAoB,EAAQ,IAAI,EACtC,cAAe,EAAmB,EAAQ,aAAa,EACvD,YAAa,EAAiB,EAAQ,WAAW,CACnD,CACF,CAEA,SAAS,EAAoB,EAAsC,CACjE,IAAM,EAAU,EAAY,CAAK,EAEjC,MAAO,CACL,iBAAkB,EAAqB,EAAQ,iBAAkB,EAAK,EACtE,GAAI,EAAoB,EAAQ,EAAE,EAClC,QAAS,EAAmB,EAAQ,OAAO,EAC3C,UAAW,EAAoB,EAAQ,SAAS,EAChD,KAAM,EAAoB,EAAQ,IAAI,CACxC,CACF,CAEA,SAAgB,EAAkB,EAA8B,CAC9D,IAAM,EAAS,EAAY,CAAK,EAC1B,EAAS,EAAO,SAAW,IAAA,GAAY,CAAC,EAAI,EAAY,EAAO,MAAM,EACrE,EACJ,EAAO,gBAAkB,IAAA,GACrB,CAAE,SAAU,MAAO,0BAA2B,CAAE,EAChD,EAAY,EAAO,aAAa,EAChC,EAAW,EAAO,WAAa,IAAA,GAAY,CAAC,EAAI,EAAO,SAC7D,GAAI,CAAC,MAAM,QAAQ,CAAQ,EACzB,MAAU,UAAU,2BAA2B,EAEjD,GAAI,EAAc,WAAa,MAC7B,MAAU,UAAU,uCAAuC,EAG7D,MAAO,CACL,OAAQ,CACN,aAAc,EAAkB,EAAO,YAAY,EACnD,OAAQ,EAAkB,EAAO,MAAM,CACzC,EACA,YAAa,EAA4B,EAAO,YAAa,IAAI,EACjE,GAAI,EAAoB,EAAO,GAAI,EAAE,EACrC,KAAM,EAAoB,EAAO,KAAM,oBAAoB,EAC3D,cAAe,CACb,SAAU,MACV,0BAA2B,EACzB,EAAc,0BACd,CACF,CACF,EACA,SAAU,EAAS,IAAI,CAAmB,EAC1C,sBAAuB,EACrB,EAAO,sBACP,EACF,EACA,MAAO,EAA4B,EAAO,MAAO,IAAI,CACvD,CACF,CAEA,SAAS,EAAsB,EAA6C,CAC1E,IAAM,EAAW,EAAY,CAAK,EAElC,MAAO,CACL,iBAAkB,EAAa,EAAS,gBAAgB,EACxD,UAAW,EAAoB,EAAS,SAAS,EACjD,YAAa,EAAoB,EAAS,WAAW,EACrD,cAAe,EAAmB,EAAS,aAAa,EACxD,YAAa,EAAiB,EAAS,WAAW,EAClD,UAAW,EAAoB,EAAS,SAAS,EACjD,YAAa,EAAoB,EAAS,WAAW,EACrD,SAAU,EAAiB,EAAS,SAAU,CAAC,EAC/C,cAAe,EAAiB,EAAS,cAAe,CAAC,EACzD,gBAAiB,EAAiB,EAAS,gBAAiB,CAAC,CAC/D,CACF,CAEA,SAAgB,EAAmB,EAAqC,CACtE,IAAM,EAAQ,EAAY,CAAK,EAC/B,GAAI,CAAC,MAAM,QAAQ,EAAM,SAAS,EAChC,MAAU,UAAU,6BAA6B,EAGnD,MAAO,CACL,YAAa,EAAiB,EAAM,YAAa,CAAC,EAClD,gBAAiB,EAAqB,EAAM,eAAe,EAC3D,mBACE,EAAM,qBAAuB,KACzB,KACA,EAAoB,EAAM,kBAAkB,EAClD,0BAA2B,EACzB,EAAM,0BACN,CACF,EACA,cAAe,EAAiB,EAAM,cAAe,CAAC,EACtD,UAAW,EAAM,UAAU,IAAI,CAAqB,EACpD,cAAe,EAAmB,EAAM,aAAa,EACrD,gBAAiB,EAAiB,EAAM,gBAAiB,CAAC,EAC1D,cAAe,EAAiB,EAAM,cAAe,CAAC,EACtD,SAAU,EAAiB,EAAM,SAAU,CAAC,EAC5C,WAAY,EAAiB,EAAM,WAAY,CAAC,CAClD,CACF,CAEA,SAAgB,EAAmB,EAA0C,CAC3E,IAAM,EAAgB,EAAY,CAAK,EAEvC,MAAO,CACL,WAAY,EAAoB,EAAc,UAAU,EACxD,eAAgB,EAAmB,EAAc,cAAc,EAC/D,aAAc,EAAoB,EAAc,YAAY,EAC5D,iBAAkB,EAAoB,EAAc,gBAAgB,EACpE,eAAgB,EAAa,EAAc,cAAc,EACzD,OAAQ,EAAoB,EAAc,MAAM,CAClD,CACF,CCxOA,MAAM,EAAyB,IAE/B,SAAS,EAAgB,EAAe,EAAiB,CACvD,GAAI,CAAC,OAAO,cAAc,CAAK,GAAK,EAAQ,EAC1C,MAAU,UAAU,CAAO,EAE7B,OAAO,CACT,CAEA,SAAS,EAAS,EAAc,EAAe,CAC7C,OAAO,EACL,EAAO,EACP,2CACF,CACF,CAEA,SAAS,EAAc,EAAe,EAAkB,CACtD,OAAO,EACL,EAAQ,EACR,yDACF,CACF,CAEA,SAAS,EAAqB,EAAe,EAAqB,CAChE,IAAM,GACH,OAAO,CAAK,EAAI,OAAO,CAAW,EAAI,OAAO,EAAyB,CAAC,GACxE,OAAO,CAAsB,EAC/B,GAAI,EAAU,cAA8B,EAC1C,MAAU,UAAU,2CAA2C,EAEjE,OAAO,OAAO,CAAO,CACvB,CAEA,SAAgB,EACd,EACA,EACA,EAC4B,CAC5B,IAAI,EAAgB,EAChB,EAA4B,EAEhC,IAAK,IAAM,KAAQ,EAAU,MAAO,CAClC,IAAM,EAAU,EAAQ,SAAS,MAC9B,CAAE,KAAI,UAAW,IAAO,EAAK,WAAa,IAAS,EAAK,WAC3D,EACA,GAAI,CAAC,EACH,MAAU,UAAU,8CAA8C,EAEpE,GAAI,EAAQ,gBAAkB,WAC5B,MAAU,UACR,gEACF,EAEF,IAAM,EACJ,aAAc,EACV,EAAc,EAAQ,aAAe,EAAG,EAAK,QAAQ,EACrD,EAAK,YACX,EAAgB,EAAS,EAAe,CAAY,EAChD,EAAQ,mBACV,EAA4B,EAC1B,EACA,CACF,EAEJ,CAEA,IAAM,EAAkB,EAAM,kBAC1B,EACE,EACA,EAAQ,cAAc,yBACxB,EACA,EACE,EAAW,EAAM,UAAY,EAC7B,EAAc,EAAS,EAAe,CAAe,EAE3D,MAAO,CACL,cACA,gBAAiB,KACjB,cAAe,GACf,4BACA,cAAe,EACf,kBACA,gBACA,WACA,WAAY,EAAS,EAAa,CAAQ,CAC5C,CACF,CCpFA,SAAS,EAAW,EAAmD,CACrE,GAAM,CAAE,WAAY,EAEpB,MAAO,CACL,iBAAkB,EAAQ,kBAAoB,GAC9C,YAAa,EAAQ,YACrB,YAAa,EAAQ,aAAe,KACpC,GAAI,EAAQ,GACZ,kBAAmB,EAAQ,kBAC3B,UAAW,EAAQ,GACnB,gBAAiB,EAAQ,YACzB,mBAAoB,EAAQ,mBAC5B,gBAAiB,EAAQ,YACzB,KAAM,EAAQ,KACd,cAAe,EAAQ,cACvB,YAAa,EAAQ,YACrB,KAAM,EAAQ,IAChB,CACF,CAEA,SAAgB,EACd,EACA,EACoB,CACpB,IAAM,EAAS,EAAO,QAAQ,QAAU,CAAC,EAEzC,MAAO,CACL,QAAS,CACP,SAAU,MACV,gBACF,EACA,cAAe,CACb,SAAU,MACV,0BACE,EAAO,eAAe,2BAA6B,CACvD,EACA,UAAW,EAAO,UAAY,CAAC,EAAA,CAAG,IAAI,CAAU,EAChD,OAAQ,CACN,aAAc,EAAO,QAAQ,cAAgB,CAAC,EAC9C,YAAa,EAAO,aAAe,KACnC,OAAQ,CACN,SAAU,EAAO,UAAY,GAC7B,UAAW,EAAO,WAAa,GAC/B,MAAO,EAAO,OAAS,GACvB,UAAW,EAAO,WAAa,GAC/B,WAAY,EAAO,YAAc,GACjC,SAAU,EAAO,UAAY,GAC7B,QAAS,EAAO,SAAW,EAC7B,EACA,GAAI,EAAO,IAAM,GACjB,KAAM,EAAO,MAAQ,qBACrB,sBAAuB,EAAO,uBAAyB,GACvD,MAAO,EAAO,OAAS,IACzB,CACF,CACF,CAEA,SAAgB,EAAa,EAAiD,CAC5E,OAAO,EAAW,CAChB,QAAS,CAAE,GAAG,EAAQ,OAAQ,EAC9B,cAAe,CAAE,GAAG,EAAQ,aAAc,EAC1C,SAAU,EAAQ,SAAS,IAAK,IAAa,CAAE,GAAG,CAAQ,EAAE,EAC5D,OAAQ,CACN,GAAG,EAAQ,OACX,aAAc,EAAQ,OAAO,aAAa,IAAK,GAC7C,YAAa,EACT,CACE,GAAG,EACH,QAAS,EAAM,QAAQ,IAAK,IAAY,CAAE,GAAG,CAAO,EAAE,CACxD,EACA,CAAE,GAAG,CAAM,CACjB,EACA,OAAQ,CAAE,GAAG,EAAQ,OAAO,MAAO,CACrC,CACF,CAAC,CACH,CAEA,SAAgB,EACd,EAC0B,CAC1B,OAAO,EAAW,CAChB,GAAG,EACH,gBAAiB,EAAM,gBACnB,CAAE,GAAG,EAAM,eAAgB,EAC3B,KACJ,UAAW,EAAM,UAAU,IAAK,IAAc,CAAE,GAAG,CAAS,EAAE,EAC9D,QAAS,CAAE,GAAG,EAAM,OAAQ,CAC9B,CAAC,CACH,CAEA,SAAgB,EACd,EAC0B,CAC1B,OAAO,EAAW,CAAE,GAAG,CAAc,CAAC,CACxC,CCxEA,SAAgB,EACd,EACmB,CACnB,GAAM,CACJ,aACA,gBACA,qBACA,cACA,sBACA,UACA,YACA,uBACA,aACA,mBACE,EAAyB,CAAO,EAChC,EAAqC,KACrC,EAAmD,KACnD,EAAiE,KACjE,EAAwC,KACxC,EAAmD,KACnD,EAAkB,EAClB,EAAgB,EAChB,EAAa,GACX,EAAY,IAAI,IAIhB,EAAa,EAAyC,CAC1D,MAAO,OACP,UAAW,EAAW,CAAE,MAAO,CAAC,CAAE,CAAC,CACrC,CAAC,EAED,SAAS,EAAW,EAAqB,CACvC,IAAM,EAAiB,EACjB,EAAU,EACZ,EAAe,SAAS,MAAM,CAAE,UAAW,IAAS,CAAW,EAC/D,IAAA,GAEJ,GAAI,CAAC,EACH,MAAU,MAAM,wBAAwB,EAAY,kBAAkB,EAGxE,OAAO,CACT,CAEA,IAAM,EAAc,EAAuB,CACzC,cAAe,EACf,cACA,gBAAmB,CACjB,iBAAkB,EAClB,WAAY,CACd,GACA,UACA,oBAAqB,qBACrB,WACF,CAAC,EAED,SAAS,EACP,EACA,EAAqC,mBAC9B,CACP,MAAM,EACJ,IAAI,EAAoB,CACtB,KAAM,oBACN,UACA,YACA,WAAY,EACd,CAAC,CACH,CACF,CAEA,GAAM,CAAE,gBAAe,qBAAsB,EAC3C,EACA,CACF,EAEA,SAAS,GAAqC,CAC5C,IAAM,EAAiB,EACvB,OAAO,EAAW,CAChB,OAAQ,EAAiB,EAAe,SAAW,CAAC,EAAA,CAAG,QACpD,GAAY,CACX,IAAM,EAAW,EAAU,IAAI,EAAQ,IAAI,EAC3C,OAAO,EACH,CACE,CACE,UAAW,EAAQ,GACnB,YAAa,EAAQ,KACrB,GAAG,CACL,CACF,EACA,CAAC,CACP,CACF,CACF,CAAC,CACH,CAEA,SAAS,GAA4B,CACnC,EAAkB,KAClB,EAAyB,KACzB,EAAyB,KACzB,EAAgB,IAClB,CAEA,SAAS,GAAyB,CAC5B,GACF,EACE,6DACF,CAEJ,CAEA,SAAS,EAAyB,EAAoC,CAChE,GACF,EACE,gEACA,CACF,CAEJ,CAEA,SAAS,GAAc,CACrB,GAAiB,EACjB,EAA0B,CAC5B,CAEA,SAAS,EAAY,EAA6C,KAAM,CACjE,GAGL,EAAW,OAAO,CAChB,UACA,MAAO,QACP,UACA,UAAW,EAAa,CAC1B,CAAC,CACH,CAEA,SAAS,EACP,EACA,EAA6C,KAC7C,CACA,EAAW,OAAO,CAChB,UACA,QACA,MAAO,QACP,8BACA,UAAW,EAAa,CAC1B,CAAC,CACH,CAEA,SAAS,EACP,EACA,EACA,CAEE,OAA2B,GAC3B,IAA6B,EAK/B,MAAM,EACJ,IAAI,EAAoB,CACtB,KAAM,2BACN,QACE,uGACF,UAAW,kBACX,WAAY,EACd,CAAC,CACH,CACF,CAEA,SAAS,EAAa,EAAyC,CAAC,EAAG,CAEjE,GADA,EAAyB,iBAAiB,EACtC,CAAC,EACH,MAAU,MACR,0DACF,EAEE,EAAU,OAAS,GACrB,EAAiB,gDAAgD,EAEnE,IAAM,EAAkB,EAAsB,EAAS,CAAK,EAC5D,EAAY,EAEZ,GAAI,CACF,IAAM,EAAU,EACd,EAAyB,EAAS,EAAa,EAAG,CAAe,CACnE,EAGA,MAFA,GAAgB,EAChB,EAAY,CAAO,EACZ,CACT,OAAS,EAAO,CACd,EACE,aAAiB,MAAQ,EAAM,QAAU,6BAC3C,CACF,CACF,CAEA,SAAS,EACP,EACA,EACiC,CACjC,EAAqB,EAAgB,CAAK,EAC1C,IAAM,EAAW,EAAM,UAAY,EAC7B,EAAQ,EAAM,OAAO,KAAK,CAAC,CAAC,YAAY,EACxC,EAAY,EAAM,WAAW,KAAK,EACxC,MAAO,CACL,GAAI,EAAQ,CAAE,OAAM,EAAI,CAAC,EACzB,GAAI,EAAM,oBAAsB,IAAA,GAC5B,CAAC,EACD,CAAE,kBAAmB,EAAM,iBAAkB,EACjD,GAAI,EAAY,CAAE,WAAU,EAAI,CAAC,EACjC,GAAI,EAAM,WAAa,IAAA,GAAY,CAAC,EAAI,CAAE,UAAS,CACrD,CACF,CAEA,SAAS,EACP,EACA,EACA,CACA,IAAM,EAAW,EAAM,UAAY,GAC/B,CAAC,OAAO,cAAc,CAAQ,GAAK,EAAW,IAChD,EAAiB,mDAAmD,EAElE,EAAM,mBAAqB,CAAC,EAAe,OAAO,OAAO,YAC3D,EAAiB,6CAA6C,EAG9D,EAAM,mBACN,EAAe,cAAc,4BAA8B,GAE3D,EACE,sEACF,EAEE,EAAW,GAAK,CAAC,EAAe,OAAO,OAAO,SAChD,EAAiB,yCAAyC,CAE9D,CAEA,eAAe,EAAe,EAAyC,CAAC,EAAG,CAEzE,GADA,EAAyB,iBAAiB,EACtC,CAAC,EACH,MAAU,MACR,2DACF,EAGF,IAAM,EAAkB,EAAsB,EAAS,CAAK,EACxD,EAAU,OAAS,GACrB,EACE,4DACA,iBACF,EAEF,IAAM,EAAmB,EAAa,EAChC,EAAU,EACd,EAAyB,EAAS,EAAkB,CAAe,CACrE,EACA,EAAgB,EAChB,EAAW,OAAO,CAChB,UACA,MAAO,UACP,UACA,UAAW,CACb,CAAC,EACD,IAAM,EAAQ,EAAiB,MAAM,KAClC,CAAE,YAAa,EAAc,GAAG,KAAW,CAC9C,EACM,EAAyB,EACzB,EAA2B,EAAkB,EACnD,EAAkB,EAClB,EAAkB,KAClB,EAAyB,KACzB,IAAI,EAEJ,GAAI,CACF,EAAW,MAAM,EACf,GAAG,EAAW,gBAAgB,EAAc,mBAAmB,EAAW,iBAC1E,CACE,KAAM,KAAK,UAAU,CAAE,GAAG,EAAiB,OAAM,CAAC,EAClD,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,OAAQ,MACV,EACA,CACE,KAAM,2BACN,QACE,iFACF,UAAW,kBACX,OAAQ,EACV,CACF,CACF,OAAS,EAAO,CAMd,MALA,EAAsB,EAAwB,CAAwB,EAClE,aAAiB,GACnB,EAAY,CAAK,EACX,EAAY,CAAK,GAEnB,CACR,CAIA,GAFA,EAAsB,EAAwB,CAAwB,EAElE,CAAC,EAAS,GAAI,CAChB,IAAM,EAAQ,IAAI,EAAoB,CACpC,KAAM,2BACN,QAAS,uDAAuD,EAAS,OAAO,IAChF,UAAW,kBACX,WAAY,EAAS,QAAU,IAC/B,OAAQ,EAAS,MACnB,CAAC,EAED,MADA,EAAY,CAAK,EACX,EAAY,CAAK,CACzB,CAEA,IAAI,EACJ,GAAI,CAOF,GANA,EAAc,MAAM,EAAkB,EAAU,EAAoB,CAClE,KAAM,2BACN,QAAS,kDACT,UAAW,kBACX,OAAQ,EACV,CAAC,EACG,EAAY,gBAAkB,WAChC,MAAM,IAAI,EAAoB,CAC5B,KAAM,2BACN,QAAS,wDACT,UAAW,kBACX,WAAY,EACd,CAAC,CAEL,OAAS,EAAO,CAMd,MALA,EAAsB,EAAwB,CAAwB,EAClE,aAAiB,GACnB,EAAY,CAAK,EACX,EAAY,CAAK,GAEnB,CACR,CACA,EAAsB,EAAwB,CAAwB,EACtE,IAAM,EAAmB,WAAW,OAAO,WAAW,EAChD,CACJ,qBACA,cAAe,EACf,GAAG,GACD,EACE,EAAsB,EAAW,CACrC,GAAG,EACH,cAAe,GACf,QAAS,CACP,GAAG,EAAQ,QACX,oBACF,EACA,cAAe,WACf,kBACF,CAAC,EAWD,MAVA,GAAkB,EAClB,EAAyB,EAAW,CAAE,GAAG,CAAgB,CAAC,EAC1D,EAAyB,EACzB,EAAW,OAAO,CAChB,UACA,MAAO,SACP,UACA,MAAO,EACP,UAAW,CACb,CAAC,EACM,EAAmB,CAAmB,CAC/C,CAEA,MAAO,CACL,iBACA,OAAQ,CACN,EAAuB,EACvB,EAAU,MAAM,EAChB,EAAY,EACZ,EAAY,CACd,EACA,MAAM,iBAAiB,EAAmB,GAA0B,GAAI,CACtE,EAAyB,oBAAoB,EACxC,GACH,EACE,qDACA,oBACF,EAEF,EAAyB,EACzB,IAAM,EAAmB,EAAa,EACtC,EAAW,OAAO,CAChB,UACA,mBACA,MAAO,aACP,UAAW,CACb,CAAC,EACD,GAAI,CACF,IAAM,EAAW,MAAM,EACrB,GAAG,EAAW,gBAAgB,EAAc,mBAAmB,EAAW,YAAY,mBAAmB,CAAgB,EAAE,SAC3H,IAAA,GACA,CACE,KAAM,wBACN,QACE,+EACF,UAAW,oBACb,CACF,EAEA,GAAI,CAAC,EAAS,GACZ,MAAM,EACJ,IAAI,EAAoB,CACtB,KAAM,wBACN,QAAS,qDAAqD,EAAS,OAAO,IAC9E,UAAW,qBACX,WAAY,EAAS,QAAU,IAC/B,OAAQ,EAAS,MACnB,CAAC,CACH,EAGF,IAAM,EAAU,EACd,MAAM,EAAkB,EAAU,EAAoB,CACpD,KAAM,wBACN,QAAS,kDACT,UAAW,oBACb,CAAC,CACH,EAWA,OAVA,EAAW,OAAO,CAChB,UACA,UACA,MAAO,UACP,MACE,GAAiB,mBAAqB,EAClC,EACA,KACN,UAAW,CACb,CAAC,EACM,EAAmB,CAAO,CACnC,OAAS,EAAO,CAId,MAHI,aAAiB,GACnB,EAAY,EAAO,CAAgB,EAE/B,CACR,CACF,EACA,eACA,SAAU,EAAW,SACrB,MAAM,MAAO,CACX,EAAyB,aAAa,EACtC,EAAY,EACZ,EAAW,OAAO,CAAE,MAAO,UAAW,UAAW,EAAa,CAAE,CAAC,EACjE,IAAM,EAAiB,CACrB,KAAM,qBACN,QACE,gEACF,UAAW,cACX,OAAQ,EACV,EACI,EAEJ,GAAI,CACF,EAAiB,MAAM,EACrB,GAAG,EAAW,gBAAgB,EAAc,mBAAmB,IAC/D,IAAA,GACA,CACF,CACF,OAAS,EAAO,CAKd,MAJI,aAAiB,GACnB,EAAY,CAAK,EACX,EAAY,CAAK,GAEnB,CACR,CAEA,GAAI,CAAC,EAAe,GAAI,CACtB,IAAM,EAAQ,IAAI,EAAoB,CACpC,KAAM,qBACN,QAAS,sCAAsC,EAAe,OAAO,IACrE,UAAW,cACX,WAAY,EAAe,QAAU,IACrC,OAAQ,EAAe,MACzB,CAAC,EAED,MADA,EAAY,CAAK,EACX,EAAY,CAAK,CACzB,CAEA,IAAM,EAAS,MAAM,EACnB,EACA,EACA,CACE,KAAM,qBACN,QAAS,kDACT,UAAW,aACb,CACF,EAMA,OAJA,EAAU,MAAM,EAChB,EAAU,EAAW,EAAc,EAAQ,CAAoB,CAAC,EAChE,EAAY,EAEL,EAAa,CAAO,CAC7B,EACA,eACA,OAAO,EAAa,CAClB,EAAuB,EACvB,EAAU,OAAO,CAAW,EAC5B,EAAY,EACZ,EAAY,CACd,EACA,UAAU,EAAa,EAAa,CAClC,EAAuB,EACvB,IAAM,EAAU,EAAW,CAAW,EAElC,EAAQ,cAAgB,UAC1B,EAAiB,oDAAoD,GAEnE,CAAC,OAAO,cAAc,CAAW,GAAK,GAAe,IACvD,EAAiB,qDAAqD,EAGtE,EAAQ,qBAAuB,MAC/B,EAAc,EAAQ,oBAEtB,EACE,mCAAmC,EAAQ,mBAAmB,QAChE,EAGF,EAAU,IAAI,EAAa,CAAE,aAAY,CAAC,EAC1C,EAAY,EACZ,EAAY,CACd,EACA,YAAY,EAAa,EAAU,CACjC,EAAuB,EACvB,IAAM,EAAU,EAAW,CAAW,EAElC,EAAQ,cAAgB,SAC1B,EAAiB,kDAAkD,GAEjE,CAAC,OAAO,cAAc,CAAQ,GAAK,GAAY,IACjD,EAAiB,8CAA8C,EAG/D,EAAQ,kBAAoB,MAC5B,EAAW,EAAQ,iBAEnB,EACE,qCAAqC,EAAQ,gBAAgB,EAC/D,EAGA,EAAQ,kBAAoB,MAC5B,EAAW,EAAQ,iBAEnB,EACE,oCAAoC,EAAQ,gBAAgB,EAC9D,EAGA,EAAQ,oBAAsB,MAC9B,EAAW,EAAQ,mBAEnB,EAAiB,4CAA4C,EAG/D,EAAU,IAAI,EAAa,CAAE,UAAS,CAAC,EACvC,EAAY,EACZ,EAAY,CACd,EACA,MAAM,cAAc,EAAY,CACxB,GAAW,GAAmB,GAClC,EACE,2DACA,gBACF,EAEE,GACF,EACE,oDACA,gBACF,EAGF,IAAM,EAAqB,EACrB,EAAmB,EACnB,EAA0B,EAC1B,EAAuB,EAAa,EACpC,EACJ,GACA,EACE,EACA,EACA,CACF,EACI,EAAkB,EAAW,MAAM,KAAK,CAAC,CAAC,YAAY,GAE1D,CAAC,GACD,IAAoB,EAAwB,QAE5C,EACE,uDACA,gBACF,EAGF,IAAM,EAAQ,EAAqB,MAAM,KACtC,CAAE,YAAa,EAAc,GAAG,KAAW,CAC9C,EACA,EAAa,GACb,EAAW,OAAO,CAChB,QAAS,EACT,MAAO,aACP,QAAS,EACT,MAAO,EACP,UAAW,CACb,CAAC,EACD,GAAI,CACF,IAAM,EAAW,MAAM,EACrB,GAAG,EAAW,gBAAgB,EAAc,mBAAmB,EAAW,mBAC1E,CACE,KAAM,KAAK,UAAU,CACnB,kBAAmB,EAAW,kBAC9B,mBAAoB,EAAW,mBAC/B,MAAO,EACP,oBAAqB,EAAiB,YACtC,wBAAyB,EAAiB,gBAC1C,2BACE,EAAiB,QAAQ,mBAC3B,kCACE,EAAiB,0BACnB,sBAAuB,EAAiB,cACxC,wBAAyB,EAAiB,gBAC1C,sBAAuB,EAAiB,cACxC,iBAAkB,EAAiB,SACnC,mBAAoB,EAAiB,WACrC,GAAG,EACH,QACA,SAAU,EAAW,SACrB,UAAW,EAAW,UACtB,SAAU,EAAW,SACrB,iBAAkB,EAAiB,iBACnC,MAAO,EAAW,MAClB,qBAAsB,CACxB,CAAC,EACD,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,OAAQ,MACV,EACA,CACE,KAAM,wBACN,QACE,uEACF,UAAW,gBACb,CACF,EAEA,GAAI,CAAC,EAAS,GACZ,MAAM,EACJ,IAAI,EAAoB,CACtB,KAAM,wBACN,QAAS,6CAA6C,EAAS,OAAO,IACtE,UAAW,iBACX,WAAY,EAAS,QAAU,IAC/B,OAAQ,EAAS,MACnB,CAAC,CACH,EAGF,IAAM,EAAU,EACd,MAAM,EAAkB,EAAU,EAAoB,CACpD,KAAM,wBACN,QAAS,wDACT,UAAW,gBACb,CAAC,CACH,EAQA,OAPA,EAAW,OAAO,CAChB,QAAS,EACT,UACA,MAAO,UACP,MAAO,EACP,UAAW,CACb,CAAC,EACM,EAAmB,CAAO,CACnC,OAAS,EAAO,CAId,MAHI,aAAiB,GACnB,EAAY,EAAO,EAAiB,gBAAgB,EAEhD,CACR,QAAU,CACR,EAAa,EACf,CACF,EACA,UAAW,EAAW,SACxB,CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { D as LockerverseSdkOperation, E as LockerverseSdkErrorCode, T as LockerverseSdkError, _ as LockerverseEnvironment, n as LOCKERVERSE_SDK_VERSION } from "./types.js";
|
|
2
|
+
export { LOCKERVERSE_SDK_VERSION, type LockerverseEnvironment, LockerverseSdkError, type LockerverseSdkErrorCode, type LockerverseSdkOperation };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e,t}from"./types.js";export{t as LOCKERVERSE_SDK_VERSION,e as LockerverseSdkError};
|
package/dist/signup.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { T as LockerverseSdkError, _ as LockerverseEnvironment, g as LockerverseCustomFieldOption, h as LockerverseCustomFieldAnswerValue, m as LockerverseCustomFieldAnswer, p as LockerverseCustomField } from "./types.js";
|
|
2
|
+
//#region src/signup-types.d.ts
|
|
3
|
+
type LockerverseSignupField = {
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
required: boolean;
|
|
6
|
+
};
|
|
7
|
+
type LockerverseSignupFields = {
|
|
8
|
+
address: LockerverseSignupField;
|
|
9
|
+
email: LockerverseSignupField;
|
|
10
|
+
name: LockerverseSignupField;
|
|
11
|
+
participantCount: LockerverseSignupField;
|
|
12
|
+
phone: LockerverseSignupField;
|
|
13
|
+
};
|
|
14
|
+
type LockerverseSignup = {
|
|
15
|
+
coverImageUrl: string | null;
|
|
16
|
+
customFields: LockerverseCustomField[];
|
|
17
|
+
description: string | null;
|
|
18
|
+
fields: LockerverseSignupFields;
|
|
19
|
+
id: string;
|
|
20
|
+
isActive: boolean;
|
|
21
|
+
name: string;
|
|
22
|
+
slug: string;
|
|
23
|
+
title: string | null;
|
|
24
|
+
};
|
|
25
|
+
type LockerverseSignupAddress = {
|
|
26
|
+
city: string;
|
|
27
|
+
country: string;
|
|
28
|
+
line1: string;
|
|
29
|
+
line2?: string | null;
|
|
30
|
+
postalCode: string;
|
|
31
|
+
state: string;
|
|
32
|
+
};
|
|
33
|
+
type LockerverseSignupSubmission = {
|
|
34
|
+
address?: LockerverseSignupAddress | null;
|
|
35
|
+
answers?: LockerverseCustomFieldAnswer[];
|
|
36
|
+
email?: string | null;
|
|
37
|
+
honeypot?: string;
|
|
38
|
+
name: string;
|
|
39
|
+
participantCount?: number | null;
|
|
40
|
+
phone?: string | null;
|
|
41
|
+
};
|
|
42
|
+
type LockerverseSignupSubmissionResult = {
|
|
43
|
+
id: string;
|
|
44
|
+
submittedAt: string;
|
|
45
|
+
};
|
|
46
|
+
type CreateLockerverseSignupBaseOptions = {
|
|
47
|
+
communitySlug: string;
|
|
48
|
+
fetch?: typeof globalThis.fetch;
|
|
49
|
+
onError?: (error: LockerverseSdkError) => void;
|
|
50
|
+
sentryDsn?: string | null;
|
|
51
|
+
signupSlug: string;
|
|
52
|
+
};
|
|
53
|
+
type CreateLockerverseSignupOptions = CreateLockerverseSignupBaseOptions & ({
|
|
54
|
+
apiBaseUrl: string;
|
|
55
|
+
environment: LockerverseEnvironment;
|
|
56
|
+
} | {
|
|
57
|
+
apiBaseUrl?: undefined;
|
|
58
|
+
environment?: "production";
|
|
59
|
+
});
|
|
60
|
+
type LockerverseSignupState = {
|
|
61
|
+
phase: "idle";
|
|
62
|
+
} | {
|
|
63
|
+
phase: "loading";
|
|
64
|
+
} | {
|
|
65
|
+
phase: "ready";
|
|
66
|
+
signup: LockerverseSignup;
|
|
67
|
+
} | {
|
|
68
|
+
phase: "submitting";
|
|
69
|
+
signup: LockerverseSignup;
|
|
70
|
+
} | {
|
|
71
|
+
phase: "submitted";
|
|
72
|
+
signup: LockerverseSignup;
|
|
73
|
+
submission: LockerverseSignupSubmissionResult;
|
|
74
|
+
} | {
|
|
75
|
+
phase: "error";
|
|
76
|
+
error: LockerverseSdkError;
|
|
77
|
+
signup: LockerverseSignup | null;
|
|
78
|
+
};
|
|
79
|
+
type LockerverseSignupClient = {
|
|
80
|
+
getState: () => LockerverseSignupState;
|
|
81
|
+
load: () => Promise<LockerverseSignup>;
|
|
82
|
+
submit: (submission: LockerverseSignupSubmission) => Promise<LockerverseSignupSubmissionResult>;
|
|
83
|
+
subscribe: (listener: (state: LockerverseSignupState) => void) => () => void;
|
|
84
|
+
};
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/signup.d.ts
|
|
87
|
+
declare function createLockerverseSignup(options: CreateLockerverseSignupOptions): LockerverseSignupClient;
|
|
88
|
+
//#endregion
|
|
89
|
+
export { type CreateLockerverseSignupOptions, type LockerverseCustomField, type LockerverseCustomFieldAnswer, type LockerverseCustomFieldAnswerValue, type LockerverseCustomFieldOption, type LockerverseEnvironment, type LockerverseSignup, type LockerverseSignupAddress, type LockerverseSignupClient, type LockerverseSignupField, type LockerverseSignupFields, type LockerverseSignupState, type LockerverseSignupSubmission, type LockerverseSignupSubmissionResult, createLockerverseSignup };
|
|
90
|
+
//# sourceMappingURL=signup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signup.d.ts","names":[],"sources":["../src/signup-types.ts","../src/signup.ts"],"mappings":";;KAOY;EACV;EACA;;KAGU;EACV,SAAS;EACT,OAAO;EACP,MAAM;EACN,kBAAkB;EAClB,OAAO;;KAGG;EACV;EACA,cAAc;EACd;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA;;KAGU;EACV;EACA;EACA;EACA;EACA;EACA;;KAGU;EACV,UAAU;EACV,UAAU;EACV;EACA;EACA;EACA;EACA;;KAGU;EACV;EACA;;KAGG;EACH;EACA,eAAe,WAAW;EAC1B,WAAW,OAAO;EAClB;EACA;;KAGU,iCACV;EAGQ;EACA,aAAa;;EAGb;EACA;;KAIE;EACN;;EACA;;EACA;EAAgB,QAAQ;;EACxB;EAAqB,QAAQ;;EAE7B;EACA,QAAQ;EACR,YAAY;;EAGZ;EACA,OAAO;EACP,QAAQ;;KAGF;EACV,gBAAgB;EAChB,YAAY,QAAQ;EACpB,SACE,YAAY,gCACT,QAAQ;EACb,YAAY,WAAW,OAAO;;;;iBCjFhB,wBACd,SAAS,iCACR"}
|
package/dist/signup.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as e,c as t,d as n,f as r,i,m as a,n as o,r as s,t as c,u as l}from"./transport.js";import{n as u}from"./types.js";function d(e){let t=l(e);return{enabled:s(t.enabled),required:s(t.required)}}function f(e){let t=l(e);return{address:d(t.address),email:d(t.email),name:d(t.name),participantCount:d(t.participantCount),phone:d(t.phone)}}function p(n){let r=l(n),a=l(r.config);return{coverImageUrl:t(r.coverImageUrl,null),customFields:i(a.customFields),description:t(r.description,null),fields:f(a.builtInFields),id:e(r.id),isActive:s(r.isActive),name:e(r.name),slug:e(r.slug),title:t(r.title,null)}}function m(t){let n=l(t),r=e(n.submittedAt);if(Number.isNaN(Date.parse(r)))throw TypeError(`Expected a submission timestamp.`);return{id:e(n.id),submittedAt:r}}function h(e){let t=a(e),i=o({phase:`idle`}),s=null,l=!1,d=!1,f=n({communitySlug:t.communitySlugValue,environment:t.environment,getContext:()=>({signupSlug:t.signupSlugValue}),onError:t.onError,resourceContextName:`lockerverse_signup`,sentryDsn:t.sentryDsn}),{fetchResponse:h,parseResponseJson:g}=c(t.fetchImplementation,f);return{getState:i.getState,async load(){let e={code:`signup_load_failed`,message:`Unable to load Lockerverse signup.`,operation:`load_signup`};if(l||d)throw f(new u({...e,reportable:!1}));l=!0,s=null,i.commit({phase:`loading`});try{let n;try{n=await h(`${t.apiBaseUrl}/community/${t.communitySlug}/sign-up-widgets/${t.signupSlug}`,void 0,e)}catch(e){throw e instanceof u&&i.commit({error:e,phase:`error`,signup:null}),e}if(!n.ok){let t=f(new u({...e,reportable:n.status>=500,status:n.status}));throw i.commit({error:t,phase:`error`,signup:null}),t}try{let t=r(await g(n,p,e));return s=t,i.commit({phase:`ready`,signup:t}),t}catch(e){throw e instanceof u&&i.commit({error:e,phase:`error`,signup:null}),e}}finally{l=!1}},async submit(e){let n=s,a={code:`signup_submit_failed`,message:`Unable to submit Lockerverse signup.`,operation:`submit_signup`};if(!n?.isActive||d)throw f(new u({...a,reportable:!1}));d=!0,i.commit({phase:`submitting`,signup:n});try{let o=await h(`${t.apiBaseUrl}/community/${t.communitySlug}/sign-up-widgets/${t.signupSlug}/submissions`,{body:JSON.stringify(e),headers:{"content-type":`application/json`},method:`POST`},a);if(!o.ok)throw f(new u({...a,reportable:o.status>=500,status:o.status}));let s=r(await g(o,m,a));return i.commit({phase:`submitted`,signup:n,submission:s}),s}catch(e){let t=e instanceof u?e:f(new u({...a,reportable:!1}));throw i.commit({error:t,phase:`error`,signup:n}),t}finally{d=!1}},subscribe:i.subscribe}}export{h as createLockerverseSignup};
|
|
2
|
+
//# sourceMappingURL=signup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signup.js","names":[],"sources":["../src/signup-parsers.ts","../src/signup.ts"],"sourcesContent":["import {\n parseBoolean,\n parseCustomFields,\n parseNonEmptyString,\n parseOptionalNullableString,\n parseRecord,\n} from \"./parsing.ts\";\nimport type {\n LockerverseSignup,\n LockerverseSignupField,\n LockerverseSignupFields,\n LockerverseSignupSubmissionResult,\n} from \"./signup-types.ts\";\n\nfunction parseSignupField(value: unknown): LockerverseSignupField {\n const field = parseRecord(value);\n return {\n enabled: parseBoolean(field.enabled),\n required: parseBoolean(field.required),\n };\n}\n\nfunction parseSignupFields(value: unknown): LockerverseSignupFields {\n const fields = parseRecord(value);\n return {\n address: parseSignupField(fields.address),\n email: parseSignupField(fields.email),\n name: parseSignupField(fields.name),\n participantCount: parseSignupField(fields.participantCount),\n phone: parseSignupField(fields.phone),\n };\n}\n\nexport function parsePublicSignup(value: unknown): LockerverseSignup {\n const signup = parseRecord(value);\n const config = parseRecord(signup.config);\n\n return {\n coverImageUrl: parseOptionalNullableString(signup.coverImageUrl, null),\n customFields: parseCustomFields(config.customFields),\n description: parseOptionalNullableString(signup.description, null),\n fields: parseSignupFields(config.builtInFields),\n id: parseNonEmptyString(signup.id),\n isActive: parseBoolean(signup.isActive),\n name: parseNonEmptyString(signup.name),\n slug: parseNonEmptyString(signup.slug),\n title: parseOptionalNullableString(signup.title, null),\n };\n}\n\nexport function parseSignupSubmissionResult(\n value: unknown\n): LockerverseSignupSubmissionResult {\n const result = parseRecord(value);\n const submittedAt = parseNonEmptyString(result.submittedAt);\n if (Number.isNaN(Date.parse(submittedAt))) {\n throw new TypeError(\"Expected a submission timestamp.\");\n }\n return {\n id: parseNonEmptyString(result.id),\n submittedAt,\n };\n}\n","import { deepFreeze } from \"./deep-freeze.ts\";\nimport { resolveSignupEnvironment } from \"./environment.ts\";\nimport { createSdkErrorReporter } from \"./error-reporting.ts\";\nimport {\n parsePublicSignup,\n parseSignupSubmissionResult,\n} from \"./signup-parsers.ts\";\nimport type {\n CreateLockerverseSignupOptions,\n LockerverseSignup,\n LockerverseSignupClient,\n LockerverseSignupState,\n LockerverseSignupSubmission,\n} from \"./signup-types.ts\";\nimport { createStateStore } from \"./state.ts\";\nimport { createTransport } from \"./transport.ts\";\nimport { LockerverseSdkError } from \"./types.ts\";\n\nexport function createLockerverseSignup(\n options: CreateLockerverseSignupOptions\n): LockerverseSignupClient {\n const runtime = resolveSignupEnvironment(options);\n const stateStore = createStateStore<LockerverseSignupState>({\n phase: \"idle\",\n });\n let loadedSignup: LockerverseSignup | null = null;\n let loading = false;\n let submitting = false;\n\n const reportError = createSdkErrorReporter({\n communitySlug: runtime.communitySlugValue,\n environment: runtime.environment,\n getContext: () => ({ signupSlug: runtime.signupSlugValue }),\n onError: runtime.onError,\n resourceContextName: \"lockerverse_signup\",\n sentryDsn: runtime.sentryDsn,\n });\n\n const { fetchResponse, parseResponseJson } = createTransport(\n runtime.fetchImplementation,\n reportError\n );\n\n return {\n getState: stateStore.getState,\n async load() {\n const errorContext = {\n code: \"signup_load_failed\" as const,\n message: \"Unable to load Lockerverse signup.\",\n operation: \"load_signup\" as const,\n };\n if (loading || submitting) {\n throw reportError(\n new LockerverseSdkError({\n ...errorContext,\n reportable: false,\n })\n );\n }\n\n loading = true;\n loadedSignup = null;\n stateStore.commit({ phase: \"loading\" });\n try {\n let response: Response;\n try {\n response = await fetchResponse(\n `${runtime.apiBaseUrl}/community/${runtime.communitySlug}/sign-up-widgets/${runtime.signupSlug}`,\n undefined,\n errorContext\n );\n } catch (error) {\n if (error instanceof LockerverseSdkError) {\n stateStore.commit({ error, phase: \"error\", signup: null });\n }\n throw error;\n }\n if (!response.ok) {\n const error = reportError(\n new LockerverseSdkError({\n ...errorContext,\n reportable: response.status >= 500,\n status: response.status,\n })\n );\n stateStore.commit({ error, phase: \"error\", signup: null });\n throw error;\n }\n try {\n const signup = deepFreeze(\n await parseResponseJson(response, parsePublicSignup, errorContext)\n );\n loadedSignup = signup;\n stateStore.commit({ phase: \"ready\", signup });\n return signup;\n } catch (error) {\n if (error instanceof LockerverseSdkError) {\n stateStore.commit({ error, phase: \"error\", signup: null });\n }\n throw error;\n }\n } finally {\n loading = false;\n }\n },\n async submit(submission: LockerverseSignupSubmission) {\n const signup = loadedSignup;\n const errorContext = {\n code: \"signup_submit_failed\" as const,\n message: \"Unable to submit Lockerverse signup.\",\n operation: \"submit_signup\" as const,\n };\n if (!signup?.isActive || submitting) {\n throw reportError(\n new LockerverseSdkError({\n ...errorContext,\n reportable: false,\n })\n );\n }\n\n submitting = true;\n stateStore.commit({ phase: \"submitting\", signup });\n try {\n const response = await fetchResponse(\n `${runtime.apiBaseUrl}/community/${runtime.communitySlug}/sign-up-widgets/${runtime.signupSlug}/submissions`,\n {\n body: JSON.stringify(submission),\n headers: { \"content-type\": \"application/json\" },\n method: \"POST\",\n },\n errorContext\n );\n if (!response.ok) {\n throw reportError(\n new LockerverseSdkError({\n ...errorContext,\n reportable: response.status >= 500,\n status: response.status,\n })\n );\n }\n const result = deepFreeze(\n await parseResponseJson(\n response,\n parseSignupSubmissionResult,\n errorContext\n )\n );\n stateStore.commit({ phase: \"submitted\", signup, submission: result });\n return result;\n } catch (error) {\n const sdkError =\n error instanceof LockerverseSdkError\n ? error\n : reportError(\n new LockerverseSdkError({\n ...errorContext,\n reportable: false,\n })\n );\n stateStore.commit({ error: sdkError, phase: \"error\", signup });\n throw sdkError;\n } finally {\n submitting = false;\n }\n },\n subscribe: stateStore.subscribe,\n };\n}\n"],"mappings":"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"}
|