@appfunnel-dev/sdk 2.0.0-canary.1 → 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.
Files changed (43) hide show
  1. package/dist/capabilities-7_hy5f5G.d.cts +114 -0
  2. package/dist/capabilities-7_hy5f5G.d.ts +114 -0
  3. package/dist/checkout-7Dy6IedP.d.ts +320 -0
  4. package/dist/checkout-Dz8cGkB_.d.cts +320 -0
  5. package/dist/chunk-AKO6XKXP.js +466 -0
  6. package/dist/chunk-AKO6XKXP.js.map +1 -0
  7. package/dist/chunk-CY4VBSMX.cjs +106 -0
  8. package/dist/chunk-CY4VBSMX.cjs.map +1 -0
  9. package/dist/chunk-JSRKA375.cjs +497 -0
  10. package/dist/chunk-JSRKA375.cjs.map +1 -0
  11. package/dist/chunk-LJYLGLFS.cjs +153 -0
  12. package/dist/chunk-LJYLGLFS.cjs.map +1 -0
  13. package/dist/chunk-M6U3FNRW.js +99 -0
  14. package/dist/chunk-M6U3FNRW.js.map +1 -0
  15. package/dist/chunk-YY375F2B.js +140 -0
  16. package/dist/chunk-YY375F2B.js.map +1 -0
  17. package/dist/driver-paddle.cjs +814 -0
  18. package/dist/driver-paddle.cjs.map +1 -0
  19. package/dist/driver-paddle.d.cts +10 -0
  20. package/dist/driver-paddle.d.ts +10 -0
  21. package/dist/driver-paddle.js +811 -0
  22. package/dist/driver-paddle.js.map +1 -0
  23. package/dist/driver-stripe.cjs +2253 -0
  24. package/dist/driver-stripe.cjs.map +1 -0
  25. package/dist/driver-stripe.d.cts +8 -0
  26. package/dist/driver-stripe.d.ts +8 -0
  27. package/dist/driver-stripe.js +2247 -0
  28. package/dist/driver-stripe.js.map +1 -0
  29. package/dist/index.cjs +1962 -811
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +183 -933
  32. package/dist/index.d.ts +183 -933
  33. package/dist/index.js +1683 -653
  34. package/dist/index.js.map +1 -1
  35. package/dist/manifest-Cr2y1op6.d.cts +814 -0
  36. package/dist/manifest-Cr2y1op6.d.ts +814 -0
  37. package/dist/manifest-entry.cjs +312 -0
  38. package/dist/manifest-entry.cjs.map +1 -0
  39. package/dist/manifest-entry.d.cts +209 -0
  40. package/dist/manifest-entry.d.ts +209 -0
  41. package/dist/manifest-entry.js +198 -0
  42. package/dist/manifest-entry.js.map +1 -0
  43. package/package.json +37 -4
@@ -0,0 +1,312 @@
1
+ 'use strict';
2
+
3
+ var chunkJSRKA375_cjs = require('./chunk-JSRKA375.cjs');
4
+ var chunkLJYLGLFS_cjs = require('./chunk-LJYLGLFS.cjs');
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
+
96
+ // src/flow/scaffold.ts
97
+ function msgId(locale) {
98
+ return "msg_" + locale.replace(/[^a-zA-Z0-9]/g, "_");
99
+ }
100
+ var DRIVERS = {
101
+ stripe: { name: "stripeCheckoutDriver", sub: "driver-stripe" },
102
+ paddle: { name: "paddleCheckoutDriver", sub: "driver-paddle" }
103
+ };
104
+ var HEADER = "// GENERATED by AppFunnel \u2014 do not edit. Built from funnel.ts + the pages/ folder.\n";
105
+ function generateMount(opts) {
106
+ const p = opts.importPrefix ?? "./";
107
+ const driver = opts.checkout ? DRIVERS[opts.checkout] : null;
108
+ const locales = opts.messageLocales ?? [];
109
+ const imports = [
110
+ `import { createFunnelTree, type MountOpts, type RuntimePage } from '@appfunnel-dev/sdk'`,
111
+ driver && `import { ${driver.name} } from '@appfunnel-dev/sdk/${driver.sub}'`,
112
+ `import { config } from '${p}funnel'`,
113
+ opts.hasLayout && `import Layout from '${p}layout'`,
114
+ ...locales.map((loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`)
115
+ ].filter(Boolean).join("\n");
116
+ const loaders = opts.pageKeys.map(
117
+ (k) => ` ${JSON.stringify(k)}: () => import(${JSON.stringify(`${p}pages/${k}`)}),`
118
+ ).join("\n");
119
+ const treeArgs = [
120
+ "config",
121
+ "pages",
122
+ opts.hasLayout && "layout: Layout",
123
+ driver && `checkoutDriver: ${driver.name}`,
124
+ locales.length > 0 && "messages"
125
+ ].filter(Boolean).join(", ");
126
+ const messagesConst = locales.length > 0 ? `
127
+ const messages = { ${locales.map((loc) => `${JSON.stringify(loc)}: ${msgId(loc)}`).join(", ")} }
128
+ ` : "";
129
+ return `${HEADER}${imports}
130
+
131
+ const loaders: Record<string, () => Promise<unknown>> = {
132
+ ${loaders}
133
+ }
134
+
135
+ // Flow pages come from funnel.ts (order + meta + routing). Any remaining page file is an off-flow
136
+ // \`@variant\` page (wired by experiment records at render time), appended so it's loadable.
137
+ const decls = config.pages ?? []
138
+ const flowKeys = new Set(decls.map((d) => d.key))
139
+ export const pages: RuntimePage[] = [
140
+ ...decls.map((d) => ({ key: d.key, meta: d, load: loaders[d.key] })),
141
+ ...Object.keys(loaders)
142
+ .filter((k) => !flowKeys.has(k))
143
+ .map((k) => ({ key: k, meta: {}, load: loaders[k] })),
144
+ ] as RuntimePage[]
145
+ ${messagesConst}
146
+ export const tree = createFunnelTree({ ${treeArgs} })
147
+
148
+ export type { MountOpts }
149
+ `;
150
+ }
151
+ function generateEntryClient(opts) {
152
+ const p = opts.importPrefix ?? "./";
153
+ const styles = opts.hasStyles ? `import '${p}styles.css'
154
+ ` : "";
155
+ return `${HEADER}${styles}import { hydrateRoot } from 'react-dom/client'
156
+ import { tree, type MountOpts } from './mount'
157
+
158
+ const dataEl = document.getElementById('__af_data')
159
+ const data = (dataEl?.textContent ? JSON.parse(dataEl.textContent) : {}) as MountOpts & {
160
+ initialKey?: string | null
161
+ }
162
+ const root = document.getElementById('root')
163
+ if (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined }))
164
+ `;
165
+ }
166
+ function generateEntryServer(opts) {
167
+ const p = opts.importPrefix ?? "./";
168
+ return `${HEADER}import { renderToReadableStream } from 'react-dom/server.browser'
169
+ import { compileManifest } from '@appfunnel-dev/sdk'
170
+ import { config } from '${p}funnel'
171
+ import { tree, pages, type MountOpts } from './mount'
172
+
173
+ export const manifest = compileManifest({
174
+ funnel: config,
175
+ pages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),
176
+ productRefs: ${JSON.stringify(opts.productRefs ?? [])},
177
+ })
178
+
179
+ export async function ssr(opts: MountOpts): Promise<string> {
180
+ const stream = await renderToReadableStream(tree(opts))
181
+ await stream.allReady
182
+ return await new Response(stream).text()
183
+ }
184
+ `;
185
+ }
186
+ function generateDevEntry(opts) {
187
+ const p = opts.importPrefix ?? "./";
188
+ const styles = opts.hasStyles ? `import '${p}styles.css'
189
+ ` : "";
190
+ return `${HEADER}${styles}import { createRoot } from 'react-dom/client'
191
+ import { tree } from './mount'
192
+
193
+ const el = document.getElementById('root')
194
+ if (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))
195
+ `;
196
+ }
197
+
198
+ Object.defineProperty(exports, "assignVariant", {
199
+ enumerable: true,
200
+ get: function () { return chunkJSRKA375_cjs.assignVariant; }
201
+ });
202
+ Object.defineProperty(exports, "bucketingSeed", {
203
+ enumerable: true,
204
+ get: function () { return chunkJSRKA375_cjs.bucketingSeed; }
205
+ });
206
+ Object.defineProperty(exports, "buildCatalog", {
207
+ enumerable: true,
208
+ get: function () { return chunkJSRKA375_cjs.buildCatalog; }
209
+ });
210
+ Object.defineProperty(exports, "compileManifest", {
211
+ enumerable: true,
212
+ get: function () { return chunkJSRKA375_cjs.compileManifest; }
213
+ });
214
+ Object.defineProperty(exports, "currencyExponent", {
215
+ enumerable: true,
216
+ get: function () { return chunkJSRKA375_cjs.currencyExponent; }
217
+ });
218
+ Object.defineProperty(exports, "defineFunnel", {
219
+ enumerable: true,
220
+ get: function () { return chunkJSRKA375_cjs.defineFunnel; }
221
+ });
222
+ Object.defineProperty(exports, "formatMoney", {
223
+ enumerable: true,
224
+ get: function () { return chunkJSRKA375_cjs.formatMoney; }
225
+ });
226
+ Object.defineProperty(exports, "formatProduct", {
227
+ enumerable: true,
228
+ get: function () { return chunkJSRKA375_cjs.formatProduct; }
229
+ });
230
+ Object.defineProperty(exports, "funnelCatalogKeys", {
231
+ enumerable: true,
232
+ get: function () { return chunkJSRKA375_cjs.funnelCatalogKeys; }
233
+ });
234
+ Object.defineProperty(exports, "isRtl", {
235
+ enumerable: true,
236
+ get: function () { return chunkJSRKA375_cjs.isRtl; }
237
+ });
238
+ Object.defineProperty(exports, "isVariantKey", {
239
+ enumerable: true,
240
+ get: function () { return chunkJSRKA375_cjs.isVariantKey; }
241
+ });
242
+ Object.defineProperty(exports, "normalizeProducts", {
243
+ enumerable: true,
244
+ get: function () { return chunkJSRKA375_cjs.normalizeProducts; }
245
+ });
246
+ Object.defineProperty(exports, "pageMeta", {
247
+ enumerable: true,
248
+ get: function () { return chunkJSRKA375_cjs.pageMeta; }
249
+ });
250
+ Object.defineProperty(exports, "parseSlotKey", {
251
+ enumerable: true,
252
+ get: function () { return chunkJSRKA375_cjs.parseSlotKey; }
253
+ });
254
+ Object.defineProperty(exports, "resolveLocale", {
255
+ enumerable: true,
256
+ get: function () { return chunkJSRKA375_cjs.resolveLocale; }
257
+ });
258
+ Object.defineProperty(exports, "resolveProduct", {
259
+ enumerable: true,
260
+ get: function () { return chunkJSRKA375_cjs.resolveProduct; }
261
+ });
262
+ Object.defineProperty(exports, "validateExperiments", {
263
+ enumerable: true,
264
+ get: function () { return chunkJSRKA375_cjs.validateExperiments; }
265
+ });
266
+ Object.defineProperty(exports, "weightsOf", {
267
+ enumerable: true,
268
+ get: function () { return chunkJSRKA375_cjs.weightsOf; }
269
+ });
270
+ Object.defineProperty(exports, "INLINE_SURFACES", {
271
+ enumerable: true,
272
+ get: function () { return chunkLJYLGLFS_cjs.INLINE_SURFACES; }
273
+ });
274
+ Object.defineProperty(exports, "PROVIDER_PROFILES", {
275
+ enumerable: true,
276
+ get: function () { return chunkLJYLGLFS_cjs.PROVIDER_PROFILES; }
277
+ });
278
+ Object.defineProperty(exports, "checkoutError", {
279
+ enumerable: true,
280
+ get: function () { return chunkLJYLGLFS_cjs.checkoutError; }
281
+ });
282
+ Object.defineProperty(exports, "isInlineSurface", {
283
+ enumerable: true,
284
+ get: function () { return chunkLJYLGLFS_cjs.isInlineSurface; }
285
+ });
286
+ Object.defineProperty(exports, "isMerchantOfRecord", {
287
+ enumerable: true,
288
+ get: function () { return chunkLJYLGLFS_cjs.isMerchantOfRecord; }
289
+ });
290
+ Object.defineProperty(exports, "isOrchestrator", {
291
+ enumerable: true,
292
+ get: function () { return chunkLJYLGLFS_cjs.isOrchestrator; }
293
+ });
294
+ Object.defineProperty(exports, "surfacesFor", {
295
+ enumerable: true,
296
+ get: function () { return chunkLJYLGLFS_cjs.surfacesFor; }
297
+ });
298
+ Object.defineProperty(exports, "validateCheckout", {
299
+ enumerable: true,
300
+ get: function () { return chunkLJYLGLFS_cjs.validateCheckout; }
301
+ });
302
+ Object.defineProperty(exports, "validateUpsell", {
303
+ enumerable: true,
304
+ get: function () { return chunkLJYLGLFS_cjs.validateUpsell; }
305
+ });
306
+ exports.generateDevEntry = generateDevEntry;
307
+ exports.generateEntryClient = generateEntryClient;
308
+ exports.generateEntryServer = generateEntryServer;
309
+ exports.generateMount = generateMount;
310
+ exports.scanProductRefs = scanProductRefs;
311
+ //# sourceMappingURL=manifest-entry.cjs.map
312
+ //# sourceMappingURL=manifest-entry.cjs.map
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,209 @@
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
+ import { C as CheckoutError, b as CheckoutIntent, U as UpsellKind, d as CheckoutSurface } from './capabilities-7_hy5f5G.cjs';
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
+ import 'react';
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
+
27
+ /**
28
+ * Source generators for the funnel build "machinery" authors no longer write. `funnel.ts` (the
29
+ * spine: id, responses, products, checkout, and the page list + declarative routing) plus the
30
+ * `pages/` folder are the ONLY authored source. The build (renderer/builder) and the CLI dev server
31
+ * call these to synthesize:
32
+ * - `mount.tsx` — code-split page loaders + `createFunnelTree`
33
+ * - `entry.client.tsx` — hydrate the SSR'd markup from injected data
34
+ * - `entry.server.tsx` — `ssr()` + the compiled `manifest`
35
+ *
36
+ * All string templates, zero runtime deps — this module lives in the pure `@appfunnel-dev/sdk/
37
+ * manifest` entry so tooling imports it without the funnel runtime.
38
+ */
39
+ interface ScaffoldOptions {
40
+ /** Page component keys = `pages/<key>.tsx` filenames (base flow pages AND `@variant` pages). */
41
+ pageKeys: string[];
42
+ /** Import prefix to reach the funnel root: `'./'` at the root (build), `'../../'` in a subdir (CLI dev). */
43
+ importPrefix?: string;
44
+ /** Whether a `layout.tsx` exists to wrap the pages. */
45
+ hasLayout?: boolean;
46
+ /** Whether a `styles.css` exists (client entry imports it). */
47
+ hasStyles?: boolean;
48
+ /** Checkout provider from `config.checkout` — wires the driver; omit for none. */
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[];
54
+ }
55
+ /** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */
56
+ declare function generateMount(opts: ScaffoldOptions): string;
57
+ /** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */
58
+ declare function generateEntryClient(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): string;
59
+ /** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */
60
+ declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'productRefs'>): string;
61
+ /** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */
62
+ declare function generateDevEntry(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {
63
+ data: unknown;
64
+ }): string;
65
+
66
+ /**
67
+ * The v2 checkout WIRE CONTRACT — the request/response types shared by the server
68
+ * services (apps/api, fresh per-flow checkout — v1 purchase.ts is frozen) and the
69
+ * client drivers (driver-stripe/driver-paddle). Both sides import THESE types from
70
+ * the pure manifest entry, so the contract cannot drift between them.
71
+ *
72
+ * Future-proofing rules (Wave-4, Simon 2026-07-02):
73
+ * - Responses discriminate on `step` (what the CLIENT must do next), NOT on the
74
+ * provider — a new provider reuses an existing step (`redirect`,
75
+ * `provider_checkout`) or adds one, without breaking existing drivers.
76
+ * - The server NEVER returns secret credentials — publishable/client tokens only;
77
+ * charges and verification happen server-side against the mode-resolved store.
78
+ * - `correlationId` is the client-minted idempotency key AND the correlation id
79
+ * the server writes into every provider object's metadata — one id links the
80
+ * trial fee to its subscription, the webhook to the funnel session, and the
81
+ * retry to the original attempt (kills v0's 5-minute-webhook-window linking).
82
+ * - Money facts settle SERVER-side: the browser only ever learns the outcome
83
+ * (`CheckoutSettlement`, with the server-minted `eventId` the pixel dedupes on).
84
+ */
85
+
86
+ /** `POST {apiBase}/campaign/{campaignId}/v2/checkout` — open a checkout attempt. */
87
+ interface CheckoutSessionRequest {
88
+ funnelId: string;
89
+ /** Render-time mode (doc 09 §2.4): resolves the product's binding + store credentials. */
90
+ mode: 'test' | 'live';
91
+ /** Logical catalog product key (`monthly`) — never a raw price id. */
92
+ productKey: string;
93
+ intent: CheckoutIntent;
94
+ /** For `upsell` — which off-session kind (validated against the capability matrix). */
95
+ kind?: UpsellKind;
96
+ /** The presenting surface; null/absent = off-session (upsell, no UI). */
97
+ surface?: CheckoutSurface | null;
98
+ /** Funnel session id (analytics + customer continuity), when one exists. */
99
+ sessionId?: string;
100
+ /** Signed-cookie-verified bare visitor id, when known. */
101
+ visitorId?: string;
102
+ /** Buyer email when the funnel collected it (Stripe Customer creation / receipts). */
103
+ email?: string;
104
+ /**
105
+ * Client-minted UUID. Idempotency key for this attempt (safe re-POST on network
106
+ * retry) and the correlation id stamped into provider-object metadata.
107
+ */
108
+ correlationId: string;
109
+ }
110
+ /** What the browser learned when the server settled the charge (or verified it). */
111
+ interface CheckoutSettlement {
112
+ ok: true;
113
+ /** Server-minted dedup id — the SDK emits `purchase.complete` with it (browser↔CAPI dedup). */
114
+ eventId: string;
115
+ amountMinor: number;
116
+ currency: string;
117
+ productKey: string;
118
+ }
119
+ /** Driver confirms in the browser with the provider's JS (Stripe Elements et al.). */
120
+ interface StepClientConfirm {
121
+ step: 'client_confirm';
122
+ provider: string;
123
+ publishableKey: string;
124
+ clientSecret: string;
125
+ /** Which secret this is — payment (charge now) vs setup (vault, e.g. free-trial start). */
126
+ secretKind: 'payment_intent' | 'setup_intent';
127
+ }
128
+ /** Driver mounts the provider-MANAGED inline checkout (Stripe Embedded). */
129
+ interface StepEmbedded {
130
+ step: 'embedded';
131
+ provider: string;
132
+ publishableKey: string;
133
+ clientSecret: string;
134
+ }
135
+ /** Driver navigates to the provider-hosted page (any provider's `redirect`). */
136
+ interface StepRedirect {
137
+ step: 'redirect';
138
+ provider: string;
139
+ url: string;
140
+ }
141
+ /**
142
+ * Driver opens the provider's own checkout UI (Paddle.js popup/inline, Whop later).
143
+ *
144
+ * WHAT the checkout opens is EXACTLY ONE of `items` | `transactionId`:
145
+ * - `items` — open a NEW checkout for these provider-native prices (the purchase shape;
146
+ * every response before 2026-07 carried this, so `items`-only stays valid unchanged);
147
+ * - `transactionId` — open the provider's checkout for an EXISTING server-created
148
+ * transaction (e.g. Paddle's payment-method-change transaction: the on-session
149
+ * re-collect leg of a failed off-session upgrade — `Checkout.open({ transactionId })`).
150
+ * A response carrying both or neither is malformed and the driver rejects it.
151
+ */
152
+ interface StepProviderCheckout {
153
+ step: 'provider_checkout';
154
+ provider: string;
155
+ /** Provider client token / publishable credential for its JS SDK. */
156
+ clientToken: string;
157
+ /** Provider environment the client SDK must target (Paddle sandbox vs production). */
158
+ providerEnvironment: 'sandbox' | 'production';
159
+ /** Provider-native line items (e.g. Paddle price ids), resolved from the binding. */
160
+ items?: {
161
+ priceId: string;
162
+ quantity: number;
163
+ }[];
164
+ /** Provider-side id of an EXISTING transaction to open (see the exactly-one rule above). */
165
+ transactionId?: string;
166
+ /**
167
+ * Echoed into the provider checkout's custom data (carries the correlationId) — `items`
168
+ * path only. A `transactionId` checkout already exists provider-side with its own custom
169
+ * data (Paddle: inherited from the subscription), so the driver does not send this.
170
+ */
171
+ customData: Record<string, string>;
172
+ }
173
+ /** The server completed the charge synchronously (off-session upsell). */
174
+ interface StepSettled {
175
+ step: 'settled';
176
+ result: CheckoutSettlement;
177
+ }
178
+ /** The attempt failed — normalized taxonomy, never a raw provider error. */
179
+ interface StepFailed {
180
+ step: 'failed';
181
+ error: CheckoutError;
182
+ }
183
+ /**
184
+ * The provider hasn't confirmed yet — the charge is in flight and will settle
185
+ * async (webhook). The driver polls `/complete` until `settled`/`failed`. On the
186
+ * OPEN response this is the Paddle off-session tail (its confirmation can outlast
187
+ * the request); money stays truthful either way — the attempt is PENDING
188
+ * server-side and the webhook/poll converge on one outcome.
189
+ */
190
+ interface StepPending {
191
+ step: 'pending';
192
+ }
193
+ type CheckoutSessionResponse = StepClientConfirm | StepEmbedded | StepRedirect | StepProviderCheckout | StepSettled | StepPending | StepFailed;
194
+ /**
195
+ * `POST {apiBase}/campaign/{campaignId}/v2/checkout/{correlationId}/complete` —
196
+ * after a client-side confirm/provider-checkout resolves, the browser asks the
197
+ * server to VERIFY with the provider and write the money facts. The server is the
198
+ * source of truth: it re-fetches the provider object; the browser's claim alone
199
+ * never creates a fact. Idempotent per correlationId (a re-POST returns the same
200
+ * settlement). MoR/async providers (Paddle) may verify via webhook before this
201
+ * call arrives — then it simply returns the already-written settlement.
202
+ */
203
+ interface CheckoutCompleteRequest {
204
+ /** Provider-side handle the client got back, when it has one (e.g. Stripe intent id). */
205
+ providerRef?: string;
206
+ }
207
+ type CheckoutCompleteResponse = StepSettled | StepPending | StepFailed;
208
+
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 };