@appfunnel-dev/sdk 2.0.0-canary.2 → 2.0.0-canary.4
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/{checkout-DiQvRT5q.d.ts → checkout-7Dy6IedP.d.ts} +3 -0
- package/dist/{checkout-CZmEvWfC.d.cts → checkout-Dz8cGkB_.d.cts} +3 -0
- package/dist/{chunk-7UC5VXOR.js → chunk-AKO6XKXP.js} +28 -8
- package/dist/chunk-AKO6XKXP.js.map +1 -0
- package/dist/{chunk-VQOD2Z6Q.cjs → chunk-CY4VBSMX.cjs} +5 -3
- package/dist/chunk-CY4VBSMX.cjs.map +1 -0
- package/dist/{chunk-Z3TWO2PW.cjs → chunk-JSRKA375.cjs} +29 -7
- package/dist/chunk-JSRKA375.cjs.map +1 -0
- package/dist/{chunk-UIR6TGEW.js → chunk-M6U3FNRW.js} +5 -3
- package/dist/chunk-M6U3FNRW.js.map +1 -0
- package/dist/driver-paddle.cjs +14 -14
- package/dist/driver-paddle.d.cts +1 -1
- package/dist/driver-paddle.d.ts +1 -1
- package/dist/driver-paddle.js +1 -1
- package/dist/driver-stripe.cjs +13 -13
- package/dist/driver-stripe.d.cts +1 -1
- package/dist/driver-stripe.d.ts +1 -1
- package/dist/driver-stripe.js +1 -1
- package/dist/index.cjs +93 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -6
- package/dist/index.d.ts +29 -6
- package/dist/index.js +55 -16
- package/dist/index.js.map +1 -1
- package/dist/{manifest-DQThneiG.d.cts → manifest-Cr2y1op6.d.cts} +40 -3
- package/dist/{manifest-DQThneiG.d.ts → manifest-Cr2y1op6.d.ts} +40 -3
- package/dist/manifest-entry.cjs +129 -20
- package/dist/manifest-entry.cjs.map +1 -1
- package/dist/manifest-entry.d.cts +28 -3
- package/dist/manifest-entry.d.ts +28 -3
- package/dist/manifest-entry.js +105 -5
- package/dist/manifest-entry.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-7UC5VXOR.js.map +0 -1
- package/dist/chunk-UIR6TGEW.js.map +0 -1
- package/dist/chunk-VQOD2Z6Q.cjs.map +0 -1
- package/dist/chunk-Z3TWO2PW.cjs.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ComponentType, ButtonHTMLAttributes } from 'react';
|
|
3
|
-
import { V as VariableValue, a as VariableConfig, A as Acquisition, P as Product, D as Direction, F as FunnelContext, R as RuntimeExperiment, b as FunnelSnapshot, c as FunnelDefinition, d as buildContext, e as ProductInput, f as PageMeta, g as PageContext } from './manifest-
|
|
4
|
-
export { B as BrowserContext, h as BuildContextOptions, C as ClickIdContext, i as CompileInput, j as Condition, k as ConditionOp, l as DeviceContext, E as EdgeCondition, m as ExperimentIssue, n as ExperimentResolution, o as ExperimentValidation, p as ExperimentVariant, q as FlowPage, r as FunnelLocales, s as FunnelManifest, G as Gate, I as IdentityContext, t as Interval, L as LocaleContext, M as ManifestEdge, u as ManifestPage, v as ManifestValidation, w as Money, O as OsContext, x as PageType, y as Predicate, z as ResolvedProduct, H as Route, S as SessionContext, J as SystemContext, U as UtmContext, K as assignVariant, N as bucketingSeed, Q as buildAcquisition, T as buildCatalog, W as compileManifest, X as currencyExponent, Y as defineFunnel, Z as definePage, _ as entryGuard, $ as evaluateCondition, a0 as evaluateGate, a1 as expectedPathLength, a2 as fnv1a, a3 as formatMoney, a4 as formatProduct, a5 as hashToUnit, a6 as isRtl, a7 as isVariantKey, a8 as nextPage, a9 as outgoingKeys, aa as pageMeta, ab as parseSlotKey, ac as pickByWeight, ad as resolveExperiments, ae as resolveLocale, af as resolveProduct, ag as resolveRoute, ah as validateExperiments } from './manifest-
|
|
5
|
-
import { a as CheckoutDriver, C as CheckoutDriverContext } from './checkout-
|
|
6
|
-
export { b as Checkout, c as CheckoutCallbacks, d as CheckoutHandle, e as CheckoutProps, f as CheckoutRequest, g as CheckoutResult, h as CheckoutResume, i as CheckoutStatus, F as FailureModalProps, j as FailureRoute, M as MockDriverOptions, O as OnFailedMap, U as Upsell, k as UpsellProps, l as UseCheckoutOptions, m as createMockDriver, n as driverWithEmail, u as useCheckout } from './checkout-
|
|
3
|
+
import { V as VariableValue, a as VariableConfig, A as Acquisition, P as Product, D as Direction, F as FunnelContext, R as RuntimeExperiment, b as FunnelSnapshot, c as FunnelDefinition, d as buildContext, e as ProductInput, f as PageMeta, g as PageContext } from './manifest-Cr2y1op6.cjs';
|
|
4
|
+
export { B as BrowserContext, h as BuildContextOptions, C as ClickIdContext, i as CompileInput, j as Condition, k as ConditionOp, l as DeviceContext, E as EdgeCondition, m as ExperimentIssue, n as ExperimentResolution, o as ExperimentValidation, p as ExperimentVariant, q as FlowPage, r as FunnelLocales, s as FunnelManifest, G as Gate, I as IdentityContext, t as Interval, L as LocaleContext, M as ManifestEdge, u as ManifestPage, v as ManifestValidation, w as Money, O as OsContext, x as PageType, y as Predicate, z as ResolvedProduct, H as Route, S as SessionContext, J as SystemContext, U as UtmContext, K as assignVariant, N as bucketingSeed, Q as buildAcquisition, T as buildCatalog, W as compileManifest, X as currencyExponent, Y as defineFunnel, Z as definePage, _ as entryGuard, $ as evaluateCondition, a0 as evaluateGate, a1 as expectedPathLength, a2 as fnv1a, a3 as formatMoney, a4 as formatProduct, a5 as hashToUnit, a6 as isRtl, a7 as isVariantKey, a8 as nextPage, a9 as outgoingKeys, aa as pageMeta, ab as parseSlotKey, ac as pickByWeight, ad as resolveExperiments, ae as resolveLocale, af as resolveProduct, ag as resolveRoute, ah as validateExperiments } from './manifest-Cr2y1op6.cjs';
|
|
5
|
+
import { a as CheckoutDriver, C as CheckoutDriverContext } from './checkout-Dz8cGkB_.cjs';
|
|
6
|
+
export { b as Checkout, c as CheckoutCallbacks, d as CheckoutHandle, e as CheckoutProps, f as CheckoutRequest, g as CheckoutResult, h as CheckoutResume, i as CheckoutStatus, F as FailureModalProps, j as FailureRoute, M as MockDriverOptions, O as OnFailedMap, U as Upsell, k as UpsellProps, l as UseCheckoutOptions, m as createMockDriver, n as driverWithEmail, u as useCheckout } from './checkout-Dz8cGkB_.cjs';
|
|
7
7
|
import { ToasterProps } from 'sonner';
|
|
8
8
|
export { ToasterProps, toast } from 'sonner';
|
|
9
9
|
export { C as CheckoutError, a as CheckoutErrorCategory, b as CheckoutIntent, c as CheckoutProvider, d as CheckoutSurface, I as INLINE_SURFACES, O as OffSessionReliability, P as PROVIDER_PROFILES, e as ProviderProfile, S as SurfaceCapability, U as UpsellKind, V as ValidationResult, f as checkoutError, i as isInlineSurface, g as isMerchantOfRecord, h as isOrchestrator, s as surfacesFor, v as validateCheckout, j as validateUpsell } from './capabilities-7_hy5f5G.cjs';
|
|
@@ -113,8 +113,16 @@ interface FunnelEventDataMap {
|
|
|
113
113
|
priceId?: string;
|
|
114
114
|
productName?: string;
|
|
115
115
|
surface?: string;
|
|
116
|
+
amount?: number;
|
|
117
|
+
currency?: string;
|
|
118
|
+
eventId?: string;
|
|
119
|
+
};
|
|
120
|
+
'checkout.payment_added': {
|
|
121
|
+
productId?: string;
|
|
122
|
+
amount?: number;
|
|
123
|
+
currency?: string;
|
|
124
|
+
eventId?: string;
|
|
116
125
|
};
|
|
117
|
-
'checkout.payment_added': Record<string, never>;
|
|
118
126
|
'checkout.failed': {
|
|
119
127
|
category: string;
|
|
120
128
|
declineCode?: string;
|
|
@@ -126,6 +134,13 @@ interface FunnelEventDataMap {
|
|
|
126
134
|
currency?: string;
|
|
127
135
|
email?: string;
|
|
128
136
|
eventId?: string;
|
|
137
|
+
productId?: string;
|
|
138
|
+
};
|
|
139
|
+
'subscription.created': {
|
|
140
|
+
amount?: number;
|
|
141
|
+
currency?: string;
|
|
142
|
+
productId?: string;
|
|
143
|
+
eventId?: string;
|
|
129
144
|
};
|
|
130
145
|
'experiment.exposure': {
|
|
131
146
|
experimentId: string;
|
|
@@ -518,6 +533,8 @@ interface MountOpts {
|
|
|
518
533
|
initialKey?: string;
|
|
519
534
|
/** Asset map: logical name → content-addressed CDN URL. */
|
|
520
535
|
assets?: Record<string, string>;
|
|
536
|
+
/** Per-locale message catalogs (`messages/<locale>.json`) — overrides the mount's baked-in ones. */
|
|
537
|
+
messages?: MessageCatalog;
|
|
521
538
|
/** The SIGNED anonymous visitor id (bare id, verified server-side; phase-1 §1.2) — the
|
|
522
539
|
* renderer mints/reads the `af_vid` cookie and injects the value here. Feeds
|
|
523
540
|
* `context.identity.visitorId` (experiment bucketing fallback seed, session continuity). */
|
|
@@ -581,6 +598,12 @@ interface CreateFunnelTreeInput {
|
|
|
581
598
|
* resolves the provider's TEST store from it (that's the quarantine, not the client).
|
|
582
599
|
*/
|
|
583
600
|
checkoutDriver?: (ctx: CheckoutDriverContext) => CheckoutDriver;
|
|
601
|
+
/**
|
|
602
|
+
* The funnel's message catalogs (`messages/<locale>.json`), keyed by locale. The generated
|
|
603
|
+
* `mount.tsx` imports the catalogs and passes them here so `t()` resolves at render (SSR + client);
|
|
604
|
+
* `MountOpts.messages` can still override per-request. Omit for funnels with no translations.
|
|
605
|
+
*/
|
|
606
|
+
messages?: MessageCatalog;
|
|
584
607
|
}
|
|
585
608
|
/**
|
|
586
609
|
* Build a funnel's `tree(opts)` — the standard provider stack over your pages.
|
|
@@ -590,7 +613,7 @@ interface CreateFunnelTreeInput {
|
|
|
590
613
|
* export const tree = createFunnelTree({ config, pages, layout: Layout })
|
|
591
614
|
* ```
|
|
592
615
|
*/
|
|
593
|
-
declare function createFunnelTree({ config, pages, layout, checkoutDriver, }: CreateFunnelTreeInput): (opts: MountOpts) => ReactNode;
|
|
616
|
+
declare function createFunnelTree({ config, pages, layout, checkoutDriver, messages, }: CreateFunnelTreeInput): (opts: MountOpts) => ReactNode;
|
|
594
617
|
|
|
595
618
|
/**
|
|
596
619
|
* The two-tier component model (doc 07 §"magic ≠ black box"): the magic lives in
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ComponentType, ButtonHTMLAttributes } from 'react';
|
|
3
|
-
import { V as VariableValue, a as VariableConfig, A as Acquisition, P as Product, D as Direction, F as FunnelContext, R as RuntimeExperiment, b as FunnelSnapshot, c as FunnelDefinition, d as buildContext, e as ProductInput, f as PageMeta, g as PageContext } from './manifest-
|
|
4
|
-
export { B as BrowserContext, h as BuildContextOptions, C as ClickIdContext, i as CompileInput, j as Condition, k as ConditionOp, l as DeviceContext, E as EdgeCondition, m as ExperimentIssue, n as ExperimentResolution, o as ExperimentValidation, p as ExperimentVariant, q as FlowPage, r as FunnelLocales, s as FunnelManifest, G as Gate, I as IdentityContext, t as Interval, L as LocaleContext, M as ManifestEdge, u as ManifestPage, v as ManifestValidation, w as Money, O as OsContext, x as PageType, y as Predicate, z as ResolvedProduct, H as Route, S as SessionContext, J as SystemContext, U as UtmContext, K as assignVariant, N as bucketingSeed, Q as buildAcquisition, T as buildCatalog, W as compileManifest, X as currencyExponent, Y as defineFunnel, Z as definePage, _ as entryGuard, $ as evaluateCondition, a0 as evaluateGate, a1 as expectedPathLength, a2 as fnv1a, a3 as formatMoney, a4 as formatProduct, a5 as hashToUnit, a6 as isRtl, a7 as isVariantKey, a8 as nextPage, a9 as outgoingKeys, aa as pageMeta, ab as parseSlotKey, ac as pickByWeight, ad as resolveExperiments, ae as resolveLocale, af as resolveProduct, ag as resolveRoute, ah as validateExperiments } from './manifest-
|
|
5
|
-
import { a as CheckoutDriver, C as CheckoutDriverContext } from './checkout-
|
|
6
|
-
export { b as Checkout, c as CheckoutCallbacks, d as CheckoutHandle, e as CheckoutProps, f as CheckoutRequest, g as CheckoutResult, h as CheckoutResume, i as CheckoutStatus, F as FailureModalProps, j as FailureRoute, M as MockDriverOptions, O as OnFailedMap, U as Upsell, k as UpsellProps, l as UseCheckoutOptions, m as createMockDriver, n as driverWithEmail, u as useCheckout } from './checkout-
|
|
3
|
+
import { V as VariableValue, a as VariableConfig, A as Acquisition, P as Product, D as Direction, F as FunnelContext, R as RuntimeExperiment, b as FunnelSnapshot, c as FunnelDefinition, d as buildContext, e as ProductInput, f as PageMeta, g as PageContext } from './manifest-Cr2y1op6.js';
|
|
4
|
+
export { B as BrowserContext, h as BuildContextOptions, C as ClickIdContext, i as CompileInput, j as Condition, k as ConditionOp, l as DeviceContext, E as EdgeCondition, m as ExperimentIssue, n as ExperimentResolution, o as ExperimentValidation, p as ExperimentVariant, q as FlowPage, r as FunnelLocales, s as FunnelManifest, G as Gate, I as IdentityContext, t as Interval, L as LocaleContext, M as ManifestEdge, u as ManifestPage, v as ManifestValidation, w as Money, O as OsContext, x as PageType, y as Predicate, z as ResolvedProduct, H as Route, S as SessionContext, J as SystemContext, U as UtmContext, K as assignVariant, N as bucketingSeed, Q as buildAcquisition, T as buildCatalog, W as compileManifest, X as currencyExponent, Y as defineFunnel, Z as definePage, _ as entryGuard, $ as evaluateCondition, a0 as evaluateGate, a1 as expectedPathLength, a2 as fnv1a, a3 as formatMoney, a4 as formatProduct, a5 as hashToUnit, a6 as isRtl, a7 as isVariantKey, a8 as nextPage, a9 as outgoingKeys, aa as pageMeta, ab as parseSlotKey, ac as pickByWeight, ad as resolveExperiments, ae as resolveLocale, af as resolveProduct, ag as resolveRoute, ah as validateExperiments } from './manifest-Cr2y1op6.js';
|
|
5
|
+
import { a as CheckoutDriver, C as CheckoutDriverContext } from './checkout-7Dy6IedP.js';
|
|
6
|
+
export { b as Checkout, c as CheckoutCallbacks, d as CheckoutHandle, e as CheckoutProps, f as CheckoutRequest, g as CheckoutResult, h as CheckoutResume, i as CheckoutStatus, F as FailureModalProps, j as FailureRoute, M as MockDriverOptions, O as OnFailedMap, U as Upsell, k as UpsellProps, l as UseCheckoutOptions, m as createMockDriver, n as driverWithEmail, u as useCheckout } from './checkout-7Dy6IedP.js';
|
|
7
7
|
import { ToasterProps } from 'sonner';
|
|
8
8
|
export { ToasterProps, toast } from 'sonner';
|
|
9
9
|
export { C as CheckoutError, a as CheckoutErrorCategory, b as CheckoutIntent, c as CheckoutProvider, d as CheckoutSurface, I as INLINE_SURFACES, O as OffSessionReliability, P as PROVIDER_PROFILES, e as ProviderProfile, S as SurfaceCapability, U as UpsellKind, V as ValidationResult, f as checkoutError, i as isInlineSurface, g as isMerchantOfRecord, h as isOrchestrator, s as surfacesFor, v as validateCheckout, j as validateUpsell } from './capabilities-7_hy5f5G.js';
|
|
@@ -113,8 +113,16 @@ interface FunnelEventDataMap {
|
|
|
113
113
|
priceId?: string;
|
|
114
114
|
productName?: string;
|
|
115
115
|
surface?: string;
|
|
116
|
+
amount?: number;
|
|
117
|
+
currency?: string;
|
|
118
|
+
eventId?: string;
|
|
119
|
+
};
|
|
120
|
+
'checkout.payment_added': {
|
|
121
|
+
productId?: string;
|
|
122
|
+
amount?: number;
|
|
123
|
+
currency?: string;
|
|
124
|
+
eventId?: string;
|
|
116
125
|
};
|
|
117
|
-
'checkout.payment_added': Record<string, never>;
|
|
118
126
|
'checkout.failed': {
|
|
119
127
|
category: string;
|
|
120
128
|
declineCode?: string;
|
|
@@ -126,6 +134,13 @@ interface FunnelEventDataMap {
|
|
|
126
134
|
currency?: string;
|
|
127
135
|
email?: string;
|
|
128
136
|
eventId?: string;
|
|
137
|
+
productId?: string;
|
|
138
|
+
};
|
|
139
|
+
'subscription.created': {
|
|
140
|
+
amount?: number;
|
|
141
|
+
currency?: string;
|
|
142
|
+
productId?: string;
|
|
143
|
+
eventId?: string;
|
|
129
144
|
};
|
|
130
145
|
'experiment.exposure': {
|
|
131
146
|
experimentId: string;
|
|
@@ -518,6 +533,8 @@ interface MountOpts {
|
|
|
518
533
|
initialKey?: string;
|
|
519
534
|
/** Asset map: logical name → content-addressed CDN URL. */
|
|
520
535
|
assets?: Record<string, string>;
|
|
536
|
+
/** Per-locale message catalogs (`messages/<locale>.json`) — overrides the mount's baked-in ones. */
|
|
537
|
+
messages?: MessageCatalog;
|
|
521
538
|
/** The SIGNED anonymous visitor id (bare id, verified server-side; phase-1 §1.2) — the
|
|
522
539
|
* renderer mints/reads the `af_vid` cookie and injects the value here. Feeds
|
|
523
540
|
* `context.identity.visitorId` (experiment bucketing fallback seed, session continuity). */
|
|
@@ -581,6 +598,12 @@ interface CreateFunnelTreeInput {
|
|
|
581
598
|
* resolves the provider's TEST store from it (that's the quarantine, not the client).
|
|
582
599
|
*/
|
|
583
600
|
checkoutDriver?: (ctx: CheckoutDriverContext) => CheckoutDriver;
|
|
601
|
+
/**
|
|
602
|
+
* The funnel's message catalogs (`messages/<locale>.json`), keyed by locale. The generated
|
|
603
|
+
* `mount.tsx` imports the catalogs and passes them here so `t()` resolves at render (SSR + client);
|
|
604
|
+
* `MountOpts.messages` can still override per-request. Omit for funnels with no translations.
|
|
605
|
+
*/
|
|
606
|
+
messages?: MessageCatalog;
|
|
584
607
|
}
|
|
585
608
|
/**
|
|
586
609
|
* Build a funnel's `tree(opts)` — the standard provider stack over your pages.
|
|
@@ -590,7 +613,7 @@ interface CreateFunnelTreeInput {
|
|
|
590
613
|
* export const tree = createFunnelTree({ config, pages, layout: Layout })
|
|
591
614
|
* ```
|
|
592
615
|
*/
|
|
593
|
-
declare function createFunnelTree({ config, pages, layout, checkoutDriver, }: CreateFunnelTreeInput): (opts: MountOpts) => ReactNode;
|
|
616
|
+
declare function createFunnelTree({ config, pages, layout, checkoutDriver, messages, }: CreateFunnelTreeInput): (opts: MountOpts) => ReactNode;
|
|
594
617
|
|
|
595
618
|
/**
|
|
596
619
|
* The two-tier component model (doc 07 §"magic ≠ black box"): the magic lives in
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isRtl, formatProduct, bucketingSeed, resolveExperiments, entryGuard, evaluateGate, expectedPathLength, nextPage, outgoingKeys, buildCatalog, resolveLocale } from './chunk-
|
|
2
|
-
export { assignVariant, bucketingSeed, buildCatalog, compileManifest, currencyExponent, defineFunnel, definePage, entryGuard, evaluateCondition, evaluateGate, expectedPathLength, fnv1a, formatMoney, formatProduct, hashToUnit, isRtl, isVariantKey, nextPage, outgoingKeys, pageMeta, parseSlotKey, pickByWeight, resolveExperiments, resolveLocale, resolveProduct, resolveRoute, validateExperiments } from './chunk-
|
|
1
|
+
import { isRtl, formatProduct, bucketingSeed, resolveExperiments, entryGuard, evaluateGate, expectedPathLength, nextPage, outgoingKeys, buildCatalog, resolveLocale } from './chunk-AKO6XKXP.js';
|
|
2
|
+
export { assignVariant, bucketingSeed, buildCatalog, compileManifest, currencyExponent, defineFunnel, definePage, entryGuard, evaluateCondition, evaluateGate, expectedPathLength, fnv1a, formatMoney, formatProduct, hashToUnit, isRtl, isVariantKey, nextPage, outgoingKeys, pageMeta, parseSlotKey, pickByWeight, resolveExperiments, resolveLocale, resolveProduct, resolveRoute, validateExperiments } from './chunk-AKO6XKXP.js';
|
|
3
3
|
import { checkoutError, isInlineSurface, PROVIDER_PROFILES } from './chunk-YY375F2B.js';
|
|
4
4
|
export { INLINE_SURFACES, PROVIDER_PROFILES, checkoutError, isInlineSurface, isMerchantOfRecord, isOrchestrator, surfacesFor, validateCheckout, validateUpsell } from './chunk-YY375F2B.js';
|
|
5
5
|
import React, { createContext, createElement, useCallback, useContext, useMemo, lazy, useRef, useState, useEffect, useTransition, Suspense, Fragment, isValidElement, cloneElement, useReducer, useSyncExternalStore } from 'react';
|
|
@@ -1098,6 +1098,14 @@ function driverWithEmail(driver, getEmail) {
|
|
|
1098
1098
|
renderInline: driver.renderInline ? (req, cb) => driver.renderInline(enrich(req), cb) : void 0
|
|
1099
1099
|
};
|
|
1100
1100
|
}
|
|
1101
|
+
function driverWithCatalog(driver, catalog) {
|
|
1102
|
+
const enrich = (req) => req.catalogKey !== void 0 ? req : { ...req, catalogKey: catalog.get(req.product)?.catalogKey };
|
|
1103
|
+
return {
|
|
1104
|
+
...driver,
|
|
1105
|
+
start: (req) => driver.start(enrich(req)),
|
|
1106
|
+
renderInline: driver.renderInline ? (req, cb) => driver.renderInline(enrich(req), cb) : void 0
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1101
1109
|
var DriverContext = createContext(null);
|
|
1102
1110
|
function CheckoutDriverProvider({
|
|
1103
1111
|
driver,
|
|
@@ -1112,12 +1120,25 @@ var FALLBACK_DRIVER = createMockDriver();
|
|
|
1112
1120
|
function useCheckout(opts = {}) {
|
|
1113
1121
|
const driver = useDriver();
|
|
1114
1122
|
const tracker = useTrackerRef();
|
|
1123
|
+
const catalog = useCatalog();
|
|
1115
1124
|
const nav = useNavigation();
|
|
1116
1125
|
const [status, setStatus] = useState("idle");
|
|
1117
1126
|
const [error, setError] = useState(null);
|
|
1118
1127
|
const intent = opts.intent ?? "purchase";
|
|
1119
1128
|
const kind = opts.kind;
|
|
1120
1129
|
const advance = opts.advanceOnSuccess ?? true;
|
|
1130
|
+
const productFacts = useCallback(
|
|
1131
|
+
(product) => {
|
|
1132
|
+
const resolved = product ? catalog.get(product) : void 0;
|
|
1133
|
+
return {
|
|
1134
|
+
productId: resolved?.catalogKey ?? product,
|
|
1135
|
+
amount: resolved ? resolved.priceMinor / 100 : void 0,
|
|
1136
|
+
currency: resolved?.currency,
|
|
1137
|
+
isSubscription: resolved ? resolved.period !== "one-time" : kind === "subscription" || kind === "upgrade"
|
|
1138
|
+
};
|
|
1139
|
+
},
|
|
1140
|
+
[catalog, kind]
|
|
1141
|
+
);
|
|
1121
1142
|
const recovering = useRef(false);
|
|
1122
1143
|
const failRef = useRef(() => {
|
|
1123
1144
|
});
|
|
@@ -1125,18 +1146,24 @@ function useCheckout(opts = {}) {
|
|
|
1125
1146
|
async () => ({ ok: false })
|
|
1126
1147
|
);
|
|
1127
1148
|
const succeed = useCallback(
|
|
1128
|
-
(result) => {
|
|
1149
|
+
(result, product) => {
|
|
1129
1150
|
setStatus("success");
|
|
1151
|
+
const { productId, isSubscription } = productFacts(product);
|
|
1152
|
+
const amount = result.amountMinor != null ? result.amountMinor / 100 : void 0;
|
|
1130
1153
|
tracker.track("purchase.complete", {
|
|
1131
|
-
amount
|
|
1154
|
+
amount,
|
|
1132
1155
|
currency: result.currency,
|
|
1156
|
+
productId,
|
|
1133
1157
|
eventId: result.eventId
|
|
1134
1158
|
// server-minted (browser↔CAPI dedup); undefined if none
|
|
1135
1159
|
});
|
|
1160
|
+
if (isSubscription) {
|
|
1161
|
+
tracker.track("subscription.created", { amount, currency: result.currency, productId, eventId: result.eventId });
|
|
1162
|
+
}
|
|
1136
1163
|
opts.onSuccess?.(result);
|
|
1137
1164
|
if (advance) nav.next();
|
|
1138
1165
|
},
|
|
1139
|
-
[tracker, nav, advance, opts]
|
|
1166
|
+
[tracker, nav, advance, opts, productFacts]
|
|
1140
1167
|
);
|
|
1141
1168
|
const succeedRef = useRef(succeed);
|
|
1142
1169
|
succeedRef.current = succeed;
|
|
@@ -1144,11 +1171,18 @@ function useCheckout(opts = {}) {
|
|
|
1144
1171
|
(product, surface) => {
|
|
1145
1172
|
setStatus("loading");
|
|
1146
1173
|
setError(null);
|
|
1147
|
-
|
|
1174
|
+
const { productId, amount, currency } = productFacts(product);
|
|
1175
|
+
tracker.track("checkout.start", { productId, amount, currency, surface, eventId: newEventId() });
|
|
1148
1176
|
},
|
|
1149
|
-
[tracker]
|
|
1177
|
+
[tracker, productFacts]
|
|
1178
|
+
);
|
|
1179
|
+
const paymentAdded = useCallback(
|
|
1180
|
+
(product) => {
|
|
1181
|
+
const { productId, amount, currency } = productFacts(product);
|
|
1182
|
+
tracker.track("checkout.payment_added", { productId, amount, currency, eventId: newEventId() });
|
|
1183
|
+
},
|
|
1184
|
+
[tracker, productFacts]
|
|
1150
1185
|
);
|
|
1151
|
-
const paymentAdded = useCallback(() => tracker.track("checkout.payment_added", {}), [tracker]);
|
|
1152
1186
|
const hostInSheet = (surface) => surface === "sheet" || isInlineSurface(surface) && !!PROVIDER_PROFILES[driver.provider]?.surfaces.sheet;
|
|
1153
1187
|
const startRecovery = (product, surface) => {
|
|
1154
1188
|
recovering.current = true;
|
|
@@ -1159,9 +1193,9 @@ function useCheckout(opts = {}) {
|
|
|
1159
1193
|
surface: "sheet",
|
|
1160
1194
|
intent,
|
|
1161
1195
|
kind,
|
|
1162
|
-
onSuccess: (r) => succeedRef.current(r),
|
|
1196
|
+
onSuccess: (r) => succeedRef.current(r, product),
|
|
1163
1197
|
onError: (e) => failRef.current(e, product),
|
|
1164
|
-
onPaymentAdded: () => paymentAdded()
|
|
1198
|
+
onPaymentAdded: () => paymentAdded(product)
|
|
1165
1199
|
});
|
|
1166
1200
|
} else {
|
|
1167
1201
|
void attemptRef.current(product, surface);
|
|
@@ -1215,7 +1249,7 @@ function useCheckout(opts = {}) {
|
|
|
1215
1249
|
begin(product, surface);
|
|
1216
1250
|
try {
|
|
1217
1251
|
const result = await driver.start({ product, intent, surface, kind });
|
|
1218
|
-
if (result.ok) succeedRef.current(result);
|
|
1252
|
+
if (result.ok) succeedRef.current(result, product);
|
|
1219
1253
|
else failRef.current(result.error ?? checkoutError("unknown", "Checkout failed"), product);
|
|
1220
1254
|
return result;
|
|
1221
1255
|
} catch (e) {
|
|
@@ -1234,9 +1268,9 @@ function useCheckout(opts = {}) {
|
|
|
1234
1268
|
recovering.current = false;
|
|
1235
1269
|
begin(product, surface);
|
|
1236
1270
|
},
|
|
1237
|
-
onSuccess: (result) => succeedRef.current(result),
|
|
1271
|
+
onSuccess: (result) => succeedRef.current(result, product),
|
|
1238
1272
|
onError: (err) => failRef.current(err, product),
|
|
1239
|
-
onPaymentAdded: () => paymentAdded()
|
|
1273
|
+
onPaymentAdded: () => paymentAdded(product)
|
|
1240
1274
|
}),
|
|
1241
1275
|
[begin, paymentAdded]
|
|
1242
1276
|
);
|
|
@@ -2567,12 +2601,15 @@ function FunnelProvider({
|
|
|
2567
2601
|
const value2 = s.get("user.email");
|
|
2568
2602
|
return typeof value2 === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(value2) ? value2 : void 0;
|
|
2569
2603
|
};
|
|
2604
|
+
const catalog = buildCatalog(products ?? []);
|
|
2570
2605
|
return {
|
|
2571
2606
|
funnel: createFunnel(s, ctx, busTracker, experiments ?? []),
|
|
2572
2607
|
store: s,
|
|
2573
2608
|
context: ctx,
|
|
2574
|
-
catalog
|
|
2575
|
-
|
|
2609
|
+
catalog,
|
|
2610
|
+
// Slot → catalog-key resolution wraps the email-enriching driver, so the wire charges the real
|
|
2611
|
+
// catalog key while pages + analytics keep the durable SLOT identity (req.product).
|
|
2612
|
+
driver: driverWithCatalog(driverWithEmail(checkout ?? createMockDriver(), emailForCheckout), catalog),
|
|
2576
2613
|
tracker: busTracker,
|
|
2577
2614
|
bus
|
|
2578
2615
|
};
|
|
@@ -2844,7 +2881,8 @@ function createFunnelTree({
|
|
|
2844
2881
|
config,
|
|
2845
2882
|
pages,
|
|
2846
2883
|
layout,
|
|
2847
|
-
checkoutDriver
|
|
2884
|
+
checkoutDriver,
|
|
2885
|
+
messages
|
|
2848
2886
|
}) {
|
|
2849
2887
|
return function tree(opts) {
|
|
2850
2888
|
const mode = opts.mode ?? "live";
|
|
@@ -2877,6 +2915,7 @@ function createFunnelTree({
|
|
|
2877
2915
|
children: createElement(FunnelProvider, {
|
|
2878
2916
|
config,
|
|
2879
2917
|
products: opts.products ?? [],
|
|
2918
|
+
messages: opts.messages ?? messages,
|
|
2880
2919
|
locale: opts.locale,
|
|
2881
2920
|
tracker,
|
|
2882
2921
|
checkout,
|