@appfunnel-dev/sdk 2.0.0-canary.2 → 2.0.0-canary.3
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 +56 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +18 -5
- 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
|
@@ -210,6 +210,8 @@ type Interval = 'day' | 'week' | 'month' | 'year' | 'one_time';
|
|
|
210
210
|
/** What the platform hands the funnel per product (a single provider-resolved price). */
|
|
211
211
|
interface ProductInput {
|
|
212
212
|
id: string;
|
|
213
|
+
/** The catalog product KEY this input charges (the slot's assignment). Defaults to `id` (legacy/identity slots). */
|
|
214
|
+
catalogKey?: string;
|
|
213
215
|
name?: string;
|
|
214
216
|
displayName?: string;
|
|
215
217
|
/** Provider-resolved price in **minor units** (the provider chose the currency). */
|
|
@@ -240,6 +242,8 @@ interface Money {
|
|
|
240
242
|
*/
|
|
241
243
|
interface ResolvedProduct {
|
|
242
244
|
id: string;
|
|
245
|
+
/** The catalog product KEY charged (the CHARGE identity; `id` is the SLOT/display identity). */
|
|
246
|
+
catalogKey: string;
|
|
243
247
|
name: string;
|
|
244
248
|
displayName: string;
|
|
245
249
|
provider: string;
|
|
@@ -258,6 +262,8 @@ interface ResolvedProduct {
|
|
|
258
262
|
/** Display-ready product the author reads (every amount locale-formatted). */
|
|
259
263
|
interface Product {
|
|
260
264
|
id: string;
|
|
265
|
+
/** The catalog product KEY charged (the CHARGE identity; `id` is the SLOT/display identity). */
|
|
266
|
+
catalogKey: string;
|
|
261
267
|
name: string;
|
|
262
268
|
displayName: string;
|
|
263
269
|
provider: string;
|
|
@@ -456,8 +462,15 @@ interface FunnelDefinition {
|
|
|
456
462
|
responses?: Record<string, VariableConfig>;
|
|
457
463
|
/** `data.*` working/scratch variables (default values). */
|
|
458
464
|
data?: Record<string, VariableConfig>;
|
|
459
|
-
/**
|
|
460
|
-
|
|
465
|
+
/**
|
|
466
|
+
* The catalog products this funnel sells, as SLOTS: a local, stable key each PAGE
|
|
467
|
+
* references (`useProduct('primary')`, `<Checkout product="primary">`) → the catalog product
|
|
468
|
+
* KEY it's assigned to. Swap the assignment to change the offer WITHOUT touching page code;
|
|
469
|
+
* `null` = a declared-but-unassigned slot. A bare `string[]` is legacy sugar for IDENTITY
|
|
470
|
+
* slots (`['pro'] ≡ { pro: 'pro' }`) — every existing funnel keeps working. Prices resolve
|
|
471
|
+
* from the project catalog per environment (Live/Test) at render.
|
|
472
|
+
*/
|
|
473
|
+
products?: string[] | Record<string, string | null>;
|
|
461
474
|
locales?: FunnelLocales;
|
|
462
475
|
/**
|
|
463
476
|
* When `true`, the funnel shows the **geo-specific** currency/price the payment
|
|
@@ -471,6 +484,19 @@ interface FunnelDefinition {
|
|
|
471
484
|
}
|
|
472
485
|
/** Identity helper for a funnel definition. */
|
|
473
486
|
declare function defineFunnel(def: FunnelDefinition): FunnelDefinition;
|
|
487
|
+
/** A funnel product SLOT: the local key pages reference → the assigned catalog product key (null = unassigned). */
|
|
488
|
+
interface ProductSlot {
|
|
489
|
+
slot: string;
|
|
490
|
+
catalogKey: string | null;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Normalize `FunnelDefinition.products` to a slot list. A legacy `string[]` becomes IDENTITY
|
|
494
|
+
* slots (`['pro'] → [{ slot:'pro', catalogKey:'pro' }]`); a `{ slot: key|null }` map becomes its
|
|
495
|
+
* entries (insertion order preserved, so `useProducts()` is deterministic).
|
|
496
|
+
*/
|
|
497
|
+
declare function normalizeProducts(products: FunnelDefinition['products']): ProductSlot[];
|
|
498
|
+
/** The unique, ASSIGNED catalog keys a funnel charges — for the promote gate + catalog reverse-lookup. */
|
|
499
|
+
declare function funnelCatalogKeys(products: FunnelDefinition['products']): string[];
|
|
474
500
|
|
|
475
501
|
/**
|
|
476
502
|
* Pure locale resolution — no React. Split out of {@link ./translation} so the
|
|
@@ -750,6 +776,10 @@ interface ManifestValidation {
|
|
|
750
776
|
* though every page can proceed. Hard error.
|
|
751
777
|
*/
|
|
752
778
|
noReachableFinish: boolean;
|
|
779
|
+
/** Slot names a PAGE references (`useProduct`/`<Checkout product>`) that the funnel doesn't declare — hard error. */
|
|
780
|
+
unknownProductRefs: string[];
|
|
781
|
+
/** Declared slots a page references but which have no catalog product assigned (map value `null`) — hard error. */
|
|
782
|
+
unassignedSlots: string[];
|
|
753
783
|
}
|
|
754
784
|
interface FunnelManifest {
|
|
755
785
|
id: string;
|
|
@@ -759,7 +789,12 @@ interface FunnelManifest {
|
|
|
759
789
|
nodes: string[];
|
|
760
790
|
edges: ManifestEdge[];
|
|
761
791
|
};
|
|
792
|
+
/** The unique, ASSIGNED catalog keys the funnel charges (for the promote gate + catalog reverse-lookup). */
|
|
762
793
|
products: string[];
|
|
794
|
+
/** Product SLOTS: slot → assigned catalog key|null. `products` above is the unique assigned keys. */
|
|
795
|
+
productSlots: ProductSlot[];
|
|
796
|
+
/** Slot names PAGES reference (from the build's scan); validated against `productSlots`. Absent = no scan ran. */
|
|
797
|
+
productRefs?: string[];
|
|
763
798
|
locales?: FunnelLocales;
|
|
764
799
|
validation: ManifestValidation;
|
|
765
800
|
}
|
|
@@ -770,8 +805,10 @@ interface CompileInput {
|
|
|
770
805
|
key: string;
|
|
771
806
|
meta?: PageMeta;
|
|
772
807
|
}[];
|
|
808
|
+
/** Slot names the funnel's PAGES reference (from `scanProductRefs`) — cross-checked against the declared slots. */
|
|
809
|
+
productRefs?: string[];
|
|
773
810
|
}
|
|
774
811
|
/** Compile a funnel's spine into its declarative {@link FunnelManifest} IR. */
|
|
775
812
|
declare function compileManifest(input: CompileInput): FunnelManifest;
|
|
776
813
|
|
|
777
|
-
export { evaluateCondition 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, type Route as H, type IdentityContext as I, type SystemContext as J, assignVariant as K, type LocaleContext as L, type ManifestEdge as M, bucketingSeed as N, type OsContext as O, type Product as P, buildAcquisition as Q, type RuntimeExperiment as R, type SessionContext as S, buildCatalog as T, type UtmContext as U, type VariableValue as V, compileManifest as W, currencyExponent as X, defineFunnel as Y, definePage as Z, entryGuard as _, type VariableConfig as a, evaluateGate as a0, expectedPathLength as a1, fnv1a as a2, formatMoney as a3, formatProduct as a4, hashToUnit as a5, isRtl as a6, isVariantKey as a7, nextPage as a8, outgoingKeys as a9, pageMeta as aa, parseSlotKey as ab, pickByWeight as ac, resolveExperiments as ad, resolveLocale as ae, resolveProduct as af, resolveRoute as ag, validateExperiments as ah, type FunnelPage as ai,
|
|
814
|
+
export { evaluateCondition 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, type Route as H, type IdentityContext as I, type SystemContext as J, assignVariant as K, type LocaleContext as L, type ManifestEdge as M, bucketingSeed as N, type OsContext as O, type Product as P, buildAcquisition as Q, type RuntimeExperiment as R, type SessionContext as S, buildCatalog as T, type UtmContext as U, type VariableValue as V, compileManifest as W, currencyExponent as X, defineFunnel as Y, definePage as Z, entryGuard as _, type VariableConfig as a, evaluateGate as a0, expectedPathLength as a1, fnv1a as a2, formatMoney as a3, formatProduct as a4, hashToUnit as a5, isRtl as a6, isVariantKey as a7, nextPage as a8, outgoingKeys as a9, pageMeta as aa, parseSlotKey as ab, pickByWeight as ac, resolveExperiments as ad, resolveLocale as ae, resolveProduct as af, resolveRoute as ag, validateExperiments as ah, type FunnelPage as ai, type ProductSlot as aj, funnelCatalogKeys as ak, normalizeProducts as al, weightsOf as am, type FunnelSnapshot as b, type FunnelDefinition as c, buildContext as d, type ProductInput as e, type PageMeta as f, type PageContext as g, type BuildContextOptions as h, type CompileInput as i, type Condition as j, type ConditionOp as k, type DeviceContext as l, type ExperimentIssue as m, type ExperimentResolution as n, type ExperimentValidation as o, type ExperimentVariant as p, type FlowPage as q, type FunnelLocales as r, type FunnelManifest as s, type Interval as t, type ManifestPage as u, type ManifestValidation as v, type Money as w, type PageType as x, type Predicate as y, type ResolvedProduct as z };
|
|
@@ -210,6 +210,8 @@ type Interval = 'day' | 'week' | 'month' | 'year' | 'one_time';
|
|
|
210
210
|
/** What the platform hands the funnel per product (a single provider-resolved price). */
|
|
211
211
|
interface ProductInput {
|
|
212
212
|
id: string;
|
|
213
|
+
/** The catalog product KEY this input charges (the slot's assignment). Defaults to `id` (legacy/identity slots). */
|
|
214
|
+
catalogKey?: string;
|
|
213
215
|
name?: string;
|
|
214
216
|
displayName?: string;
|
|
215
217
|
/** Provider-resolved price in **minor units** (the provider chose the currency). */
|
|
@@ -240,6 +242,8 @@ interface Money {
|
|
|
240
242
|
*/
|
|
241
243
|
interface ResolvedProduct {
|
|
242
244
|
id: string;
|
|
245
|
+
/** The catalog product KEY charged (the CHARGE identity; `id` is the SLOT/display identity). */
|
|
246
|
+
catalogKey: string;
|
|
243
247
|
name: string;
|
|
244
248
|
displayName: string;
|
|
245
249
|
provider: string;
|
|
@@ -258,6 +262,8 @@ interface ResolvedProduct {
|
|
|
258
262
|
/** Display-ready product the author reads (every amount locale-formatted). */
|
|
259
263
|
interface Product {
|
|
260
264
|
id: string;
|
|
265
|
+
/** The catalog product KEY charged (the CHARGE identity; `id` is the SLOT/display identity). */
|
|
266
|
+
catalogKey: string;
|
|
261
267
|
name: string;
|
|
262
268
|
displayName: string;
|
|
263
269
|
provider: string;
|
|
@@ -456,8 +462,15 @@ interface FunnelDefinition {
|
|
|
456
462
|
responses?: Record<string, VariableConfig>;
|
|
457
463
|
/** `data.*` working/scratch variables (default values). */
|
|
458
464
|
data?: Record<string, VariableConfig>;
|
|
459
|
-
/**
|
|
460
|
-
|
|
465
|
+
/**
|
|
466
|
+
* The catalog products this funnel sells, as SLOTS: a local, stable key each PAGE
|
|
467
|
+
* references (`useProduct('primary')`, `<Checkout product="primary">`) → the catalog product
|
|
468
|
+
* KEY it's assigned to. Swap the assignment to change the offer WITHOUT touching page code;
|
|
469
|
+
* `null` = a declared-but-unassigned slot. A bare `string[]` is legacy sugar for IDENTITY
|
|
470
|
+
* slots (`['pro'] ≡ { pro: 'pro' }`) — every existing funnel keeps working. Prices resolve
|
|
471
|
+
* from the project catalog per environment (Live/Test) at render.
|
|
472
|
+
*/
|
|
473
|
+
products?: string[] | Record<string, string | null>;
|
|
461
474
|
locales?: FunnelLocales;
|
|
462
475
|
/**
|
|
463
476
|
* When `true`, the funnel shows the **geo-specific** currency/price the payment
|
|
@@ -471,6 +484,19 @@ interface FunnelDefinition {
|
|
|
471
484
|
}
|
|
472
485
|
/** Identity helper for a funnel definition. */
|
|
473
486
|
declare function defineFunnel(def: FunnelDefinition): FunnelDefinition;
|
|
487
|
+
/** A funnel product SLOT: the local key pages reference → the assigned catalog product key (null = unassigned). */
|
|
488
|
+
interface ProductSlot {
|
|
489
|
+
slot: string;
|
|
490
|
+
catalogKey: string | null;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Normalize `FunnelDefinition.products` to a slot list. A legacy `string[]` becomes IDENTITY
|
|
494
|
+
* slots (`['pro'] → [{ slot:'pro', catalogKey:'pro' }]`); a `{ slot: key|null }` map becomes its
|
|
495
|
+
* entries (insertion order preserved, so `useProducts()` is deterministic).
|
|
496
|
+
*/
|
|
497
|
+
declare function normalizeProducts(products: FunnelDefinition['products']): ProductSlot[];
|
|
498
|
+
/** The unique, ASSIGNED catalog keys a funnel charges — for the promote gate + catalog reverse-lookup. */
|
|
499
|
+
declare function funnelCatalogKeys(products: FunnelDefinition['products']): string[];
|
|
474
500
|
|
|
475
501
|
/**
|
|
476
502
|
* Pure locale resolution — no React. Split out of {@link ./translation} so the
|
|
@@ -750,6 +776,10 @@ interface ManifestValidation {
|
|
|
750
776
|
* though every page can proceed. Hard error.
|
|
751
777
|
*/
|
|
752
778
|
noReachableFinish: boolean;
|
|
779
|
+
/** Slot names a PAGE references (`useProduct`/`<Checkout product>`) that the funnel doesn't declare — hard error. */
|
|
780
|
+
unknownProductRefs: string[];
|
|
781
|
+
/** Declared slots a page references but which have no catalog product assigned (map value `null`) — hard error. */
|
|
782
|
+
unassignedSlots: string[];
|
|
753
783
|
}
|
|
754
784
|
interface FunnelManifest {
|
|
755
785
|
id: string;
|
|
@@ -759,7 +789,12 @@ interface FunnelManifest {
|
|
|
759
789
|
nodes: string[];
|
|
760
790
|
edges: ManifestEdge[];
|
|
761
791
|
};
|
|
792
|
+
/** The unique, ASSIGNED catalog keys the funnel charges (for the promote gate + catalog reverse-lookup). */
|
|
762
793
|
products: string[];
|
|
794
|
+
/** Product SLOTS: slot → assigned catalog key|null. `products` above is the unique assigned keys. */
|
|
795
|
+
productSlots: ProductSlot[];
|
|
796
|
+
/** Slot names PAGES reference (from the build's scan); validated against `productSlots`. Absent = no scan ran. */
|
|
797
|
+
productRefs?: string[];
|
|
763
798
|
locales?: FunnelLocales;
|
|
764
799
|
validation: ManifestValidation;
|
|
765
800
|
}
|
|
@@ -770,8 +805,10 @@ interface CompileInput {
|
|
|
770
805
|
key: string;
|
|
771
806
|
meta?: PageMeta;
|
|
772
807
|
}[];
|
|
808
|
+
/** Slot names the funnel's PAGES reference (from `scanProductRefs`) — cross-checked against the declared slots. */
|
|
809
|
+
productRefs?: string[];
|
|
773
810
|
}
|
|
774
811
|
/** Compile a funnel's spine into its declarative {@link FunnelManifest} IR. */
|
|
775
812
|
declare function compileManifest(input: CompileInput): FunnelManifest;
|
|
776
813
|
|
|
777
|
-
export { evaluateCondition 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, type Route as H, type IdentityContext as I, type SystemContext as J, assignVariant as K, type LocaleContext as L, type ManifestEdge as M, bucketingSeed as N, type OsContext as O, type Product as P, buildAcquisition as Q, type RuntimeExperiment as R, type SessionContext as S, buildCatalog as T, type UtmContext as U, type VariableValue as V, compileManifest as W, currencyExponent as X, defineFunnel as Y, definePage as Z, entryGuard as _, type VariableConfig as a, evaluateGate as a0, expectedPathLength as a1, fnv1a as a2, formatMoney as a3, formatProduct as a4, hashToUnit as a5, isRtl as a6, isVariantKey as a7, nextPage as a8, outgoingKeys as a9, pageMeta as aa, parseSlotKey as ab, pickByWeight as ac, resolveExperiments as ad, resolveLocale as ae, resolveProduct as af, resolveRoute as ag, validateExperiments as ah, type FunnelPage as ai,
|
|
814
|
+
export { evaluateCondition 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, type Route as H, type IdentityContext as I, type SystemContext as J, assignVariant as K, type LocaleContext as L, type ManifestEdge as M, bucketingSeed as N, type OsContext as O, type Product as P, buildAcquisition as Q, type RuntimeExperiment as R, type SessionContext as S, buildCatalog as T, type UtmContext as U, type VariableValue as V, compileManifest as W, currencyExponent as X, defineFunnel as Y, definePage as Z, entryGuard as _, type VariableConfig as a, evaluateGate as a0, expectedPathLength as a1, fnv1a as a2, formatMoney as a3, formatProduct as a4, hashToUnit as a5, isRtl as a6, isVariantKey as a7, nextPage as a8, outgoingKeys as a9, pageMeta as aa, parseSlotKey as ab, pickByWeight as ac, resolveExperiments as ad, resolveLocale as ae, resolveProduct as af, resolveRoute as ag, validateExperiments as ah, type FunnelPage as ai, type ProductSlot as aj, funnelCatalogKeys as ak, normalizeProducts as al, weightsOf as am, type FunnelSnapshot as b, type FunnelDefinition as c, buildContext as d, type ProductInput as e, type PageMeta as f, type PageContext as g, type BuildContextOptions as h, type CompileInput as i, type Condition as j, type ConditionOp as k, type DeviceContext as l, type ExperimentIssue as m, type ExperimentResolution as n, type ExperimentValidation as o, type ExperimentVariant as p, type FlowPage as q, type FunnelLocales as r, type FunnelManifest as s, type Interval as t, type ManifestPage as u, type ManifestValidation as v, type Money as w, type PageType as x, type Predicate as y, type ResolvedProduct as z };
|
package/dist/manifest-entry.cjs
CHANGED
|
@@ -1,9 +1,102 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkJSRKA375_cjs = require('./chunk-JSRKA375.cjs');
|
|
4
4
|
var chunkLJYLGLFS_cjs = require('./chunk-LJYLGLFS.cjs');
|
|
5
5
|
|
|
6
|
+
// src/manifest/product-refs.ts
|
|
7
|
+
function mask(src) {
|
|
8
|
+
const out = src.split("");
|
|
9
|
+
const n = src.length;
|
|
10
|
+
let i = 0;
|
|
11
|
+
while (i < n) {
|
|
12
|
+
const c = src[i];
|
|
13
|
+
const d = src[i + 1];
|
|
14
|
+
if (c === "/" && d === "/") {
|
|
15
|
+
while (i < n && src[i] !== "\n") {
|
|
16
|
+
out[i] = " ";
|
|
17
|
+
i++;
|
|
18
|
+
}
|
|
19
|
+
} else if (c === "/" && d === "*") {
|
|
20
|
+
out[i] = " ";
|
|
21
|
+
out[i + 1] = " ";
|
|
22
|
+
i += 2;
|
|
23
|
+
while (i < n) {
|
|
24
|
+
if (src[i] === "*" && src[i + 1] === "/") {
|
|
25
|
+
out[i] = " ";
|
|
26
|
+
out[i + 1] = " ";
|
|
27
|
+
i += 2;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
if (src[i] !== "\n") out[i] = " ";
|
|
31
|
+
i++;
|
|
32
|
+
}
|
|
33
|
+
} else if (c === "'" || c === '"' || c === "`") {
|
|
34
|
+
i++;
|
|
35
|
+
while (i < n && src[i] !== c) {
|
|
36
|
+
if (src[i] === "\\") {
|
|
37
|
+
out[i] = " ";
|
|
38
|
+
i++;
|
|
39
|
+
if (i < n && src[i] !== "\n") out[i] = " ";
|
|
40
|
+
i++;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (src[i] !== "\n") out[i] = " ";
|
|
44
|
+
i++;
|
|
45
|
+
}
|
|
46
|
+
i++;
|
|
47
|
+
} else i++;
|
|
48
|
+
}
|
|
49
|
+
return out.join("");
|
|
50
|
+
}
|
|
51
|
+
function literalAt(src, masked, open) {
|
|
52
|
+
const q = masked[open];
|
|
53
|
+
if (q !== "'" && q !== '"' && q !== "`") return null;
|
|
54
|
+
const close = masked.indexOf(q, open + 1);
|
|
55
|
+
if (close === -1) return null;
|
|
56
|
+
return src.slice(open + 1, close);
|
|
57
|
+
}
|
|
58
|
+
function skipWs(masked, i) {
|
|
59
|
+
while (i < masked.length && (masked[i] === " " || masked[i] === " " || masked[i] === "\n" || masked[i] === "\r")) i++;
|
|
60
|
+
return i;
|
|
61
|
+
}
|
|
62
|
+
function scanProductRefs(files) {
|
|
63
|
+
const seen = /* @__PURE__ */ new Set();
|
|
64
|
+
const order = [];
|
|
65
|
+
let dynamic = false;
|
|
66
|
+
const add = (v) => {
|
|
67
|
+
if (v && !seen.has(v)) {
|
|
68
|
+
seen.add(v);
|
|
69
|
+
order.push(v);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
for (const [path, source] of Object.entries(files)) {
|
|
73
|
+
if (!/\.(tsx|jsx|ts|js)$/.test(path)) continue;
|
|
74
|
+
const masked = mask(source);
|
|
75
|
+
for (const m of masked.matchAll(/\buseProducts?\s*\(/g)) {
|
|
76
|
+
const plural = source.slice(m.index, m.index + 11) === "useProducts";
|
|
77
|
+
const j = skipWs(masked, m.index + m[0].length);
|
|
78
|
+
if (masked[j] === ")") {
|
|
79
|
+
if (plural) dynamic = true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const lit = literalAt(source, masked, j);
|
|
83
|
+
if (lit !== null) add(lit);
|
|
84
|
+
else dynamic = true;
|
|
85
|
+
}
|
|
86
|
+
for (const m of masked.matchAll(/<(?:Checkout|Upsell)\b[^>]*?\bproduct\s*=\s*/g)) {
|
|
87
|
+
const j = m.index + m[0].length;
|
|
88
|
+
const lit = literalAt(source, masked, j);
|
|
89
|
+
if (lit !== null) add(lit);
|
|
90
|
+
else if (masked[j] === "{") dynamic = true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { slots: order, dynamic };
|
|
94
|
+
}
|
|
95
|
+
|
|
6
96
|
// src/flow/scaffold.ts
|
|
97
|
+
function msgId(locale) {
|
|
98
|
+
return "msg_" + locale.replace(/[^a-zA-Z0-9]/g, "_");
|
|
99
|
+
}
|
|
7
100
|
var DRIVERS = {
|
|
8
101
|
stripe: { name: "stripeCheckoutDriver", sub: "driver-stripe" },
|
|
9
102
|
paddle: { name: "paddleCheckoutDriver", sub: "driver-paddle" }
|
|
@@ -12,11 +105,13 @@ var HEADER = "// GENERATED by AppFunnel \u2014 do not edit. Built from funnel.ts
|
|
|
12
105
|
function generateMount(opts) {
|
|
13
106
|
const p = opts.importPrefix ?? "./";
|
|
14
107
|
const driver = opts.checkout ? DRIVERS[opts.checkout] : null;
|
|
108
|
+
const locales = opts.messageLocales ?? [];
|
|
15
109
|
const imports = [
|
|
16
110
|
`import { createFunnelTree, type MountOpts, type RuntimePage } from '@appfunnel-dev/sdk'`,
|
|
17
111
|
driver && `import { ${driver.name} } from '@appfunnel-dev/sdk/${driver.sub}'`,
|
|
18
112
|
`import { config } from '${p}funnel'`,
|
|
19
|
-
opts.hasLayout && `import Layout from '${p}layout'
|
|
113
|
+
opts.hasLayout && `import Layout from '${p}layout'`,
|
|
114
|
+
...locales.map((loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`)
|
|
20
115
|
].filter(Boolean).join("\n");
|
|
21
116
|
const loaders = opts.pageKeys.map(
|
|
22
117
|
(k) => ` ${JSON.stringify(k)}: () => import(${JSON.stringify(`${p}pages/${k}`)}),`
|
|
@@ -25,8 +120,12 @@ function generateMount(opts) {
|
|
|
25
120
|
"config",
|
|
26
121
|
"pages",
|
|
27
122
|
opts.hasLayout && "layout: Layout",
|
|
28
|
-
driver && `checkoutDriver: ${driver.name}
|
|
123
|
+
driver && `checkoutDriver: ${driver.name}`,
|
|
124
|
+
locales.length > 0 && "messages"
|
|
29
125
|
].filter(Boolean).join(", ");
|
|
126
|
+
const messagesConst = locales.length > 0 ? `
|
|
127
|
+
const messages = { ${locales.map((loc) => `${JSON.stringify(loc)}: ${msgId(loc)}`).join(", ")} }
|
|
128
|
+
` : "";
|
|
30
129
|
return `${HEADER}${imports}
|
|
31
130
|
|
|
32
131
|
const loaders: Record<string, () => Promise<unknown>> = {
|
|
@@ -43,7 +142,7 @@ export const pages: RuntimePage[] = [
|
|
|
43
142
|
.filter((k) => !flowKeys.has(k))
|
|
44
143
|
.map((k) => ({ key: k, meta: {}, load: loaders[k] })),
|
|
45
144
|
] as RuntimePage[]
|
|
46
|
-
|
|
145
|
+
${messagesConst}
|
|
47
146
|
export const tree = createFunnelTree({ ${treeArgs} })
|
|
48
147
|
|
|
49
148
|
export type { MountOpts }
|
|
@@ -74,6 +173,7 @@ import { tree, pages, type MountOpts } from './mount'
|
|
|
74
173
|
export const manifest = compileManifest({
|
|
75
174
|
funnel: config,
|
|
76
175
|
pages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),
|
|
176
|
+
productRefs: ${JSON.stringify(opts.productRefs ?? [])},
|
|
77
177
|
})
|
|
78
178
|
|
|
79
179
|
export async function ssr(opts: MountOpts): Promise<string> {
|
|
@@ -97,67 +197,75 @@ if (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))
|
|
|
97
197
|
|
|
98
198
|
Object.defineProperty(exports, "assignVariant", {
|
|
99
199
|
enumerable: true,
|
|
100
|
-
get: function () { return
|
|
200
|
+
get: function () { return chunkJSRKA375_cjs.assignVariant; }
|
|
101
201
|
});
|
|
102
202
|
Object.defineProperty(exports, "bucketingSeed", {
|
|
103
203
|
enumerable: true,
|
|
104
|
-
get: function () { return
|
|
204
|
+
get: function () { return chunkJSRKA375_cjs.bucketingSeed; }
|
|
105
205
|
});
|
|
106
206
|
Object.defineProperty(exports, "buildCatalog", {
|
|
107
207
|
enumerable: true,
|
|
108
|
-
get: function () { return
|
|
208
|
+
get: function () { return chunkJSRKA375_cjs.buildCatalog; }
|
|
109
209
|
});
|
|
110
210
|
Object.defineProperty(exports, "compileManifest", {
|
|
111
211
|
enumerable: true,
|
|
112
|
-
get: function () { return
|
|
212
|
+
get: function () { return chunkJSRKA375_cjs.compileManifest; }
|
|
113
213
|
});
|
|
114
214
|
Object.defineProperty(exports, "currencyExponent", {
|
|
115
215
|
enumerable: true,
|
|
116
|
-
get: function () { return
|
|
216
|
+
get: function () { return chunkJSRKA375_cjs.currencyExponent; }
|
|
117
217
|
});
|
|
118
218
|
Object.defineProperty(exports, "defineFunnel", {
|
|
119
219
|
enumerable: true,
|
|
120
|
-
get: function () { return
|
|
220
|
+
get: function () { return chunkJSRKA375_cjs.defineFunnel; }
|
|
121
221
|
});
|
|
122
222
|
Object.defineProperty(exports, "formatMoney", {
|
|
123
223
|
enumerable: true,
|
|
124
|
-
get: function () { return
|
|
224
|
+
get: function () { return chunkJSRKA375_cjs.formatMoney; }
|
|
125
225
|
});
|
|
126
226
|
Object.defineProperty(exports, "formatProduct", {
|
|
127
227
|
enumerable: true,
|
|
128
|
-
get: function () { return
|
|
228
|
+
get: function () { return chunkJSRKA375_cjs.formatProduct; }
|
|
229
|
+
});
|
|
230
|
+
Object.defineProperty(exports, "funnelCatalogKeys", {
|
|
231
|
+
enumerable: true,
|
|
232
|
+
get: function () { return chunkJSRKA375_cjs.funnelCatalogKeys; }
|
|
129
233
|
});
|
|
130
234
|
Object.defineProperty(exports, "isRtl", {
|
|
131
235
|
enumerable: true,
|
|
132
|
-
get: function () { return
|
|
236
|
+
get: function () { return chunkJSRKA375_cjs.isRtl; }
|
|
133
237
|
});
|
|
134
238
|
Object.defineProperty(exports, "isVariantKey", {
|
|
135
239
|
enumerable: true,
|
|
136
|
-
get: function () { return
|
|
240
|
+
get: function () { return chunkJSRKA375_cjs.isVariantKey; }
|
|
241
|
+
});
|
|
242
|
+
Object.defineProperty(exports, "normalizeProducts", {
|
|
243
|
+
enumerable: true,
|
|
244
|
+
get: function () { return chunkJSRKA375_cjs.normalizeProducts; }
|
|
137
245
|
});
|
|
138
246
|
Object.defineProperty(exports, "pageMeta", {
|
|
139
247
|
enumerable: true,
|
|
140
|
-
get: function () { return
|
|
248
|
+
get: function () { return chunkJSRKA375_cjs.pageMeta; }
|
|
141
249
|
});
|
|
142
250
|
Object.defineProperty(exports, "parseSlotKey", {
|
|
143
251
|
enumerable: true,
|
|
144
|
-
get: function () { return
|
|
252
|
+
get: function () { return chunkJSRKA375_cjs.parseSlotKey; }
|
|
145
253
|
});
|
|
146
254
|
Object.defineProperty(exports, "resolveLocale", {
|
|
147
255
|
enumerable: true,
|
|
148
|
-
get: function () { return
|
|
256
|
+
get: function () { return chunkJSRKA375_cjs.resolveLocale; }
|
|
149
257
|
});
|
|
150
258
|
Object.defineProperty(exports, "resolveProduct", {
|
|
151
259
|
enumerable: true,
|
|
152
|
-
get: function () { return
|
|
260
|
+
get: function () { return chunkJSRKA375_cjs.resolveProduct; }
|
|
153
261
|
});
|
|
154
262
|
Object.defineProperty(exports, "validateExperiments", {
|
|
155
263
|
enumerable: true,
|
|
156
|
-
get: function () { return
|
|
264
|
+
get: function () { return chunkJSRKA375_cjs.validateExperiments; }
|
|
157
265
|
});
|
|
158
266
|
Object.defineProperty(exports, "weightsOf", {
|
|
159
267
|
enumerable: true,
|
|
160
|
-
get: function () { return
|
|
268
|
+
get: function () { return chunkJSRKA375_cjs.weightsOf; }
|
|
161
269
|
});
|
|
162
270
|
Object.defineProperty(exports, "INLINE_SURFACES", {
|
|
163
271
|
enumerable: true,
|
|
@@ -199,5 +307,6 @@ exports.generateDevEntry = generateDevEntry;
|
|
|
199
307
|
exports.generateEntryClient = generateEntryClient;
|
|
200
308
|
exports.generateEntryServer = generateEntryServer;
|
|
201
309
|
exports.generateMount = generateMount;
|
|
310
|
+
exports.scanProductRefs = scanProductRefs;
|
|
202
311
|
//# sourceMappingURL=manifest-entry.cjs.map
|
|
203
312
|
//# sourceMappingURL=manifest-entry.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/flow/scaffold.ts"],"names":[],"mappings":"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","file":"manifest-entry.cjs","sourcesContent":["/**\n * Source generators for the funnel build \"machinery\" authors no longer write. `funnel.ts` (the\n * spine: id, responses, products, 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}\n\nconst DRIVERS = {\n\tstripe: { name: 'stripeCheckoutDriver', sub: 'driver-stripe' },\n\tpaddle: { name: 'paddleCheckoutDriver', sub: 'driver-paddle' },\n} as const\n\nconst HEADER = '// 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 imports = [\n\t\t`import { createFunnelTree, type MountOpts, type RuntimePage } from '@appfunnel-dev/sdk'`,\n\t\tdriver && `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]\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) => `\\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]\n\t\t.filter(Boolean)\n\t\t.join(', ')\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). Any remaining page file is an off-flow\n// \\`@variant\\` page (wired by experiment records at render time), appended so it's 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\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(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): 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')\nif (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined }))\n`\n}\n\n/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */\nexport function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix'>): 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})\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'> & { data: unknown }\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/product-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 product SLOTS a funnel's pages reference — the first\n * string-literal arg of `useProduct(...)` and the `product` 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({ productRefs })`, which flags references to slots the\n * funnel doesn't declare (unknown) or hasn't assigned a catalog product to (unassigned).\n *\n * Non-literal args (`useProduct(selectedId)`, `product={expr}`) and the `useProducts()` 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 `useProduct('x')` inside a comment or string literal\n * can't false-positive.\n */\n\nexport interface ProductRefScan {\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 `useProducts()` 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 scanProductRefs(files: Record<string, string>): ProductRefScan {\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 // useProduct( … ) / useProducts( … ) — positions on the MASK (a call inside a string won't match).\n for (const m of masked.matchAll(/\\buseProducts?\\s*\\(/g)) {\n const plural = source.slice(m.index!, m.index! + 11) === 'useProducts'\n const j = skipWs(masked, m.index! + m[0].length)\n if (masked[j] === ')') { if (plural) dynamic = true; continue } // useProducts() = whole-catalog wildcard\n const lit = literalAt(source, masked, j)\n if (lit !== null) add(lit)\n else dynamic = true // useProduct(variable) — can't resolve statically\n }\n\n // <Checkout product=\"…\"> / <Upsell product=\"…\"> — the `product` attribute value.\n for (const m of masked.matchAll(/<(?:Checkout|Upsell)\\b[^>]*?\\bproduct\\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 // product={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, products, 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 `scanProductRefs`), baked into the manifest for validation. */\n\tproductRefs?: 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 = '// 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 && `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((loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`),\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) => `\\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). Any remaining page file is an off-flow\n// \\`@variant\\` page (wired by experiment records at render time), appended so it's 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(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): 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')\nif (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined }))\n`\n}\n\n/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */\nexport function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'productRefs'>): 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\tproductRefs: ${JSON.stringify(opts.productRefs ?? [])},\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'> & { data: unknown }\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,8 +1,29 @@
|
|
|
1
|
-
export { i as CompileInput, j as Condition, k as ConditionOp, E as EdgeCondition, m as ExperimentIssue, o as ExperimentValidation, p as ExperimentVariant, q as FlowPage, c as FunnelDefinition, r as FunnelLocales, s as FunnelManifest, ai as FunnelPage, b as FunnelSnapshot, G as Gate, t as Interval, M as ManifestEdge, u as ManifestPage, v as ManifestValidation, w as Money, f as PageMeta, x as PageType, y as Predicate, P as Product, e as ProductInput, z as ResolvedProduct, H as Route, R as RuntimeExperiment, K as assignVariant, N as bucketingSeed, T as buildCatalog, W as compileManifest, X as currencyExponent, Y as defineFunnel, a3 as formatMoney, a4 as formatProduct, a6 as isRtl, a7 as isVariantKey, aa as pageMeta, ab as parseSlotKey, ae as resolveLocale, af as resolveProduct, ah as validateExperiments,
|
|
1
|
+
export { i as CompileInput, j as Condition, k as ConditionOp, E as EdgeCondition, m as ExperimentIssue, o as ExperimentValidation, p as ExperimentVariant, q as FlowPage, c as FunnelDefinition, r as FunnelLocales, s as FunnelManifest, ai as FunnelPage, b as FunnelSnapshot, G as Gate, t as Interval, M as ManifestEdge, u as ManifestPage, v as ManifestValidation, w as Money, f as PageMeta, x as PageType, y as Predicate, P as Product, e as ProductInput, aj as ProductSlot, z as ResolvedProduct, H as Route, R as RuntimeExperiment, K as assignVariant, N as bucketingSeed, T as buildCatalog, W as compileManifest, X as currencyExponent, Y as defineFunnel, a3 as formatMoney, a4 as formatProduct, ak as funnelCatalogKeys, a6 as isRtl, a7 as isVariantKey, al as normalizeProducts, aa as pageMeta, ab as parseSlotKey, ae as resolveLocale, af as resolveProduct, ah as validateExperiments, am as weightsOf } from './manifest-Cr2y1op6.cjs';
|
|
2
2
|
import { C as CheckoutError, b as CheckoutIntent, U as UpsellKind, d as CheckoutSurface } from './capabilities-7_hy5f5G.cjs';
|
|
3
3
|
export { a as CheckoutErrorCategory, c as CheckoutProvider, I as INLINE_SURFACES, O as OffSessionReliability, P as PROVIDER_PROFILES, e as ProviderProfile, S as SurfaceCapability, 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';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Pure, React-free page scan: find which product SLOTS a funnel's pages reference — the first
|
|
8
|
+
* string-literal arg of `useProduct(...)` and the `product` 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({ productRefs })`, which flags references to slots the
|
|
11
|
+
* funnel doesn't declare (unknown) or hasn't assigned a catalog product to (unassigned).
|
|
12
|
+
*
|
|
13
|
+
* Non-literal args (`useProduct(selectedId)`, `product={expr}`) and the `useProducts()` 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 `useProduct('x')` inside a comment or string literal
|
|
17
|
+
* can't false-positive.
|
|
18
|
+
*/
|
|
19
|
+
interface ProductRefScan {
|
|
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 `useProducts()` wildcard (not statically enumerable). */
|
|
23
|
+
dynamic: boolean;
|
|
24
|
+
}
|
|
25
|
+
declare function scanProductRefs(files: Record<string, string>): ProductRefScan;
|
|
26
|
+
|
|
6
27
|
/**
|
|
7
28
|
* Source generators for the funnel build "machinery" authors no longer write. `funnel.ts` (the
|
|
8
29
|
* spine: id, responses, products, checkout, and the page list + declarative routing) plus the
|
|
@@ -26,13 +47,17 @@ interface ScaffoldOptions {
|
|
|
26
47
|
hasStyles?: boolean;
|
|
27
48
|
/** Checkout provider from `config.checkout` — wires the driver; omit for none. */
|
|
28
49
|
checkout?: 'stripe' | 'paddle' | null;
|
|
50
|
+
/** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */
|
|
51
|
+
messageLocales?: string[];
|
|
52
|
+
/** Slot names the pages reference (from `scanProductRefs`), baked into the manifest for validation. */
|
|
53
|
+
productRefs?: string[];
|
|
29
54
|
}
|
|
30
55
|
/** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */
|
|
31
56
|
declare function generateMount(opts: ScaffoldOptions): string;
|
|
32
57
|
/** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */
|
|
33
58
|
declare function generateEntryClient(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): string;
|
|
34
59
|
/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */
|
|
35
|
-
declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix'>): string;
|
|
60
|
+
declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'productRefs'>): string;
|
|
36
61
|
/** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */
|
|
37
62
|
declare function generateDevEntry(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {
|
|
38
63
|
data: unknown;
|
|
@@ -181,4 +206,4 @@ interface CheckoutCompleteRequest {
|
|
|
181
206
|
}
|
|
182
207
|
type CheckoutCompleteResponse = StepSettled | StepPending | StepFailed;
|
|
183
208
|
|
|
184
|
-
export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount };
|
|
209
|
+
export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, type ProductRefScan, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount, scanProductRefs };
|
package/dist/manifest-entry.d.ts
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
|
-
export { i as CompileInput, j as Condition, k as ConditionOp, E as EdgeCondition, m as ExperimentIssue, o as ExperimentValidation, p as ExperimentVariant, q as FlowPage, c as FunnelDefinition, r as FunnelLocales, s as FunnelManifest, ai as FunnelPage, b as FunnelSnapshot, G as Gate, t as Interval, M as ManifestEdge, u as ManifestPage, v as ManifestValidation, w as Money, f as PageMeta, x as PageType, y as Predicate, P as Product, e as ProductInput, z as ResolvedProduct, H as Route, R as RuntimeExperiment, K as assignVariant, N as bucketingSeed, T as buildCatalog, W as compileManifest, X as currencyExponent, Y as defineFunnel, a3 as formatMoney, a4 as formatProduct, a6 as isRtl, a7 as isVariantKey, aa as pageMeta, ab as parseSlotKey, ae as resolveLocale, af as resolveProduct, ah as validateExperiments,
|
|
1
|
+
export { i as CompileInput, j as Condition, k as ConditionOp, E as EdgeCondition, m as ExperimentIssue, o as ExperimentValidation, p as ExperimentVariant, q as FlowPage, c as FunnelDefinition, r as FunnelLocales, s as FunnelManifest, ai as FunnelPage, b as FunnelSnapshot, G as Gate, t as Interval, M as ManifestEdge, u as ManifestPage, v as ManifestValidation, w as Money, f as PageMeta, x as PageType, y as Predicate, P as Product, e as ProductInput, aj as ProductSlot, z as ResolvedProduct, H as Route, R as RuntimeExperiment, K as assignVariant, N as bucketingSeed, T as buildCatalog, W as compileManifest, X as currencyExponent, Y as defineFunnel, a3 as formatMoney, a4 as formatProduct, ak as funnelCatalogKeys, a6 as isRtl, a7 as isVariantKey, al as normalizeProducts, aa as pageMeta, ab as parseSlotKey, ae as resolveLocale, af as resolveProduct, ah as validateExperiments, am as weightsOf } from './manifest-Cr2y1op6.js';
|
|
2
2
|
import { C as CheckoutError, b as CheckoutIntent, U as UpsellKind, d as CheckoutSurface } from './capabilities-7_hy5f5G.js';
|
|
3
3
|
export { a as CheckoutErrorCategory, c as CheckoutProvider, I as INLINE_SURFACES, O as OffSessionReliability, P as PROVIDER_PROFILES, e as ProviderProfile, S as SurfaceCapability, 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';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Pure, React-free page scan: find which product SLOTS a funnel's pages reference — the first
|
|
8
|
+
* string-literal arg of `useProduct(...)` and the `product` 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({ productRefs })`, which flags references to slots the
|
|
11
|
+
* funnel doesn't declare (unknown) or hasn't assigned a catalog product to (unassigned).
|
|
12
|
+
*
|
|
13
|
+
* Non-literal args (`useProduct(selectedId)`, `product={expr}`) and the `useProducts()` 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 `useProduct('x')` inside a comment or string literal
|
|
17
|
+
* can't false-positive.
|
|
18
|
+
*/
|
|
19
|
+
interface ProductRefScan {
|
|
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 `useProducts()` wildcard (not statically enumerable). */
|
|
23
|
+
dynamic: boolean;
|
|
24
|
+
}
|
|
25
|
+
declare function scanProductRefs(files: Record<string, string>): ProductRefScan;
|
|
26
|
+
|
|
6
27
|
/**
|
|
7
28
|
* Source generators for the funnel build "machinery" authors no longer write. `funnel.ts` (the
|
|
8
29
|
* spine: id, responses, products, checkout, and the page list + declarative routing) plus the
|
|
@@ -26,13 +47,17 @@ interface ScaffoldOptions {
|
|
|
26
47
|
hasStyles?: boolean;
|
|
27
48
|
/** Checkout provider from `config.checkout` — wires the driver; omit for none. */
|
|
28
49
|
checkout?: 'stripe' | 'paddle' | null;
|
|
50
|
+
/** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */
|
|
51
|
+
messageLocales?: string[];
|
|
52
|
+
/** Slot names the pages reference (from `scanProductRefs`), baked into the manifest for validation. */
|
|
53
|
+
productRefs?: string[];
|
|
29
54
|
}
|
|
30
55
|
/** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */
|
|
31
56
|
declare function generateMount(opts: ScaffoldOptions): string;
|
|
32
57
|
/** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */
|
|
33
58
|
declare function generateEntryClient(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): string;
|
|
34
59
|
/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */
|
|
35
|
-
declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix'>): string;
|
|
60
|
+
declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'productRefs'>): string;
|
|
36
61
|
/** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */
|
|
37
62
|
declare function generateDevEntry(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {
|
|
38
63
|
data: unknown;
|
|
@@ -181,4 +206,4 @@ interface CheckoutCompleteRequest {
|
|
|
181
206
|
}
|
|
182
207
|
type CheckoutCompleteResponse = StepSettled | StepPending | StepFailed;
|
|
183
208
|
|
|
184
|
-
export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount };
|
|
209
|
+
export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, type ProductRefScan, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount, scanProductRefs };
|