@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.
- package/README.md +1 -1
- package/dist/{checkout-Dz8cGkB_.d.cts → checkout-CMEdxpgo.d.cts} +13 -13
- package/dist/{checkout-7Dy6IedP.d.ts → checkout-D1NUPv4p.d.ts} +13 -13
- package/dist/{chunk-AKO6XKXP.js → chunk-7YQLPPPG.js} +66 -91
- package/dist/chunk-7YQLPPPG.js.map +1 -0
- package/dist/{chunk-JSRKA375.cjs → chunk-BPOAWI4G.cjs} +68 -94
- package/dist/chunk-BPOAWI4G.cjs.map +1 -0
- package/dist/{chunk-M6U3FNRW.js → chunk-CFFMZYPE.js} +3 -3
- package/dist/{chunk-M6U3FNRW.js.map → chunk-CFFMZYPE.js.map} +1 -1
- package/dist/chunk-EMMSS5I5.cjs +37 -0
- package/dist/chunk-EMMSS5I5.cjs.map +1 -0
- package/dist/chunk-G3PMV62Z.js +33 -0
- package/dist/chunk-G3PMV62Z.js.map +1 -0
- package/dist/{chunk-LJYLGLFS.cjs → chunk-QMAZGLGV.cjs} +2 -35
- package/dist/chunk-QMAZGLGV.cjs.map +1 -0
- package/dist/{chunk-YY375F2B.js → chunk-TNLRQPVY.js} +3 -33
- package/dist/chunk-TNLRQPVY.js.map +1 -0
- package/dist/{chunk-CY4VBSMX.cjs → chunk-VAOR77NW.cjs} +7 -7
- package/dist/{chunk-CY4VBSMX.cjs.map → chunk-VAOR77NW.cjs.map} +1 -1
- package/dist/chunk-WYUDL4FI.cjs +8 -0
- package/dist/chunk-WYUDL4FI.cjs.map +1 -0
- package/dist/chunk-ZZJG4EYL.js +6 -0
- package/dist/chunk-ZZJG4EYL.js.map +1 -0
- package/dist/driver-paddle.cjs +23 -22
- package/dist/driver-paddle.cjs.map +1 -1
- package/dist/driver-paddle.d.cts +1 -1
- package/dist/driver-paddle.d.ts +1 -1
- package/dist/driver-paddle.js +3 -2
- package/dist/driver-paddle.js.map +1 -1
- package/dist/driver-stripe.cjs +277 -224
- package/dist/driver-stripe.cjs.map +1 -1
- package/dist/driver-stripe.d.cts +18 -2
- package/dist/driver-stripe.d.ts +18 -2
- package/dist/driver-stripe.js +244 -192
- package/dist/driver-stripe.js.map +1 -1
- package/dist/index.cjs +750 -150
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +151 -90
- package/dist/index.d.ts +151 -90
- package/dist/index.js +702 -98
- package/dist/index.js.map +1 -1
- package/dist/{manifest-Cr2y1op6.d.cts → manifest-CMe8yVkr.d.cts} +131 -88
- package/dist/{manifest-Cr2y1op6.d.ts → manifest-CMe8yVkr.d.ts} +131 -88
- package/dist/manifest-entry.cjs +62 -47
- package/dist/manifest-entry.cjs.map +1 -1
- package/dist/manifest-entry.d.cts +15 -15
- package/dist/manifest-entry.d.ts +15 -15
- package/dist/manifest-entry.js +25 -14
- package/dist/manifest-entry.js.map +1 -1
- package/dist/protocol.cjs +13 -0
- package/dist/protocol.cjs.map +1 -0
- package/dist/protocol.d.cts +182 -0
- package/dist/protocol.d.ts +182 -0
- package/dist/protocol.js +4 -0
- package/dist/protocol.js.map +1 -0
- package/package.json +14 -2
- package/dist/chunk-AKO6XKXP.js.map +0 -1
- package/dist/chunk-JSRKA375.cjs.map +0 -1
- package/dist/chunk-LJYLGLFS.cjs.map +0 -1
- package/dist/chunk-YY375F2B.js.map +0 -1
package/dist/manifest-entry.cjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
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/
|
|
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
|
|
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(/\
|
|
76
|
-
const plural = source.slice(m.index, m.index +
|
|
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[^>]*?\
|
|
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
|
|
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(
|
|
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).
|
|
136
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
211
|
+
get: function () { return chunkBPOAWI4G_cjs.assignVariant; }
|
|
201
212
|
});
|
|
202
213
|
Object.defineProperty(exports, "bucketingSeed", {
|
|
203
214
|
enumerable: true,
|
|
204
|
-
get: function () { return
|
|
215
|
+
get: function () { return chunkBPOAWI4G_cjs.bucketingSeed; }
|
|
205
216
|
});
|
|
206
217
|
Object.defineProperty(exports, "buildCatalog", {
|
|
207
218
|
enumerable: true,
|
|
208
|
-
get: function () { return
|
|
219
|
+
get: function () { return chunkBPOAWI4G_cjs.buildCatalog; }
|
|
209
220
|
});
|
|
210
221
|
Object.defineProperty(exports, "compileManifest", {
|
|
211
222
|
enumerable: true,
|
|
212
|
-
get: function () { return
|
|
223
|
+
get: function () { return chunkBPOAWI4G_cjs.compileManifest; }
|
|
213
224
|
});
|
|
214
225
|
Object.defineProperty(exports, "currencyExponent", {
|
|
215
226
|
enumerable: true,
|
|
216
|
-
get: function () { return
|
|
227
|
+
get: function () { return chunkBPOAWI4G_cjs.currencyExponent; }
|
|
217
228
|
});
|
|
218
229
|
Object.defineProperty(exports, "defineFunnel", {
|
|
219
230
|
enumerable: true,
|
|
220
|
-
get: function () { return
|
|
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
|
|
243
|
+
get: function () { return chunkBPOAWI4G_cjs.formatMoney; }
|
|
225
244
|
});
|
|
226
|
-
Object.defineProperty(exports, "
|
|
245
|
+
Object.defineProperty(exports, "formatOffering", {
|
|
227
246
|
enumerable: true,
|
|
228
|
-
get: function () { return
|
|
247
|
+
get: function () { return chunkBPOAWI4G_cjs.formatOffering; }
|
|
229
248
|
});
|
|
230
249
|
Object.defineProperty(exports, "funnelCatalogKeys", {
|
|
231
250
|
enumerable: true,
|
|
232
|
-
get: function () { return
|
|
251
|
+
get: function () { return chunkBPOAWI4G_cjs.funnelCatalogKeys; }
|
|
233
252
|
});
|
|
234
253
|
Object.defineProperty(exports, "isRtl", {
|
|
235
254
|
enumerable: true,
|
|
236
|
-
get: function () { return
|
|
255
|
+
get: function () { return chunkBPOAWI4G_cjs.isRtl; }
|
|
237
256
|
});
|
|
238
257
|
Object.defineProperty(exports, "isVariantKey", {
|
|
239
258
|
enumerable: true,
|
|
240
|
-
get: function () { return
|
|
259
|
+
get: function () { return chunkBPOAWI4G_cjs.isVariantKey; }
|
|
241
260
|
});
|
|
242
|
-
Object.defineProperty(exports, "
|
|
261
|
+
Object.defineProperty(exports, "normalizeOfferings", {
|
|
243
262
|
enumerable: true,
|
|
244
|
-
get: function () { return
|
|
263
|
+
get: function () { return chunkBPOAWI4G_cjs.normalizeOfferings; }
|
|
245
264
|
});
|
|
246
265
|
Object.defineProperty(exports, "pageMeta", {
|
|
247
266
|
enumerable: true,
|
|
248
|
-
get: function () { return
|
|
267
|
+
get: function () { return chunkBPOAWI4G_cjs.pageMeta; }
|
|
249
268
|
});
|
|
250
269
|
Object.defineProperty(exports, "parseSlotKey", {
|
|
251
270
|
enumerable: true,
|
|
252
|
-
get: function () { return
|
|
271
|
+
get: function () { return chunkBPOAWI4G_cjs.parseSlotKey; }
|
|
253
272
|
});
|
|
254
273
|
Object.defineProperty(exports, "resolveLocale", {
|
|
255
274
|
enumerable: true,
|
|
256
|
-
get: function () { return
|
|
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, "
|
|
277
|
+
Object.defineProperty(exports, "resolveOffering", {
|
|
263
278
|
enumerable: true,
|
|
264
|
-
get: function () { return
|
|
279
|
+
get: function () { return chunkBPOAWI4G_cjs.resolveOffering; }
|
|
265
280
|
});
|
|
266
281
|
Object.defineProperty(exports, "weightsOf", {
|
|
267
282
|
enumerable: true,
|
|
268
|
-
get: function () { return
|
|
283
|
+
get: function () { return chunkBPOAWI4G_cjs.weightsOf; }
|
|
269
284
|
});
|
|
270
285
|
Object.defineProperty(exports, "INLINE_SURFACES", {
|
|
271
286
|
enumerable: true,
|
|
272
|
-
get: function () { return
|
|
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
|
|
291
|
+
get: function () { return chunkQMAZGLGV_cjs.PROVIDER_PROFILES; }
|
|
277
292
|
});
|
|
278
293
|
Object.defineProperty(exports, "checkoutError", {
|
|
279
294
|
enumerable: true,
|
|
280
|
-
get: function () { return
|
|
295
|
+
get: function () { return chunkQMAZGLGV_cjs.checkoutError; }
|
|
281
296
|
});
|
|
282
297
|
Object.defineProperty(exports, "isInlineSurface", {
|
|
283
298
|
enumerable: true,
|
|
284
|
-
get: function () { return
|
|
299
|
+
get: function () { return chunkQMAZGLGV_cjs.isInlineSurface; }
|
|
285
300
|
});
|
|
286
301
|
Object.defineProperty(exports, "isMerchantOfRecord", {
|
|
287
302
|
enumerable: true,
|
|
288
|
-
get: function () { return
|
|
303
|
+
get: function () { return chunkQMAZGLGV_cjs.isMerchantOfRecord; }
|
|
289
304
|
});
|
|
290
305
|
Object.defineProperty(exports, "isOrchestrator", {
|
|
291
306
|
enumerable: true,
|
|
292
|
-
get: function () { return
|
|
307
|
+
get: function () { return chunkQMAZGLGV_cjs.isOrchestrator; }
|
|
293
308
|
});
|
|
294
309
|
Object.defineProperty(exports, "surfacesFor", {
|
|
295
310
|
enumerable: true,
|
|
296
|
-
get: function () { return
|
|
311
|
+
get: function () { return chunkQMAZGLGV_cjs.surfacesFor; }
|
|
297
312
|
});
|
|
298
313
|
Object.defineProperty(exports, "validateCheckout", {
|
|
299
314
|
enumerable: true,
|
|
300
|
-
get: function () { return
|
|
315
|
+
get: function () { return chunkQMAZGLGV_cjs.validateCheckout; }
|
|
301
316
|
});
|
|
302
317
|
Object.defineProperty(exports, "validateUpsell", {
|
|
303
318
|
enumerable: true,
|
|
304
|
-
get: function () { return
|
|
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.
|
|
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 {
|
|
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
|
|
8
|
-
* string-literal arg of `
|
|
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({
|
|
11
|
-
* funnel doesn't declare (unknown) or hasn't assigned a catalog
|
|
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 (`
|
|
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 `
|
|
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
|
|
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 `
|
|
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
|
|
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,
|
|
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 `
|
|
53
|
-
|
|
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' | '
|
|
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
|
|
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 };
|
package/dist/manifest-entry.d.ts
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
export {
|
|
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
|
|
8
|
-
* string-literal arg of `
|
|
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({
|
|
11
|
-
* funnel doesn't declare (unknown) or hasn't assigned a catalog
|
|
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 (`
|
|
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 `
|
|
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
|
|
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 `
|
|
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
|
|
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,
|
|
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 `
|
|
53
|
-
|
|
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' | '
|
|
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
|
|
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 };
|
package/dist/manifest-entry.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export { assignVariant, bucketingSeed, buildCatalog, compileManifest, currencyExponent, defineFunnel, formatMoney,
|
|
2
|
-
export { INLINE_SURFACES, PROVIDER_PROFILES, checkoutError, isInlineSurface, isMerchantOfRecord, isOrchestrator, surfacesFor, validateCheckout, validateUpsell } from './chunk-
|
|
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/
|
|
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
|
|
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(/\
|
|
74
|
-
const plural = source.slice(m.index, m.index +
|
|
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[^>]*?\
|
|
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
|
|
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(
|
|
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).
|
|
134
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
207
|
+
export { generateDevEntry, generateEntryClient, generateEntryServer, generateMount, scanOfferingRefs };
|
|
197
208
|
//# sourceMappingURL=manifest-entry.js.map
|
|
198
209
|
//# sourceMappingURL=manifest-entry.js.map
|