@appfunnel-dev/sdk 2.0.0-canary.5 → 2.0.0-canary.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +1 -1
  2. package/dist/{capabilities-7_hy5f5G.d.cts → capabilities-CsnkVwna.d.cts} +34 -1
  3. package/dist/{capabilities-7_hy5f5G.d.ts → capabilities-CsnkVwna.d.ts} +34 -1
  4. package/dist/{checkout-7Dy6IedP.d.ts → checkout-3PkKwPd7.d.ts} +14 -14
  5. package/dist/{checkout-Dz8cGkB_.d.cts → checkout-Cg20l53c.d.cts} +14 -14
  6. package/dist/{chunk-VAOR77NW.cjs → chunk-FY3TMSRU.cjs} +7 -7
  7. package/dist/{chunk-VAOR77NW.cjs.map → chunk-FY3TMSRU.cjs.map} +1 -1
  8. package/dist/{chunk-CFFMZYPE.js → chunk-PWXMQGO6.js} +3 -3
  9. package/dist/{chunk-CFFMZYPE.js.map → chunk-PWXMQGO6.js.map} +1 -1
  10. package/dist/{chunk-TNLRQPVY.js → chunk-RVJLR4RS.js} +36 -8
  11. package/dist/chunk-RVJLR4RS.js.map +1 -0
  12. package/dist/{chunk-QMAZGLGV.cjs → chunk-RY3LOSVZ.cjs} +37 -7
  13. package/dist/chunk-RY3LOSVZ.cjs.map +1 -0
  14. package/dist/{chunk-AXXG3ODP.js → chunk-VW2HVPR4.js} +63 -90
  15. package/dist/chunk-VW2HVPR4.js.map +1 -0
  16. package/dist/{chunk-G44BUG6G.cjs → chunk-Y4YNJ2EX.cjs} +65 -93
  17. package/dist/chunk-Y4YNJ2EX.cjs.map +1 -0
  18. package/dist/driver-paddle.cjs +22 -22
  19. package/dist/driver-paddle.d.cts +2 -2
  20. package/dist/driver-paddle.d.ts +2 -2
  21. package/dist/driver-paddle.js +2 -2
  22. package/dist/driver-stripe.cjs +264 -212
  23. package/dist/driver-stripe.cjs.map +1 -1
  24. package/dist/driver-stripe.d.cts +19 -3
  25. package/dist/driver-stripe.d.ts +19 -3
  26. package/dist/driver-stripe.js +244 -193
  27. package/dist/driver-stripe.js.map +1 -1
  28. package/dist/index.cjs +310 -134
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +25 -25
  31. package/dist/index.d.ts +25 -25
  32. package/dist/index.js +262 -82
  33. package/dist/index.js.map +1 -1
  34. package/dist/{manifest-Dl7faaKe.d.cts → manifest-B3Tdab0M.d.cts} +157 -85
  35. package/dist/{manifest-Dl7faaKe.d.ts → manifest-B3Tdab0M.d.ts} +157 -85
  36. package/dist/manifest-entry.cjs +118 -49
  37. package/dist/manifest-entry.cjs.map +1 -1
  38. package/dist/manifest-entry.d.cts +12 -29
  39. package/dist/manifest-entry.d.ts +12 -29
  40. package/dist/manifest-entry.js +79 -14
  41. package/dist/manifest-entry.js.map +1 -1
  42. package/package.json +1 -1
  43. package/dist/chunk-AXXG3ODP.js.map +0 -1
  44. package/dist/chunk-G44BUG6G.cjs.map +0 -1
  45. package/dist/chunk-QMAZGLGV.cjs.map +0 -1
  46. package/dist/chunk-TNLRQPVY.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var chunkG44BUG6G_cjs = require('./chunk-G44BUG6G.cjs');
4
- var chunkQMAZGLGV_cjs = require('./chunk-QMAZGLGV.cjs');
3
+ var chunkY4YNJ2EX_cjs = require('./chunk-Y4YNJ2EX.cjs');
4
+ var chunkRY3LOSVZ_cjs = require('./chunk-RY3LOSVZ.cjs');
5
5
  require('./chunk-EMMSS5I5.cjs');
6
6
 
7
- // src/manifest/product-refs.ts
7
+ // src/manifest/offering-refs.ts
8
8
  function mask(src) {
9
9
  const out = src.split("");
10
10
  const n = src.length;
@@ -60,7 +60,28 @@ function skipWs(masked, i) {
60
60
  while (i < masked.length && (masked[i] === " " || masked[i] === " " || masked[i] === "\n" || masked[i] === "\r")) i++;
61
61
  return i;
62
62
  }
63
- function scanProductRefs(files) {
63
+ function tagAttrEnd(masked, from) {
64
+ let depth = 0;
65
+ for (let i = from; i < masked.length; i++) {
66
+ const c = masked[i];
67
+ if (c === "{") depth++;
68
+ else if (c === "}") {
69
+ if (depth > 0) depth--;
70
+ } else if (c === ">" && depth === 0) return i;
71
+ }
72
+ return masked.length;
73
+ }
74
+ function readAttr(src, masked, start, end, name) {
75
+ const re = new RegExp(`\\b${name}\\s*=\\s*`, "g");
76
+ re.lastIndex = start;
77
+ const m = re.exec(masked);
78
+ if (!m || m.index >= end) return null;
79
+ const at = m.index + m[0].length;
80
+ if (masked[at] === "{") return { dynamic: true };
81
+ const lit = literalAt(src, masked, at);
82
+ return lit !== null ? { value: lit } : { dynamic: true };
83
+ }
84
+ function scanOfferingRefs(files) {
64
85
  const seen = /* @__PURE__ */ new Set();
65
86
  const order = [];
66
87
  let dynamic = false;
@@ -70,11 +91,28 @@ function scanProductRefs(files) {
70
91
  order.push(v);
71
92
  }
72
93
  };
94
+ const surfaceSeen = /* @__PURE__ */ new Set();
95
+ const surfaces = [];
96
+ const kindSeen = /* @__PURE__ */ new Set();
97
+ const upsellKinds = [];
98
+ let checkoutDynamic = false;
99
+ const addSurface = (v) => {
100
+ if (v && !surfaceSeen.has(v)) {
101
+ surfaceSeen.add(v);
102
+ surfaces.push(v);
103
+ }
104
+ };
105
+ const addKind = (v) => {
106
+ if (v && !kindSeen.has(v)) {
107
+ kindSeen.add(v);
108
+ upsellKinds.push(v);
109
+ }
110
+ };
73
111
  for (const [path, source] of Object.entries(files)) {
74
112
  if (!/\.(tsx|jsx|ts|js)$/.test(path)) continue;
75
113
  const masked = mask(source);
76
- for (const m of masked.matchAll(/\buseProducts?\s*\(/g)) {
77
- const plural = source.slice(m.index, m.index + 11) === "useProducts";
114
+ for (const m of masked.matchAll(/\buseOfferings?\s*\(/g)) {
115
+ const plural = source.slice(m.index, m.index + 12) === "useOfferings";
78
116
  const j = skipWs(masked, m.index + m[0].length);
79
117
  if (masked[j] === ")") {
80
118
  if (plural) dynamic = true;
@@ -84,14 +122,36 @@ function scanProductRefs(files) {
84
122
  if (lit !== null) add(lit);
85
123
  else dynamic = true;
86
124
  }
87
- for (const m of masked.matchAll(/<(?:Checkout|Upsell)\b[^>]*?\bproduct\s*=\s*/g)) {
125
+ for (const m of masked.matchAll(/<(?:Checkout|Upsell)\b[^>]*?\boffering\s*=\s*/g)) {
88
126
  const j = m.index + m[0].length;
89
127
  const lit = literalAt(source, masked, j);
90
128
  if (lit !== null) add(lit);
91
129
  else if (masked[j] === "{") dynamic = true;
92
130
  }
131
+ for (const m of masked.matchAll(/<(Checkout|Upsell)\b/g)) {
132
+ const comp = m[1];
133
+ const tagStart = m.index + m[0].length;
134
+ const tagEnd = tagAttrEnd(masked, tagStart);
135
+ const attr = (name) => readAttr(source, masked, tagStart, tagEnd, name);
136
+ const fallback = attr("fallback");
137
+ if (fallback?.value) addSurface(fallback.value);
138
+ else if (fallback?.dynamic) checkoutDynamic = true;
139
+ const recovery = attr("recoverySurface");
140
+ if (recovery?.value) addSurface(recovery.value);
141
+ else if (recovery?.dynamic) checkoutDynamic = true;
142
+ if (comp === "Checkout") {
143
+ const surface = attr("surface");
144
+ if (surface?.value) addSurface(surface.value);
145
+ else if (surface?.dynamic) checkoutDynamic = true;
146
+ } else {
147
+ const kind = attr("kind");
148
+ if (kind?.value) addKind(kind.value);
149
+ else if (kind?.dynamic) checkoutDynamic = true;
150
+ else addKind("subscription");
151
+ }
152
+ }
93
153
  }
94
- return { slots: order, dynamic };
154
+ return { slots: order, dynamic, checkout: { surfaces, upsellKinds, dynamic: checkoutDynamic } };
95
155
  }
96
156
 
97
157
  // src/flow/scaffold.ts
@@ -102,7 +162,7 @@ var DRIVERS = {
102
162
  stripe: { name: "stripeCheckoutDriver", sub: "driver-stripe" },
103
163
  paddle: { name: "paddleCheckoutDriver", sub: "driver-paddle" }
104
164
  };
105
- var HEADER = "// GENERATED by AppFunnel \u2014 do not edit. Built from funnel.ts + the pages/ folder.\n";
165
+ var HEADER = "// GENERATED by Appfunnel \u2014 do not edit. Built from funnel.ts + the pages/ folder.\n";
106
166
  function generateMount(opts) {
107
167
  const p = opts.importPrefix ?? "./";
108
168
  const driver = opts.checkout ? DRIVERS[opts.checkout] : null;
@@ -112,7 +172,9 @@ function generateMount(opts) {
112
172
  driver && `import { ${driver.name} } from '@appfunnel-dev/sdk/${driver.sub}'`,
113
173
  `import { config } from '${p}funnel'`,
114
174
  opts.hasLayout && `import Layout from '${p}layout'`,
115
- ...locales.map((loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`)
175
+ ...locales.map(
176
+ (loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`
177
+ )
116
178
  ].filter(Boolean).join("\n");
117
179
  const loaders = opts.pageKeys.map(
118
180
  (k) => ` ${JSON.stringify(k)}: () => import(${JSON.stringify(`${p}pages/${k}`)}),`
@@ -133,8 +195,10 @@ const loaders: Record<string, () => Promise<unknown>> = {
133
195
  ${loaders}
134
196
  }
135
197
 
136
- // Flow pages come from funnel.ts (order + meta + routing). Any remaining page file is an off-flow
137
- // \`@variant\` page (wired by experiment records at render time), appended so it's loadable.
198
+ // Flow pages come from funnel.ts (order + meta + routing). A \`@variant\` page MAY also be declared
199
+ // there (with its \`@\` key) to carry its OWN optional routing (\`next\`) \u2014 it still collapses out of
200
+ // the linear flow by the \`@\` marker, but its meta rides along here. Any page file NOT declared is an
201
+ // off-flow \`@variant\` with no own routing, appended with empty meta so it's still loadable.
138
202
  const decls = config.pages ?? []
139
203
  const flowKeys = new Set(decls.map((d) => d.key))
140
204
  export const pages: RuntimePage[] = [
@@ -180,7 +244,8 @@ import { tree, pages, type MountOpts } from './mount'
180
244
  export const manifest = compileManifest({
181
245
  funnel: config,
182
246
  pages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),
183
- productRefs: ${JSON.stringify(opts.productRefs ?? [])},
247
+ offeringRefs: ${JSON.stringify(opts.offeringRefs ?? [])},
248
+ checkoutRefs: ${JSON.stringify(opts.checkoutRefs ?? { surfaces: [], upsellKinds: [], dynamic: false })},
184
249
  })
185
250
 
186
251
  export async function ssr(opts: MountOpts): Promise<string> {
@@ -204,124 +269,128 @@ if (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))
204
269
 
205
270
  Object.defineProperty(exports, "assignVariant", {
206
271
  enumerable: true,
207
- get: function () { return chunkG44BUG6G_cjs.assignVariant; }
272
+ get: function () { return chunkY4YNJ2EX_cjs.assignVariant; }
208
273
  });
209
274
  Object.defineProperty(exports, "bucketingSeed", {
210
275
  enumerable: true,
211
- get: function () { return chunkG44BUG6G_cjs.bucketingSeed; }
276
+ get: function () { return chunkY4YNJ2EX_cjs.bucketingSeed; }
212
277
  });
213
278
  Object.defineProperty(exports, "buildCatalog", {
214
279
  enumerable: true,
215
- get: function () { return chunkG44BUG6G_cjs.buildCatalog; }
280
+ get: function () { return chunkY4YNJ2EX_cjs.buildCatalog; }
216
281
  });
217
282
  Object.defineProperty(exports, "compileManifest", {
218
283
  enumerable: true,
219
- get: function () { return chunkG44BUG6G_cjs.compileManifest; }
284
+ get: function () { return chunkY4YNJ2EX_cjs.compileManifest; }
220
285
  });
221
286
  Object.defineProperty(exports, "currencyExponent", {
222
287
  enumerable: true,
223
- get: function () { return chunkG44BUG6G_cjs.currencyExponent; }
288
+ get: function () { return chunkY4YNJ2EX_cjs.currencyExponent; }
224
289
  });
225
290
  Object.defineProperty(exports, "defineFunnel", {
226
291
  enumerable: true,
227
- get: function () { return chunkG44BUG6G_cjs.defineFunnel; }
292
+ get: function () { return chunkY4YNJ2EX_cjs.defineFunnel; }
228
293
  });
229
294
  Object.defineProperty(exports, "entryGuard", {
230
295
  enumerable: true,
231
- get: function () { return chunkG44BUG6G_cjs.entryGuard; }
296
+ get: function () { return chunkY4YNJ2EX_cjs.entryGuard; }
232
297
  });
233
298
  Object.defineProperty(exports, "evaluateCondition", {
234
299
  enumerable: true,
235
- get: function () { return chunkG44BUG6G_cjs.evaluateCondition; }
300
+ get: function () { return chunkY4YNJ2EX_cjs.evaluateCondition; }
236
301
  });
237
302
  Object.defineProperty(exports, "formatMoney", {
238
303
  enumerable: true,
239
- get: function () { return chunkG44BUG6G_cjs.formatMoney; }
304
+ get: function () { return chunkY4YNJ2EX_cjs.formatMoney; }
240
305
  });
241
- Object.defineProperty(exports, "formatProduct", {
306
+ Object.defineProperty(exports, "formatOffering", {
242
307
  enumerable: true,
243
- get: function () { return chunkG44BUG6G_cjs.formatProduct; }
308
+ get: function () { return chunkY4YNJ2EX_cjs.formatOffering; }
244
309
  });
245
310
  Object.defineProperty(exports, "funnelCatalogKeys", {
246
311
  enumerable: true,
247
- get: function () { return chunkG44BUG6G_cjs.funnelCatalogKeys; }
312
+ get: function () { return chunkY4YNJ2EX_cjs.funnelCatalogKeys; }
248
313
  });
249
314
  Object.defineProperty(exports, "isRtl", {
250
315
  enumerable: true,
251
- get: function () { return chunkG44BUG6G_cjs.isRtl; }
316
+ get: function () { return chunkY4YNJ2EX_cjs.isRtl; }
252
317
  });
253
318
  Object.defineProperty(exports, "isVariantKey", {
254
319
  enumerable: true,
255
- get: function () { return chunkG44BUG6G_cjs.isVariantKey; }
320
+ get: function () { return chunkY4YNJ2EX_cjs.isVariantKey; }
256
321
  });
257
- Object.defineProperty(exports, "normalizeProducts", {
322
+ Object.defineProperty(exports, "normalizeOfferings", {
258
323
  enumerable: true,
259
- get: function () { return chunkG44BUG6G_cjs.normalizeProducts; }
324
+ get: function () { return chunkY4YNJ2EX_cjs.normalizeOfferings; }
260
325
  });
261
326
  Object.defineProperty(exports, "pageMeta", {
262
327
  enumerable: true,
263
- get: function () { return chunkG44BUG6G_cjs.pageMeta; }
328
+ get: function () { return chunkY4YNJ2EX_cjs.pageMeta; }
264
329
  });
265
330
  Object.defineProperty(exports, "parseSlotKey", {
266
331
  enumerable: true,
267
- get: function () { return chunkG44BUG6G_cjs.parseSlotKey; }
332
+ get: function () { return chunkY4YNJ2EX_cjs.parseSlotKey; }
268
333
  });
269
334
  Object.defineProperty(exports, "resolveLocale", {
270
335
  enumerable: true,
271
- get: function () { return chunkG44BUG6G_cjs.resolveLocale; }
272
- });
273
- Object.defineProperty(exports, "resolveProduct", {
274
- enumerable: true,
275
- get: function () { return chunkG44BUG6G_cjs.resolveProduct; }
336
+ get: function () { return chunkY4YNJ2EX_cjs.resolveLocale; }
276
337
  });
277
- Object.defineProperty(exports, "validateExperiments", {
338
+ Object.defineProperty(exports, "resolveOffering", {
278
339
  enumerable: true,
279
- get: function () { return chunkG44BUG6G_cjs.validateExperiments; }
340
+ get: function () { return chunkY4YNJ2EX_cjs.resolveOffering; }
280
341
  });
281
342
  Object.defineProperty(exports, "weightsOf", {
282
343
  enumerable: true,
283
- get: function () { return chunkG44BUG6G_cjs.weightsOf; }
344
+ get: function () { return chunkY4YNJ2EX_cjs.weightsOf; }
284
345
  });
285
346
  Object.defineProperty(exports, "INLINE_SURFACES", {
286
347
  enumerable: true,
287
- get: function () { return chunkQMAZGLGV_cjs.INLINE_SURFACES; }
348
+ get: function () { return chunkRY3LOSVZ_cjs.INLINE_SURFACES; }
288
349
  });
289
350
  Object.defineProperty(exports, "PROVIDER_PROFILES", {
290
351
  enumerable: true,
291
- get: function () { return chunkQMAZGLGV_cjs.PROVIDER_PROFILES; }
352
+ get: function () { return chunkRY3LOSVZ_cjs.PROVIDER_PROFILES; }
292
353
  });
293
354
  Object.defineProperty(exports, "checkoutError", {
294
355
  enumerable: true,
295
- get: function () { return chunkQMAZGLGV_cjs.checkoutError; }
356
+ get: function () { return chunkRY3LOSVZ_cjs.checkoutError; }
296
357
  });
297
358
  Object.defineProperty(exports, "isInlineSurface", {
298
359
  enumerable: true,
299
- get: function () { return chunkQMAZGLGV_cjs.isInlineSurface; }
360
+ get: function () { return chunkRY3LOSVZ_cjs.isInlineSurface; }
300
361
  });
301
362
  Object.defineProperty(exports, "isMerchantOfRecord", {
302
363
  enumerable: true,
303
- get: function () { return chunkQMAZGLGV_cjs.isMerchantOfRecord; }
364
+ get: function () { return chunkRY3LOSVZ_cjs.isMerchantOfRecord; }
304
365
  });
305
366
  Object.defineProperty(exports, "isOrchestrator", {
306
367
  enumerable: true,
307
- get: function () { return chunkQMAZGLGV_cjs.isOrchestrator; }
368
+ get: function () { return chunkRY3LOSVZ_cjs.isOrchestrator; }
308
369
  });
309
370
  Object.defineProperty(exports, "surfacesFor", {
310
371
  enumerable: true,
311
- get: function () { return chunkQMAZGLGV_cjs.surfacesFor; }
372
+ get: function () { return chunkRY3LOSVZ_cjs.surfacesFor; }
373
+ });
374
+ Object.defineProperty(exports, "trialShapesFor", {
375
+ enumerable: true,
376
+ get: function () { return chunkRY3LOSVZ_cjs.trialShapesFor; }
312
377
  });
313
378
  Object.defineProperty(exports, "validateCheckout", {
314
379
  enumerable: true,
315
- get: function () { return chunkQMAZGLGV_cjs.validateCheckout; }
380
+ get: function () { return chunkRY3LOSVZ_cjs.validateCheckout; }
381
+ });
382
+ Object.defineProperty(exports, "validateTrial", {
383
+ enumerable: true,
384
+ get: function () { return chunkRY3LOSVZ_cjs.validateTrial; }
316
385
  });
317
386
  Object.defineProperty(exports, "validateUpsell", {
318
387
  enumerable: true,
319
- get: function () { return chunkQMAZGLGV_cjs.validateUpsell; }
388
+ get: function () { return chunkRY3LOSVZ_cjs.validateUpsell; }
320
389
  });
321
390
  exports.generateDevEntry = generateDevEntry;
322
391
  exports.generateEntryClient = generateEntryClient;
323
392
  exports.generateEntryServer = generateEntryServer;
324
393
  exports.generateMount = generateMount;
325
- exports.scanProductRefs = scanProductRefs;
394
+ exports.scanOfferingRefs = scanOfferingRefs;
326
395
  //# sourceMappingURL=manifest-entry.cjs.map
327
396
  //# sourceMappingURL=manifest-entry.cjs.map
@@ -1 +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')\n// FLASH-FREE HYDRATION (SSR-isolation Option B): always DEFER sessionValues on the client. The\n// markup we hydrate against is DEFAULT-state (build-time prerendered, or an SSR render with empty\n// sessionValues), so seeding the store with defaults for the first render is a byte-clean match —\n// no hydration mismatch. The visitor's saved answers (data.sessionValues, present on the \"tail\"\n// path) are then applied post-hydration, popping into already-visible controls with no empty\n// flash. On the cold path sessionValues is absent, so deferring is a no-op (identical output).\nif (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined, deferSessionValues: true }))\n`\n}\n\n/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */\nexport function generateEntryServer(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
+ {"version":3,"sources":["../src/manifest/offering-refs.ts","../src/flow/scaffold.ts"],"names":[],"mappings":"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","file":"manifest-entry.cjs","sourcesContent":["/**\n * Pure, React-free page scan: find which offering SLOTS a funnel's pages reference — the first\n * string-literal arg of `useOffering(...)` and the `offering` prop of `<Checkout>` / `<Upsell>`.\n * Ships via `@appfunnel-dev/sdk/manifest` so the BUILD, the EDITOR, and the AI all run the SAME\n * check. The result feeds `compileManifest({ offeringRefs })`, which flags references to slots the\n * funnel doesn't declare (unknown) or hasn't assigned a catalog charge key to (unassigned).\n *\n * Non-literal args (`useOffering(selectedId)`, `offering={expr}`) and the `useOfferings()` wildcard are\n * DYNAMIC — they can't be statically enumerated, so they're reported via `dynamic` and never turned\n * into a hard error (validation relaxes when a funnel is dynamic). Mirrors the mask-then-read\n * discipline the funnel.ts code-mods use, so a `useOffering('x')` inside a comment or string literal\n * can't false-positive.\n */\n\nexport interface OfferingRefScan {\n /** Concrete slot names referenced by LITERAL args, deduped, in first-seen order. */\n slots: string[]\n /** True if any ref is a non-literal arg or a `useOfferings()` wildcard (not statically enumerable). */\n dynamic: boolean\n /**\n * Checkout-SURFACE usage the pages express — feeds the publish (provider × surface) capability\n * gate. Absent-field back-compat: a manifest compiled before this existed simply omits it, and\n * the gate skips (no false blocks). See {@link CheckoutUsageScan}.\n */\n checkout: CheckoutUsageScan\n}\n\n/**\n * What the pages ask the checkout to DO, statically — the surfaces they mount and the off-session\n * upsell kinds they charge. Literal values only; a computed value (`surface={expr}`) sets\n * {@link dynamic} so the publish gate WARNS instead of hard-failing (it can't enumerate it).\n */\nexport interface CheckoutUsageScan {\n /**\n * Purchase SURFACES the pages request, deduped in first-seen order. Captures every literal\n * `<Checkout surface=\"…\">` plus the on-session re-collect surfaces `<Checkout|Upsell fallback=\"…\">`\n * and `recoverySurface=\"…\"` (a fallback re-collects a card → it IS a purchase surface the provider\n * must support). Validated with `validateCheckout(provider, surface)`.\n */\n surfaces: string[]\n /**\n * Off-session upsell KINDS from `<Upsell kind=\"…\">`, deduped. A `<Upsell>` with no `kind` attr\n * defaults to `'subscription'` (mirrors the runtime default), so an unadorned `<Upsell>` records\n * `'subscription'`. Validated with `validateUpsell(provider, paywallSurface, kind)`.\n */\n upsellKinds: string[]\n /** True if any surface/kind was a non-literal (computed) value → the gate WARNS, never blocks, on it. */\n dynamic: boolean\n}\n\n/** Blank comment + string/template CONTENTS (keep quote delimiters + length) so scans don't fire inside them. */\nfunction mask(src: string): string {\n const out = src.split('')\n const n = src.length\n let i = 0\n while (i < n) {\n const c = src[i]\n const d = src[i + 1]\n if (c === '/' && d === '/') {\n while (i < n && src[i] !== '\\n') { out[i] = ' '; i++ }\n } else if (c === '/' && d === '*') {\n out[i] = ' '; out[i + 1] = ' '; i += 2\n while (i < n) {\n if (src[i] === '*' && src[i + 1] === '/') { out[i] = ' '; out[i + 1] = ' '; i += 2; break }\n if (src[i] !== '\\n') out[i] = ' '\n i++\n }\n } else if (c === \"'\" || c === '\"' || c === '`') {\n i++\n while (i < n && src[i] !== c) {\n if (src[i] === '\\\\') { out[i] = ' '; i++; if (i < n && src[i] !== '\\n') out[i] = ' '; i++; continue }\n if (src[i] !== '\\n') out[i] = ' '\n i++\n }\n i++ // closing delimiter (kept)\n } else i++\n }\n return out.join('')\n}\n\n/** A quoted string literal starting at `open` (a quote char in the MASK). Value read from the ORIGINAL. */\nfunction literalAt(src: string, masked: string, open: number): string | null {\n const q = masked[open]\n if (q !== \"'\" && q !== '\"' && q !== '`') return null\n const close = masked.indexOf(q, open + 1)\n if (close === -1) return null\n return src.slice(open + 1, close)\n}\n\n/** Advance past whitespace in `masked` from `i`. */\nfunction skipWs(masked: string, i: number): number {\n while (i < masked.length && (masked[i] === ' ' || masked[i] === '\\t' || masked[i] === '\\n' || masked[i] === '\\r')) i++\n return i\n}\n\n/**\n * Index of the `>` that closes the opening tag begun at `from` (the char after `<Checkout`). Tracks\n * brace depth so a `surface={a > b}` attribute expression doesn't end the tag early; `>` at depth 0\n * closes it (covers `/>` too — the `/` is at depth 0 and we stop at `>`). Returns end-of-string if\n * the tag never closes (masked never fires a value scan past it).\n */\nfunction tagAttrEnd(masked: string, from: number): number {\n let depth = 0\n for (let i = from; i < masked.length; i++) {\n const c = masked[i]\n if (c === '{') depth++\n else if (c === '}') { if (depth > 0) depth-- }\n else if (c === '>' && depth === 0) return i\n }\n return masked.length\n}\n\n/**\n * Read a JSX attribute `name` inside the opening-tag span `[start, end)`: returns its literal value,\n * `{ dynamic: true }` for a `{expr}` value, or null when the attribute is absent. Positions are on\n * the MASK; the value is read from the ORIGINAL (so a string-literal value survives masking).\n */\nfunction readAttr(\n src: string,\n masked: string,\n start: number,\n end: number,\n name: string,\n): { value?: string; dynamic?: boolean } | null {\n const re = new RegExp(`\\\\b${name}\\\\s*=\\\\s*`, 'g')\n re.lastIndex = start\n const m = re.exec(masked)\n if (!m || m.index >= end) return null\n const at = m.index + m[0].length\n if (masked[at] === '{') return { dynamic: true }\n const lit = literalAt(src, masked, at)\n return lit !== null ? { value: lit } : { dynamic: true }\n}\n\nexport function scanOfferingRefs(files: Record<string, string>): OfferingRefScan {\n const seen = new Set<string>()\n const order: string[] = []\n let dynamic = false\n const add = (v: string) => { if (v && !seen.has(v)) { seen.add(v); order.push(v) } }\n\n // Checkout-surface usage (separate dynamic flag: a computed SURFACE relaxes the capability gate,\n // independent of whether an OFFERING ref is computed).\n const surfaceSeen = new Set<string>()\n const surfaces: string[] = []\n const kindSeen = new Set<string>()\n const upsellKinds: string[] = []\n let checkoutDynamic = false\n const addSurface = (v: string) => { if (v && !surfaceSeen.has(v)) { surfaceSeen.add(v); surfaces.push(v) } }\n const addKind = (v: string) => { if (v && !kindSeen.has(v)) { kindSeen.add(v); upsellKinds.push(v) } }\n\n for (const [path, source] of Object.entries(files)) {\n if (!/\\.(tsx|jsx|ts|js)$/.test(path)) continue\n const masked = mask(source)\n\n // useOffering( … ) / useOfferings( … ) — positions on the MASK (a call inside a string won't match).\n for (const m of masked.matchAll(/\\buseOfferings?\\s*\\(/g)) {\n const plural = source.slice(m.index!, m.index! + 12) === 'useOfferings'\n const j = skipWs(masked, m.index! + m[0].length)\n if (masked[j] === ')') { if (plural) dynamic = true; continue } // useOfferings() = whole-catalog wildcard\n const lit = literalAt(source, masked, j)\n if (lit !== null) add(lit)\n else dynamic = true // useOffering(variable) — can't resolve statically\n }\n\n // <Checkout offering=\"…\"> / <Upsell offering=\"…\"> — the `offering` attribute value.\n for (const m of masked.matchAll(/<(?:Checkout|Upsell)\\b[^>]*?\\boffering\\s*=\\s*/g)) {\n const j = m.index! + m[0].length\n const lit = literalAt(source, masked, j)\n if (lit !== null) add(lit)\n else if (masked[j] === '{') dynamic = true // offering={expr}\n }\n\n // <Checkout …> / <Upsell …> checkout-SURFACE usage. Parse each opening tag's attribute span so\n // attribute order doesn't matter and a `>` inside a `{expr}` value can't truncate it.\n for (const m of masked.matchAll(/<(Checkout|Upsell)\\b/g)) {\n const comp = m[1]\n const tagStart = m.index! + m[0].length\n const tagEnd = tagAttrEnd(masked, tagStart)\n const attr = (name: string) => readAttr(source, masked, tagStart, tagEnd, name)\n // A fallback / recoverySurface re-collects a card ON-SESSION → it's a purchase surface too.\n const fallback = attr('fallback')\n if (fallback?.value) addSurface(fallback.value)\n else if (fallback?.dynamic) checkoutDynamic = true\n const recovery = attr('recoverySurface')\n if (recovery?.value) addSurface(recovery.value)\n else if (recovery?.dynamic) checkoutDynamic = true\n\n if (comp === 'Checkout') {\n const surface = attr('surface')\n if (surface?.value) addSurface(surface.value)\n else if (surface?.dynamic) checkoutDynamic = true\n } else {\n // <Upsell>: off-session; `kind` defaults to 'subscription' when the attr is absent.\n const kind = attr('kind')\n if (kind?.value) addKind(kind.value)\n else if (kind?.dynamic) checkoutDynamic = true\n else addKind('subscription')\n }\n }\n }\n return { slots: order, dynamic, checkout: { surfaces, upsellKinds, dynamic: checkoutDynamic } }\n}\n","/**\n * Source generators for the funnel build \"machinery\" authors no longer write. `funnel.ts` (the\n * spine: id, responses, offerings, checkout, and the page list + declarative routing) plus the\n * `pages/` folder are the ONLY authored source. The build (renderer/builder) and the CLI dev server\n * call these to synthesize:\n * - `mount.tsx` — code-split page loaders + `createFunnelTree`\n * - `entry.client.tsx` — hydrate the SSR'd markup from injected data\n * - `entry.server.tsx` — `ssr()` + the compiled `manifest`\n *\n * All string templates, zero runtime deps — this module lives in the pure `@appfunnel-dev/sdk/\n * manifest` entry so tooling imports it without the funnel runtime.\n */\n\nimport type { CheckoutUsageScan } from '../manifest/offering-refs'\n\nexport interface ScaffoldOptions {\n\t/** Page component keys = `pages/<key>.tsx` filenames (base flow pages AND `@variant` pages). */\n\tpageKeys: string[]\n\t/** Import prefix to reach the funnel root: `'./'` at the root (build), `'../../'` in a subdir (CLI dev). */\n\timportPrefix?: string\n\t/** Whether a `layout.tsx` exists to wrap the pages. */\n\thasLayout?: boolean\n\t/** Whether a `styles.css` exists (client entry imports it). */\n\thasStyles?: boolean\n\t/** Checkout provider from `config.checkout` — wires the driver; omit for none. */\n\tcheckout?: 'stripe' | 'paddle' | null\n\t/** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */\n\tmessageLocales?: string[]\n\t/** Slot names the pages reference (from `scanOfferingRefs`), baked into the manifest for validation. */\n\tofferingRefs?: string[]\n\t/** Checkout-surface usage the pages express (from `scanOfferingRefs(...).checkout`), baked into the manifest for the publish capability gate. */\n\tcheckoutRefs?: CheckoutUsageScan\n}\n\n/** A safe JS identifier for a message-catalog import (`en` → `msg_en`, `pt-BR` → `msg_pt_BR`). */\nfunction msgId(locale: string): string {\n\treturn 'msg_' + locale.replace(/[^a-zA-Z0-9]/g, '_')\n}\n\nconst DRIVERS = {\n\tstripe: { name: 'stripeCheckoutDriver', sub: 'driver-stripe' },\n\tpaddle: { name: 'paddleCheckoutDriver', sub: 'driver-paddle' },\n} as const\n\nconst HEADER =\n\t'// GENERATED by Appfunnel — do not edit. Built from funnel.ts + the pages/ folder.\\n'\n\n/** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */\nexport function generateMount(opts: ScaffoldOptions): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst driver = opts.checkout ? DRIVERS[opts.checkout] : null\n\n\tconst locales = opts.messageLocales ?? []\n\tconst imports = [\n\t\t`import { createFunnelTree, type MountOpts, type RuntimePage } from '@appfunnel-dev/sdk'`,\n\t\tdriver &&\n\t\t\t`import { ${driver.name} } from '@appfunnel-dev/sdk/${driver.sub}'`,\n\t\t`import { config } from '${p}funnel'`,\n\t\topts.hasLayout && `import Layout from '${p}layout'`,\n\t\t...locales.map(\n\t\t\t(loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`\n\t\t),\n\t]\n\t\t.filter(Boolean)\n\t\t.join('\\n')\n\n\t// A static import() per page file so Vite emits one code-split chunk each.\n\tconst loaders = opts.pageKeys\n\t\t.map(\n\t\t\t(k) =>\n\t\t\t\t`\\t${JSON.stringify(k)}: () => import(${JSON.stringify(`${p}pages/${k}`)}),`\n\t\t)\n\t\t.join('\\n')\n\n\tconst treeArgs = [\n\t\t'config',\n\t\t'pages',\n\t\topts.hasLayout && 'layout: Layout',\n\t\tdriver && `checkoutDriver: ${driver.name}`,\n\t\tlocales.length > 0 && 'messages',\n\t]\n\t\t.filter(Boolean)\n\t\t.join(', ')\n\n\t// The baked message catalog: locale → messages/<locale>.json (so `t()` resolves at render).\n\tconst messagesConst =\n\t\tlocales.length > 0\n\t\t\t? `\\nconst messages = { ${locales.map((loc) => `${JSON.stringify(loc)}: ${msgId(loc)}`).join(', ')} }\\n`\n\t\t\t: ''\n\n\treturn `${HEADER}${imports}\n\nconst loaders: Record<string, () => Promise<unknown>> = {\n${loaders}\n}\n\n// Flow pages come from funnel.ts (order + meta + routing). A \\`@variant\\` page MAY also be declared\n// there (with its \\`@\\` key) to carry its OWN optional routing (\\`next\\`) — it still collapses out of\n// the linear flow by the \\`@\\` marker, but its meta rides along here. Any page file NOT declared is an\n// off-flow \\`@variant\\` with no own routing, appended with empty meta so it's still loadable.\nconst decls = config.pages ?? []\nconst flowKeys = new Set(decls.map((d) => d.key))\nexport const pages: RuntimePage[] = [\n\t...decls.map((d) => ({ key: d.key, meta: d, load: loaders[d.key] })),\n\t...Object.keys(loaders)\n\t\t.filter((k) => !flowKeys.has(k))\n\t\t.map((k) => ({ key: k, meta: {}, load: loaders[k] })),\n] as RuntimePage[]\n${messagesConst}\nexport const tree = createFunnelTree({ ${treeArgs} })\n\nexport type { MountOpts }\n`\n}\n\n/** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */\nexport function generateEntryClient(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>\n): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst styles = opts.hasStyles ? `import '${p}styles.css'\\n` : ''\n\treturn `${HEADER}${styles}import { hydrateRoot } from 'react-dom/client'\nimport { tree, type MountOpts } from './mount'\n\nconst dataEl = document.getElementById('__af_data')\nconst data = (dataEl?.textContent ? JSON.parse(dataEl.textContent) : {}) as MountOpts & {\n\tinitialKey?: string | null\n}\nconst root = document.getElementById('root')\n// FLASH-FREE HYDRATION (SSR-isolation Option B): always DEFER sessionValues on the client. The\n// markup we hydrate against is DEFAULT-state (build-time prerendered, or an SSR render with empty\n// sessionValues), so seeding the store with defaults for the first render is a byte-clean match —\n// no hydration mismatch. The visitor's saved answers (data.sessionValues, present on the \"tail\"\n// path) are then applied post-hydration, popping into already-visible controls with no empty\n// flash. On the cold path sessionValues is absent, so deferring is a no-op (identical output).\nif (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined, deferSessionValues: true }))\n`\n}\n\n/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */\nexport function generateEntryServer(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs' | 'checkoutRefs'>\n): string {\n\tconst p = opts.importPrefix ?? './'\n\treturn `${HEADER}import { renderToReadableStream } from 'react-dom/server.browser'\nimport { compileManifest } from '@appfunnel-dev/sdk'\nimport { config } from '${p}funnel'\nimport { tree, pages, type MountOpts } from './mount'\n\nexport const manifest = compileManifest({\n\tfunnel: config,\n\tpages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),\n\tofferingRefs: ${JSON.stringify(opts.offeringRefs ?? [])},\n\tcheckoutRefs: ${JSON.stringify(opts.checkoutRefs ?? { surfaces: [], upsellKinds: [], dynamic: false })},\n})\n\nexport async function ssr(opts: MountOpts): Promise<string> {\n\tconst stream = await renderToReadableStream(tree(opts))\n\tawait stream.allReady\n\treturn await new Response(stream).text()\n}\n`\n}\n\n/** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */\nexport function generateDevEntry(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {\n\t\tdata: unknown\n\t}\n): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst styles = opts.hasStyles ? `import '${p}styles.css'\\n` : ''\n\treturn `${HEADER}${styles}import { createRoot } from 'react-dom/client'\nimport { tree } from './mount'\n\nconst el = document.getElementById('root')\nif (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))\n`\n}\n"]}
@@ -1,32 +1,12 @@
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, _ as entryGuard, $ as evaluateCondition, 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-Dl7faaKe.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';
1
+ import { af as CheckoutUsageScan } from './manifest-B3Tdab0M.cjs';
2
+ export { h as CompileInput, i as Condition, j as ConditionOp, E as EdgeCondition, l as ExperimentArm, n as FlowPage, c as FunnelDefinition, o as FunnelLocales, p as FunnelManifest, ag as FunnelPage, b as FunnelSnapshot, G as Gate, q as Interval, M as ManifestEdge, r as ManifestPage, s as ManifestValidation, t as Money, O as Offering, e as OfferingInput, ah as OfferingRefScan, ai as OfferingSlot, P as PageMeta, v as PageType, w as Predicate, x as ResolvedOffering, y as Route, R as RuntimeExperiment, H as assignVariant, J as bucketingSeed, N as buildCatalog, Q as compileManifest, T as currencyExponent, W as defineFunnel, Y as entryGuard, Z as evaluateCondition, a1 as formatMoney, a2 as formatOffering, aj as funnelCatalogKeys, a4 as isRtl, a5 as isVariantKey, ak as normalizeOfferings, a8 as pageMeta, a9 as parseSlotKey, ac as resolveLocale, ad as resolveOffering, al as scanOfferingRefs, am as weightsOf } from './manifest-B3Tdab0M.cjs';
3
+ import { C as CheckoutError, b as CheckoutIntent, U as UpsellKind, d as CheckoutSurface } from './capabilities-CsnkVwna.cjs';
4
+ export { a as CheckoutErrorCategory, c as CheckoutProvider, I as INLINE_SURFACES, O as OffSessionReliability, P as PROVIDER_PROFILES, e as ProviderProfile, S as SurfaceCapability, T as TrialShape, V as ValidationResult, f as checkoutError, i as isInlineSurface, g as isMerchantOfRecord, h as isOrchestrator, s as surfacesFor, t as trialShapesFor, v as validateCheckout, k as validateTrial, j as validateUpsell } from './capabilities-CsnkVwna.cjs';
4
5
  import 'react';
5
6
 
6
- /**
7
- * Pure, React-free page scan: find which 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
7
  /**
28
8
  * 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
9
+ * spine: id, responses, offerings, checkout, and the page list + declarative routing) plus the
30
10
  * `pages/` folder are the ONLY authored source. The build (renderer/builder) and the CLI dev server
31
11
  * call these to synthesize:
32
12
  * - `mount.tsx` — code-split page loaders + `createFunnelTree`
@@ -36,6 +16,7 @@ declare function scanProductRefs(files: Record<string, string>): ProductRefScan;
36
16
  * All string templates, zero runtime deps — this module lives in the pure `@appfunnel-dev/sdk/
37
17
  * manifest` entry so tooling imports it without the funnel runtime.
38
18
  */
19
+
39
20
  interface ScaffoldOptions {
40
21
  /** Page component keys = `pages/<key>.tsx` filenames (base flow pages AND `@variant` pages). */
41
22
  pageKeys: string[];
@@ -49,15 +30,17 @@ interface ScaffoldOptions {
49
30
  checkout?: 'stripe' | 'paddle' | null;
50
31
  /** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */
51
32
  messageLocales?: string[];
52
- /** Slot names the pages reference (from `scanProductRefs`), baked into the manifest for validation. */
53
- productRefs?: string[];
33
+ /** Slot names the pages reference (from `scanOfferingRefs`), baked into the manifest for validation. */
34
+ offeringRefs?: string[];
35
+ /** Checkout-surface usage the pages express (from `scanOfferingRefs(...).checkout`), baked into the manifest for the publish capability gate. */
36
+ checkoutRefs?: CheckoutUsageScan;
54
37
  }
55
38
  /** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */
56
39
  declare function generateMount(opts: ScaffoldOptions): string;
57
40
  /** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */
58
41
  declare function generateEntryClient(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): string;
59
42
  /** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */
60
- declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'productRefs'>): string;
43
+ declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs' | 'checkoutRefs'>): string;
61
44
  /** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */
62
45
  declare function generateDevEntry(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {
63
46
  data: unknown;
@@ -206,4 +189,4 @@ interface CheckoutCompleteRequest {
206
189
  }
207
190
  type CheckoutCompleteResponse = StepSettled | StepPending | StepFailed;
208
191
 
209
- export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, type ProductRefScan, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount, scanProductRefs };
192
+ export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, CheckoutUsageScan, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount };
@@ -1,32 +1,12 @@
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, _ as entryGuard, $ as evaluateCondition, 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-Dl7faaKe.js';
2
- import { C as CheckoutError, b as CheckoutIntent, U as UpsellKind, d as CheckoutSurface } from './capabilities-7_hy5f5G.js';
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';
1
+ import { af as CheckoutUsageScan } from './manifest-B3Tdab0M.js';
2
+ export { h as CompileInput, i as Condition, j as ConditionOp, E as EdgeCondition, l as ExperimentArm, n as FlowPage, c as FunnelDefinition, o as FunnelLocales, p as FunnelManifest, ag as FunnelPage, b as FunnelSnapshot, G as Gate, q as Interval, M as ManifestEdge, r as ManifestPage, s as ManifestValidation, t as Money, O as Offering, e as OfferingInput, ah as OfferingRefScan, ai as OfferingSlot, P as PageMeta, v as PageType, w as Predicate, x as ResolvedOffering, y as Route, R as RuntimeExperiment, H as assignVariant, J as bucketingSeed, N as buildCatalog, Q as compileManifest, T as currencyExponent, W as defineFunnel, Y as entryGuard, Z as evaluateCondition, a1 as formatMoney, a2 as formatOffering, aj as funnelCatalogKeys, a4 as isRtl, a5 as isVariantKey, ak as normalizeOfferings, a8 as pageMeta, a9 as parseSlotKey, ac as resolveLocale, ad as resolveOffering, al as scanOfferingRefs, am as weightsOf } from './manifest-B3Tdab0M.js';
3
+ import { C as CheckoutError, b as CheckoutIntent, U as UpsellKind, d as CheckoutSurface } from './capabilities-CsnkVwna.js';
4
+ export { a as CheckoutErrorCategory, c as CheckoutProvider, I as INLINE_SURFACES, O as OffSessionReliability, P as PROVIDER_PROFILES, e as ProviderProfile, S as SurfaceCapability, T as TrialShape, V as ValidationResult, f as checkoutError, i as isInlineSurface, g as isMerchantOfRecord, h as isOrchestrator, s as surfacesFor, t as trialShapesFor, v as validateCheckout, k as validateTrial, j as validateUpsell } from './capabilities-CsnkVwna.js';
4
5
  import 'react';
5
6
 
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
7
  /**
28
8
  * 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
9
+ * spine: id, responses, offerings, checkout, and the page list + declarative routing) plus the
30
10
  * `pages/` folder are the ONLY authored source. The build (renderer/builder) and the CLI dev server
31
11
  * call these to synthesize:
32
12
  * - `mount.tsx` — code-split page loaders + `createFunnelTree`
@@ -36,6 +16,7 @@ declare function scanProductRefs(files: Record<string, string>): ProductRefScan;
36
16
  * All string templates, zero runtime deps — this module lives in the pure `@appfunnel-dev/sdk/
37
17
  * manifest` entry so tooling imports it without the funnel runtime.
38
18
  */
19
+
39
20
  interface ScaffoldOptions {
40
21
  /** Page component keys = `pages/<key>.tsx` filenames (base flow pages AND `@variant` pages). */
41
22
  pageKeys: string[];
@@ -49,15 +30,17 @@ interface ScaffoldOptions {
49
30
  checkout?: 'stripe' | 'paddle' | null;
50
31
  /** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */
51
32
  messageLocales?: string[];
52
- /** Slot names the pages reference (from `scanProductRefs`), baked into the manifest for validation. */
53
- productRefs?: string[];
33
+ /** Slot names the pages reference (from `scanOfferingRefs`), baked into the manifest for validation. */
34
+ offeringRefs?: string[];
35
+ /** Checkout-surface usage the pages express (from `scanOfferingRefs(...).checkout`), baked into the manifest for the publish capability gate. */
36
+ checkoutRefs?: CheckoutUsageScan;
54
37
  }
55
38
  /** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */
56
39
  declare function generateMount(opts: ScaffoldOptions): string;
57
40
  /** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */
58
41
  declare function generateEntryClient(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): string;
59
42
  /** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */
60
- declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'productRefs'>): string;
43
+ declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs' | 'checkoutRefs'>): string;
61
44
  /** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */
62
45
  declare function generateDevEntry(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {
63
46
  data: unknown;
@@ -206,4 +189,4 @@ interface CheckoutCompleteRequest {
206
189
  }
207
190
  type CheckoutCompleteResponse = StepSettled | StepPending | StepFailed;
208
191
 
209
- export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, type ProductRefScan, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount, scanProductRefs };
192
+ export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, CheckoutUsageScan, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount };