@funnelsgrove/runtime 0.1.56 → 0.1.59

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 (54) hide show
  1. package/dist/components/FunnelContext.d.ts +5 -1
  2. package/dist/components/FunnelContext.js +2 -1
  3. package/dist/components/ManageSubscriptionScreen.js +4 -1
  4. package/dist/components/SubscriptionHandoffScreen.d.ts +2 -1
  5. package/dist/components/SubscriptionHandoffScreen.js +11 -6
  6. package/dist/config/funnel.manifest.types.d.ts +4 -2
  7. package/dist/generated/step-contract-hash.d.ts +1 -0
  8. package/dist/generated/step-contract-hash.js +2 -0
  9. package/dist/index.d.ts +12 -0
  10. package/dist/index.js +10 -0
  11. package/dist/migrations/step-contract-v2.d.ts +50 -0
  12. package/dist/migrations/step-contract-v2.js +310 -0
  13. package/dist/migrations/step-contract-v3.d.ts +41 -0
  14. package/dist/migrations/step-contract-v3.js +26 -0
  15. package/dist/runtime/funnel-manifest.validation.d.ts +7 -2
  16. package/dist/runtime/funnel-manifest.validation.js +24 -68
  17. package/dist/runtime/funnel-step-lifecycle.d.ts +35 -0
  18. package/dist/runtime/funnel-step-lifecycle.js +49 -0
  19. package/dist/runtime/funnel-step-metadata.validation.d.ts +7 -0
  20. package/dist/runtime/funnel-step-metadata.validation.js +88 -0
  21. package/dist/runtime/submit-email-capture.d.ts +23 -0
  22. package/dist/runtime/submit-email-capture.js +54 -0
  23. package/dist/runtime/use-funnel-flow-controller.d.ts +58 -5
  24. package/dist/runtime/use-funnel-flow-controller.js +804 -122
  25. package/dist/runtime/use-step-choices.d.ts +58 -0
  26. package/dist/runtime/use-step-choices.js +187 -0
  27. package/dist/sdk/userAnswers.d.ts +1 -0
  28. package/dist/services/api.service.d.ts +10 -0
  29. package/dist/services/api.service.js +32 -0
  30. package/dist/services/funnel-sdk.service.d.ts +17 -0
  31. package/dist/services/funnel-sdk.service.js +13 -0
  32. package/dist/steps/choice-contract.d.ts +33 -0
  33. package/dist/steps/choice-contract.js +302 -0
  34. package/dist/steps/step-contract.d.ts +498 -0
  35. package/dist/steps/step-contract.js +506 -0
  36. package/dist/steps/types.d.ts +7 -5
  37. package/dist/steps/types.js +1 -18
  38. package/dist/testing/funnel-contract-journey-driver.d.ts +35 -0
  39. package/dist/testing/funnel-contract-journey-driver.js +266 -0
  40. package/dist/testing/index.d.ts +1 -0
  41. package/dist/testing/index.js +1 -0
  42. package/dist/validation/fixtures/invalid-reserved-identities.d.ts +249 -0
  43. package/dist/validation/fixtures/invalid-reserved-identities.js +20 -0
  44. package/dist/validation/fixtures/valid-v2-project.d.ts +419 -0
  45. package/dist/validation/fixtures/valid-v2-project.js +228 -0
  46. package/dist/validation/fixtures/valid-v3-project.d.ts +419 -0
  47. package/dist/validation/fixtures/valid-v3-project.js +30 -0
  48. package/dist/validation/funnel-contract-diagnostics.d.ts +49 -0
  49. package/dist/validation/funnel-contract-diagnostics.js +67 -0
  50. package/dist/validation/funnel-contract-validator.d.ts +30 -0
  51. package/dist/validation/funnel-contract-validator.js +1458 -0
  52. package/dist/validation/funnel-manifest-input.normalization.d.ts +67 -0
  53. package/dist/validation/funnel-manifest-input.normalization.js +386 -0
  54. package/package.json +9 -1
@@ -0,0 +1,419 @@
1
+ export declare const validV3ProjectManifest: {
2
+ stepContractVersion: number;
3
+ meta: {
4
+ description: string;
5
+ title: "Contract fixture";
6
+ };
7
+ steps: ({
8
+ readonly id: "step-1";
9
+ readonly name: "step-one";
10
+ readonly path: "/step-1";
11
+ readonly filePath: "src/steps/step-01.tsx";
12
+ readonly componentKey: "stepOne";
13
+ readonly type: "intro_hero";
14
+ readonly title: "Introduction";
15
+ } | {
16
+ readonly id: "step-2";
17
+ readonly name: "device-choice";
18
+ readonly path: "/step-2";
19
+ readonly filePath: "src/steps/step-02.tsx";
20
+ readonly componentKey: "stepTwo";
21
+ readonly type: "multi_select_choice";
22
+ readonly choice: {
23
+ readonly answerKey: "selectedDevices";
24
+ readonly allowEmpty: true;
25
+ };
26
+ readonly title: "Choose devices";
27
+ } | {
28
+ readonly id: "email-capture";
29
+ readonly name: "email-capture";
30
+ readonly path: "/email-capture";
31
+ readonly filePath: "src/steps/step-31-email-capture.tsx";
32
+ readonly componentKey: "stepEmailCapture";
33
+ readonly type: "form_input";
34
+ readonly title: "Email capture";
35
+ } | {
36
+ readonly id: "paywall";
37
+ readonly name: "paywall";
38
+ readonly path: "/paywall";
39
+ readonly filePath: "src/steps/step-32-paywall.tsx";
40
+ readonly componentKey: "stepPaywall";
41
+ readonly type: "paywall_offer";
42
+ readonly kind: "paywall";
43
+ readonly title: "Paywall";
44
+ } | {
45
+ readonly id: "paywall-b";
46
+ readonly name: "paywall-b";
47
+ readonly path: "/paywall-b";
48
+ readonly filePath: "src/steps/step-32b-paywall-b.tsx";
49
+ readonly componentKey: "stepPaywallB";
50
+ readonly type: "paywall_offer";
51
+ readonly kind: "paywall";
52
+ readonly title: "Paywall B";
53
+ } | {
54
+ readonly id: "manage-subscription";
55
+ readonly name: "manage-subscription";
56
+ readonly path: "/manage-subscription";
57
+ readonly filePath: "src/steps/step-35-manage-subscription.tsx";
58
+ readonly componentKey: "stepManageSubscription";
59
+ readonly type: "subscription_management";
60
+ readonly kind: "manage-subscription";
61
+ readonly title: "Manage subscription";
62
+ } | {
63
+ type: "purchase_completed";
64
+ id: "subscription-started";
65
+ name: "subscription-started";
66
+ path: "/subscription-started";
67
+ filePath: "src/steps/step-33-subscription-started.tsx";
68
+ componentKey: "stepSubscriptionStarted";
69
+ kind: "subscription-handoff";
70
+ title: "Subscription started";
71
+ })[];
72
+ templateArchitectureVersion: 1;
73
+ viewport: {
74
+ readonly width: 390;
75
+ readonly height: 844;
76
+ };
77
+ assets: {};
78
+ entryPoints: readonly [{
79
+ readonly id: "default";
80
+ readonly stepId: "step-1";
81
+ readonly isDefault: true;
82
+ }, {
83
+ readonly id: "manage-subscription";
84
+ readonly stepId: "manage-subscription";
85
+ }];
86
+ edgesByStepId: {
87
+ readonly 'step-1': readonly [{
88
+ readonly toStepId: "step-2";
89
+ }];
90
+ readonly 'step-2': readonly [{
91
+ readonly toStepId: "email-capture";
92
+ }];
93
+ readonly 'email-capture': readonly [{
94
+ readonly toStepId: "paywall";
95
+ }];
96
+ readonly paywall: readonly [{
97
+ readonly toStepId: "subscription-started";
98
+ }];
99
+ readonly 'paywall-b': readonly [{
100
+ readonly toStepId: "subscription-started";
101
+ }];
102
+ };
103
+ branches: readonly [{
104
+ readonly id: "device-owners";
105
+ readonly name: "Device owners";
106
+ readonly sourceStepId: "step-2";
107
+ readonly stepIds: readonly ["email-capture", "paywall"];
108
+ }];
109
+ experiments: readonly [{
110
+ readonly experimentId: "paywall-offer";
111
+ readonly stepId: "paywall";
112
+ readonly variants: readonly [{
113
+ readonly variantKey: "control";
114
+ readonly routeToStepId: "paywall";
115
+ }, {
116
+ readonly variantKey: "variant-b";
117
+ readonly routeToStepId: "paywall-b";
118
+ }];
119
+ }];
120
+ };
121
+ export declare const validV3ProjectComponentMetaByKey: {
122
+ readonly stepSubscriptionStarted: {
123
+ readonly type: "purchase_completed";
124
+ readonly description: "Complete the funnel after a verified purchase.";
125
+ readonly id: "subscription-started";
126
+ readonly name: "subscription-started";
127
+ readonly kind: "subscription-handoff";
128
+ readonly figmaNodeId: "fixture:subscription-started";
129
+ readonly title: "Subscription started";
130
+ };
131
+ readonly stepOne: {
132
+ readonly id: "step-1";
133
+ readonly name: "step-one";
134
+ readonly type: "intro_hero";
135
+ readonly figmaNodeId: "fixture:step-1";
136
+ readonly title: "Introduction";
137
+ readonly description: "Introduce the funnel.";
138
+ };
139
+ readonly stepTwo: {
140
+ readonly id: "step-2";
141
+ readonly name: "device-choice";
142
+ readonly type: "multi_select_choice";
143
+ readonly choice: {
144
+ readonly answerKey: "selectedDevices";
145
+ readonly allowEmpty: true;
146
+ };
147
+ readonly figmaNodeId: "fixture:step-2";
148
+ readonly title: "Choose devices";
149
+ readonly description: "Choose every device that applies.";
150
+ };
151
+ readonly stepEmailCapture: {
152
+ readonly id: "email-capture";
153
+ readonly name: "email-capture";
154
+ readonly type: "form_input";
155
+ readonly figmaNodeId: "fixture:email-capture";
156
+ readonly title: "Email capture";
157
+ readonly description: "Capture an email address.";
158
+ };
159
+ readonly stepPaywall: {
160
+ readonly id: "paywall";
161
+ readonly name: "paywall";
162
+ readonly type: "paywall_offer";
163
+ readonly kind: "paywall";
164
+ readonly figmaNodeId: "fixture:paywall";
165
+ readonly title: "Paywall";
166
+ readonly description: "Present the primary offer.";
167
+ };
168
+ readonly stepPaywallB: {
169
+ readonly id: "paywall-b";
170
+ readonly name: "paywall-b";
171
+ readonly type: "paywall_offer";
172
+ readonly kind: "paywall";
173
+ readonly figmaNodeId: "fixture:paywall-b";
174
+ readonly title: "Paywall B";
175
+ readonly description: "Present the alternate offer.";
176
+ };
177
+ readonly stepManageSubscription: {
178
+ readonly id: "manage-subscription";
179
+ readonly name: "manage-subscription";
180
+ readonly type: "subscription_management";
181
+ readonly kind: "manage-subscription";
182
+ readonly figmaNodeId: "fixture:manage-subscription";
183
+ readonly title: "Manage subscription";
184
+ readonly description: "Manage the active subscription.";
185
+ };
186
+ };
187
+ export declare const validV3ProjectSnapshot: {
188
+ readonly manifest: {
189
+ stepContractVersion: number;
190
+ meta: {
191
+ description: string;
192
+ title: "Contract fixture";
193
+ };
194
+ steps: ({
195
+ readonly id: "step-1";
196
+ readonly name: "step-one";
197
+ readonly path: "/step-1";
198
+ readonly filePath: "src/steps/step-01.tsx";
199
+ readonly componentKey: "stepOne";
200
+ readonly type: "intro_hero";
201
+ readonly title: "Introduction";
202
+ } | {
203
+ readonly id: "step-2";
204
+ readonly name: "device-choice";
205
+ readonly path: "/step-2";
206
+ readonly filePath: "src/steps/step-02.tsx";
207
+ readonly componentKey: "stepTwo";
208
+ readonly type: "multi_select_choice";
209
+ readonly choice: {
210
+ readonly answerKey: "selectedDevices";
211
+ readonly allowEmpty: true;
212
+ };
213
+ readonly title: "Choose devices";
214
+ } | {
215
+ readonly id: "email-capture";
216
+ readonly name: "email-capture";
217
+ readonly path: "/email-capture";
218
+ readonly filePath: "src/steps/step-31-email-capture.tsx";
219
+ readonly componentKey: "stepEmailCapture";
220
+ readonly type: "form_input";
221
+ readonly title: "Email capture";
222
+ } | {
223
+ readonly id: "paywall";
224
+ readonly name: "paywall";
225
+ readonly path: "/paywall";
226
+ readonly filePath: "src/steps/step-32-paywall.tsx";
227
+ readonly componentKey: "stepPaywall";
228
+ readonly type: "paywall_offer";
229
+ readonly kind: "paywall";
230
+ readonly title: "Paywall";
231
+ } | {
232
+ readonly id: "paywall-b";
233
+ readonly name: "paywall-b";
234
+ readonly path: "/paywall-b";
235
+ readonly filePath: "src/steps/step-32b-paywall-b.tsx";
236
+ readonly componentKey: "stepPaywallB";
237
+ readonly type: "paywall_offer";
238
+ readonly kind: "paywall";
239
+ readonly title: "Paywall B";
240
+ } | {
241
+ readonly id: "manage-subscription";
242
+ readonly name: "manage-subscription";
243
+ readonly path: "/manage-subscription";
244
+ readonly filePath: "src/steps/step-35-manage-subscription.tsx";
245
+ readonly componentKey: "stepManageSubscription";
246
+ readonly type: "subscription_management";
247
+ readonly kind: "manage-subscription";
248
+ readonly title: "Manage subscription";
249
+ } | {
250
+ type: "purchase_completed";
251
+ id: "subscription-started";
252
+ name: "subscription-started";
253
+ path: "/subscription-started";
254
+ filePath: "src/steps/step-33-subscription-started.tsx";
255
+ componentKey: "stepSubscriptionStarted";
256
+ kind: "subscription-handoff";
257
+ title: "Subscription started";
258
+ })[];
259
+ templateArchitectureVersion: 1;
260
+ viewport: {
261
+ readonly width: 390;
262
+ readonly height: 844;
263
+ };
264
+ assets: {};
265
+ entryPoints: readonly [{
266
+ readonly id: "default";
267
+ readonly stepId: "step-1";
268
+ readonly isDefault: true;
269
+ }, {
270
+ readonly id: "manage-subscription";
271
+ readonly stepId: "manage-subscription";
272
+ }];
273
+ edgesByStepId: {
274
+ readonly 'step-1': readonly [{
275
+ readonly toStepId: "step-2";
276
+ }];
277
+ readonly 'step-2': readonly [{
278
+ readonly toStepId: "email-capture";
279
+ }];
280
+ readonly 'email-capture': readonly [{
281
+ readonly toStepId: "paywall";
282
+ }];
283
+ readonly paywall: readonly [{
284
+ readonly toStepId: "subscription-started";
285
+ }];
286
+ readonly 'paywall-b': readonly [{
287
+ readonly toStepId: "subscription-started";
288
+ }];
289
+ };
290
+ branches: readonly [{
291
+ readonly id: "device-owners";
292
+ readonly name: "Device owners";
293
+ readonly sourceStepId: "step-2";
294
+ readonly stepIds: readonly ["email-capture", "paywall"];
295
+ }];
296
+ experiments: readonly [{
297
+ readonly experimentId: "paywall-offer";
298
+ readonly stepId: "paywall";
299
+ readonly variants: readonly [{
300
+ readonly variantKey: "control";
301
+ readonly routeToStepId: "paywall";
302
+ }, {
303
+ readonly variantKey: "variant-b";
304
+ readonly routeToStepId: "paywall-b";
305
+ }];
306
+ }];
307
+ };
308
+ readonly componentMetaByKey: {
309
+ readonly stepSubscriptionStarted: {
310
+ readonly type: "purchase_completed";
311
+ readonly description: "Complete the funnel after a verified purchase.";
312
+ readonly id: "subscription-started";
313
+ readonly name: "subscription-started";
314
+ readonly kind: "subscription-handoff";
315
+ readonly figmaNodeId: "fixture:subscription-started";
316
+ readonly title: "Subscription started";
317
+ };
318
+ readonly stepOne: {
319
+ readonly id: "step-1";
320
+ readonly name: "step-one";
321
+ readonly type: "intro_hero";
322
+ readonly figmaNodeId: "fixture:step-1";
323
+ readonly title: "Introduction";
324
+ readonly description: "Introduce the funnel.";
325
+ };
326
+ readonly stepTwo: {
327
+ readonly id: "step-2";
328
+ readonly name: "device-choice";
329
+ readonly type: "multi_select_choice";
330
+ readonly choice: {
331
+ readonly answerKey: "selectedDevices";
332
+ readonly allowEmpty: true;
333
+ };
334
+ readonly figmaNodeId: "fixture:step-2";
335
+ readonly title: "Choose devices";
336
+ readonly description: "Choose every device that applies.";
337
+ };
338
+ readonly stepEmailCapture: {
339
+ readonly id: "email-capture";
340
+ readonly name: "email-capture";
341
+ readonly type: "form_input";
342
+ readonly figmaNodeId: "fixture:email-capture";
343
+ readonly title: "Email capture";
344
+ readonly description: "Capture an email address.";
345
+ };
346
+ readonly stepPaywall: {
347
+ readonly id: "paywall";
348
+ readonly name: "paywall";
349
+ readonly type: "paywall_offer";
350
+ readonly kind: "paywall";
351
+ readonly figmaNodeId: "fixture:paywall";
352
+ readonly title: "Paywall";
353
+ readonly description: "Present the primary offer.";
354
+ };
355
+ readonly stepPaywallB: {
356
+ readonly id: "paywall-b";
357
+ readonly name: "paywall-b";
358
+ readonly type: "paywall_offer";
359
+ readonly kind: "paywall";
360
+ readonly figmaNodeId: "fixture:paywall-b";
361
+ readonly title: "Paywall B";
362
+ readonly description: "Present the alternate offer.";
363
+ };
364
+ readonly stepManageSubscription: {
365
+ readonly id: "manage-subscription";
366
+ readonly name: "manage-subscription";
367
+ readonly type: "subscription_management";
368
+ readonly kind: "manage-subscription";
369
+ readonly figmaNodeId: "fixture:manage-subscription";
370
+ readonly title: "Manage subscription";
371
+ readonly description: "Manage the active subscription.";
372
+ };
373
+ };
374
+ readonly registeredComponentKeys: string[];
375
+ readonly contentOptionsByStepId: {
376
+ readonly 'step-2': readonly [{
377
+ readonly id: "phone";
378
+ readonly label: "Phone";
379
+ readonly imageSrc: "/images/phone.png";
380
+ }];
381
+ };
382
+ readonly edgesByStepId: {
383
+ readonly 'step-1': readonly [{
384
+ readonly toStepId: "step-2";
385
+ }];
386
+ readonly 'step-2': readonly [{
387
+ readonly toStepId: "email-capture";
388
+ }];
389
+ readonly 'email-capture': readonly [{
390
+ readonly toStepId: "paywall";
391
+ }];
392
+ readonly paywall: readonly [{
393
+ readonly toStepId: "subscription-started";
394
+ }];
395
+ readonly 'paywall-b': readonly [{
396
+ readonly toStepId: "subscription-started";
397
+ }];
398
+ };
399
+ readonly experiments: readonly [{
400
+ readonly experimentId: "paywall-offer";
401
+ readonly stepId: "paywall";
402
+ readonly variants: readonly [{
403
+ readonly variantKey: "control";
404
+ readonly routeToStepId: "paywall";
405
+ }, {
406
+ readonly variantKey: "variant-b";
407
+ readonly routeToStepId: "paywall-b";
408
+ }];
409
+ }];
410
+ readonly docs: {
411
+ readonly schemaVersion: 1;
412
+ readonly bundleVersion: "3.0.0";
413
+ readonly stepContractVersion: 3;
414
+ readonly contractHash: "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf";
415
+ readonly missing: readonly [];
416
+ readonly changed: readonly [];
417
+ readonly conflicts: readonly [];
418
+ };
419
+ };
@@ -0,0 +1,30 @@
1
+ import { CURRENT_STEP_CONTRACT_HASH } from '../../generated/step-contract-hash.js';
2
+ import { validV2ProjectComponentMetaByKey, validV2ProjectManifest, } from './valid-v2-project.js';
3
+ export const validV3ProjectManifest = Object.assign(Object.assign({}, validV2ProjectManifest), { stepContractVersion: 3, meta: Object.assign(Object.assign({}, validV2ProjectManifest.meta), { description: 'A valid version 3 funnel contract fixture.' }), steps: validV2ProjectManifest.steps.map((step) => (step.id === 'subscription-started'
4
+ ? Object.assign(Object.assign({}, step), { type: 'purchase_completed' }) : step)) });
5
+ export const validV3ProjectComponentMetaByKey = Object.assign(Object.assign({}, validV2ProjectComponentMetaByKey), { stepSubscriptionStarted: Object.assign(Object.assign({}, validV2ProjectComponentMetaByKey.stepSubscriptionStarted), { type: 'purchase_completed', description: 'Complete the funnel after a verified purchase.' }) });
6
+ export const validV3ProjectSnapshot = {
7
+ manifest: validV3ProjectManifest,
8
+ componentMetaByKey: validV3ProjectComponentMetaByKey,
9
+ registeredComponentKeys: Object.keys(validV3ProjectComponentMetaByKey),
10
+ contentOptionsByStepId: {
11
+ 'step-2': [
12
+ {
13
+ id: 'phone',
14
+ label: 'Phone',
15
+ imageSrc: '/images/phone.png',
16
+ },
17
+ ],
18
+ },
19
+ edgesByStepId: validV3ProjectManifest.edgesByStepId,
20
+ experiments: validV3ProjectManifest.experiments,
21
+ docs: {
22
+ schemaVersion: 1,
23
+ bundleVersion: '3.0.0',
24
+ stepContractVersion: 3,
25
+ contractHash: CURRENT_STEP_CONTRACT_HASH,
26
+ missing: [],
27
+ changed: [],
28
+ conflicts: [],
29
+ },
30
+ };
@@ -0,0 +1,49 @@
1
+ import { type DeferrableFunnelContractDiagnosticCode } from '../steps/step-contract.js';
2
+ export declare const FUNNEL_CONTRACT_DIAGNOSTIC_CODES: readonly ["FG-VERSION-001", "FG-VERSION-002", "FG-STEP-001", "FG-STEP-002", "FG-STEP-104", "FG-RESERVED-001", "FG-RESERVED-002", "FG-PARITY-001", "FG-REGISTRY-001", "FG-CONTENT-001", "FG-FLOW-001", "FG-FLOW-002", "FG-CHOICE-001", "FG-CHOICE-002", "FG-CHOICE-006", "FG-ANALYTICS-001", "FG-ANALYTICS-002", "FG-ANALYTICS-003", "FG-DOC-001", "FG-DOC-002", "FG-CLIENT-001", "FG-CANDIDATE-001"];
3
+ export type FunnelContractDiagnosticCode = (typeof FUNNEL_CONTRACT_DIAGNOSTIC_CODES)[number];
4
+ export declare const FUNNEL_CONTRACT_DIAGNOSTIC_SUMMARIES: Readonly<{
5
+ 'FG-VERSION-001': string;
6
+ 'FG-VERSION-002': string;
7
+ 'FG-STEP-001': string;
8
+ 'FG-STEP-002': string;
9
+ 'FG-STEP-104': string;
10
+ 'FG-RESERVED-001': string;
11
+ 'FG-RESERVED-002': string;
12
+ 'FG-PARITY-001': string;
13
+ 'FG-REGISTRY-001': string;
14
+ 'FG-CONTENT-001': string;
15
+ 'FG-FLOW-001': string;
16
+ 'FG-FLOW-002': string;
17
+ 'FG-CHOICE-001': string;
18
+ 'FG-CHOICE-002': string;
19
+ 'FG-CHOICE-006': string;
20
+ 'FG-ANALYTICS-001': string;
21
+ 'FG-ANALYTICS-002': string;
22
+ 'FG-ANALYTICS-003': string;
23
+ 'FG-DOC-001': string;
24
+ 'FG-DOC-002': string;
25
+ 'FG-CLIENT-001': string;
26
+ 'FG-CANDIDATE-001': string;
27
+ }>;
28
+ type FunnelContractDiagnosticDetails = {
29
+ file: string | null;
30
+ stepId: string | null;
31
+ expected: unknown;
32
+ received: unknown;
33
+ reason: string;
34
+ guide: string;
35
+ repair: string;
36
+ };
37
+ export type FunnelContractErrorDiagnostic = FunnelContractDiagnosticDetails & {
38
+ code: FunnelContractDiagnosticCode;
39
+ severity: 'error';
40
+ };
41
+ export type FunnelContractDiagnostic = FunnelContractErrorDiagnostic;
42
+ export type FunnelContractDiagnosticInput = Omit<FunnelContractDiagnosticDetails, 'file' | 'stepId'> & {
43
+ code: FunnelContractDiagnosticCode;
44
+ file?: string | null;
45
+ stepId?: string | null;
46
+ };
47
+ export declare const isDeferrableFunnelContractDiagnosticCode: (code: FunnelContractDiagnosticCode) => code is DeferrableFunnelContractDiagnosticCode;
48
+ export declare const createFunnelContractDiagnostic: (input: FunnelContractDiagnosticInput) => FunnelContractDiagnostic;
49
+ export {};
@@ -0,0 +1,67 @@
1
+ import { DEFERRABLE_FUNNEL_CONTRACT_DIAGNOSTIC_CODES, } from '../steps/step-contract.js';
2
+ export const FUNNEL_CONTRACT_DIAGNOSTIC_CODES = Object.freeze([
3
+ 'FG-VERSION-001',
4
+ 'FG-VERSION-002',
5
+ 'FG-STEP-001',
6
+ 'FG-STEP-002',
7
+ 'FG-STEP-104',
8
+ 'FG-RESERVED-001',
9
+ 'FG-RESERVED-002',
10
+ 'FG-PARITY-001',
11
+ 'FG-REGISTRY-001',
12
+ 'FG-CONTENT-001',
13
+ 'FG-FLOW-001',
14
+ 'FG-FLOW-002',
15
+ 'FG-CHOICE-001',
16
+ 'FG-CHOICE-002',
17
+ 'FG-CHOICE-006',
18
+ 'FG-ANALYTICS-001',
19
+ 'FG-ANALYTICS-002',
20
+ 'FG-ANALYTICS-003',
21
+ 'FG-DOC-001',
22
+ 'FG-DOC-002',
23
+ 'FG-CLIENT-001',
24
+ 'FG-CANDIDATE-001',
25
+ ]);
26
+ export const FUNNEL_CONTRACT_DIAGNOSTIC_SUMMARIES = Object.freeze({
27
+ 'FG-VERSION-001': 'Future or unsupported funnel step contract version.',
28
+ 'FG-VERSION-002': 'Legacy or downgraded contract used for authoring or publish.',
29
+ 'FG-STEP-001': 'Unknown step type or kind.',
30
+ 'FG-STEP-002': 'Invalid step type/kind/name contract.',
31
+ 'FG-STEP-104': 'Non-purchasable screen incorrectly classified as a paywall.',
32
+ 'FG-RESERVED-001': 'Reserved identity/type/kind mismatch or duplicate reserved identity.',
33
+ 'FG-RESERVED-002': 'Missing or duplicate primary paywall.',
34
+ 'FG-PARITY-001': 'Component and manifest metadata do not match.',
35
+ 'FG-REGISTRY-001': 'Declared step is missing from the component registry.',
36
+ 'FG-CONTENT-001': 'Choice options or content registry entry is missing.',
37
+ 'FG-FLOW-001': 'Step or edge references an unwritten declared path.',
38
+ 'FG-FLOW-002': 'Hard-coded or outcome-less navigation bypasses manifest/controller routing.',
39
+ 'FG-CHOICE-001': 'Choice descriptor or answer key is missing or invalid.',
40
+ 'FG-CHOICE-002': 'Choice option ID, cardinality, or emoji schema is invalid.',
41
+ 'FG-CHOICE-006': 'Choice write bypasses useStepChoices.',
42
+ 'FG-ANALYTICS-001': 'Shared analytics adapter is missing.',
43
+ 'FG-ANALYTICS-002': 'Provider-direct analytics or a manually emitted owned event is forbidden.',
44
+ 'FG-ANALYTICS-003': 'Checkout metadata is incomplete or a preview emitted analytics.',
45
+ 'FG-DOC-001': 'Managed documentation is unsupported, stale, or missing.',
46
+ 'FG-DOC-002': 'Managed-document conflict is unresolved.',
47
+ 'FG-CLIENT-001': 'Legacy client protocol cannot provide an atomic version-2 candidate.',
48
+ 'FG-CANDIDATE-001': 'Candidate ownership, resource, path, hash, or base invariant failed.',
49
+ });
50
+ const DEFERRABLE_DIAGNOSTIC_CODE_SET = new Set(DEFERRABLE_FUNNEL_CONTRACT_DIAGNOSTIC_CODES);
51
+ export const isDeferrableFunnelContractDiagnosticCode = (code) => {
52
+ return DEFERRABLE_DIAGNOSTIC_CODE_SET.has(code);
53
+ };
54
+ export const createFunnelContractDiagnostic = (input) => {
55
+ var _a, _b;
56
+ return {
57
+ code: input.code,
58
+ severity: 'error',
59
+ file: (_a = input.file) !== null && _a !== void 0 ? _a : null,
60
+ stepId: (_b = input.stepId) !== null && _b !== void 0 ? _b : null,
61
+ expected: input.expected,
62
+ received: input.received,
63
+ reason: input.reason,
64
+ guide: input.guide,
65
+ repair: input.repair,
66
+ };
67
+ };
@@ -0,0 +1,30 @@
1
+ import type { FunnelManifest } from '../config/funnel.manifest.types.js';
2
+ import { type FunnelChoiceOption, type FunnelEmojiChoiceOption } from '../steps/step-contract.js';
3
+ import type { FunnelStepMeta } from '../steps/types.js';
4
+ import { type FunnelContractDiagnostic } from './funnel-contract-diagnostics.js';
5
+ export type FunnelContractValidationMode = 'legacy-read' | 'authoring' | 'publish';
6
+ export type FunnelManifestContractInput = Omit<FunnelManifest, 'stepContractVersion'> & {
7
+ stepContractVersion?: number;
8
+ };
9
+ export type FunnelManifestContractValidationOptions = {
10
+ mode: FunnelContractValidationMode;
11
+ };
12
+ export type FunnelStepContractProjectSnapshot = {
13
+ manifest: FunnelManifest;
14
+ componentMetaByKey: Record<string, FunnelStepMeta>;
15
+ registeredComponentKeys: readonly string[];
16
+ contentOptionsByStepId: Record<string, readonly (FunnelChoiceOption | FunnelEmojiChoiceOption)[]>;
17
+ edgesByStepId: FunnelManifest['edgesByStepId'];
18
+ experiments: FunnelManifest['experiments'];
19
+ docs: {
20
+ schemaVersion: number;
21
+ bundleVersion: string;
22
+ stepContractVersion: number;
23
+ contractHash: string;
24
+ missing: readonly string[];
25
+ changed: readonly string[];
26
+ conflicts: readonly string[];
27
+ };
28
+ };
29
+ export declare const validateFunnelManifestContract: (input: unknown, options: FunnelManifestContractValidationOptions) => FunnelContractDiagnostic[];
30
+ export declare const validateFunnelStepContractSnapshot: (input: FunnelStepContractProjectSnapshot, options: FunnelManifestContractValidationOptions) => FunnelContractDiagnostic[];