@funnelsgrove/cli 0.1.87 → 0.1.89

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 (121) hide show
  1. package/dist/apiClient.d.ts +1 -0
  2. package/dist/apiClient.js +32 -1
  3. package/funnel-contract-compatibility.json +28 -28
  4. package/package.json +3 -3
  5. package/template_docs/.funnelsgrove-docs.json +3 -3
  6. package/template_docs/docs/funnelsgrove/migrations/step-contract-v3.md +1 -1
  7. package/template_docs/funnel-docs.config.json +1 -1
  8. package/template_scaffold/.funnelsgrove-docs.json +3 -3
  9. package/template_scaffold/.funnelsgrove-scaffold.json +26 -471
  10. package/template_scaffold/PLAN.md +15 -29
  11. package/template_scaffold/context/build-context.md +3 -3
  12. package/template_scaffold/docs/funnelsgrove/migrations/step-contract-v3.md +1 -1
  13. package/template_scaffold/funnel-docs.config.json +1 -1
  14. package/template_scaffold/package-lock.json +9 -9
  15. package/template_scaffold/package.json +2 -2
  16. package/template_scaffold/public/assets/email-capture-preview.svg +5 -0
  17. package/template_scaffold/public/assets/paywall-preview.svg +6 -0
  18. package/template_scaffold/src/app/sdk/page.tsx +14 -26
  19. package/template_scaffold/src/components/FunnelFlow.tsx +8 -1
  20. package/template_scaffold/src/config/billing.plans.ts +71 -21
  21. package/template_scaffold/src/config/funnel.manifest.ts +20 -59
  22. package/template_scaffold/src/runtime/checkout-runtime-config.ts +0 -7
  23. package/template_scaffold/src/runtime/step-registry.ts +0 -28
  24. package/template_scaffold/src/steps/content/step-01.content.ts +4 -9
  25. package/template_scaffold/src/steps/content/step-32-paywall.content.ts +12 -50
  26. package/template_scaffold/src/steps/step-01.tsx +43 -50
  27. package/template_scaffold/src/steps/step-31-email-capture.tsx +18 -1
  28. package/template_scaffold/src/steps/step-32-paywall.tsx +93 -299
  29. package/template_scaffold/src/steps/step-33-subscription-started.tsx +1 -1
  30. package/template_scaffold/src/steps/step-content.registry.ts +1 -26
  31. package/template_scaffold/public/claimbee/bee.png +0 -0
  32. package/template_scaffold/public/claimbee/device-iphone.png +0 -0
  33. package/template_scaffold/public/claimbee/device-macbook.png +0 -0
  34. package/template_scaffold/public/claimbee/device-none.png +0 -0
  35. package/template_scaffold/public/claimbee/device-watch.png +0 -0
  36. package/template_scaffold/public/claimbee/glow.svg +0 -3
  37. package/template_scaffold/public/claimbee/steps-sprite-alt.png +0 -0
  38. package/template_scaffold/public/claimbee/steps-sprite-default.png +0 -0
  39. package/template_scaffold/public/claimbee/testimonial-avatar.png +0 -0
  40. package/template_scaffold/public/claimbee/testimonial-star.svg +0 -3
  41. package/template_scaffold/public/paywall/ai-claim-assistant.png +0 -0
  42. package/template_scaffold/public/paywall/claim-history.png +0 -0
  43. package/template_scaffold/public/paywall/clear-progress.png +0 -0
  44. package/template_scaffold/public/paywall/hero.png +0 -0
  45. package/template_scaffold/public/paywall/money-alerts.png +0 -0
  46. package/template_scaffold/public/paywall/money-back-badge.png +0 -0
  47. package/template_scaffold/public/paywall/paywall-image.png +0 -0
  48. package/template_scaffold/public/paywall/r1.png +0 -0
  49. package/template_scaffold/public/paywall/r2.png +0 -0
  50. package/template_scaffold/public/paywall/r3.png +0 -0
  51. package/template_scaffold/public/paywall/r4.png +0 -0
  52. package/template_scaffold/public/paywall/r5.png +0 -0
  53. package/template_scaffold/public/paywall/r6.png +0 -0
  54. package/template_scaffold/public/paywall/special-offer-gift.png +0 -0
  55. package/template_scaffold/public/please/bee.png +0 -0
  56. package/template_scaffold/public/please/device-iphone.png +0 -0
  57. package/template_scaffold/public/please/device-macbook.png +0 -0
  58. package/template_scaffold/public/please/device-none.png +0 -0
  59. package/template_scaffold/public/please/device-watch.png +0 -0
  60. package/template_scaffold/public/please/glow.svg +0 -3
  61. package/template_scaffold/public/please/steps-sprite-alt.png +0 -0
  62. package/template_scaffold/public/please/steps-sprite-default.png +0 -0
  63. package/template_scaffold/public/please/testimonial-avatar.png +0 -0
  64. package/template_scaffold/public/please/testimonial-star.svg +0 -3
  65. package/template_scaffold/public/upsell/upgrade-hero.png +0 -0
  66. package/template_scaffold/src/assets/claimbee/bee.png +0 -0
  67. package/template_scaffold/src/assets/claimbee/device-iphone.png +0 -0
  68. package/template_scaffold/src/assets/claimbee/device-macbook.png +0 -0
  69. package/template_scaffold/src/assets/claimbee/device-none.png +0 -0
  70. package/template_scaffold/src/assets/claimbee/device-watch.png +0 -0
  71. package/template_scaffold/src/assets/claimbee/glow.svg +0 -3
  72. package/template_scaffold/src/assets/claimbee/steps-sprite-alt.png +0 -0
  73. package/template_scaffold/src/assets/claimbee/steps-sprite-default.png +0 -0
  74. package/template_scaffold/src/assets/claimbee/testimonial-avatar.png +0 -0
  75. package/template_scaffold/src/assets/claimbee/testimonial-star.svg +0 -3
  76. package/template_scaffold/src/components/FunnelStepImage.tsx +0 -28
  77. package/template_scaffold/src/config/offer-sets.generated.ts +0 -4
  78. package/template_scaffold/src/steps/content/manage-subscription.content.ts +0 -62
  79. package/template_scaffold/src/steps/content/paywall.content.ts +0 -191
  80. package/template_scaffold/src/steps/content/step-02.content.ts +0 -77
  81. package/template_scaffold/src/steps/content/step-03.content.ts +0 -40
  82. package/template_scaffold/src/steps/content/step-04.content.ts +0 -49
  83. package/template_scaffold/src/steps/editor/manage-subscription.editor.ts +0 -179
  84. package/template_scaffold/src/steps/editor/paywall.editor.ts +0 -232
  85. package/template_scaffold/src/steps/editor/step-02.editor.ts +0 -41
  86. package/template_scaffold/src/steps/editor/step-03.editor.ts +0 -58
  87. package/template_scaffold/src/steps/editor/step-04.editor.ts +0 -98
  88. package/template_scaffold/src/steps/pricing/paywall-b.pricing.ts +0 -12
  89. package/template_scaffold/src/steps/step-02.tsx +0 -140
  90. package/template_scaffold/src/steps/step-03.tsx +0 -262
  91. package/template_scaffold/src/steps/step-04.tsx +0 -673
  92. package/template_scaffold/src/steps/step-32b-paywall-b.tsx +0 -35
  93. package/template_scaffold/src/steps/step-35-manage-subscription.tsx +0 -46
  94. package/template_scaffold/src/steps/use-claimbee-step-content.ts +0 -15
  95. package/template_scaffold/tests/funnel-agent-docs.test.ts +0 -751
  96. package/template_scaffold/tests/package.test.ts +0 -37
  97. package/template_scaffold/tests/src/app/[stepId]/page.test.tsx +0 -59
  98. package/template_scaffold/tests/src/app/layout.test.ts +0 -26
  99. package/template_scaffold/tests/src/components/FunnelFlow.test.tsx +0 -38
  100. package/template_scaffold/tests/src/components/FunnelStepImage.test.ts +0 -15
  101. package/template_scaffold/tests/src/config/billing.plans.test.ts +0 -143
  102. package/template_scaffold/tests/src/config/funnel.manifest.test.ts +0 -166
  103. package/template_scaffold/tests/src/contract/funnel-project.validation.test.ts +0 -79
  104. package/template_scaffold/tests/src/contract/golden/golden-fixtures.test.ts +0 -190
  105. package/template_scaffold/tests/src/contract/validate-funnel.cli.test.ts +0 -191
  106. package/template_scaffold/tests/src/runtime/checkout-runtime-config.test.ts +0 -60
  107. package/template_scaffold/tests/src/runtime/funnel-runtime.test.ts +0 -25
  108. package/template_scaffold/tests/src/runtime/step-content-context.test.ts +0 -38
  109. package/template_scaffold/tests/src/runtime/use-funnel-flow-controller.integration.test.ts +0 -203
  110. package/template_scaffold/tests/src/runtime/use-funnel-flow-controller.test.ts +0 -76
  111. package/template_scaffold/tests/src/steps/paywall-checkout-options.test.ts +0 -104
  112. package/template_scaffold/tests/src/steps/shared-header-contract.test.ts +0 -29
  113. package/template_scaffold/tests/src/steps/step-01.test.ts +0 -38
  114. package/template_scaffold/tests/src/steps/step-02.test.ts +0 -43
  115. package/template_scaffold/tests/src/steps/step-03.test.ts +0 -15
  116. package/template_scaffold/tests/src/steps/step-04.test.ts +0 -32
  117. package/template_scaffold/tests/src/steps/step-31-email-capture.test.ts +0 -22
  118. package/template_scaffold/tests/src/steps/step-32-paywall.test.ts +0 -773
  119. package/template_scaffold/tests/src/steps/step-33-subscription-started.test.ts +0 -44
  120. package/template_scaffold/tests/src/steps/step-34-upsell-form.test.ts +0 -27
  121. package/template_scaffold/tests/src/steps/step-image-migration.test.ts +0 -20
@@ -1,140 +0,0 @@
1
- import { useMemo, useState } from 'react';
2
- import { FunnelStepImage } from '@/components/FunnelStepImage';
3
- import { FunnelStepHeader } from '@/components/step/FunnelStepHeader';
4
- import { getStepContentLocale } from '@/runtime/step-content-context';
5
- import {
6
- stepTwoContent,
7
- stepTwoOptions,
8
- type StepTwoOptionId,
9
- } from '@/steps/content/step-02.content';
10
- import {
11
- PrimaryButton,
12
- usePreviewStepLocalizedContent,
13
- useFunnel,
14
- useStepChoices,
15
- type FunnelStepMeta,
16
- } from '@funnelsgrove/runtime';
17
-
18
- export const stepTwoId = 'step-2';
19
-
20
- export const stepTwo: FunnelStepMeta = {
21
- id: stepTwoId,
22
- name: 'step-2',
23
- type: 'multi_select_choice',
24
- choice: {
25
- answerKey: 'selectedDevices',
26
- allowEmpty: true,
27
- },
28
- figmaNodeId: 'template-02-devices',
29
- title: 'Step 2',
30
- description: 'Device selection step with visual options.',
31
- actionBar: {
32
- hidden: true,
33
- },
34
- };
35
-
36
- export function StepTwo() {
37
- const { attributes } = useFunnel();
38
- const { completeMulti } = useStepChoices(stepTwo, stepTwoOptions);
39
- const [selectedIds, setSelectedIds] = useState<StepTwoOptionId[]>([]);
40
- const content = usePreviewStepLocalizedContent(
41
- stepTwoId,
42
- stepTwoContent,
43
- getStepContentLocale(attributes),
44
- );
45
-
46
- const selectedLookup = useMemo(() => new Set(selectedIds), [selectedIds]);
47
-
48
- const toggleOption = (optionId: StepTwoOptionId) => {
49
- setSelectedIds((prev) => {
50
- const exists = prev.includes(optionId);
51
- return exists ? prev.filter((id) => id !== optionId) : [...prev, optionId];
52
- });
53
- };
54
-
55
- return (
56
- <>
57
- <section className="devices-step" data-node-id="template:02-devices">
58
- <FunnelStepHeader
59
- className="devices-header"
60
- titleClassName="devices-title"
61
- title={
62
- <>
63
- {content.title[0]}
64
- <br />
65
- <span className="is-accent">{content.title[1]}</span>
66
- </>
67
- }
68
- subtitle={content.description}
69
- subtitleClassName="devices-description"
70
- />
71
-
72
- <div className="devices-options" role="group" aria-label={content.optionsLabel}>
73
- {content.options.map((option) => {
74
- const isSelected = selectedLookup.has(option.id);
75
-
76
- return (
77
- <button
78
- key={option.id}
79
- type="button"
80
- aria-pressed={isSelected}
81
- className={
82
- isSelected
83
- ? 'device-option is-interactive is-selected'
84
- : 'device-option is-interactive'
85
- }
86
- onClick={() => toggleOption(option.id)}
87
- >
88
- <span className="device-option-main">
89
- <FunnelStepImage
90
- src={option.image.src}
91
- alt={option.image.alt || ''}
92
- width={42}
93
- height={42}
94
- className="device-option-image"
95
- draggable={false}
96
- />
97
- <span className="device-option-label">{option.label}</span>
98
- </span>
99
-
100
- <span
101
- className={isSelected ? 'device-option-checkbox is-selected' : 'device-option-checkbox'}
102
- aria-hidden="true"
103
- >
104
- {isSelected ? <span className="device-option-checkbox-icon">✓</span> : null}
105
- </span>
106
- </button>
107
- );
108
- })}
109
- </div>
110
- </section>
111
-
112
- <footer className="action-bar">
113
- <PrimaryButton onClick={() => completeMulti(selectedIds)}>
114
- {content.continueLabel}
115
- </PrimaryButton>
116
- </footer>
117
-
118
- {stepTwoStyles ? <style>{stepTwoStyles}</style> : null}
119
- </>
120
- );
121
- }
122
-
123
- const stepTwoStyles = `
124
- .device-option {
125
- cursor: pointer;
126
- }
127
-
128
- .device-option-image {
129
- width: 42px;
130
- height: 42px;
131
- object-fit: contain;
132
- border-radius: 8px;
133
- }
134
-
135
- .device-option-checkbox-icon {
136
- font-size: 12px;
137
- line-height: 1;
138
- font-weight: 800;
139
- }
140
- `;
@@ -1,262 +0,0 @@
1
- import { useEffect } from 'react';
2
- import { FunnelStepImage } from '@/components/FunnelStepImage';
3
- import {
4
- usePreviewStepLocalizedContent,
5
- useFunnel,
6
- type FunnelStepMeta,
7
- } from '@funnelsgrove/runtime';
8
- import bee from '@/assets/claimbee/bee.png';
9
- import glow from '@/assets/claimbee/glow.svg';
10
- import stepsSpriteAlt from '@/assets/claimbee/steps-sprite-alt.png';
11
- import { getStepContentLocale } from '@/runtime/step-content-context';
12
- import { stepThreeContent } from '@/steps/content/step-03.content';
13
-
14
- export const stepThreeId = 'step-3';
15
- const STEP_THREE_AUTO_ADVANCE_MS = 2200;
16
-
17
- export const resolveStepThreeAutoAdvanceMs = (isBuilder: boolean): number | null => {
18
- return isBuilder ? null : STEP_THREE_AUTO_ADVANCE_MS;
19
- };
20
-
21
- export const stepThree: FunnelStepMeta = {
22
- id: stepThreeId,
23
- name: 'step-3',
24
- type: 'progress_interstitial',
25
- figmaNodeId: 'template-03-processing',
26
- title: 'Step 3',
27
- description: 'Animated processing step before decision.',
28
- actionBar: {
29
- hidden: true,
30
- },
31
- };
32
-
33
- export function StepThree() {
34
- const { attributes, goNext, isBuilder } = useFunnel();
35
- const content = usePreviewStepLocalizedContent(
36
- stepThreeId,
37
- stepThreeContent,
38
- getStepContentLocale(attributes),
39
- );
40
- const autoAdvanceMs = resolveStepThreeAutoAdvanceMs(isBuilder);
41
-
42
- useEffect(() => {
43
- if (!autoAdvanceMs) {
44
- return;
45
- }
46
-
47
- const timer = window.setTimeout(() => {
48
- goNext();
49
- }, autoAdvanceMs);
50
-
51
- return () => window.clearTimeout(timer);
52
- }, [autoAdvanceMs, goNext]);
53
-
54
- return (
55
- <>
56
- <section className="owners-step" data-node-id="template:03-processing">
57
- <div className="owners-copy-wrap">
58
- <p className="owners-kicker">{content.kicker}</p>
59
- <h2 className="owners-title">
60
- {content.title[0]}
61
- <br />
62
- <span className="is-accent">{content.title[1]}</span>
63
- </h2>
64
- <p className="owners-copy">{content.description}</p>
65
- </div>
66
-
67
- <div className="owners-artwork" aria-hidden>
68
- <FunnelStepImage
69
- src={content.artwork.sprite.src || stepsSpriteAlt.src}
70
- alt={content.artwork.sprite.alt || ''}
71
- width={1364}
72
- height={909}
73
- className="owners-sprite"
74
- draggable={false}
75
- />
76
- <FunnelStepImage
77
- src={content.artwork.glow.src || glow.src}
78
- alt={content.artwork.glow.alt || ''}
79
- width={122}
80
- height={116}
81
- className="owners-glow"
82
- draggable={false}
83
- />
84
- <FunnelStepImage
85
- src={content.artwork.bee.src || bee.src}
86
- alt={content.artwork.bee.alt || ''}
87
- width={88}
88
- height={88}
89
- className="owners-bee"
90
- draggable={false}
91
- />
92
- </div>
93
-
94
- <div className="owners-status" role="status" aria-live="polite">
95
- <p className="owners-status-label">{content.progressLabel}</p>
96
- <div className="owners-progress-track">
97
- <span
98
- className="owners-progress-fill"
99
- style={{ animationDuration: `${STEP_THREE_AUTO_ADVANCE_MS}ms` }}
100
- />
101
- </div>
102
- </div>
103
- </section>
104
-
105
- {stepThreeStyles ? <style>{stepThreeStyles}</style> : null}
106
- </>
107
- );
108
- }
109
-
110
- const stepThreeStyles = `
111
- .owners-step {
112
- min-height: 100%;
113
- background: var(--color-bg-success);
114
- padding: calc(env(safe-area-inset-top, 0px) + 84px) var(--padding) 40px;
115
- display: flex;
116
- flex-direction: column;
117
- gap: 24px;
118
- overflow: hidden;
119
- }
120
-
121
- .owners-copy-wrap {
122
- display: flex;
123
- flex-direction: column;
124
- gap: 12px;
125
- }
126
-
127
- .owners-kicker {
128
- margin: 0;
129
- color: var(--color-accent);
130
- font-size: 13px;
131
- font-weight: 700;
132
- letter-spacing: 0.04em;
133
- text-transform: uppercase;
134
- }
135
-
136
- .owners-title {
137
- margin: 0;
138
- color: var(--color-text);
139
- font-size: 34px;
140
- line-height: 1.12;
141
- font-weight: 800;
142
- letter-spacing: -0.02em;
143
- }
144
-
145
- .owners-title .is-accent {
146
- color: var(--color-button);
147
- }
148
-
149
- .owners-copy {
150
- margin: 0;
151
- color: var(--color-text-muted);
152
- font-size: 17px;
153
- line-height: 1.44;
154
- font-weight: 500;
155
- }
156
-
157
- .owners-artwork {
158
- position: relative;
159
- width: 100%;
160
- height: 300px;
161
- margin-top: 4px;
162
- border-radius: 20px;
163
- background: linear-gradient(180deg, rgba(77, 181, 63, 0.06), rgba(63, 81, 181, 0.08));
164
- overflow: hidden;
165
- }
166
-
167
- .owners-sprite {
168
- position: absolute;
169
- left: -520px;
170
- top: -250px;
171
- width: 1364px;
172
- height: 909px;
173
- max-width: none;
174
- }
175
-
176
- .owners-glow {
177
- position: absolute;
178
- left: 50%;
179
- top: 52%;
180
- width: 122px;
181
- height: 116px;
182
- transform: translate(-50%, -50%);
183
- }
184
-
185
- .owners-bee {
186
- position: absolute;
187
- left: 50%;
188
- top: 52%;
189
- width: 88px;
190
- height: 88px;
191
- transform: translate(-50%, -50%);
192
- }
193
-
194
- .owners-status {
195
- margin-top: auto;
196
- display: flex;
197
- flex-direction: column;
198
- gap: 10px;
199
- background: rgba(255, 255, 255, 0.84);
200
- border: 1px solid var(--color-border);
201
- border-radius: 14px;
202
- padding: 12px;
203
- }
204
-
205
- .owners-status-label {
206
- margin: 0;
207
- color: var(--color-text);
208
- font-size: 14px;
209
- line-height: 1.35;
210
- font-weight: 600;
211
- }
212
-
213
- .owners-progress-track {
214
- height: 10px;
215
- border-radius: 999px;
216
- background: rgba(63, 81, 181, 0.16);
217
- overflow: hidden;
218
- }
219
-
220
- .owners-progress-fill {
221
- display: block;
222
- height: 100%;
223
- width: 0%;
224
- border-radius: inherit;
225
- background: linear-gradient(90deg, #4db53f, #3f51b5);
226
- animation-name: ownersProgress;
227
- animation-timing-function: linear;
228
- animation-fill-mode: forwards;
229
- animation-duration: 2200ms;
230
- }
231
-
232
- @keyframes ownersProgress {
233
- 0% {
234
- width: 0%;
235
- opacity: 0.88;
236
- }
237
-
238
- 100% {
239
- width: 100%;
240
- opacity: 1;
241
- }
242
- }
243
-
244
- @media (max-width: 430px) {
245
- .owners-step {
246
- padding-left: 20px;
247
- padding-right: 20px;
248
- }
249
-
250
- .owners-title {
251
- font-size: 30px;
252
- }
253
-
254
- .owners-copy {
255
- font-size: 16px;
256
- }
257
-
258
- .owners-artwork {
259
- height: 284px;
260
- }
261
- }
262
- `;