@appfunnel-dev/sdk 2.0.0-canary.4 → 2.0.0-canary.7

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 (60) hide show
  1. package/README.md +1 -1
  2. package/dist/{checkout-Dz8cGkB_.d.cts → checkout-CMEdxpgo.d.cts} +13 -13
  3. package/dist/{checkout-7Dy6IedP.d.ts → checkout-D1NUPv4p.d.ts} +13 -13
  4. package/dist/{chunk-AKO6XKXP.js → chunk-7YQLPPPG.js} +66 -91
  5. package/dist/chunk-7YQLPPPG.js.map +1 -0
  6. package/dist/{chunk-JSRKA375.cjs → chunk-BPOAWI4G.cjs} +68 -94
  7. package/dist/chunk-BPOAWI4G.cjs.map +1 -0
  8. package/dist/{chunk-M6U3FNRW.js → chunk-CFFMZYPE.js} +3 -3
  9. package/dist/{chunk-M6U3FNRW.js.map → chunk-CFFMZYPE.js.map} +1 -1
  10. package/dist/chunk-EMMSS5I5.cjs +37 -0
  11. package/dist/chunk-EMMSS5I5.cjs.map +1 -0
  12. package/dist/chunk-G3PMV62Z.js +33 -0
  13. package/dist/chunk-G3PMV62Z.js.map +1 -0
  14. package/dist/{chunk-LJYLGLFS.cjs → chunk-QMAZGLGV.cjs} +2 -35
  15. package/dist/chunk-QMAZGLGV.cjs.map +1 -0
  16. package/dist/{chunk-YY375F2B.js → chunk-TNLRQPVY.js} +3 -33
  17. package/dist/chunk-TNLRQPVY.js.map +1 -0
  18. package/dist/{chunk-CY4VBSMX.cjs → chunk-VAOR77NW.cjs} +7 -7
  19. package/dist/{chunk-CY4VBSMX.cjs.map → chunk-VAOR77NW.cjs.map} +1 -1
  20. package/dist/chunk-WYUDL4FI.cjs +8 -0
  21. package/dist/chunk-WYUDL4FI.cjs.map +1 -0
  22. package/dist/chunk-ZZJG4EYL.js +6 -0
  23. package/dist/chunk-ZZJG4EYL.js.map +1 -0
  24. package/dist/driver-paddle.cjs +23 -22
  25. package/dist/driver-paddle.cjs.map +1 -1
  26. package/dist/driver-paddle.d.cts +1 -1
  27. package/dist/driver-paddle.d.ts +1 -1
  28. package/dist/driver-paddle.js +3 -2
  29. package/dist/driver-paddle.js.map +1 -1
  30. package/dist/driver-stripe.cjs +277 -224
  31. package/dist/driver-stripe.cjs.map +1 -1
  32. package/dist/driver-stripe.d.cts +18 -2
  33. package/dist/driver-stripe.d.ts +18 -2
  34. package/dist/driver-stripe.js +244 -192
  35. package/dist/driver-stripe.js.map +1 -1
  36. package/dist/index.cjs +750 -150
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +151 -90
  39. package/dist/index.d.ts +151 -90
  40. package/dist/index.js +702 -98
  41. package/dist/index.js.map +1 -1
  42. package/dist/{manifest-Cr2y1op6.d.cts → manifest-CMe8yVkr.d.cts} +131 -88
  43. package/dist/{manifest-Cr2y1op6.d.ts → manifest-CMe8yVkr.d.ts} +131 -88
  44. package/dist/manifest-entry.cjs +62 -47
  45. package/dist/manifest-entry.cjs.map +1 -1
  46. package/dist/manifest-entry.d.cts +15 -15
  47. package/dist/manifest-entry.d.ts +15 -15
  48. package/dist/manifest-entry.js +25 -14
  49. package/dist/manifest-entry.js.map +1 -1
  50. package/dist/protocol.cjs +13 -0
  51. package/dist/protocol.cjs.map +1 -0
  52. package/dist/protocol.d.cts +182 -0
  53. package/dist/protocol.d.ts +182 -0
  54. package/dist/protocol.js +4 -0
  55. package/dist/protocol.js.map +1 -0
  56. package/package.json +14 -2
  57. package/dist/chunk-AKO6XKXP.js.map +0 -1
  58. package/dist/chunk-JSRKA375.cjs.map +0 -1
  59. package/dist/chunk-LJYLGLFS.cjs.map +0 -1
  60. package/dist/chunk-YY375F2B.js.map +0 -1
@@ -1,9 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var chunkJSRKA375_cjs = require('./chunk-JSRKA375.cjs');
4
- var chunkLJYLGLFS_cjs = require('./chunk-LJYLGLFS.cjs');
3
+ var chunkBPOAWI4G_cjs = require('./chunk-BPOAWI4G.cjs');
4
+ var chunkQMAZGLGV_cjs = require('./chunk-QMAZGLGV.cjs');
5
+ require('./chunk-EMMSS5I5.cjs');
5
6
 
6
- // src/manifest/product-refs.ts
7
+ // src/manifest/offering-refs.ts
7
8
  function mask(src) {
8
9
  const out = src.split("");
9
10
  const n = src.length;
@@ -59,7 +60,7 @@ function skipWs(masked, i) {
59
60
  while (i < masked.length && (masked[i] === " " || masked[i] === " " || masked[i] === "\n" || masked[i] === "\r")) i++;
60
61
  return i;
61
62
  }
62
- function scanProductRefs(files) {
63
+ function scanOfferingRefs(files) {
63
64
  const seen = /* @__PURE__ */ new Set();
64
65
  const order = [];
65
66
  let dynamic = false;
@@ -72,8 +73,8 @@ function scanProductRefs(files) {
72
73
  for (const [path, source] of Object.entries(files)) {
73
74
  if (!/\.(tsx|jsx|ts|js)$/.test(path)) continue;
74
75
  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";
76
+ for (const m of masked.matchAll(/\buseOfferings?\s*\(/g)) {
77
+ const plural = source.slice(m.index, m.index + 12) === "useOfferings";
77
78
  const j = skipWs(masked, m.index + m[0].length);
78
79
  if (masked[j] === ")") {
79
80
  if (plural) dynamic = true;
@@ -83,7 +84,7 @@ function scanProductRefs(files) {
83
84
  if (lit !== null) add(lit);
84
85
  else dynamic = true;
85
86
  }
86
- for (const m of masked.matchAll(/<(?:Checkout|Upsell)\b[^>]*?\bproduct\s*=\s*/g)) {
87
+ for (const m of masked.matchAll(/<(?:Checkout|Upsell)\b[^>]*?\boffering\s*=\s*/g)) {
87
88
  const j = m.index + m[0].length;
88
89
  const lit = literalAt(source, masked, j);
89
90
  if (lit !== null) add(lit);
@@ -101,7 +102,7 @@ var DRIVERS = {
101
102
  stripe: { name: "stripeCheckoutDriver", sub: "driver-stripe" },
102
103
  paddle: { name: "paddleCheckoutDriver", sub: "driver-paddle" }
103
104
  };
104
- var HEADER = "// GENERATED by AppFunnel \u2014 do not edit. Built from funnel.ts + the pages/ folder.\n";
105
+ var HEADER = "// GENERATED by Appfunnel \u2014 do not edit. Built from funnel.ts + the pages/ folder.\n";
105
106
  function generateMount(opts) {
106
107
  const p = opts.importPrefix ?? "./";
107
108
  const driver = opts.checkout ? DRIVERS[opts.checkout] : null;
@@ -111,7 +112,9 @@ function generateMount(opts) {
111
112
  driver && `import { ${driver.name} } from '@appfunnel-dev/sdk/${driver.sub}'`,
112
113
  `import { config } from '${p}funnel'`,
113
114
  opts.hasLayout && `import Layout from '${p}layout'`,
114
- ...locales.map((loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`)
115
+ ...locales.map(
116
+ (loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`
117
+ )
115
118
  ].filter(Boolean).join("\n");
116
119
  const loaders = opts.pageKeys.map(
117
120
  (k) => ` ${JSON.stringify(k)}: () => import(${JSON.stringify(`${p}pages/${k}`)}),`
@@ -132,8 +135,10 @@ const loaders: Record<string, () => Promise<unknown>> = {
132
135
  ${loaders}
133
136
  }
134
137
 
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.
138
+ // Flow pages come from funnel.ts (order + meta + routing). A \`@variant\` page MAY also be declared
139
+ // there (with its \`@\` key) to carry its OWN optional routing (\`next\`) \u2014 it still collapses out of
140
+ // the linear flow by the \`@\` marker, but its meta rides along here. Any page file NOT declared is an
141
+ // off-flow \`@variant\` with no own routing, appended with empty meta so it's still loadable.
137
142
  const decls = config.pages ?? []
138
143
  const flowKeys = new Set(decls.map((d) => d.key))
139
144
  export const pages: RuntimePage[] = [
@@ -160,7 +165,13 @@ const data = (dataEl?.textContent ? JSON.parse(dataEl.textContent) : {}) as Moun
160
165
  initialKey?: string | null
161
166
  }
162
167
  const root = document.getElementById('root')
163
- if (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined }))
168
+ // FLASH-FREE HYDRATION (SSR-isolation Option B): always DEFER sessionValues on the client. The
169
+ // markup we hydrate against is DEFAULT-state (build-time prerendered, or an SSR render with empty
170
+ // sessionValues), so seeding the store with defaults for the first render is a byte-clean match \u2014
171
+ // no hydration mismatch. The visitor's saved answers (data.sessionValues, present on the "tail"
172
+ // path) are then applied post-hydration, popping into already-visible controls with no empty
173
+ // flash. On the cold path sessionValues is absent, so deferring is a no-op (identical output).
174
+ if (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined, deferSessionValues: true }))
164
175
  `;
165
176
  }
166
177
  function generateEntryServer(opts) {
@@ -173,7 +184,7 @@ import { tree, pages, type MountOpts } from './mount'
173
184
  export const manifest = compileManifest({
174
185
  funnel: config,
175
186
  pages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),
176
- productRefs: ${JSON.stringify(opts.productRefs ?? [])},
187
+ offeringRefs: ${JSON.stringify(opts.offeringRefs ?? [])},
177
188
  })
178
189
 
179
190
  export async function ssr(opts: MountOpts): Promise<string> {
@@ -197,116 +208,120 @@ if (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))
197
208
 
198
209
  Object.defineProperty(exports, "assignVariant", {
199
210
  enumerable: true,
200
- get: function () { return chunkJSRKA375_cjs.assignVariant; }
211
+ get: function () { return chunkBPOAWI4G_cjs.assignVariant; }
201
212
  });
202
213
  Object.defineProperty(exports, "bucketingSeed", {
203
214
  enumerable: true,
204
- get: function () { return chunkJSRKA375_cjs.bucketingSeed; }
215
+ get: function () { return chunkBPOAWI4G_cjs.bucketingSeed; }
205
216
  });
206
217
  Object.defineProperty(exports, "buildCatalog", {
207
218
  enumerable: true,
208
- get: function () { return chunkJSRKA375_cjs.buildCatalog; }
219
+ get: function () { return chunkBPOAWI4G_cjs.buildCatalog; }
209
220
  });
210
221
  Object.defineProperty(exports, "compileManifest", {
211
222
  enumerable: true,
212
- get: function () { return chunkJSRKA375_cjs.compileManifest; }
223
+ get: function () { return chunkBPOAWI4G_cjs.compileManifest; }
213
224
  });
214
225
  Object.defineProperty(exports, "currencyExponent", {
215
226
  enumerable: true,
216
- get: function () { return chunkJSRKA375_cjs.currencyExponent; }
227
+ get: function () { return chunkBPOAWI4G_cjs.currencyExponent; }
217
228
  });
218
229
  Object.defineProperty(exports, "defineFunnel", {
219
230
  enumerable: true,
220
- get: function () { return chunkJSRKA375_cjs.defineFunnel; }
231
+ get: function () { return chunkBPOAWI4G_cjs.defineFunnel; }
232
+ });
233
+ Object.defineProperty(exports, "entryGuard", {
234
+ enumerable: true,
235
+ get: function () { return chunkBPOAWI4G_cjs.entryGuard; }
236
+ });
237
+ Object.defineProperty(exports, "evaluateCondition", {
238
+ enumerable: true,
239
+ get: function () { return chunkBPOAWI4G_cjs.evaluateCondition; }
221
240
  });
222
241
  Object.defineProperty(exports, "formatMoney", {
223
242
  enumerable: true,
224
- get: function () { return chunkJSRKA375_cjs.formatMoney; }
243
+ get: function () { return chunkBPOAWI4G_cjs.formatMoney; }
225
244
  });
226
- Object.defineProperty(exports, "formatProduct", {
245
+ Object.defineProperty(exports, "formatOffering", {
227
246
  enumerable: true,
228
- get: function () { return chunkJSRKA375_cjs.formatProduct; }
247
+ get: function () { return chunkBPOAWI4G_cjs.formatOffering; }
229
248
  });
230
249
  Object.defineProperty(exports, "funnelCatalogKeys", {
231
250
  enumerable: true,
232
- get: function () { return chunkJSRKA375_cjs.funnelCatalogKeys; }
251
+ get: function () { return chunkBPOAWI4G_cjs.funnelCatalogKeys; }
233
252
  });
234
253
  Object.defineProperty(exports, "isRtl", {
235
254
  enumerable: true,
236
- get: function () { return chunkJSRKA375_cjs.isRtl; }
255
+ get: function () { return chunkBPOAWI4G_cjs.isRtl; }
237
256
  });
238
257
  Object.defineProperty(exports, "isVariantKey", {
239
258
  enumerable: true,
240
- get: function () { return chunkJSRKA375_cjs.isVariantKey; }
259
+ get: function () { return chunkBPOAWI4G_cjs.isVariantKey; }
241
260
  });
242
- Object.defineProperty(exports, "normalizeProducts", {
261
+ Object.defineProperty(exports, "normalizeOfferings", {
243
262
  enumerable: true,
244
- get: function () { return chunkJSRKA375_cjs.normalizeProducts; }
263
+ get: function () { return chunkBPOAWI4G_cjs.normalizeOfferings; }
245
264
  });
246
265
  Object.defineProperty(exports, "pageMeta", {
247
266
  enumerable: true,
248
- get: function () { return chunkJSRKA375_cjs.pageMeta; }
267
+ get: function () { return chunkBPOAWI4G_cjs.pageMeta; }
249
268
  });
250
269
  Object.defineProperty(exports, "parseSlotKey", {
251
270
  enumerable: true,
252
- get: function () { return chunkJSRKA375_cjs.parseSlotKey; }
271
+ get: function () { return chunkBPOAWI4G_cjs.parseSlotKey; }
253
272
  });
254
273
  Object.defineProperty(exports, "resolveLocale", {
255
274
  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; }
275
+ get: function () { return chunkBPOAWI4G_cjs.resolveLocale; }
261
276
  });
262
- Object.defineProperty(exports, "validateExperiments", {
277
+ Object.defineProperty(exports, "resolveOffering", {
263
278
  enumerable: true,
264
- get: function () { return chunkJSRKA375_cjs.validateExperiments; }
279
+ get: function () { return chunkBPOAWI4G_cjs.resolveOffering; }
265
280
  });
266
281
  Object.defineProperty(exports, "weightsOf", {
267
282
  enumerable: true,
268
- get: function () { return chunkJSRKA375_cjs.weightsOf; }
283
+ get: function () { return chunkBPOAWI4G_cjs.weightsOf; }
269
284
  });
270
285
  Object.defineProperty(exports, "INLINE_SURFACES", {
271
286
  enumerable: true,
272
- get: function () { return chunkLJYLGLFS_cjs.INLINE_SURFACES; }
287
+ get: function () { return chunkQMAZGLGV_cjs.INLINE_SURFACES; }
273
288
  });
274
289
  Object.defineProperty(exports, "PROVIDER_PROFILES", {
275
290
  enumerable: true,
276
- get: function () { return chunkLJYLGLFS_cjs.PROVIDER_PROFILES; }
291
+ get: function () { return chunkQMAZGLGV_cjs.PROVIDER_PROFILES; }
277
292
  });
278
293
  Object.defineProperty(exports, "checkoutError", {
279
294
  enumerable: true,
280
- get: function () { return chunkLJYLGLFS_cjs.checkoutError; }
295
+ get: function () { return chunkQMAZGLGV_cjs.checkoutError; }
281
296
  });
282
297
  Object.defineProperty(exports, "isInlineSurface", {
283
298
  enumerable: true,
284
- get: function () { return chunkLJYLGLFS_cjs.isInlineSurface; }
299
+ get: function () { return chunkQMAZGLGV_cjs.isInlineSurface; }
285
300
  });
286
301
  Object.defineProperty(exports, "isMerchantOfRecord", {
287
302
  enumerable: true,
288
- get: function () { return chunkLJYLGLFS_cjs.isMerchantOfRecord; }
303
+ get: function () { return chunkQMAZGLGV_cjs.isMerchantOfRecord; }
289
304
  });
290
305
  Object.defineProperty(exports, "isOrchestrator", {
291
306
  enumerable: true,
292
- get: function () { return chunkLJYLGLFS_cjs.isOrchestrator; }
307
+ get: function () { return chunkQMAZGLGV_cjs.isOrchestrator; }
293
308
  });
294
309
  Object.defineProperty(exports, "surfacesFor", {
295
310
  enumerable: true,
296
- get: function () { return chunkLJYLGLFS_cjs.surfacesFor; }
311
+ get: function () { return chunkQMAZGLGV_cjs.surfacesFor; }
297
312
  });
298
313
  Object.defineProperty(exports, "validateCheckout", {
299
314
  enumerable: true,
300
- get: function () { return chunkLJYLGLFS_cjs.validateCheckout; }
315
+ get: function () { return chunkQMAZGLGV_cjs.validateCheckout; }
301
316
  });
302
317
  Object.defineProperty(exports, "validateUpsell", {
303
318
  enumerable: true,
304
- get: function () { return chunkLJYLGLFS_cjs.validateUpsell; }
319
+ get: function () { return chunkQMAZGLGV_cjs.validateUpsell; }
305
320
  });
306
321
  exports.generateDevEntry = generateDevEntry;
307
322
  exports.generateEntryClient = generateEntryClient;
308
323
  exports.generateEntryServer = generateEntryServer;
309
324
  exports.generateMount = generateMount;
310
- exports.scanProductRefs = scanProductRefs;
325
+ exports.scanOfferingRefs = scanOfferingRefs;
311
326
  //# sourceMappingURL=manifest-entry.cjs.map
312
327
  //# 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')\nif (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined }))\n`\n}\n\n/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */\nexport function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'productRefs'>): string {\n\tconst p = opts.importPrefix ?? './'\n\treturn `${HEADER}import { renderToReadableStream } from 'react-dom/server.browser'\nimport { compileManifest } from '@appfunnel-dev/sdk'\nimport { config } from '${p}funnel'\nimport { tree, pages, type MountOpts } from './mount'\n\nexport const manifest = compileManifest({\n\tfunnel: config,\n\tpages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),\n\tproductRefs: ${JSON.stringify(opts.productRefs ?? [])},\n})\n\nexport async function ssr(opts: MountOpts): Promise<string> {\n\tconst stream = await renderToReadableStream(tree(opts))\n\tawait stream.allReady\n\treturn await new Response(stream).text()\n}\n`\n}\n\n/** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */\nexport function generateDevEntry(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & { data: unknown }\n): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst styles = opts.hasStyles ? `import '${p}styles.css'\\n` : ''\n\treturn `${HEADER}${styles}import { createRoot } from 'react-dom/client'\nimport { tree } from './mount'\n\nconst el = document.getElementById('root')\nif (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))\n`\n}\n"]}
1
+ {"version":3,"sources":["../src/manifest/offering-refs.ts","../src/flow/scaffold.ts"],"names":[],"mappings":"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","file":"manifest-entry.cjs","sourcesContent":["/**\n * Pure, React-free page scan: find which offering SLOTS a funnel's pages reference — the first\n * string-literal arg of `useOffering(...)` and the `offering` prop of `<Checkout>` / `<Upsell>`.\n * Ships via `@appfunnel-dev/sdk/manifest` so the BUILD, the EDITOR, and the AI all run the SAME\n * check. The result feeds `compileManifest({ offeringRefs })`, which flags references to slots the\n * funnel doesn't declare (unknown) or hasn't assigned a catalog charge key to (unassigned).\n *\n * Non-literal args (`useOffering(selectedId)`, `offering={expr}`) and the `useOfferings()` wildcard are\n * DYNAMIC — they can't be statically enumerated, so they're reported via `dynamic` and never turned\n * into a hard error (validation relaxes when a funnel is dynamic). Mirrors the mask-then-read\n * discipline the funnel.ts code-mods use, so a `useOffering('x')` inside a comment or string literal\n * can't false-positive.\n */\n\nexport interface OfferingRefScan {\n /** Concrete slot names referenced by LITERAL args, deduped, in first-seen order. */\n slots: string[]\n /** True if any ref is a non-literal arg or a `useOfferings()` wildcard (not statically enumerable). */\n dynamic: boolean\n}\n\n/** Blank comment + string/template CONTENTS (keep quote delimiters + length) so scans don't fire inside them. */\nfunction mask(src: string): string {\n const out = src.split('')\n const n = src.length\n let i = 0\n while (i < n) {\n const c = src[i]\n const d = src[i + 1]\n if (c === '/' && d === '/') {\n while (i < n && src[i] !== '\\n') { out[i] = ' '; i++ }\n } else if (c === '/' && d === '*') {\n out[i] = ' '; out[i + 1] = ' '; i += 2\n while (i < n) {\n if (src[i] === '*' && src[i + 1] === '/') { out[i] = ' '; out[i + 1] = ' '; i += 2; break }\n if (src[i] !== '\\n') out[i] = ' '\n i++\n }\n } else if (c === \"'\" || c === '\"' || c === '`') {\n i++\n while (i < n && src[i] !== c) {\n if (src[i] === '\\\\') { out[i] = ' '; i++; if (i < n && src[i] !== '\\n') out[i] = ' '; i++; continue }\n if (src[i] !== '\\n') out[i] = ' '\n i++\n }\n i++ // closing delimiter (kept)\n } else i++\n }\n return out.join('')\n}\n\n/** A quoted string literal starting at `open` (a quote char in the MASK). Value read from the ORIGINAL. */\nfunction literalAt(src: string, masked: string, open: number): string | null {\n const q = masked[open]\n if (q !== \"'\" && q !== '\"' && q !== '`') return null\n const close = masked.indexOf(q, open + 1)\n if (close === -1) return null\n return src.slice(open + 1, close)\n}\n\n/** Advance past whitespace in `masked` from `i`. */\nfunction skipWs(masked: string, i: number): number {\n while (i < masked.length && (masked[i] === ' ' || masked[i] === '\\t' || masked[i] === '\\n' || masked[i] === '\\r')) i++\n return i\n}\n\nexport function scanOfferingRefs(files: Record<string, string>): OfferingRefScan {\n const seen = new Set<string>()\n const order: string[] = []\n let dynamic = false\n const add = (v: string) => { if (v && !seen.has(v)) { seen.add(v); order.push(v) } }\n\n for (const [path, source] of Object.entries(files)) {\n if (!/\\.(tsx|jsx|ts|js)$/.test(path)) continue\n const masked = mask(source)\n\n // useOffering( … ) / useOfferings( … ) — positions on the MASK (a call inside a string won't match).\n for (const m of masked.matchAll(/\\buseOfferings?\\s*\\(/g)) {\n const plural = source.slice(m.index!, m.index! + 12) === 'useOfferings'\n const j = skipWs(masked, m.index! + m[0].length)\n if (masked[j] === ')') { if (plural) dynamic = true; continue } // useOfferings() = whole-catalog wildcard\n const lit = literalAt(source, masked, j)\n if (lit !== null) add(lit)\n else dynamic = true // useOffering(variable) — can't resolve statically\n }\n\n // <Checkout offering=\"…\"> / <Upsell offering=\"…\"> — the `offering` attribute value.\n for (const m of masked.matchAll(/<(?:Checkout|Upsell)\\b[^>]*?\\boffering\\s*=\\s*/g)) {\n const j = m.index! + m[0].length\n const lit = literalAt(source, masked, j)\n if (lit !== null) add(lit)\n else if (masked[j] === '{') dynamic = true // offering={expr}\n }\n }\n return { slots: order, dynamic }\n}\n","/**\n * Source generators for the funnel build \"machinery\" authors no longer write. `funnel.ts` (the\n * spine: id, responses, offerings, checkout, and the page list + declarative routing) plus the\n * `pages/` folder are the ONLY authored source. The build (renderer/builder) and the CLI dev server\n * call these to synthesize:\n * - `mount.tsx` — code-split page loaders + `createFunnelTree`\n * - `entry.client.tsx` — hydrate the SSR'd markup from injected data\n * - `entry.server.tsx` — `ssr()` + the compiled `manifest`\n *\n * All string templates, zero runtime deps — this module lives in the pure `@appfunnel-dev/sdk/\n * manifest` entry so tooling imports it without the funnel runtime.\n */\n\nexport interface ScaffoldOptions {\n\t/** Page component keys = `pages/<key>.tsx` filenames (base flow pages AND `@variant` pages). */\n\tpageKeys: string[]\n\t/** Import prefix to reach the funnel root: `'./'` at the root (build), `'../../'` in a subdir (CLI dev). */\n\timportPrefix?: string\n\t/** Whether a `layout.tsx` exists to wrap the pages. */\n\thasLayout?: boolean\n\t/** Whether a `styles.css` exists (client entry imports it). */\n\thasStyles?: boolean\n\t/** Checkout provider from `config.checkout` — wires the driver; omit for none. */\n\tcheckout?: 'stripe' | 'paddle' | null\n\t/** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */\n\tmessageLocales?: string[]\n\t/** Slot names the pages reference (from `scanOfferingRefs`), baked into the manifest for validation. */\n\tofferingRefs?: string[]\n}\n\n/** A safe JS identifier for a message-catalog import (`en` → `msg_en`, `pt-BR` → `msg_pt_BR`). */\nfunction msgId(locale: string): string {\n\treturn 'msg_' + locale.replace(/[^a-zA-Z0-9]/g, '_')\n}\n\nconst DRIVERS = {\n\tstripe: { name: 'stripeCheckoutDriver', sub: 'driver-stripe' },\n\tpaddle: { name: 'paddleCheckoutDriver', sub: 'driver-paddle' },\n} as const\n\nconst HEADER =\n\t'// GENERATED by Appfunnel — do not edit. Built from funnel.ts + the pages/ folder.\\n'\n\n/** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */\nexport function generateMount(opts: ScaffoldOptions): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst driver = opts.checkout ? DRIVERS[opts.checkout] : null\n\n\tconst locales = opts.messageLocales ?? []\n\tconst imports = [\n\t\t`import { createFunnelTree, type MountOpts, type RuntimePage } from '@appfunnel-dev/sdk'`,\n\t\tdriver &&\n\t\t\t`import { ${driver.name} } from '@appfunnel-dev/sdk/${driver.sub}'`,\n\t\t`import { config } from '${p}funnel'`,\n\t\topts.hasLayout && `import Layout from '${p}layout'`,\n\t\t...locales.map(\n\t\t\t(loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`\n\t\t),\n\t]\n\t\t.filter(Boolean)\n\t\t.join('\\n')\n\n\t// A static import() per page file so Vite emits one code-split chunk each.\n\tconst loaders = opts.pageKeys\n\t\t.map(\n\t\t\t(k) =>\n\t\t\t\t`\\t${JSON.stringify(k)}: () => import(${JSON.stringify(`${p}pages/${k}`)}),`\n\t\t)\n\t\t.join('\\n')\n\n\tconst treeArgs = [\n\t\t'config',\n\t\t'pages',\n\t\topts.hasLayout && 'layout: Layout',\n\t\tdriver && `checkoutDriver: ${driver.name}`,\n\t\tlocales.length > 0 && 'messages',\n\t]\n\t\t.filter(Boolean)\n\t\t.join(', ')\n\n\t// The baked message catalog: locale → messages/<locale>.json (so `t()` resolves at render).\n\tconst messagesConst =\n\t\tlocales.length > 0\n\t\t\t? `\\nconst messages = { ${locales.map((loc) => `${JSON.stringify(loc)}: ${msgId(loc)}`).join(', ')} }\\n`\n\t\t\t: ''\n\n\treturn `${HEADER}${imports}\n\nconst loaders: Record<string, () => Promise<unknown>> = {\n${loaders}\n}\n\n// Flow pages come from funnel.ts (order + meta + routing). A \\`@variant\\` page MAY also be declared\n// there (with its \\`@\\` key) to carry its OWN optional routing (\\`next\\`) — it still collapses out of\n// the linear flow by the \\`@\\` marker, but its meta rides along here. Any page file NOT declared is an\n// off-flow \\`@variant\\` with no own routing, appended with empty meta so it's still loadable.\nconst decls = config.pages ?? []\nconst flowKeys = new Set(decls.map((d) => d.key))\nexport const pages: RuntimePage[] = [\n\t...decls.map((d) => ({ key: d.key, meta: d, load: loaders[d.key] })),\n\t...Object.keys(loaders)\n\t\t.filter((k) => !flowKeys.has(k))\n\t\t.map((k) => ({ key: k, meta: {}, load: loaders[k] })),\n] as RuntimePage[]\n${messagesConst}\nexport const tree = createFunnelTree({ ${treeArgs} })\n\nexport type { MountOpts }\n`\n}\n\n/** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */\nexport function generateEntryClient(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>\n): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst styles = opts.hasStyles ? `import '${p}styles.css'\\n` : ''\n\treturn `${HEADER}${styles}import { hydrateRoot } from 'react-dom/client'\nimport { tree, type MountOpts } from './mount'\n\nconst dataEl = document.getElementById('__af_data')\nconst data = (dataEl?.textContent ? JSON.parse(dataEl.textContent) : {}) as MountOpts & {\n\tinitialKey?: string | null\n}\nconst root = document.getElementById('root')\n// FLASH-FREE HYDRATION (SSR-isolation Option B): always DEFER sessionValues on the client. The\n// markup we hydrate against is DEFAULT-state (build-time prerendered, or an SSR render with empty\n// sessionValues), so seeding the store with defaults for the first render is a byte-clean match —\n// no hydration mismatch. The visitor's saved answers (data.sessionValues, present on the \"tail\"\n// path) are then applied post-hydration, popping into already-visible controls with no empty\n// flash. On the cold path sessionValues is absent, so deferring is a no-op (identical output).\nif (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined, deferSessionValues: true }))\n`\n}\n\n/** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */\nexport function generateEntryServer(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs'>\n): string {\n\tconst p = opts.importPrefix ?? './'\n\treturn `${HEADER}import { renderToReadableStream } from 'react-dom/server.browser'\nimport { compileManifest } from '@appfunnel-dev/sdk'\nimport { config } from '${p}funnel'\nimport { tree, pages, type MountOpts } from './mount'\n\nexport const manifest = compileManifest({\n\tfunnel: config,\n\tpages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),\n\tofferingRefs: ${JSON.stringify(opts.offeringRefs ?? [])},\n})\n\nexport async function ssr(opts: MountOpts): Promise<string> {\n\tconst stream = await renderToReadableStream(tree(opts))\n\tawait stream.allReady\n\treturn await new Response(stream).text()\n}\n`\n}\n\n/** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */\nexport function generateDevEntry(\n\topts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {\n\t\tdata: unknown\n\t}\n): string {\n\tconst p = opts.importPrefix ?? './'\n\tconst styles = opts.hasStyles ? `import '${p}styles.css'\\n` : ''\n\treturn `${HEADER}${styles}import { createRoot } from 'react-dom/client'\nimport { tree } from './mount'\n\nconst el = document.getElementById('root')\nif (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))\n`\n}\n"]}
@@ -1,32 +1,32 @@
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';
1
+ 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, af 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, ag 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, ah as funnelCatalogKeys, a4 as isRtl, a5 as isVariantKey, ai as normalizeOfferings, a8 as pageMeta, a9 as parseSlotKey, ac as resolveLocale, ad as resolveOffering, aj as weightsOf } from './manifest-CMe8yVkr.cjs';
2
2
  import { C as CheckoutError, b as CheckoutIntent, U as UpsellKind, d as CheckoutSurface } from './capabilities-7_hy5f5G.cjs';
3
3
  export { a as CheckoutErrorCategory, c as CheckoutProvider, I as INLINE_SURFACES, O as OffSessionReliability, P as PROVIDER_PROFILES, e as ProviderProfile, S as SurfaceCapability, V as ValidationResult, f as checkoutError, i as isInlineSurface, g as isMerchantOfRecord, h as isOrchestrator, s as surfacesFor, v as validateCheckout, j as validateUpsell } from './capabilities-7_hy5f5G.cjs';
4
4
  import 'react';
5
5
 
6
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>`.
7
+ * Pure, React-free page scan: find which offering SLOTS a funnel's pages reference — the first
8
+ * string-literal arg of `useOffering(...)` and the `offering` prop of `<Checkout>` / `<Upsell>`.
9
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).
10
+ * check. The result feeds `compileManifest({ offeringRefs })`, which flags references to slots the
11
+ * funnel doesn't declare (unknown) or hasn't assigned a catalog charge key to (unassigned).
12
12
  *
13
- * Non-literal args (`useProduct(selectedId)`, `product={expr}`) and the `useProducts()` wildcard are
13
+ * Non-literal args (`useOffering(selectedId)`, `offering={expr}`) and the `useOfferings()` wildcard are
14
14
  * DYNAMIC — they can't be statically enumerated, so they're reported via `dynamic` and never turned
15
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
16
+ * discipline the funnel.ts code-mods use, so a `useOffering('x')` inside a comment or string literal
17
17
  * can't false-positive.
18
18
  */
19
- interface ProductRefScan {
19
+ interface OfferingRefScan {
20
20
  /** Concrete slot names referenced by LITERAL args, deduped, in first-seen order. */
21
21
  slots: string[];
22
- /** True if any ref is a non-literal arg or a `useProducts()` wildcard (not statically enumerable). */
22
+ /** True if any ref is a non-literal arg or a `useOfferings()` wildcard (not statically enumerable). */
23
23
  dynamic: boolean;
24
24
  }
25
- declare function scanProductRefs(files: Record<string, string>): ProductRefScan;
25
+ declare function scanOfferingRefs(files: Record<string, string>): OfferingRefScan;
26
26
 
27
27
  /**
28
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
29
+ * spine: id, responses, offerings, checkout, and the page list + declarative routing) plus the
30
30
  * `pages/` folder are the ONLY authored source. The build (renderer/builder) and the CLI dev server
31
31
  * call these to synthesize:
32
32
  * - `mount.tsx` — code-split page loaders + `createFunnelTree`
@@ -49,15 +49,15 @@ interface ScaffoldOptions {
49
49
  checkout?: 'stripe' | 'paddle' | null;
50
50
  /** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */
51
51
  messageLocales?: string[];
52
- /** Slot names the pages reference (from `scanProductRefs`), baked into the manifest for validation. */
53
- productRefs?: string[];
52
+ /** Slot names the pages reference (from `scanOfferingRefs`), baked into the manifest for validation. */
53
+ offeringRefs?: string[];
54
54
  }
55
55
  /** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */
56
56
  declare function generateMount(opts: ScaffoldOptions): string;
57
57
  /** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */
58
58
  declare function generateEntryClient(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): string;
59
59
  /** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */
60
- declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'productRefs'>): string;
60
+ declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs'>): string;
61
61
  /** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */
62
62
  declare function generateDevEntry(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {
63
63
  data: unknown;
@@ -206,4 +206,4 @@ interface CheckoutCompleteRequest {
206
206
  }
207
207
  type CheckoutCompleteResponse = StepSettled | StepPending | StepFailed;
208
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 };
209
+ export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, type OfferingRefScan, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount, scanOfferingRefs };
@@ -1,32 +1,32 @@
1
- export { i as CompileInput, j as Condition, k as ConditionOp, E as EdgeCondition, m as ExperimentIssue, o as ExperimentValidation, p as ExperimentVariant, q as FlowPage, c as FunnelDefinition, r as FunnelLocales, s as FunnelManifest, ai as FunnelPage, b as FunnelSnapshot, G as Gate, t as Interval, M as ManifestEdge, u as ManifestPage, v as ManifestValidation, w as Money, f as PageMeta, x as PageType, y as Predicate, P as Product, e as ProductInput, aj as ProductSlot, z as ResolvedProduct, H as Route, R as RuntimeExperiment, K as assignVariant, N as bucketingSeed, T as buildCatalog, W as compileManifest, X as currencyExponent, Y as defineFunnel, a3 as formatMoney, a4 as formatProduct, ak as funnelCatalogKeys, a6 as isRtl, a7 as isVariantKey, al as normalizeProducts, aa as pageMeta, ab as parseSlotKey, ae as resolveLocale, af as resolveProduct, ah as validateExperiments, am as weightsOf } from './manifest-Cr2y1op6.js';
1
+ 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, af 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, ag 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, ah as funnelCatalogKeys, a4 as isRtl, a5 as isVariantKey, ai as normalizeOfferings, a8 as pageMeta, a9 as parseSlotKey, ac as resolveLocale, ad as resolveOffering, aj as weightsOf } from './manifest-CMe8yVkr.js';
2
2
  import { C as CheckoutError, b as CheckoutIntent, U as UpsellKind, d as CheckoutSurface } from './capabilities-7_hy5f5G.js';
3
3
  export { a as CheckoutErrorCategory, c as CheckoutProvider, I as INLINE_SURFACES, O as OffSessionReliability, P as PROVIDER_PROFILES, e as ProviderProfile, S as SurfaceCapability, V as ValidationResult, f as checkoutError, i as isInlineSurface, g as isMerchantOfRecord, h as isOrchestrator, s as surfacesFor, v as validateCheckout, j as validateUpsell } from './capabilities-7_hy5f5G.js';
4
4
  import 'react';
5
5
 
6
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>`.
7
+ * Pure, React-free page scan: find which offering SLOTS a funnel's pages reference — the first
8
+ * string-literal arg of `useOffering(...)` and the `offering` prop of `<Checkout>` / `<Upsell>`.
9
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).
10
+ * check. The result feeds `compileManifest({ offeringRefs })`, which flags references to slots the
11
+ * funnel doesn't declare (unknown) or hasn't assigned a catalog charge key to (unassigned).
12
12
  *
13
- * Non-literal args (`useProduct(selectedId)`, `product={expr}`) and the `useProducts()` wildcard are
13
+ * Non-literal args (`useOffering(selectedId)`, `offering={expr}`) and the `useOfferings()` wildcard are
14
14
  * DYNAMIC — they can't be statically enumerated, so they're reported via `dynamic` and never turned
15
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
16
+ * discipline the funnel.ts code-mods use, so a `useOffering('x')` inside a comment or string literal
17
17
  * can't false-positive.
18
18
  */
19
- interface ProductRefScan {
19
+ interface OfferingRefScan {
20
20
  /** Concrete slot names referenced by LITERAL args, deduped, in first-seen order. */
21
21
  slots: string[];
22
- /** True if any ref is a non-literal arg or a `useProducts()` wildcard (not statically enumerable). */
22
+ /** True if any ref is a non-literal arg or a `useOfferings()` wildcard (not statically enumerable). */
23
23
  dynamic: boolean;
24
24
  }
25
- declare function scanProductRefs(files: Record<string, string>): ProductRefScan;
25
+ declare function scanOfferingRefs(files: Record<string, string>): OfferingRefScan;
26
26
 
27
27
  /**
28
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
29
+ * spine: id, responses, offerings, checkout, and the page list + declarative routing) plus the
30
30
  * `pages/` folder are the ONLY authored source. The build (renderer/builder) and the CLI dev server
31
31
  * call these to synthesize:
32
32
  * - `mount.tsx` — code-split page loaders + `createFunnelTree`
@@ -49,15 +49,15 @@ interface ScaffoldOptions {
49
49
  checkout?: 'stripe' | 'paddle' | null;
50
50
  /** Locales with a `messages/<locale>.json` catalog to bake into the mount (so `t()` resolves at render). */
51
51
  messageLocales?: string[];
52
- /** Slot names the pages reference (from `scanProductRefs`), baked into the manifest for validation. */
53
- productRefs?: string[];
52
+ /** Slot names the pages reference (from `scanOfferingRefs`), baked into the manifest for validation. */
53
+ offeringRefs?: string[];
54
54
  }
55
55
  /** `mount.tsx` — the code-split loaders + tree, derived from `config.pages` and the `pages/` files. */
56
56
  declare function generateMount(opts: ScaffoldOptions): string;
57
57
  /** `entry.client.tsx` — hydrate the SSR'd markup from the injected `#__af_data`. */
58
58
  declare function generateEntryClient(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'>): string;
59
59
  /** `entry.server.tsx` — `ssr(opts)` HTML + the compiled `manifest` (read by the build). */
60
- declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'productRefs'>): string;
60
+ declare function generateEntryServer(opts: Pick<ScaffoldOptions, 'importPrefix' | 'offeringRefs'>): string;
61
61
  /** Client-only dev entry (createRoot, no SSR) — for the CLI `dev` server. */
62
62
  declare function generateDevEntry(opts: Pick<ScaffoldOptions, 'importPrefix' | 'hasStyles'> & {
63
63
  data: unknown;
@@ -206,4 +206,4 @@ interface CheckoutCompleteRequest {
206
206
  }
207
207
  type CheckoutCompleteResponse = StepSettled | StepPending | StepFailed;
208
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 };
209
+ export { type CheckoutCompleteRequest, type CheckoutCompleteResponse, CheckoutError, CheckoutIntent, type CheckoutSessionRequest, type CheckoutSessionResponse, type CheckoutSettlement, CheckoutSurface, type OfferingRefScan, type ScaffoldOptions, type StepClientConfirm, type StepEmbedded, type StepFailed, type StepPending, type StepProviderCheckout, type StepRedirect, type StepSettled, UpsellKind, generateDevEntry, generateEntryClient, generateEntryServer, generateMount, scanOfferingRefs };
@@ -1,7 +1,8 @@
1
- export { assignVariant, bucketingSeed, buildCatalog, compileManifest, currencyExponent, defineFunnel, formatMoney, formatProduct, funnelCatalogKeys, isRtl, isVariantKey, normalizeProducts, pageMeta, parseSlotKey, resolveLocale, resolveProduct, validateExperiments, weightsOf } from './chunk-AKO6XKXP.js';
2
- export { INLINE_SURFACES, PROVIDER_PROFILES, checkoutError, isInlineSurface, isMerchantOfRecord, isOrchestrator, surfacesFor, validateCheckout, validateUpsell } from './chunk-YY375F2B.js';
1
+ export { assignVariant, bucketingSeed, buildCatalog, compileManifest, currencyExponent, defineFunnel, entryGuard, evaluateCondition, formatMoney, formatOffering, funnelCatalogKeys, isRtl, isVariantKey, normalizeOfferings, pageMeta, parseSlotKey, resolveLocale, resolveOffering, weightsOf } from './chunk-7YQLPPPG.js';
2
+ export { INLINE_SURFACES, PROVIDER_PROFILES, checkoutError, isInlineSurface, isMerchantOfRecord, isOrchestrator, surfacesFor, validateCheckout, validateUpsell } from './chunk-TNLRQPVY.js';
3
+ import './chunk-G3PMV62Z.js';
3
4
 
4
- // src/manifest/product-refs.ts
5
+ // src/manifest/offering-refs.ts
5
6
  function mask(src) {
6
7
  const out = src.split("");
7
8
  const n = src.length;
@@ -57,7 +58,7 @@ function skipWs(masked, i) {
57
58
  while (i < masked.length && (masked[i] === " " || masked[i] === " " || masked[i] === "\n" || masked[i] === "\r")) i++;
58
59
  return i;
59
60
  }
60
- function scanProductRefs(files) {
61
+ function scanOfferingRefs(files) {
61
62
  const seen = /* @__PURE__ */ new Set();
62
63
  const order = [];
63
64
  let dynamic = false;
@@ -70,8 +71,8 @@ function scanProductRefs(files) {
70
71
  for (const [path, source] of Object.entries(files)) {
71
72
  if (!/\.(tsx|jsx|ts|js)$/.test(path)) continue;
72
73
  const masked = mask(source);
73
- for (const m of masked.matchAll(/\buseProducts?\s*\(/g)) {
74
- const plural = source.slice(m.index, m.index + 11) === "useProducts";
74
+ for (const m of masked.matchAll(/\buseOfferings?\s*\(/g)) {
75
+ const plural = source.slice(m.index, m.index + 12) === "useOfferings";
75
76
  const j = skipWs(masked, m.index + m[0].length);
76
77
  if (masked[j] === ")") {
77
78
  if (plural) dynamic = true;
@@ -81,7 +82,7 @@ function scanProductRefs(files) {
81
82
  if (lit !== null) add(lit);
82
83
  else dynamic = true;
83
84
  }
84
- for (const m of masked.matchAll(/<(?:Checkout|Upsell)\b[^>]*?\bproduct\s*=\s*/g)) {
85
+ for (const m of masked.matchAll(/<(?:Checkout|Upsell)\b[^>]*?\boffering\s*=\s*/g)) {
85
86
  const j = m.index + m[0].length;
86
87
  const lit = literalAt(source, masked, j);
87
88
  if (lit !== null) add(lit);
@@ -99,7 +100,7 @@ var DRIVERS = {
99
100
  stripe: { name: "stripeCheckoutDriver", sub: "driver-stripe" },
100
101
  paddle: { name: "paddleCheckoutDriver", sub: "driver-paddle" }
101
102
  };
102
- var HEADER = "// GENERATED by AppFunnel \u2014 do not edit. Built from funnel.ts + the pages/ folder.\n";
103
+ var HEADER = "// GENERATED by Appfunnel \u2014 do not edit. Built from funnel.ts + the pages/ folder.\n";
103
104
  function generateMount(opts) {
104
105
  const p = opts.importPrefix ?? "./";
105
106
  const driver = opts.checkout ? DRIVERS[opts.checkout] : null;
@@ -109,7 +110,9 @@ function generateMount(opts) {
109
110
  driver && `import { ${driver.name} } from '@appfunnel-dev/sdk/${driver.sub}'`,
110
111
  `import { config } from '${p}funnel'`,
111
112
  opts.hasLayout && `import Layout from '${p}layout'`,
112
- ...locales.map((loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`)
113
+ ...locales.map(
114
+ (loc) => `import ${msgId(loc)} from '${p}messages/${loc}.json'`
115
+ )
113
116
  ].filter(Boolean).join("\n");
114
117
  const loaders = opts.pageKeys.map(
115
118
  (k) => ` ${JSON.stringify(k)}: () => import(${JSON.stringify(`${p}pages/${k}`)}),`
@@ -130,8 +133,10 @@ const loaders: Record<string, () => Promise<unknown>> = {
130
133
  ${loaders}
131
134
  }
132
135
 
133
- // Flow pages come from funnel.ts (order + meta + routing). Any remaining page file is an off-flow
134
- // \`@variant\` page (wired by experiment records at render time), appended so it's loadable.
136
+ // Flow pages come from funnel.ts (order + meta + routing). A \`@variant\` page MAY also be declared
137
+ // there (with its \`@\` key) to carry its OWN optional routing (\`next\`) \u2014 it still collapses out of
138
+ // the linear flow by the \`@\` marker, but its meta rides along here. Any page file NOT declared is an
139
+ // off-flow \`@variant\` with no own routing, appended with empty meta so it's still loadable.
135
140
  const decls = config.pages ?? []
136
141
  const flowKeys = new Set(decls.map((d) => d.key))
137
142
  export const pages: RuntimePage[] = [
@@ -158,7 +163,13 @@ const data = (dataEl?.textContent ? JSON.parse(dataEl.textContent) : {}) as Moun
158
163
  initialKey?: string | null
159
164
  }
160
165
  const root = document.getElementById('root')
161
- if (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined }))
166
+ // FLASH-FREE HYDRATION (SSR-isolation Option B): always DEFER sessionValues on the client. The
167
+ // markup we hydrate against is DEFAULT-state (build-time prerendered, or an SSR render with empty
168
+ // sessionValues), so seeding the store with defaults for the first render is a byte-clean match \u2014
169
+ // no hydration mismatch. The visitor's saved answers (data.sessionValues, present on the "tail"
170
+ // path) are then applied post-hydration, popping into already-visible controls with no empty
171
+ // flash. On the cold path sessionValues is absent, so deferring is a no-op (identical output).
172
+ if (root) hydrateRoot(root, tree({ ...data, initialKey: data.initialKey ?? undefined, deferSessionValues: true }))
162
173
  `;
163
174
  }
164
175
  function generateEntryServer(opts) {
@@ -171,7 +182,7 @@ import { tree, pages, type MountOpts } from './mount'
171
182
  export const manifest = compileManifest({
172
183
  funnel: config,
173
184
  pages: pages.map((pg) => ({ key: pg.key, meta: pg.meta })),
174
- productRefs: ${JSON.stringify(opts.productRefs ?? [])},
185
+ offeringRefs: ${JSON.stringify(opts.offeringRefs ?? [])},
175
186
  })
176
187
 
177
188
  export async function ssr(opts: MountOpts): Promise<string> {
@@ -193,6 +204,6 @@ if (el) createRoot(el).render(tree(${JSON.stringify(opts.data)}))
193
204
  `;
194
205
  }
195
206
 
196
- export { generateDevEntry, generateEntryClient, generateEntryServer, generateMount, scanProductRefs };
207
+ export { generateDevEntry, generateEntryClient, generateEntryServer, generateMount, scanOfferingRefs };
197
208
  //# sourceMappingURL=manifest-entry.js.map
198
209
  //# sourceMappingURL=manifest-entry.js.map