@appfunnel-dev/sdk 2.0.0-canary.7 → 2.0.0-canary.8
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/{capabilities-7_hy5f5G.d.cts → capabilities-CsnkVwna.d.cts} +34 -1
- package/dist/{capabilities-7_hy5f5G.d.ts → capabilities-CsnkVwna.d.ts} +34 -1
- package/dist/{checkout-D1NUPv4p.d.ts → checkout-3PkKwPd7.d.ts} +1 -1
- package/dist/{checkout-CMEdxpgo.d.cts → checkout-Cg20l53c.d.cts} +1 -1
- package/dist/{chunk-VAOR77NW.cjs → chunk-FY3TMSRU.cjs} +7 -7
- package/dist/{chunk-VAOR77NW.cjs.map → chunk-FY3TMSRU.cjs.map} +1 -1
- package/dist/{chunk-CFFMZYPE.js → chunk-PWXMQGO6.js} +3 -3
- package/dist/{chunk-CFFMZYPE.js.map → chunk-PWXMQGO6.js.map} +1 -1
- package/dist/{chunk-TNLRQPVY.js → chunk-RVJLR4RS.js} +36 -8
- package/dist/chunk-RVJLR4RS.js.map +1 -0
- package/dist/{chunk-QMAZGLGV.cjs → chunk-RY3LOSVZ.cjs} +37 -7
- package/dist/chunk-RY3LOSVZ.cjs.map +1 -0
- package/dist/{chunk-7YQLPPPG.js → chunk-VW2HVPR4.js} +7 -2
- package/dist/chunk-VW2HVPR4.js.map +1 -0
- package/dist/{chunk-BPOAWI4G.cjs → chunk-Y4YNJ2EX.cjs} +7 -2
- package/dist/chunk-Y4YNJ2EX.cjs.map +1 -0
- package/dist/driver-paddle.cjs +22 -22
- package/dist/driver-paddle.d.cts +2 -2
- package/dist/driver-paddle.d.ts +2 -2
- package/dist/driver-paddle.js +2 -2
- package/dist/driver-stripe.cjs +24 -24
- package/dist/driver-stripe.d.cts +2 -2
- package/dist/driver-stripe.d.ts +2 -2
- package/dist/driver-stripe.js +2 -2
- package/dist/index.cjs +60 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/{manifest-CMe8yVkr.d.cts → manifest-B3Tdab0M.d.cts} +64 -1
- package/dist/{manifest-CMe8yVkr.d.ts → manifest-B3Tdab0M.d.ts} +64 -1
- package/dist/manifest-entry.cjs +100 -31
- package/dist/manifest-entry.cjs.map +1 -1
- package/dist/manifest-entry.d.cts +9 -26
- package/dist/manifest-entry.d.ts +9 -26
- package/dist/manifest-entry.js +64 -3
- package/dist/manifest-entry.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-7YQLPPPG.js.map +0 -1
- package/dist/chunk-BPOAWI4G.cjs.map +0 -1
- package/dist/chunk-QMAZGLGV.cjs.map +0 -1
- package/dist/chunk-TNLRQPVY.js.map +0 -1
|
@@ -701,6 +701,55 @@ declare function resolveExperiments(pages: {
|
|
|
701
701
|
key: string;
|
|
702
702
|
}[], experiments: RuntimeExperiment[], seed: string | null): ExperimentResolution;
|
|
703
703
|
|
|
704
|
+
/**
|
|
705
|
+
* Pure, React-free page scan: find which offering SLOTS a funnel's pages reference — the first
|
|
706
|
+
* string-literal arg of `useOffering(...)` and the `offering` prop of `<Checkout>` / `<Upsell>`.
|
|
707
|
+
* Ships via `@appfunnel-dev/sdk/manifest` so the BUILD, the EDITOR, and the AI all run the SAME
|
|
708
|
+
* check. The result feeds `compileManifest({ offeringRefs })`, which flags references to slots the
|
|
709
|
+
* funnel doesn't declare (unknown) or hasn't assigned a catalog charge key to (unassigned).
|
|
710
|
+
*
|
|
711
|
+
* Non-literal args (`useOffering(selectedId)`, `offering={expr}`) and the `useOfferings()` wildcard are
|
|
712
|
+
* DYNAMIC — they can't be statically enumerated, so they're reported via `dynamic` and never turned
|
|
713
|
+
* into a hard error (validation relaxes when a funnel is dynamic). Mirrors the mask-then-read
|
|
714
|
+
* discipline the funnel.ts code-mods use, so a `useOffering('x')` inside a comment or string literal
|
|
715
|
+
* can't false-positive.
|
|
716
|
+
*/
|
|
717
|
+
interface OfferingRefScan {
|
|
718
|
+
/** Concrete slot names referenced by LITERAL args, deduped, in first-seen order. */
|
|
719
|
+
slots: string[];
|
|
720
|
+
/** True if any ref is a non-literal arg or a `useOfferings()` wildcard (not statically enumerable). */
|
|
721
|
+
dynamic: boolean;
|
|
722
|
+
/**
|
|
723
|
+
* Checkout-SURFACE usage the pages express — feeds the publish (provider × surface) capability
|
|
724
|
+
* gate. Absent-field back-compat: a manifest compiled before this existed simply omits it, and
|
|
725
|
+
* the gate skips (no false blocks). See {@link CheckoutUsageScan}.
|
|
726
|
+
*/
|
|
727
|
+
checkout: CheckoutUsageScan;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* What the pages ask the checkout to DO, statically — the surfaces they mount and the off-session
|
|
731
|
+
* upsell kinds they charge. Literal values only; a computed value (`surface={expr}`) sets
|
|
732
|
+
* {@link dynamic} so the publish gate WARNS instead of hard-failing (it can't enumerate it).
|
|
733
|
+
*/
|
|
734
|
+
interface CheckoutUsageScan {
|
|
735
|
+
/**
|
|
736
|
+
* Purchase SURFACES the pages request, deduped in first-seen order. Captures every literal
|
|
737
|
+
* `<Checkout surface="…">` plus the on-session re-collect surfaces `<Checkout|Upsell fallback="…">`
|
|
738
|
+
* and `recoverySurface="…"` (a fallback re-collects a card → it IS a purchase surface the provider
|
|
739
|
+
* must support). Validated with `validateCheckout(provider, surface)`.
|
|
740
|
+
*/
|
|
741
|
+
surfaces: string[];
|
|
742
|
+
/**
|
|
743
|
+
* Off-session upsell KINDS from `<Upsell kind="…">`, deduped. A `<Upsell>` with no `kind` attr
|
|
744
|
+
* defaults to `'subscription'` (mirrors the runtime default), so an unadorned `<Upsell>` records
|
|
745
|
+
* `'subscription'`. Validated with `validateUpsell(provider, paywallSurface, kind)`.
|
|
746
|
+
*/
|
|
747
|
+
upsellKinds: string[];
|
|
748
|
+
/** True if any surface/kind was a non-literal (computed) value → the gate WARNS, never blocks, on it. */
|
|
749
|
+
dynamic: boolean;
|
|
750
|
+
}
|
|
751
|
+
declare function scanOfferingRefs(files: Record<string, string>): OfferingRefScan;
|
|
752
|
+
|
|
704
753
|
/**
|
|
705
754
|
* The **manifest** — the declarative IR a funnel project compiles to (doc 06).
|
|
706
755
|
* It's the machine-readable artifact the platform operates on without executing
|
|
@@ -838,6 +887,18 @@ interface FunnelManifest {
|
|
|
838
887
|
offeringSlots: OfferingSlot[];
|
|
839
888
|
/** Slot names PAGES reference (from the build's scan); validated against `offeringSlots`. Absent = no scan ran. */
|
|
840
889
|
offeringRefs?: string[];
|
|
890
|
+
/**
|
|
891
|
+
* The funnel's `checkout:` driver bundle from `funnel.ts` (`FunnelDefinition.checkout`), carried so
|
|
892
|
+
* the publish gate can cross-validate it against the offerings' RESOLVED provider (§7 item 5 — the
|
|
893
|
+
* redundant field is never checked today). Absent = the funnel declares no `checkout:`.
|
|
894
|
+
*/
|
|
895
|
+
checkout?: 'stripe' | 'paddle';
|
|
896
|
+
/**
|
|
897
|
+
* Checkout-SURFACE usage the pages express (from `scanOfferingRefs(...).checkout`), carried so the
|
|
898
|
+
* publish (provider × surface) capability gate can run `validateCheckout`/`validateUpsell`. Absent =
|
|
899
|
+
* no scan ran (old manifest) → the gate skips capability validation (back-compat, no false blocks).
|
|
900
|
+
*/
|
|
901
|
+
checkoutRefs?: CheckoutUsageScan;
|
|
841
902
|
locales?: FunnelLocales;
|
|
842
903
|
validation: ManifestValidation;
|
|
843
904
|
}
|
|
@@ -850,8 +911,10 @@ interface CompileInput {
|
|
|
850
911
|
}[];
|
|
851
912
|
/** Slot names the funnel's PAGES reference (from `scanOfferingRefs`) — cross-checked against the declared slots. */
|
|
852
913
|
offeringRefs?: string[];
|
|
914
|
+
/** Checkout-surface usage the pages express (from `scanOfferingRefs(...).checkout`) — carried onto the manifest for the publish capability gate. */
|
|
915
|
+
checkoutRefs?: CheckoutUsageScan;
|
|
853
916
|
}
|
|
854
917
|
/** Compile a funnel's spine into its declarative {@link FunnelManifest} IR. */
|
|
855
918
|
declare function compileManifest(input: CompileInput): FunnelManifest;
|
|
856
919
|
|
|
857
|
-
export { expectedPathLength as $, type Acquisition as A, type BrowserContext as B, type ClickIdContext as C, type Direction as D, type EdgeCondition as E, type FunnelContext as F, type Gate as G, assignVariant as H, type IdentityContext as I, bucketingSeed as J, buildAcquisition as K, type LocaleContext as L, type ManifestEdge as M, buildCatalog as N, type Offering as O, type PageMeta as P, compileManifest as Q, type RuntimeExperiment as R, type SessionContext as S, currencyExponent as T, type UtmContext as U, type VariableValue as V, defineFunnel as W, definePage as X, entryGuard as Y, evaluateCondition as Z, evaluateGate as _, type VariableConfig as a, fnv1a as a0, formatMoney as a1, formatOffering as a2, hashToUnit as a3, isRtl as a4, isVariantKey as a5, nextPage as a6, outgoingKeys as a7, pageMeta as a8, parseSlotKey as a9, pickByWeight as aa, resolveExperiments as ab, resolveLocale as ac, resolveOffering as ad, resolveRoute as ae, type
|
|
920
|
+
export { expectedPathLength as $, type Acquisition as A, type BrowserContext as B, type ClickIdContext as C, type Direction as D, type EdgeCondition as E, type FunnelContext as F, type Gate as G, assignVariant as H, type IdentityContext as I, bucketingSeed as J, buildAcquisition as K, type LocaleContext as L, type ManifestEdge as M, buildCatalog as N, type Offering as O, type PageMeta as P, compileManifest as Q, type RuntimeExperiment as R, type SessionContext as S, currencyExponent as T, type UtmContext as U, type VariableValue as V, defineFunnel as W, definePage as X, entryGuard as Y, evaluateCondition as Z, evaluateGate as _, type VariableConfig as a, fnv1a as a0, formatMoney as a1, formatOffering as a2, hashToUnit as a3, isRtl as a4, isVariantKey as a5, nextPage as a6, outgoingKeys as a7, pageMeta as a8, parseSlotKey as a9, pickByWeight as aa, resolveExperiments as ab, resolveLocale as ac, resolveOffering as ad, resolveRoute as ae, type CheckoutUsageScan as af, type FunnelPage as ag, type OfferingRefScan as ah, type OfferingSlot as ai, funnelCatalogKeys as aj, normalizeOfferings as ak, scanOfferingRefs as al, weightsOf as am, type FunnelSnapshot as b, type FunnelDefinition as c, buildContext as d, type OfferingInput as e, type PageContext as f, type BuildContextOptions as g, type CompileInput as h, type Condition as i, type ConditionOp as j, type DeviceContext as k, type ExperimentArm as l, type ExperimentResolution as m, type FlowPage as n, type FunnelLocales as o, type FunnelManifest as p, type Interval as q, type ManifestPage as r, type ManifestValidation as s, type Money as t, type OsContext as u, type PageType as v, type Predicate as w, type ResolvedOffering as x, type Route as y, type SystemContext as z };
|
|
@@ -701,6 +701,55 @@ declare function resolveExperiments(pages: {
|
|
|
701
701
|
key: string;
|
|
702
702
|
}[], experiments: RuntimeExperiment[], seed: string | null): ExperimentResolution;
|
|
703
703
|
|
|
704
|
+
/**
|
|
705
|
+
* Pure, React-free page scan: find which offering SLOTS a funnel's pages reference — the first
|
|
706
|
+
* string-literal arg of `useOffering(...)` and the `offering` prop of `<Checkout>` / `<Upsell>`.
|
|
707
|
+
* Ships via `@appfunnel-dev/sdk/manifest` so the BUILD, the EDITOR, and the AI all run the SAME
|
|
708
|
+
* check. The result feeds `compileManifest({ offeringRefs })`, which flags references to slots the
|
|
709
|
+
* funnel doesn't declare (unknown) or hasn't assigned a catalog charge key to (unassigned).
|
|
710
|
+
*
|
|
711
|
+
* Non-literal args (`useOffering(selectedId)`, `offering={expr}`) and the `useOfferings()` wildcard are
|
|
712
|
+
* DYNAMIC — they can't be statically enumerated, so they're reported via `dynamic` and never turned
|
|
713
|
+
* into a hard error (validation relaxes when a funnel is dynamic). Mirrors the mask-then-read
|
|
714
|
+
* discipline the funnel.ts code-mods use, so a `useOffering('x')` inside a comment or string literal
|
|
715
|
+
* can't false-positive.
|
|
716
|
+
*/
|
|
717
|
+
interface OfferingRefScan {
|
|
718
|
+
/** Concrete slot names referenced by LITERAL args, deduped, in first-seen order. */
|
|
719
|
+
slots: string[];
|
|
720
|
+
/** True if any ref is a non-literal arg or a `useOfferings()` wildcard (not statically enumerable). */
|
|
721
|
+
dynamic: boolean;
|
|
722
|
+
/**
|
|
723
|
+
* Checkout-SURFACE usage the pages express — feeds the publish (provider × surface) capability
|
|
724
|
+
* gate. Absent-field back-compat: a manifest compiled before this existed simply omits it, and
|
|
725
|
+
* the gate skips (no false blocks). See {@link CheckoutUsageScan}.
|
|
726
|
+
*/
|
|
727
|
+
checkout: CheckoutUsageScan;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* What the pages ask the checkout to DO, statically — the surfaces they mount and the off-session
|
|
731
|
+
* upsell kinds they charge. Literal values only; a computed value (`surface={expr}`) sets
|
|
732
|
+
* {@link dynamic} so the publish gate WARNS instead of hard-failing (it can't enumerate it).
|
|
733
|
+
*/
|
|
734
|
+
interface CheckoutUsageScan {
|
|
735
|
+
/**
|
|
736
|
+
* Purchase SURFACES the pages request, deduped in first-seen order. Captures every literal
|
|
737
|
+
* `<Checkout surface="…">` plus the on-session re-collect surfaces `<Checkout|Upsell fallback="…">`
|
|
738
|
+
* and `recoverySurface="…"` (a fallback re-collects a card → it IS a purchase surface the provider
|
|
739
|
+
* must support). Validated with `validateCheckout(provider, surface)`.
|
|
740
|
+
*/
|
|
741
|
+
surfaces: string[];
|
|
742
|
+
/**
|
|
743
|
+
* Off-session upsell KINDS from `<Upsell kind="…">`, deduped. A `<Upsell>` with no `kind` attr
|
|
744
|
+
* defaults to `'subscription'` (mirrors the runtime default), so an unadorned `<Upsell>` records
|
|
745
|
+
* `'subscription'`. Validated with `validateUpsell(provider, paywallSurface, kind)`.
|
|
746
|
+
*/
|
|
747
|
+
upsellKinds: string[];
|
|
748
|
+
/** True if any surface/kind was a non-literal (computed) value → the gate WARNS, never blocks, on it. */
|
|
749
|
+
dynamic: boolean;
|
|
750
|
+
}
|
|
751
|
+
declare function scanOfferingRefs(files: Record<string, string>): OfferingRefScan;
|
|
752
|
+
|
|
704
753
|
/**
|
|
705
754
|
* The **manifest** — the declarative IR a funnel project compiles to (doc 06).
|
|
706
755
|
* It's the machine-readable artifact the platform operates on without executing
|
|
@@ -838,6 +887,18 @@ interface FunnelManifest {
|
|
|
838
887
|
offeringSlots: OfferingSlot[];
|
|
839
888
|
/** Slot names PAGES reference (from the build's scan); validated against `offeringSlots`. Absent = no scan ran. */
|
|
840
889
|
offeringRefs?: string[];
|
|
890
|
+
/**
|
|
891
|
+
* The funnel's `checkout:` driver bundle from `funnel.ts` (`FunnelDefinition.checkout`), carried so
|
|
892
|
+
* the publish gate can cross-validate it against the offerings' RESOLVED provider (§7 item 5 — the
|
|
893
|
+
* redundant field is never checked today). Absent = the funnel declares no `checkout:`.
|
|
894
|
+
*/
|
|
895
|
+
checkout?: 'stripe' | 'paddle';
|
|
896
|
+
/**
|
|
897
|
+
* Checkout-SURFACE usage the pages express (from `scanOfferingRefs(...).checkout`), carried so the
|
|
898
|
+
* publish (provider × surface) capability gate can run `validateCheckout`/`validateUpsell`. Absent =
|
|
899
|
+
* no scan ran (old manifest) → the gate skips capability validation (back-compat, no false blocks).
|
|
900
|
+
*/
|
|
901
|
+
checkoutRefs?: CheckoutUsageScan;
|
|
841
902
|
locales?: FunnelLocales;
|
|
842
903
|
validation: ManifestValidation;
|
|
843
904
|
}
|
|
@@ -850,8 +911,10 @@ interface CompileInput {
|
|
|
850
911
|
}[];
|
|
851
912
|
/** Slot names the funnel's PAGES reference (from `scanOfferingRefs`) — cross-checked against the declared slots. */
|
|
852
913
|
offeringRefs?: string[];
|
|
914
|
+
/** Checkout-surface usage the pages express (from `scanOfferingRefs(...).checkout`) — carried onto the manifest for the publish capability gate. */
|
|
915
|
+
checkoutRefs?: CheckoutUsageScan;
|
|
853
916
|
}
|
|
854
917
|
/** Compile a funnel's spine into its declarative {@link FunnelManifest} IR. */
|
|
855
918
|
declare function compileManifest(input: CompileInput): FunnelManifest;
|
|
856
919
|
|
|
857
|
-
export { expectedPathLength as $, type Acquisition as A, type BrowserContext as B, type ClickIdContext as C, type Direction as D, type EdgeCondition as E, type FunnelContext as F, type Gate as G, assignVariant as H, type IdentityContext as I, bucketingSeed as J, buildAcquisition as K, type LocaleContext as L, type ManifestEdge as M, buildCatalog as N, type Offering as O, type PageMeta as P, compileManifest as Q, type RuntimeExperiment as R, type SessionContext as S, currencyExponent as T, type UtmContext as U, type VariableValue as V, defineFunnel as W, definePage as X, entryGuard as Y, evaluateCondition as Z, evaluateGate as _, type VariableConfig as a, fnv1a as a0, formatMoney as a1, formatOffering as a2, hashToUnit as a3, isRtl as a4, isVariantKey as a5, nextPage as a6, outgoingKeys as a7, pageMeta as a8, parseSlotKey as a9, pickByWeight as aa, resolveExperiments as ab, resolveLocale as ac, resolveOffering as ad, resolveRoute as ae, type
|
|
920
|
+
export { expectedPathLength as $, type Acquisition as A, type BrowserContext as B, type ClickIdContext as C, type Direction as D, type EdgeCondition as E, type FunnelContext as F, type Gate as G, assignVariant as H, type IdentityContext as I, bucketingSeed as J, buildAcquisition as K, type LocaleContext as L, type ManifestEdge as M, buildCatalog as N, type Offering as O, type PageMeta as P, compileManifest as Q, type RuntimeExperiment as R, type SessionContext as S, currencyExponent as T, type UtmContext as U, type VariableValue as V, defineFunnel as W, definePage as X, entryGuard as Y, evaluateCondition as Z, evaluateGate as _, type VariableConfig as a, fnv1a as a0, formatMoney as a1, formatOffering as a2, hashToUnit as a3, isRtl as a4, isVariantKey as a5, nextPage as a6, outgoingKeys as a7, pageMeta as a8, parseSlotKey as a9, pickByWeight as aa, resolveExperiments as ab, resolveLocale as ac, resolveOffering as ad, resolveRoute as ae, type CheckoutUsageScan as af, type FunnelPage as ag, type OfferingRefScan as ah, type OfferingSlot as ai, funnelCatalogKeys as aj, normalizeOfferings as ak, scanOfferingRefs as al, weightsOf as am, type FunnelSnapshot as b, type FunnelDefinition as c, buildContext as d, type OfferingInput as e, type PageContext as f, type BuildContextOptions as g, type CompileInput as h, type Condition as i, type ConditionOp as j, type DeviceContext as k, type ExperimentArm as l, type ExperimentResolution as m, type FlowPage as n, type FunnelLocales as o, type FunnelManifest as p, type Interval as q, type ManifestPage as r, type ManifestValidation as s, type Money as t, type OsContext as u, type PageType as v, type Predicate as w, type ResolvedOffering as x, type Route as y, type SystemContext as z };
|
package/dist/manifest-entry.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkY4YNJ2EX_cjs = require('./chunk-Y4YNJ2EX.cjs');
|
|
4
|
+
var chunkRY3LOSVZ_cjs = require('./chunk-RY3LOSVZ.cjs');
|
|
5
5
|
require('./chunk-EMMSS5I5.cjs');
|
|
6
6
|
|
|
7
7
|
// src/manifest/offering-refs.ts
|
|
@@ -60,6 +60,27 @@ function skipWs(masked, i) {
|
|
|
60
60
|
while (i < masked.length && (masked[i] === " " || masked[i] === " " || masked[i] === "\n" || masked[i] === "\r")) i++;
|
|
61
61
|
return i;
|
|
62
62
|
}
|
|
63
|
+
function tagAttrEnd(masked, from) {
|
|
64
|
+
let depth = 0;
|
|
65
|
+
for (let i = from; i < masked.length; i++) {
|
|
66
|
+
const c = masked[i];
|
|
67
|
+
if (c === "{") depth++;
|
|
68
|
+
else if (c === "}") {
|
|
69
|
+
if (depth > 0) depth--;
|
|
70
|
+
} else if (c === ">" && depth === 0) return i;
|
|
71
|
+
}
|
|
72
|
+
return masked.length;
|
|
73
|
+
}
|
|
74
|
+
function readAttr(src, masked, start, end, name) {
|
|
75
|
+
const re = new RegExp(`\\b${name}\\s*=\\s*`, "g");
|
|
76
|
+
re.lastIndex = start;
|
|
77
|
+
const m = re.exec(masked);
|
|
78
|
+
if (!m || m.index >= end) return null;
|
|
79
|
+
const at = m.index + m[0].length;
|
|
80
|
+
if (masked[at] === "{") return { dynamic: true };
|
|
81
|
+
const lit = literalAt(src, masked, at);
|
|
82
|
+
return lit !== null ? { value: lit } : { dynamic: true };
|
|
83
|
+
}
|
|
63
84
|
function scanOfferingRefs(files) {
|
|
64
85
|
const seen = /* @__PURE__ */ new Set();
|
|
65
86
|
const order = [];
|
|
@@ -70,6 +91,23 @@ function scanOfferingRefs(files) {
|
|
|
70
91
|
order.push(v);
|
|
71
92
|
}
|
|
72
93
|
};
|
|
94
|
+
const surfaceSeen = /* @__PURE__ */ new Set();
|
|
95
|
+
const surfaces = [];
|
|
96
|
+
const kindSeen = /* @__PURE__ */ new Set();
|
|
97
|
+
const upsellKinds = [];
|
|
98
|
+
let checkoutDynamic = false;
|
|
99
|
+
const addSurface = (v) => {
|
|
100
|
+
if (v && !surfaceSeen.has(v)) {
|
|
101
|
+
surfaceSeen.add(v);
|
|
102
|
+
surfaces.push(v);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const addKind = (v) => {
|
|
106
|
+
if (v && !kindSeen.has(v)) {
|
|
107
|
+
kindSeen.add(v);
|
|
108
|
+
upsellKinds.push(v);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
73
111
|
for (const [path, source] of Object.entries(files)) {
|
|
74
112
|
if (!/\.(tsx|jsx|ts|js)$/.test(path)) continue;
|
|
75
113
|
const masked = mask(source);
|
|
@@ -90,8 +128,30 @@ function scanOfferingRefs(files) {
|
|
|
90
128
|
if (lit !== null) add(lit);
|
|
91
129
|
else if (masked[j] === "{") dynamic = true;
|
|
92
130
|
}
|
|
131
|
+
for (const m of masked.matchAll(/<(Checkout|Upsell)\b/g)) {
|
|
132
|
+
const comp = m[1];
|
|
133
|
+
const tagStart = m.index + m[0].length;
|
|
134
|
+
const tagEnd = tagAttrEnd(masked, tagStart);
|
|
135
|
+
const attr = (name) => readAttr(source, masked, tagStart, tagEnd, name);
|
|
136
|
+
const fallback = attr("fallback");
|
|
137
|
+
if (fallback?.value) addSurface(fallback.value);
|
|
138
|
+
else if (fallback?.dynamic) checkoutDynamic = true;
|
|
139
|
+
const recovery = attr("recoverySurface");
|
|
140
|
+
if (recovery?.value) addSurface(recovery.value);
|
|
141
|
+
else if (recovery?.dynamic) checkoutDynamic = true;
|
|
142
|
+
if (comp === "Checkout") {
|
|
143
|
+
const surface = attr("surface");
|
|
144
|
+
if (surface?.value) addSurface(surface.value);
|
|
145
|
+
else if (surface?.dynamic) checkoutDynamic = true;
|
|
146
|
+
} else {
|
|
147
|
+
const kind = attr("kind");
|
|
148
|
+
if (kind?.value) addKind(kind.value);
|
|
149
|
+
else if (kind?.dynamic) checkoutDynamic = true;
|
|
150
|
+
else addKind("subscription");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
93
153
|
}
|
|
94
|
-
return { slots: order, dynamic };
|
|
154
|
+
return { slots: order, dynamic, checkout: { surfaces, upsellKinds, dynamic: checkoutDynamic } };
|
|
95
155
|
}
|
|
96
156
|
|
|
97
157
|
// src/flow/scaffold.ts
|
|
@@ -185,6 +245,7 @@ export const manifest = compileManifest({
|
|
|
185
245
|
funnel: config,
|
|
186
246
|
pages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),
|
|
187
247
|
offeringRefs: ${JSON.stringify(opts.offeringRefs ?? [])},
|
|
248
|
+
checkoutRefs: ${JSON.stringify(opts.checkoutRefs ?? { surfaces: [], upsellKinds: [], dynamic: false })},
|
|
188
249
|
})
|
|
189
250
|
|
|
190
251
|
export async function ssr(opts: MountOpts): Promise<string> {
|
|
@@ -208,115 +269,123 @@ if (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))
|
|
|
208
269
|
|
|
209
270
|
Object.defineProperty(exports, "assignVariant", {
|
|
210
271
|
enumerable: true,
|
|
211
|
-
get: function () { return
|
|
272
|
+
get: function () { return chunkY4YNJ2EX_cjs.assignVariant; }
|
|
212
273
|
});
|
|
213
274
|
Object.defineProperty(exports, "bucketingSeed", {
|
|
214
275
|
enumerable: true,
|
|
215
|
-
get: function () { return
|
|
276
|
+
get: function () { return chunkY4YNJ2EX_cjs.bucketingSeed; }
|
|
216
277
|
});
|
|
217
278
|
Object.defineProperty(exports, "buildCatalog", {
|
|
218
279
|
enumerable: true,
|
|
219
|
-
get: function () { return
|
|
280
|
+
get: function () { return chunkY4YNJ2EX_cjs.buildCatalog; }
|
|
220
281
|
});
|
|
221
282
|
Object.defineProperty(exports, "compileManifest", {
|
|
222
283
|
enumerable: true,
|
|
223
|
-
get: function () { return
|
|
284
|
+
get: function () { return chunkY4YNJ2EX_cjs.compileManifest; }
|
|
224
285
|
});
|
|
225
286
|
Object.defineProperty(exports, "currencyExponent", {
|
|
226
287
|
enumerable: true,
|
|
227
|
-
get: function () { return
|
|
288
|
+
get: function () { return chunkY4YNJ2EX_cjs.currencyExponent; }
|
|
228
289
|
});
|
|
229
290
|
Object.defineProperty(exports, "defineFunnel", {
|
|
230
291
|
enumerable: true,
|
|
231
|
-
get: function () { return
|
|
292
|
+
get: function () { return chunkY4YNJ2EX_cjs.defineFunnel; }
|
|
232
293
|
});
|
|
233
294
|
Object.defineProperty(exports, "entryGuard", {
|
|
234
295
|
enumerable: true,
|
|
235
|
-
get: function () { return
|
|
296
|
+
get: function () { return chunkY4YNJ2EX_cjs.entryGuard; }
|
|
236
297
|
});
|
|
237
298
|
Object.defineProperty(exports, "evaluateCondition", {
|
|
238
299
|
enumerable: true,
|
|
239
|
-
get: function () { return
|
|
300
|
+
get: function () { return chunkY4YNJ2EX_cjs.evaluateCondition; }
|
|
240
301
|
});
|
|
241
302
|
Object.defineProperty(exports, "formatMoney", {
|
|
242
303
|
enumerable: true,
|
|
243
|
-
get: function () { return
|
|
304
|
+
get: function () { return chunkY4YNJ2EX_cjs.formatMoney; }
|
|
244
305
|
});
|
|
245
306
|
Object.defineProperty(exports, "formatOffering", {
|
|
246
307
|
enumerable: true,
|
|
247
|
-
get: function () { return
|
|
308
|
+
get: function () { return chunkY4YNJ2EX_cjs.formatOffering; }
|
|
248
309
|
});
|
|
249
310
|
Object.defineProperty(exports, "funnelCatalogKeys", {
|
|
250
311
|
enumerable: true,
|
|
251
|
-
get: function () { return
|
|
312
|
+
get: function () { return chunkY4YNJ2EX_cjs.funnelCatalogKeys; }
|
|
252
313
|
});
|
|
253
314
|
Object.defineProperty(exports, "isRtl", {
|
|
254
315
|
enumerable: true,
|
|
255
|
-
get: function () { return
|
|
316
|
+
get: function () { return chunkY4YNJ2EX_cjs.isRtl; }
|
|
256
317
|
});
|
|
257
318
|
Object.defineProperty(exports, "isVariantKey", {
|
|
258
319
|
enumerable: true,
|
|
259
|
-
get: function () { return
|
|
320
|
+
get: function () { return chunkY4YNJ2EX_cjs.isVariantKey; }
|
|
260
321
|
});
|
|
261
322
|
Object.defineProperty(exports, "normalizeOfferings", {
|
|
262
323
|
enumerable: true,
|
|
263
|
-
get: function () { return
|
|
324
|
+
get: function () { return chunkY4YNJ2EX_cjs.normalizeOfferings; }
|
|
264
325
|
});
|
|
265
326
|
Object.defineProperty(exports, "pageMeta", {
|
|
266
327
|
enumerable: true,
|
|
267
|
-
get: function () { return
|
|
328
|
+
get: function () { return chunkY4YNJ2EX_cjs.pageMeta; }
|
|
268
329
|
});
|
|
269
330
|
Object.defineProperty(exports, "parseSlotKey", {
|
|
270
331
|
enumerable: true,
|
|
271
|
-
get: function () { return
|
|
332
|
+
get: function () { return chunkY4YNJ2EX_cjs.parseSlotKey; }
|
|
272
333
|
});
|
|
273
334
|
Object.defineProperty(exports, "resolveLocale", {
|
|
274
335
|
enumerable: true,
|
|
275
|
-
get: function () { return
|
|
336
|
+
get: function () { return chunkY4YNJ2EX_cjs.resolveLocale; }
|
|
276
337
|
});
|
|
277
338
|
Object.defineProperty(exports, "resolveOffering", {
|
|
278
339
|
enumerable: true,
|
|
279
|
-
get: function () { return
|
|
340
|
+
get: function () { return chunkY4YNJ2EX_cjs.resolveOffering; }
|
|
280
341
|
});
|
|
281
342
|
Object.defineProperty(exports, "weightsOf", {
|
|
282
343
|
enumerable: true,
|
|
283
|
-
get: function () { return
|
|
344
|
+
get: function () { return chunkY4YNJ2EX_cjs.weightsOf; }
|
|
284
345
|
});
|
|
285
346
|
Object.defineProperty(exports, "INLINE_SURFACES", {
|
|
286
347
|
enumerable: true,
|
|
287
|
-
get: function () { return
|
|
348
|
+
get: function () { return chunkRY3LOSVZ_cjs.INLINE_SURFACES; }
|
|
288
349
|
});
|
|
289
350
|
Object.defineProperty(exports, "PROVIDER_PROFILES", {
|
|
290
351
|
enumerable: true,
|
|
291
|
-
get: function () { return
|
|
352
|
+
get: function () { return chunkRY3LOSVZ_cjs.PROVIDER_PROFILES; }
|
|
292
353
|
});
|
|
293
354
|
Object.defineProperty(exports, "checkoutError", {
|
|
294
355
|
enumerable: true,
|
|
295
|
-
get: function () { return
|
|
356
|
+
get: function () { return chunkRY3LOSVZ_cjs.checkoutError; }
|
|
296
357
|
});
|
|
297
358
|
Object.defineProperty(exports, "isInlineSurface", {
|
|
298
359
|
enumerable: true,
|
|
299
|
-
get: function () { return
|
|
360
|
+
get: function () { return chunkRY3LOSVZ_cjs.isInlineSurface; }
|
|
300
361
|
});
|
|
301
362
|
Object.defineProperty(exports, "isMerchantOfRecord", {
|
|
302
363
|
enumerable: true,
|
|
303
|
-
get: function () { return
|
|
364
|
+
get: function () { return chunkRY3LOSVZ_cjs.isMerchantOfRecord; }
|
|
304
365
|
});
|
|
305
366
|
Object.defineProperty(exports, "isOrchestrator", {
|
|
306
367
|
enumerable: true,
|
|
307
|
-
get: function () { return
|
|
368
|
+
get: function () { return chunkRY3LOSVZ_cjs.isOrchestrator; }
|
|
308
369
|
});
|
|
309
370
|
Object.defineProperty(exports, "surfacesFor", {
|
|
310
371
|
enumerable: true,
|
|
311
|
-
get: function () { return
|
|
372
|
+
get: function () { return chunkRY3LOSVZ_cjs.surfacesFor; }
|
|
373
|
+
});
|
|
374
|
+
Object.defineProperty(exports, "trialShapesFor", {
|
|
375
|
+
enumerable: true,
|
|
376
|
+
get: function () { return chunkRY3LOSVZ_cjs.trialShapesFor; }
|
|
312
377
|
});
|
|
313
378
|
Object.defineProperty(exports, "validateCheckout", {
|
|
314
379
|
enumerable: true,
|
|
315
|
-
get: function () { return
|
|
380
|
+
get: function () { return chunkRY3LOSVZ_cjs.validateCheckout; }
|
|
381
|
+
});
|
|
382
|
+
Object.defineProperty(exports, "validateTrial", {
|
|
383
|
+
enumerable: true,
|
|
384
|
+
get: function () { return chunkRY3LOSVZ_cjs.validateTrial; }
|
|
316
385
|
});
|
|
317
386
|
Object.defineProperty(exports, "validateUpsell", {
|
|
318
387
|
enumerable: true,
|
|
319
|
-
get: function () { return
|
|
388
|
+
get: function () { return chunkRY3LOSVZ_cjs.validateUpsell; }
|
|
320
389
|
});
|
|
321
390
|
exports.generateDevEntry = generateDevEntry;
|
|
322
391
|
exports.generateEntryClient = generateEntryClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/manifest/offering-refs.ts","../src/flow/scaffold.ts"],"names":[],"mappings":"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","file":"manifest-entry.cjs","sourcesContent":["/**\n * Pure, React-free page scan: find which offering SLOTS a funnel's pages reference — the first\n * string-literal arg of `useOffering(...)` and the `offering` prop of `<Checkout>` / `<Upsell>`.\n * Ships via `@appfunnel-dev/sdk/manifest` so the BUILD, the EDITOR, and the AI all run the SAME\n * check. The result feeds `compileManifest({ offeringRefs })`, which flags references to slots the\n * funnel doesn't declare (unknown) or hasn't assigned a catalog charge key to (unassigned).\n *\n * Non-literal args (`useOffering(selectedId)`, `offering={expr}`) and the `useOfferings()` wildcard are\n * DYNAMIC — they can't be statically enumerated, so they're reported via `dynamic` and never turned\n * into a hard error (validation relaxes when a funnel is dynamic). Mirrors the mask-then-read\n * discipline the funnel.ts code-mods use, so a `useOffering('x')` inside a comment or string literal\n * can't false-positive.\n */\n\nexport interface OfferingRefScan {\n /** Concrete slot names referenced by LITERAL args, deduped, in first-seen order. */\n slots: string[]\n /** True if any ref is a non-literal arg or a `useOfferings()` wildcard (not statically enumerable). */\n dynamic: boolean\n}\n\n/** Blank comment + string/template CONTENTS (keep quote delimiters + length) so scans don't fire inside them. */\nfunction mask(src: string): string {\n const out = src.split('')\n const n = src.length\n let i = 0\n while (i < n) {\n const c = src[i]\n const d = src[i + 1]\n if (c === '/' && d === '/') {\n while (i < n && src[i] !== '\\n') { out[i] = ' '; i++ }\n } else if (c === '/' && d === '*') {\n out[i] = ' '; out[i + 1] = ' '; i += 2\n while (i < n) {\n if (src[i] === '*' && src[i + 1] === '/') { out[i] = ' '; out[i + 1] = ' '; i += 2; break }\n if (src[i] !== '\\n') out[i] = ' '\n i++\n }\n } else if (c === \"'\" || c === '\"' || c === '`') {\n i++\n while (i < n && src[i] !== c) {\n if (src[i] === '\\\\') { out[i] = ' '; i++; if (i < n && src[i] !== '\\n') out[i] = ' '; i++; continue }\n if (src[i] !== '\\n') out[i] = ' '\n i++\n }\n i++ // closing delimiter (kept)\n } else i++\n }\n return out.join('')\n}\n\n/** A quoted string literal starting at `open` (a quote char in the MASK). Value read from the ORIGINAL. */\nfunction literalAt(src: string, masked: string, open: number): string | null {\n const q = masked[open]\n if (q !== \"'\" && q !== '\"' && q !== '`') return null\n const close = masked.indexOf(q, open + 1)\n if (close === -1) return null\n return src.slice(open + 1, close)\n}\n\n/** Advance past whitespace in `masked` from `i`. */\nfunction skipWs(masked: string, i: number): number {\n while (i < masked.length && (masked[i] === ' ' || masked[i] === '\\t' || masked[i] === '\\n' || masked[i] === '\\r')) i++\n return i\n}\n\nexport function scanOfferingRefs(files: Record<string, string>): OfferingRefScan {\n const seen = new Set<string>()\n const order: string[] = []\n let dynamic = false\n const add = (v: string) => { if (v && !seen.has(v)) { seen.add(v); order.push(v) } }\n\n for (const [path, source] of Object.entries(files)) {\n if (!/\\.(tsx|jsx|ts|js)$/.test(path)) continue\n const masked = mask(source)\n\n // useOffering( … ) / useOfferings( … ) — positions on the MASK (a call inside a string won't match).\n for (const m of masked.matchAll(/\\buseOfferings?\\s*\\(/g)) {\n const plural = source.slice(m.index!, m.index! + 12) === 'useOfferings'\n const j = skipWs(masked, m.index! + m[0].length)\n if (masked[j] === ')') { if (plural) dynamic = true; continue } // useOfferings() = whole-catalog wildcard\n const lit = literalAt(source, masked, j)\n if (lit !== null) add(lit)\n else dynamic = true // useOffering(variable) — can't resolve statically\n }\n\n // <Checkout offering=\"…\"> / <Upsell offering=\"…\"> — the `offering` attribute value.\n for (const m of masked.matchAll(/<(?:Checkout|Upsell)\\b[^>]*?\\boffering\\s*=\\s*/g)) {\n const j = m.index! + m[0].length\n const lit = literalAt(source, masked, j)\n if (lit !== null) add(lit)\n else if (masked[j] === '{') dynamic = true // offering={expr}\n }\n }\n return { slots: order, dynamic }\n}\n","/**\n * Source generators for the funnel build \"machinery\" authors no longer write. `funnel.ts` (the\n * spine: id, responses, offerings, checkout, and the page list + declarative routing) plus the\n * `pages/` folder are the ONLY authored source. The build (renderer/builder) and the CLI dev server\n * call these to synthesize:\n * - `mount.tsx` — code-split page loaders + `createFunnelTree`\n * - `entry.client.tsx` — hydrate the SSR'd markup from injected data\n * - `entry.server.tsx` — `ssr()` + the compiled `manifest`\n *\n * All string templates, zero runtime deps — this module lives in the pure `@appfunnel-dev/sdk/\n * manifest` entry so tooling imports it without the funnel runtime.\n */\n\nexport interface ScaffoldOptions {\n\t/** Page component keys = `pages/<key>.tsx` filenames (base flow pages AND `@variant` pages). */\n\tpageKeys: string[]\n\t/** Import prefix to reach the funnel root: `'./'` at the root (build), `'../../'` in a subdir (CLI dev). */\n\timportPrefix?: string\n\t/** Whether a `layout.tsx` exists to wrap the pages. */\n\thasLayout?: boolean\n\t/** Whether a `styles.css` exists (client entry imports it). */\n\thasStyles?: boolean\n\t/** Checkout provider from `config.checkout` — wires the driver; omit for none. */\n\tcheckout?: 'stripe' | 'paddle' | null\n\t/** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */\n\tmessageLocales?: string[]\n\t/** Slot names the pages reference (from `scanOfferingRefs`), baked into the manifest for validation. */\n\tofferingRefs?: string[]\n}\n\n/** A safe JS identifier for a message-catalog import (`en` → `msg_en`, `pt-BR` → `msg_pt_BR`). */\nfunction msgId(locale: string): string {\n\treturn 'msg_' + locale.replace(/[^a-zA-Z0-9]/g, '_')\n}\n\nconst DRIVERS = {\n\tstripe: { name: 'stripeCheckoutDriver', sub: 'driver-stripe' },\n\tpaddle: { name: 'paddleCheckoutDriver', sub: 'driver-paddle' },\n} as const\n\nconst HEADER =\n\t'// GENERATED by Appfunnel — do not edit. Built from funnel.ts + the pages/ folder.\\n'\n\n/** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */\nexport function generateMount(opts: ScaffoldOptions): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst driver = opts.checkout ? DRIVERS[opts.checkout] : null\n\n\tconst locales = opts.messageLocales ?? []\n\tconst imports = [\n\t\t`import { createFunnelTree, type MountOpts, type RuntimePage } from '@appfunnel-dev/sdk'`,\n\t\tdriver &&\n\t\t\t`import { ${driver.name} } from '@appfunnel-dev/sdk/${driver.sub}'`,\n\t\t`import { config } from '${p}funnel'`,\n\t\topts.hasLayout && `import Layout from '${p}layout'`,\n\t\t...locales.map(\n\t\t\t(loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`\n\t\t),\n\t]\n\t\t.filter(Boolean)\n\t\t.join('\\n')\n\n\t// A static import() per page file so Vite emits one code-split chunk each.\n\tconst loaders = opts.pageKeys\n\t\t.map(\n\t\t\t(k) =>\n\t\t\t\t`\\t${JSON.stringify(k)}: () => import(${JSON.stringify(`${p}pages/${k}`)}),`\n\t\t)\n\t\t.join('\\n')\n\n\tconst treeArgs = [\n\t\t'config',\n\t\t'pages',\n\t\topts.hasLayout && 'layout: Layout',\n\t\tdriver && `checkoutDriver: ${driver.name}`,\n\t\tlocales.length > 0 && 'messages',\n\t]\n\t\t.filter(Boolean)\n\t\t.join(', ')\n\n\t// The baked message catalog: locale → messages/<locale>.json (so `t()` resolves at render).\n\tconst messagesConst =\n\t\tlocales.length > 0\n\t\t\t? `\\nconst messages = { ${locales.map((loc) => `${JSON.stringify(loc)}: ${msgId(loc)}`).join(', ')} }\\n`\n\t\t\t: ''\n\n\treturn `${HEADER}${imports}\n\nconst loaders: Record<string, () => Promise<unknown>> = {\n${loaders}\n}\n\n// Flow pages come from funnel.ts (order + meta + routing). A \\`@variant\\` page MAY also be declared\n// there (with its \\`@\\` key) to carry its OWN optional routing (\\`next\\`) — it still collapses out of\n// the linear flow by the \\`@\\` marker, but its meta rides along here. Any page file NOT declared is an\n// off-flow \\`@variant\\` with no own routing, appended with empty meta so it's still loadable.\nconst decls = config.pages ?? []\nconst flowKeys = new Set(decls.map((d) => d.key))\nexport const pages: RuntimePage[] = [\n\t...decls.map((d) => ({ key: d.key, meta: d, load: loaders[d.key] })),\n\t...Object.keys(loaders)\n\t\t.filter((k) => !flowKeys.has(k))\n\t\t.map((k) => ({ key: k, meta: {}, load: loaders[k] })),\n] as RuntimePage[]\n${messagesConst}\nexport const tree = createFunnelTree({ ${treeArgs} })\n\nexport type { MountOpts }\n`\n}\n\n/** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */\nexport function generateEntryClient(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>\n): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst styles = opts.hasStyles ? `import '${p}styles.css'\\n` : ''\n\treturn `${HEADER}${styles}import { hydrateRoot } from 'react-dom/client'\nimport { tree, type MountOpts } from './mount'\n\nconst dataEl = document.getElementById('__af_data')\nconst data = (dataEl?.textContent ? JSON.parse(dataEl.textContent) : {}) as MountOpts & {\n\tinitialKey?: string | null\n}\nconst root = document.getElementById('root')\n// FLASH-FREE HYDRATION (SSR-isolation Option B): always DEFER sessionValues on the client. The\n// markup we hydrate against is DEFAULT-state (build-time prerendered, or an SSR render with empty\n// sessionValues), so seeding the store with defaults for the first render is a byte-clean match —\n// no hydration mismatch. The visitor's saved answers (data.sessionValues, present on the \"tail\"\n// path) are then applied post-hydration, popping into already-visible controls with no empty\n// flash. On the cold path sessionValues is absent, so deferring is a no-op (identical output).\nif (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined, deferSessionValues: true }))\n`\n}\n\n/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */\nexport function generateEntryServer(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs'>\n): string {\n\tconst p = opts.importPrefix ?? './'\n\treturn `${HEADER}import { renderToReadableStream } from 'react-dom/server.browser'\nimport { compileManifest } from '@appfunnel-dev/sdk'\nimport { config } from '${p}funnel'\nimport { tree, pages, type MountOpts } from './mount'\n\nexport const manifest = compileManifest({\n\tfunnel: config,\n\tpages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),\n\tofferingRefs: ${JSON.stringify(opts.offeringRefs ?? [])},\n})\n\nexport async function ssr(opts: MountOpts): Promise<string> {\n\tconst stream = await renderToReadableStream(tree(opts))\n\tawait stream.allReady\n\treturn await new Response(stream).text()\n}\n`\n}\n\n/** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */\nexport function generateDevEntry(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {\n\t\tdata: unknown\n\t}\n): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst styles = opts.hasStyles ? `import '${p}styles.css'\\n` : ''\n\treturn `${HEADER}${styles}import { createRoot } from 'react-dom/client'\nimport { tree } from './mount'\n\nconst el = document.getElementById('root')\nif (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))\n`\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/manifest/offering-refs.ts","../src/flow/scaffold.ts"],"names":[],"mappings":";;;;;;;AAmDA,SAAS,KAAK,GAAA,EAAqB;AACjC,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,KAAA,CAAM,EAAE,CAAA;AACxB,EAAA,MAAM,IAAI,GAAA,CAAI,MAAA;AACd,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,IAAI,CAAA,EAAG;AACZ,IAAA,MAAM,CAAA,GAAI,IAAI,CAAC,CAAA;AACf,IAAA,MAAM,CAAA,GAAI,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA;AACnB,IAAA,IAAI,CAAA,KAAM,GAAA,IAAO,CAAA,KAAM,GAAA,EAAK;AAC1B,MAAA,OAAO,CAAA,GAAI,CAAA,IAAK,GAAA,CAAI,CAAC,MAAM,IAAA,EAAM;AAAE,QAAA,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA;AAAK,QAAA,CAAA,EAAA;AAAA,MAAI;AAAA,IACvD,CAAA,MAAA,IAAW,CAAA,KAAM,GAAA,IAAO,CAAA,KAAM,GAAA,EAAK;AACjC,MAAA,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA;AAAK,MAAA,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AAAK,MAAA,CAAA,IAAK,CAAA;AACrC,MAAA,OAAO,IAAI,CAAA,EAAG;AACZ,QAAA,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,GAAA,IAAO,IAAI,CAAA,GAAI,CAAC,MAAM,GAAA,EAAK;AAAE,UAAA,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA;AAAK,UAAA,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA;AAAK,UAAA,CAAA,IAAK,CAAA;AAAG,UAAA;AAAA,QAAM;AAC1F,QAAA,IAAI,IAAI,CAAC,CAAA,KAAM,IAAA,EAAM,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA;AAC9B,QAAA,CAAA,EAAA;AAAA,MACF;AAAA,IACF,WAAW,CAAA,KAAM,GAAA,IAAO,CAAA,KAAM,GAAA,IAAO,MAAM,GAAA,EAAK;AAC9C,MAAA,CAAA,EAAA;AACA,MAAA,OAAO,CAAA,GAAI,CAAA,IAAK,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG;AAC5B,QAAA,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,IAAA,EAAM;AAAE,UAAA,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA;AAAK,UAAA,CAAA,EAAA;AAAK,UAAA,IAAI,CAAA,GAAI,KAAK,GAAA,CAAI,CAAC,MAAM,IAAA,EAAM,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA;AAAK,UAAA,CAAA,EAAA;AAAK,UAAA;AAAA,QAAS;AACpG,QAAA,IAAI,IAAI,CAAC,CAAA,KAAM,IAAA,EAAM,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA;AAC9B,QAAA,CAAA,EAAA;AAAA,MACF;AACA,MAAA,CAAA,EAAA;AAAA,IACF,CAAA,MAAO,CAAA,EAAA;AAAA,EACT;AACA,EAAA,OAAO,GAAA,CAAI,KAAK,EAAE,CAAA;AACpB;AAGA,SAAS,SAAA,CAAU,GAAA,EAAa,MAAA,EAAgB,IAAA,EAA6B;AAC3E,EAAA,MAAM,CAAA,GAAI,OAAO,IAAI,CAAA;AACrB,EAAA,IAAI,MAAM,GAAA,IAAO,CAAA,KAAM,GAAA,IAAO,CAAA,KAAM,KAAK,OAAO,IAAA;AAChD,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,CAAQ,CAAA,EAAG,OAAO,CAAC,CAAA;AACxC,EAAA,IAAI,KAAA,KAAU,IAAI,OAAO,IAAA;AACzB,EAAA,OAAO,GAAA,CAAI,KAAA,CAAM,IAAA,GAAO,CAAA,EAAG,KAAK,CAAA;AAClC;AAGA,SAAS,MAAA,CAAO,QAAgB,CAAA,EAAmB;AACjD,EAAA,OAAO,IAAI,MAAA,CAAO,MAAA,KAAW,OAAO,CAAC,CAAA,KAAM,OAAO,MAAA,CAAO,CAAC,CAAA,KAAM,GAAA,IAAQ,OAAO,CAAC,CAAA,KAAM,QAAQ,MAAA,CAAO,CAAC,MAAM,IAAA,CAAA,EAAO,CAAA,EAAA;AACnH,EAAA,OAAO,CAAA;AACT;AAQA,SAAS,UAAA,CAAW,QAAgB,IAAA,EAAsB;AACxD,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,IAAS,CAAA,GAAI,IAAA,EAAM,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACzC,IAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,IAAA,IAAI,MAAM,GAAA,EAAK,KAAA,EAAA;AAAA,SAAA,IACN,MAAM,GAAA,EAAK;AAAE,MAAA,IAAI,QAAQ,CAAA,EAAG,KAAA,EAAA;AAAA,IAAQ,CAAA,MAAA,IACpC,CAAA,KAAM,GAAA,IAAO,KAAA,KAAU,GAAG,OAAO,CAAA;AAAA,EAC5C;AACA,EAAA,OAAO,MAAA,CAAO,MAAA;AAChB;AAOA,SAAS,QAAA,CACP,GAAA,EACA,MAAA,EACA,KAAA,EACA,KACA,IAAA,EAC8C;AAC9C,EAAA,MAAM,KAAK,IAAI,MAAA,CAAO,CAAA,GAAA,EAAM,IAAI,aAAa,GAAG,CAAA;AAChD,EAAA,EAAA,CAAG,SAAA,GAAY,KAAA;AACf,EAAA,MAAM,CAAA,GAAI,EAAA,CAAG,IAAA,CAAK,MAAM,CAAA;AACxB,EAAA,IAAI,CAAC,CAAA,IAAK,CAAA,CAAE,KAAA,IAAS,KAAK,OAAO,IAAA;AACjC,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,KAAA,GAAQ,CAAA,CAAE,CAAC,CAAA,CAAE,MAAA;AAC1B,EAAA,IAAI,OAAO,EAAE,CAAA,KAAM,KAAK,OAAO,EAAE,SAAS,IAAA,EAAK;AAC/C,EAAA,MAAM,GAAA,GAAM,SAAA,CAAU,GAAA,EAAK,MAAA,EAAQ,EAAE,CAAA;AACrC,EAAA,OAAO,GAAA,KAAQ,OAAO,EAAE,KAAA,EAAO,KAAI,GAAI,EAAE,SAAS,IAAA,EAAK;AACzD;AAEO,SAAS,iBAAiB,KAAA,EAAgD;AAC/E,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,MAAM,GAAA,GAAM,CAAC,CAAA,KAAc;AAAE,IAAA,IAAI,CAAA,IAAK,CAAC,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG;AAAE,MAAA,IAAA,CAAK,IAAI,CAAC,CAAA;AAAG,MAAA,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,IAAE;AAAA,EAAE,CAAA;AAInF,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,EAAA,MAAM,WAAqB,EAAC;AAC5B,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAY;AACjC,EAAA,MAAM,cAAwB,EAAC;AAC/B,EAAA,IAAI,eAAA,GAAkB,KAAA;AACtB,EAAA,MAAM,UAAA,GAAa,CAAC,CAAA,KAAc;AAAE,IAAA,IAAI,CAAA,IAAK,CAAC,WAAA,CAAY,GAAA,CAAI,CAAC,CAAA,EAAG;AAAE,MAAA,WAAA,CAAY,IAAI,CAAC,CAAA;AAAG,MAAA,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,IAAE;AAAA,EAAE,CAAA;AAC3G,EAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAAc;AAAE,IAAA,IAAI,CAAA,IAAK,CAAC,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,EAAG;AAAE,MAAA,QAAA,CAAS,IAAI,CAAC,CAAA;AAAG,MAAA,WAAA,CAAY,KAAK,CAAC,CAAA;AAAA,IAAE;AAAA,EAAE,CAAA;AAErG,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,MAAM,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAClD,IAAA,IAAI,CAAC,oBAAA,CAAqB,IAAA,CAAK,IAAI,CAAA,EAAG;AACtC,IAAA,MAAM,MAAA,GAAS,KAAK,MAAM,CAAA;AAG1B,IAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,QAAA,CAAS,uBAAuB,CAAA,EAAG;AACxD,MAAA,MAAM,MAAA,GAAS,OAAO,KAAA,CAAM,CAAA,CAAE,OAAQ,CAAA,CAAE,KAAA,GAAS,EAAE,CAAA,KAAM,cAAA;AACzD,MAAA,MAAM,CAAA,GAAI,OAAO,MAAA,EAAQ,CAAA,CAAE,QAAS,CAAA,CAAE,CAAC,EAAE,MAAM,CAAA;AAC/C,MAAA,IAAI,MAAA,CAAO,CAAC,CAAA,KAAM,GAAA,EAAK;AAAE,QAAA,IAAI,QAAQ,OAAA,GAAU,IAAA;AAAM,QAAA;AAAA,MAAS;AAC9D,MAAA,MAAM,GAAA,GAAM,SAAA,CAAU,MAAA,EAAQ,MAAA,EAAQ,CAAC,CAAA;AACvC,MAAA,IAAI,GAAA,KAAQ,IAAA,EAAM,GAAA,CAAI,GAAG,CAAA;AAAA,WACpB,OAAA,GAAU,IAAA;AAAA,IACjB;AAGA,IAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,QAAA,CAAS,gDAAgD,CAAA,EAAG;AACjF,MAAA,MAAM,CAAA,GAAI,CAAA,CAAE,KAAA,GAAS,CAAA,CAAE,CAAC,CAAA,CAAE,MAAA;AAC1B,MAAA,MAAM,GAAA,GAAM,SAAA,CAAU,MAAA,EAAQ,MAAA,EAAQ,CAAC,CAAA;AACvC,MAAA,IAAI,GAAA,KAAQ,IAAA,EAAM,GAAA,CAAI,GAAG,CAAA;AAAA,WAAA,IAChB,MAAA,CAAO,CAAC,CAAA,KAAM,GAAA,EAAK,OAAA,GAAU,IAAA;AAAA,IACxC;AAIA,IAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,QAAA,CAAS,uBAAuB,CAAA,EAAG;AACxD,MAAA,MAAM,IAAA,GAAO,EAAE,CAAC,CAAA;AAChB,MAAA,MAAM,QAAA,GAAW,CAAA,CAAE,KAAA,GAAS,CAAA,CAAE,CAAC,CAAA,CAAE,MAAA;AACjC,MAAA,MAAM,MAAA,GAAS,UAAA,CAAW,MAAA,EAAQ,QAAQ,CAAA;AAC1C,MAAA,MAAM,IAAA,GAAO,CAAC,IAAA,KAAiB,QAAA,CAAS,QAAQ,MAAA,EAAQ,QAAA,EAAU,QAAQ,IAAI,CAAA;AAE9E,MAAA,MAAM,QAAA,GAAW,KAAK,UAAU,CAAA;AAChC,MAAA,IAAI,QAAA,EAAU,KAAA,EAAO,UAAA,CAAW,QAAA,CAAS,KAAK,CAAA;AAAA,WAAA,IACrC,QAAA,EAAU,SAAS,eAAA,GAAkB,IAAA;AAC9C,MAAA,MAAM,QAAA,GAAW,KAAK,iBAAiB,CAAA;AACvC,MAAA,IAAI,QAAA,EAAU,KAAA,EAAO,UAAA,CAAW,QAAA,CAAS,KAAK,CAAA;AAAA,WAAA,IACrC,QAAA,EAAU,SAAS,eAAA,GAAkB,IAAA;AAE9C,MAAA,IAAI,SAAS,UAAA,EAAY;AACvB,QAAA,MAAM,OAAA,GAAU,KAAK,SAAS,CAAA;AAC9B,QAAA,IAAI,OAAA,EAAS,KAAA,EAAO,UAAA,CAAW,OAAA,CAAQ,KAAK,CAAA;AAAA,aAAA,IACnC,OAAA,EAAS,SAAS,eAAA,GAAkB,IAAA;AAAA,MAC/C,CAAA,MAAO;AAEL,QAAA,MAAM,IAAA,GAAO,KAAK,MAAM,CAAA;AACxB,QAAA,IAAI,IAAA,EAAM,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA;AAAA,aAAA,IAC1B,IAAA,EAAM,SAAS,eAAA,GAAkB,IAAA;AAAA,qBAC7B,cAAc,CAAA;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,QAAA,EAAU,EAAE,QAAA,EAAU,WAAA,EAAa,OAAA,EAAS,eAAA,EAAgB,EAAE;AAChG;;;ACtKA,SAAS,MAAM,MAAA,EAAwB;AACtC,EAAA,OAAO,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,eAAA,EAAiB,GAAG,CAAA;AACpD;AAEA,IAAM,OAAA,GAAU;AAAA,EACf,MAAA,EAAQ,EAAE,IAAA,EAAM,sBAAA,EAAwB,KAAK,eAAA,EAAgB;AAAA,EAC7D,MAAA,EAAQ,EAAE,IAAA,EAAM,sBAAA,EAAwB,KAAK,eAAA;AAC9C,CAAA;AAEA,IAAM,MAAA,GACL,2FAAA;AAGM,SAAS,cAAc,IAAA,EAA+B;AAC5D,EAAA,MAAM,CAAA,GAAI,KAAK,YAAA,IAAgB,IAAA;AAC/B,EAAA,MAAM,SAAS,IAAA,CAAK,QAAA,GAAW,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,GAAI,IAAA;AAExD,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,cAAA,IAAkB,EAAC;AACxC,EAAA,MAAM,OAAA,GAAU;AAAA,IACf,CAAA,uFAAA,CAAA;AAAA,IACA,UACC,CAAA,SAAA,EAAY,MAAA,CAAO,IAAI,CAAA,4BAAA,EAA+B,OAAO,GAAG,CAAA,CAAA,CAAA;AAAA,IACjE,2BAA2B,CAAC,CAAA,OAAA,CAAA;AAAA,IAC5B,IAAA,CAAK,SAAA,IAAa,CAAA,oBAAA,EAAuB,CAAC,CAAA,OAAA,CAAA;AAAA,IAC1C,GAAG,OAAA,CAAQ,GAAA;AAAA,MACV,CAAC,QAAQ,CAAA,OAAA,EAAU,KAAA,CAAM,GAAG,CAAC,CAAA,OAAA,EAAU,CAAC,CAAA,SAAA,EAAY,GAAG,CAAA,MAAA;AAAA;AACxD,GACD,CACE,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,IAAI,CAAA;AAGX,EAAA,MAAM,OAAA,GAAU,KAAK,QAAA,CACnB,GAAA;AAAA,IACA,CAAC,CAAA,KACA,CAAA,CAAA,EAAK,IAAA,CAAK,UAAU,CAAC,CAAC,CAAA,eAAA,EAAkB,IAAA,CAAK,UAAU,CAAA,EAAG,CAAC,CAAA,MAAA,EAAS,CAAC,EAAE,CAAC,CAAA,EAAA;AAAA,GAC1E,CACC,KAAK,IAAI,CAAA;AAEX,EAAA,MAAM,QAAA,GAAW;AAAA,IAChB,QAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAK,SAAA,IAAa,gBAAA;AAAA,IAClB,MAAA,IAAU,CAAA,gBAAA,EAAmB,MAAA,CAAO,IAAI,CAAA,CAAA;AAAA,IACxC,OAAA,CAAQ,SAAS,CAAA,IAAK;AAAA,GACvB,CACE,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,IAAI,CAAA;AAGX,EAAA,MAAM,aAAA,GACL,OAAA,CAAQ,MAAA,GAAS,CAAA,GACd;AAAA,mBAAA,EAAwB,QAAQ,GAAA,CAAI,CAAC,GAAA,KAAQ,CAAA,EAAG,KAAK,SAAA,CAAU,GAAG,CAAC,CAAA,EAAA,EAAK,MAAM,GAAG,CAAC,EAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,CAAA,GAChG,EAAA;AAEJ,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,OAAO;;AAAA;AAAA,EAGzB,OAAO;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeP,aAAa;AAAA,uCAAA,EAC0B,QAAQ,CAAA;;AAAA;AAAA,CAAA;AAIjD;AAGO,SAAS,oBACf,IAAA,EACS;AACT,EAAA,MAAM,CAAA,GAAI,KAAK,YAAA,IAAgB,IAAA;AAC/B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,GAAY,CAAA,QAAA,EAAW,CAAC,CAAA;AAAA,CAAA,GAAkB,EAAA;AAC9D,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,MAAM,CAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAgB1B;AAGO,SAAS,oBACf,IAAA,EACS;AACT,EAAA,MAAM,CAAA,GAAI,KAAK,YAAA,IAAgB,IAAA;AAC/B,EAAA,OAAO,GAAG,MAAM,CAAA;AAAA;AAAA,wBAAA,EAES,CAAC,CAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,eAAA,EAMV,KAAK,SAAA,CAAU,IAAA,CAAK,YAAA,IAAgB,EAAE,CAAC,CAAA;AAAA,eAAA,EACvC,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,YAAA,IAAgB,EAAE,QAAA,EAAU,EAAC,EAAG,WAAA,EAAa,EAAC,EAAG,OAAA,EAAS,KAAA,EAAO,CAAC,CAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AASvG;AAGO,SAAS,iBACf,IAAA,EAGS;AACT,EAAA,MAAM,CAAA,GAAI,KAAK,YAAA,IAAgB,IAAA;AAC/B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,GAAY,CAAA,QAAA,EAAW,CAAC,CAAA;AAAA,CAAA,GAAkB,EAAA;AAC9D,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,MAAM,CAAA;AAAA;;AAAA;AAAA,mCAAA,EAIW,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,CAAA;AAE9D","file":"manifest-entry.cjs","sourcesContent":["/**\n * Pure, React-free page scan: find which offering SLOTS a funnel's pages reference — the first\n * string-literal arg of `useOffering(...)` and the `offering` prop of `<Checkout>` / `<Upsell>`.\n * Ships via `@appfunnel-dev/sdk/manifest` so the BUILD, the EDITOR, and the AI all run the SAME\n * check. The result feeds `compileManifest({ offeringRefs })`, which flags references to slots the\n * funnel doesn't declare (unknown) or hasn't assigned a catalog charge key to (unassigned).\n *\n * Non-literal args (`useOffering(selectedId)`, `offering={expr}`) and the `useOfferings()` wildcard are\n * DYNAMIC — they can't be statically enumerated, so they're reported via `dynamic` and never turned\n * into a hard error (validation relaxes when a funnel is dynamic). Mirrors the mask-then-read\n * discipline the funnel.ts code-mods use, so a `useOffering('x')` inside a comment or string literal\n * can't false-positive.\n */\n\nexport interface OfferingRefScan {\n /** Concrete slot names referenced by LITERAL args, deduped, in first-seen order. */\n slots: string[]\n /** True if any ref is a non-literal arg or a `useOfferings()` wildcard (not statically enumerable). */\n dynamic: boolean\n /**\n * Checkout-SURFACE usage the pages express — feeds the publish (provider × surface) capability\n * gate. Absent-field back-compat: a manifest compiled before this existed simply omits it, and\n * the gate skips (no false blocks). See {@link CheckoutUsageScan}.\n */\n checkout: CheckoutUsageScan\n}\n\n/**\n * What the pages ask the checkout to DO, statically — the surfaces they mount and the off-session\n * upsell kinds they charge. Literal values only; a computed value (`surface={expr}`) sets\n * {@link dynamic} so the publish gate WARNS instead of hard-failing (it can't enumerate it).\n */\nexport interface CheckoutUsageScan {\n /**\n * Purchase SURFACES the pages request, deduped in first-seen order. Captures every literal\n * `<Checkout surface=\"…\">` plus the on-session re-collect surfaces `<Checkout|Upsell fallback=\"…\">`\n * and `recoverySurface=\"…\"` (a fallback re-collects a card → it IS a purchase surface the provider\n * must support). Validated with `validateCheckout(provider, surface)`.\n */\n surfaces: string[]\n /**\n * Off-session upsell KINDS from `<Upsell kind=\"…\">`, deduped. A `<Upsell>` with no `kind` attr\n * defaults to `'subscription'` (mirrors the runtime default), so an unadorned `<Upsell>` records\n * `'subscription'`. Validated with `validateUpsell(provider, paywallSurface, kind)`.\n */\n upsellKinds: string[]\n /** True if any surface/kind was a non-literal (computed) value → the gate WARNS, never blocks, on it. */\n dynamic: boolean\n}\n\n/** Blank comment + string/template CONTENTS (keep quote delimiters + length) so scans don't fire inside them. */\nfunction mask(src: string): string {\n const out = src.split('')\n const n = src.length\n let i = 0\n while (i < n) {\n const c = src[i]\n const d = src[i + 1]\n if (c === '/' && d === '/') {\n while (i < n && src[i] !== '\\n') { out[i] = ' '; i++ }\n } else if (c === '/' && d === '*') {\n out[i] = ' '; out[i + 1] = ' '; i += 2\n while (i < n) {\n if (src[i] === '*' && src[i + 1] === '/') { out[i] = ' '; out[i + 1] = ' '; i += 2; break }\n if (src[i] !== '\\n') out[i] = ' '\n i++\n }\n } else if (c === \"'\" || c === '\"' || c === '`') {\n i++\n while (i < n && src[i] !== c) {\n if (src[i] === '\\\\') { out[i] = ' '; i++; if (i < n && src[i] !== '\\n') out[i] = ' '; i++; continue }\n if (src[i] !== '\\n') out[i] = ' '\n i++\n }\n i++ // closing delimiter (kept)\n } else i++\n }\n return out.join('')\n}\n\n/** A quoted string literal starting at `open` (a quote char in the MASK). Value read from the ORIGINAL. */\nfunction literalAt(src: string, masked: string, open: number): string | null {\n const q = masked[open]\n if (q !== \"'\" && q !== '\"' && q !== '`') return null\n const close = masked.indexOf(q, open + 1)\n if (close === -1) return null\n return src.slice(open + 1, close)\n}\n\n/** Advance past whitespace in `masked` from `i`. */\nfunction skipWs(masked: string, i: number): number {\n while (i < masked.length && (masked[i] === ' ' || masked[i] === '\\t' || masked[i] === '\\n' || masked[i] === '\\r')) i++\n return i\n}\n\n/**\n * Index of the `>` that closes the opening tag begun at `from` (the char after `<Checkout`). Tracks\n * brace depth so a `surface={a > b}` attribute expression doesn't end the tag early; `>` at depth 0\n * closes it (covers `/>` too — the `/` is at depth 0 and we stop at `>`). Returns end-of-string if\n * the tag never closes (masked never fires a value scan past it).\n */\nfunction tagAttrEnd(masked: string, from: number): number {\n let depth = 0\n for (let i = from; i < masked.length; i++) {\n const c = masked[i]\n if (c === '{') depth++\n else if (c === '}') { if (depth > 0) depth-- }\n else if (c === '>' && depth === 0) return i\n }\n return masked.length\n}\n\n/**\n * Read a JSX attribute `name` inside the opening-tag span `[start, end)`: returns its literal value,\n * `{ dynamic: true }` for a `{expr}` value, or null when the attribute is absent. Positions are on\n * the MASK; the value is read from the ORIGINAL (so a string-literal value survives masking).\n */\nfunction readAttr(\n src: string,\n masked: string,\n start: number,\n end: number,\n name: string,\n): { value?: string; dynamic?: boolean } | null {\n const re = new RegExp(`\\\\b${name}\\\\s*=\\\\s*`, 'g')\n re.lastIndex = start\n const m = re.exec(masked)\n if (!m || m.index >= end) return null\n const at = m.index + m[0].length\n if (masked[at] === '{') return { dynamic: true }\n const lit = literalAt(src, masked, at)\n return lit !== null ? { value: lit } : { dynamic: true }\n}\n\nexport function scanOfferingRefs(files: Record<string, string>): OfferingRefScan {\n const seen = new Set<string>()\n const order: string[] = []\n let dynamic = false\n const add = (v: string) => { if (v && !seen.has(v)) { seen.add(v); order.push(v) } }\n\n // Checkout-surface usage (separate dynamic flag: a computed SURFACE relaxes the capability gate,\n // independent of whether an OFFERING ref is computed).\n const surfaceSeen = new Set<string>()\n const surfaces: string[] = []\n const kindSeen = new Set<string>()\n const upsellKinds: string[] = []\n let checkoutDynamic = false\n const addSurface = (v: string) => { if (v && !surfaceSeen.has(v)) { surfaceSeen.add(v); surfaces.push(v) } }\n const addKind = (v: string) => { if (v && !kindSeen.has(v)) { kindSeen.add(v); upsellKinds.push(v) } }\n\n for (const [path, source] of Object.entries(files)) {\n if (!/\\.(tsx|jsx|ts|js)$/.test(path)) continue\n const masked = mask(source)\n\n // useOffering( … ) / useOfferings( … ) — positions on the MASK (a call inside a string won't match).\n for (const m of masked.matchAll(/\\buseOfferings?\\s*\\(/g)) {\n const plural = source.slice(m.index!, m.index! + 12) === 'useOfferings'\n const j = skipWs(masked, m.index! + m[0].length)\n if (masked[j] === ')') { if (plural) dynamic = true; continue } // useOfferings() = whole-catalog wildcard\n const lit = literalAt(source, masked, j)\n if (lit !== null) add(lit)\n else dynamic = true // useOffering(variable) — can't resolve statically\n }\n\n // <Checkout offering=\"…\"> / <Upsell offering=\"…\"> — the `offering` attribute value.\n for (const m of masked.matchAll(/<(?:Checkout|Upsell)\\b[^>]*?\\boffering\\s*=\\s*/g)) {\n const j = m.index! + m[0].length\n const lit = literalAt(source, masked, j)\n if (lit !== null) add(lit)\n else if (masked[j] === '{') dynamic = true // offering={expr}\n }\n\n // <Checkout …> / <Upsell …> checkout-SURFACE usage. Parse each opening tag's attribute span so\n // attribute order doesn't matter and a `>` inside a `{expr}` value can't truncate it.\n for (const m of masked.matchAll(/<(Checkout|Upsell)\\b/g)) {\n const comp = m[1]\n const tagStart = m.index! + m[0].length\n const tagEnd = tagAttrEnd(masked, tagStart)\n const attr = (name: string) => readAttr(source, masked, tagStart, tagEnd, name)\n // A fallback / recoverySurface re-collects a card ON-SESSION → it's a purchase surface too.\n const fallback = attr('fallback')\n if (fallback?.value) addSurface(fallback.value)\n else if (fallback?.dynamic) checkoutDynamic = true\n const recovery = attr('recoverySurface')\n if (recovery?.value) addSurface(recovery.value)\n else if (recovery?.dynamic) checkoutDynamic = true\n\n if (comp === 'Checkout') {\n const surface = attr('surface')\n if (surface?.value) addSurface(surface.value)\n else if (surface?.dynamic) checkoutDynamic = true\n } else {\n // <Upsell>: off-session; `kind` defaults to 'subscription' when the attr is absent.\n const kind = attr('kind')\n if (kind?.value) addKind(kind.value)\n else if (kind?.dynamic) checkoutDynamic = true\n else addKind('subscription')\n }\n }\n }\n return { slots: order, dynamic, checkout: { surfaces, upsellKinds, dynamic: checkoutDynamic } }\n}\n","/**\n * Source generators for the funnel build \"machinery\" authors no longer write. `funnel.ts` (the\n * spine: id, responses, offerings, checkout, and the page list + declarative routing) plus the\n * `pages/` folder are the ONLY authored source. The build (renderer/builder) and the CLI dev server\n * call these to synthesize:\n * - `mount.tsx` — code-split page loaders + `createFunnelTree`\n * - `entry.client.tsx` — hydrate the SSR'd markup from injected data\n * - `entry.server.tsx` — `ssr()` + the compiled `manifest`\n *\n * All string templates, zero runtime deps — this module lives in the pure `@appfunnel-dev/sdk/\n * manifest` entry so tooling imports it without the funnel runtime.\n */\n\nimport type { CheckoutUsageScan } from '../manifest/offering-refs'\n\nexport interface ScaffoldOptions {\n\t/** Page component keys = `pages/<key>.tsx` filenames (base flow pages AND `@variant` pages). */\n\tpageKeys: string[]\n\t/** Import prefix to reach the funnel root: `'./'` at the root (build), `'../../'` in a subdir (CLI dev). */\n\timportPrefix?: string\n\t/** Whether a `layout.tsx` exists to wrap the pages. */\n\thasLayout?: boolean\n\t/** Whether a `styles.css` exists (client entry imports it). */\n\thasStyles?: boolean\n\t/** Checkout provider from `config.checkout` — wires the driver; omit for none. */\n\tcheckout?: 'stripe' | 'paddle' | null\n\t/** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */\n\tmessageLocales?: string[]\n\t/** Slot names the pages reference (from `scanOfferingRefs`), baked into the manifest for validation. */\n\tofferingRefs?: string[]\n\t/** Checkout-surface usage the pages express (from `scanOfferingRefs(...).checkout`), baked into the manifest for the publish capability gate. */\n\tcheckoutRefs?: CheckoutUsageScan\n}\n\n/** A safe JS identifier for a message-catalog import (`en` → `msg_en`, `pt-BR` → `msg_pt_BR`). */\nfunction msgId(locale: string): string {\n\treturn 'msg_' + locale.replace(/[^a-zA-Z0-9]/g, '_')\n}\n\nconst DRIVERS = {\n\tstripe: { name: 'stripeCheckoutDriver', sub: 'driver-stripe' },\n\tpaddle: { name: 'paddleCheckoutDriver', sub: 'driver-paddle' },\n} as const\n\nconst HEADER =\n\t'// GENERATED by Appfunnel — do not edit. Built from funnel.ts + the pages/ folder.\\n'\n\n/** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */\nexport function generateMount(opts: ScaffoldOptions): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst driver = opts.checkout ? DRIVERS[opts.checkout] : null\n\n\tconst locales = opts.messageLocales ?? []\n\tconst imports = [\n\t\t`import { createFunnelTree, type MountOpts, type RuntimePage } from '@appfunnel-dev/sdk'`,\n\t\tdriver &&\n\t\t\t`import { ${driver.name} } from '@appfunnel-dev/sdk/${driver.sub}'`,\n\t\t`import { config } from '${p}funnel'`,\n\t\topts.hasLayout && `import Layout from '${p}layout'`,\n\t\t...locales.map(\n\t\t\t(loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`\n\t\t),\n\t]\n\t\t.filter(Boolean)\n\t\t.join('\\n')\n\n\t// A static import() per page file so Vite emits one code-split chunk each.\n\tconst loaders = opts.pageKeys\n\t\t.map(\n\t\t\t(k) =>\n\t\t\t\t`\\t${JSON.stringify(k)}: () => import(${JSON.stringify(`${p}pages/${k}`)}),`\n\t\t)\n\t\t.join('\\n')\n\n\tconst treeArgs = [\n\t\t'config',\n\t\t'pages',\n\t\topts.hasLayout && 'layout: Layout',\n\t\tdriver && `checkoutDriver: ${driver.name}`,\n\t\tlocales.length > 0 && 'messages',\n\t]\n\t\t.filter(Boolean)\n\t\t.join(', ')\n\n\t// The baked message catalog: locale → messages/<locale>.json (so `t()` resolves at render).\n\tconst messagesConst =\n\t\tlocales.length > 0\n\t\t\t? `\\nconst messages = { ${locales.map((loc) => `${JSON.stringify(loc)}: ${msgId(loc)}`).join(', ')} }\\n`\n\t\t\t: ''\n\n\treturn `${HEADER}${imports}\n\nconst loaders: Record<string, () => Promise<unknown>> = {\n${loaders}\n}\n\n// Flow pages come from funnel.ts (order + meta + routing). A \\`@variant\\` page MAY also be declared\n// there (with its \\`@\\` key) to carry its OWN optional routing (\\`next\\`) — it still collapses out of\n// the linear flow by the \\`@\\` marker, but its meta rides along here. Any page file NOT declared is an\n// off-flow \\`@variant\\` with no own routing, appended with empty meta so it's still loadable.\nconst decls = config.pages ?? []\nconst flowKeys = new Set(decls.map((d) => d.key))\nexport const pages: RuntimePage[] = [\n\t...decls.map((d) => ({ key: d.key, meta: d, load: loaders[d.key] })),\n\t...Object.keys(loaders)\n\t\t.filter((k) => !flowKeys.has(k))\n\t\t.map((k) => ({ key: k, meta: {}, load: loaders[k] })),\n] as RuntimePage[]\n${messagesConst}\nexport const tree = createFunnelTree({ ${treeArgs} })\n\nexport type { MountOpts }\n`\n}\n\n/** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */\nexport function generateEntryClient(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>\n): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst styles = opts.hasStyles ? `import '${p}styles.css'\\n` : ''\n\treturn `${HEADER}${styles}import { hydrateRoot } from 'react-dom/client'\nimport { tree, type MountOpts } from './mount'\n\nconst dataEl = document.getElementById('__af_data')\nconst data = (dataEl?.textContent ? JSON.parse(dataEl.textContent) : {}) as MountOpts & {\n\tinitialKey?: string | null\n}\nconst root = document.getElementById('root')\n// FLASH-FREE HYDRATION (SSR-isolation Option B): always DEFER sessionValues on the client. The\n// markup we hydrate against is DEFAULT-state (build-time prerendered, or an SSR render with empty\n// sessionValues), so seeding the store with defaults for the first render is a byte-clean match —\n// no hydration mismatch. The visitor's saved answers (data.sessionValues, present on the \"tail\"\n// path) are then applied post-hydration, popping into already-visible controls with no empty\n// flash. On the cold path sessionValues is absent, so deferring is a no-op (identical output).\nif (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined, deferSessionValues: true }))\n`\n}\n\n/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */\nexport function generateEntryServer(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs' | 'checkoutRefs'>\n): string {\n\tconst p = opts.importPrefix ?? './'\n\treturn `${HEADER}import { renderToReadableStream } from 'react-dom/server.browser'\nimport { compileManifest } from '@appfunnel-dev/sdk'\nimport { config } from '${p}funnel'\nimport { tree, pages, type MountOpts } from './mount'\n\nexport const manifest = compileManifest({\n\tfunnel: config,\n\tpages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),\n\tofferingRefs: ${JSON.stringify(opts.offeringRefs ?? [])},\n\tcheckoutRefs: ${JSON.stringify(opts.checkoutRefs ?? { surfaces: [], upsellKinds: [], dynamic: false })},\n})\n\nexport async function ssr(opts: MountOpts): Promise<string> {\n\tconst stream = await renderToReadableStream(tree(opts))\n\tawait stream.allReady\n\treturn await new Response(stream).text()\n}\n`\n}\n\n/** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */\nexport function generateDevEntry(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {\n\t\tdata: unknown\n\t}\n): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst styles = opts.hasStyles ? `import '${p}styles.css'\\n` : ''\n\treturn `${HEADER}${styles}import { createRoot } from 'react-dom/client'\nimport { tree } from './mount'\n\nconst el = document.getElementById('root')\nif (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))\n`\n}\n"]}
|
|
@@ -1,29 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { af as CheckoutUsageScan } from './manifest-B3Tdab0M.cjs';
|
|
2
|
+
export { h as CompileInput, i as Condition, j as ConditionOp, E as EdgeCondition, l as ExperimentArm, n as FlowPage, c as FunnelDefinition, o as FunnelLocales, p as FunnelManifest, ag as FunnelPage, b as FunnelSnapshot, G as Gate, q as Interval, M as ManifestEdge, r as ManifestPage, s as ManifestValidation, t as Money, O as Offering, e as OfferingInput, ah as OfferingRefScan, ai as OfferingSlot, P as PageMeta, v as PageType, w as Predicate, x as ResolvedOffering, y as Route, R as RuntimeExperiment, H as assignVariant, J as bucketingSeed, N as buildCatalog, Q as compileManifest, T as currencyExponent, W as defineFunnel, Y as entryGuard, Z as evaluateCondition, a1 as formatMoney, a2 as formatOffering, aj as funnelCatalogKeys, a4 as isRtl, a5 as isVariantKey, ak as normalizeOfferings, a8 as pageMeta, a9 as parseSlotKey, ac as resolveLocale, ad as resolveOffering, al as scanOfferingRefs, am as weightsOf } from './manifest-B3Tdab0M.cjs';
|
|
3
|
+
import { C as CheckoutError, b as CheckoutIntent, U as UpsellKind, d as CheckoutSurface } from './capabilities-CsnkVwna.cjs';
|
|
4
|
+
export { a as CheckoutErrorCategory, c as CheckoutProvider, I as INLINE_SURFACES, O as OffSessionReliability, P as PROVIDER_PROFILES, e as ProviderProfile, S as SurfaceCapability, T as TrialShape, V as ValidationResult, f as checkoutError, i as isInlineSurface, g as isMerchantOfRecord, h as isOrchestrator, s as surfacesFor, t as trialShapesFor, v as validateCheckout, k as validateTrial, j as validateUpsell } from './capabilities-CsnkVwna.cjs';
|
|
4
5
|
import 'react';
|
|
5
6
|
|
|
6
|
-
/**
|
|
7
|
-
* Pure, React-free page scan: find which offering SLOTS a funnel's pages reference — the first
|
|
8
|
-
* string-literal arg of `useOffering(...)` and the `offering` prop of `<Checkout>` / `<Upsell>`.
|
|
9
|
-
* Ships via `@appfunnel-dev/sdk/manifest` so the BUILD, the EDITOR, and the AI all run the SAME
|
|
10
|
-
* check. The result feeds `compileManifest({ offeringRefs })`, which flags references to slots the
|
|
11
|
-
* funnel doesn't declare (unknown) or hasn't assigned a catalog charge key to (unassigned).
|
|
12
|
-
*
|
|
13
|
-
* Non-literal args (`useOffering(selectedId)`, `offering={expr}`) and the `useOfferings()` wildcard are
|
|
14
|
-
* DYNAMIC — they can't be statically enumerated, so they're reported via `dynamic` and never turned
|
|
15
|
-
* into a hard error (validation relaxes when a funnel is dynamic). Mirrors the mask-then-read
|
|
16
|
-
* discipline the funnel.ts code-mods use, so a `useOffering('x')` inside a comment or string literal
|
|
17
|
-
* can't false-positive.
|
|
18
|
-
*/
|
|
19
|
-
interface OfferingRefScan {
|
|
20
|
-
/** Concrete slot names referenced by LITERAL args, deduped, in first-seen order. */
|
|
21
|
-
slots: string[];
|
|
22
|
-
/** True if any ref is a non-literal arg or a `useOfferings()` wildcard (not statically enumerable). */
|
|
23
|
-
dynamic: boolean;
|
|
24
|
-
}
|
|
25
|
-
declare function scanOfferingRefs(files: Record<string, string>): OfferingRefScan;
|
|
26
|
-
|
|
27
7
|
/**
|
|
28
8
|
* Source generators for the funnel build "machinery" authors no longer write. `funnel.ts` (the
|
|
29
9
|
* spine: id, responses, offerings, checkout, and the page list + declarative routing) plus the
|
|
@@ -36,6 +16,7 @@ declare function scanOfferingRefs(files: Record<string, string>): OfferingRefSca
|
|
|
36
16
|
* All string templates, zero runtime deps — this module lives in the pure `@appfunnel-dev/sdk/
|
|
37
17
|
* manifest` entry so tooling imports it without the funnel runtime.
|
|
38
18
|
*/
|
|
19
|
+
|
|
39
20
|
interface ScaffoldOptions {
|
|
40
21
|
/** Page component keys = `pages/<key>.tsx` filenames (base flow pages AND `@variant` pages). */
|
|
41
22
|
pageKeys: string[];
|
|
@@ -51,13 +32,15 @@ interface ScaffoldOptions {
|
|
|
51
32
|
messageLocales?: string[];
|
|
52
33
|
/** Slot names the pages reference (from `scanOfferingRefs`), baked into the manifest for validation. */
|
|
53
34
|
offeringRefs?: string[];
|
|
35
|
+
/** Checkout-surface usage the pages express (from `scanOfferingRefs(...).checkout`), baked into the manifest for the publish capability gate. */
|
|
36
|
+
checkoutRefs?: CheckoutUsageScan;
|
|
54
37
|
}
|
|
55
38
|
/** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */
|
|
56
39
|
declare function generateMount(opts: ScaffoldOptions): string;
|
|
57
40
|
/** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */
|
|
58
41
|
declare function generateEntryClient(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): string;
|
|
59
42
|
/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */
|
|
60
|
-
declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs'>): string;
|
|
43
|
+
declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs' | 'checkoutRefs'>): string;
|
|
61
44
|
/** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */
|
|
62
45
|
declare function generateDevEntry(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {
|
|
63
46
|
data: unknown;
|
|
@@ -206,4 +189,4 @@ interface CheckoutCompleteRequest {
|
|
|
206
189
|
}
|
|
207
190
|
type CheckoutCompleteResponse = StepSettled | StepPending | StepFailed;
|
|
208
191
|
|
|
209
|
-
export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface,
|
|
192
|
+
export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, CheckoutUsageScan, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount };
|