digital-products 2.1.3 → 2.3.0

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 (122) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +2 -0
  3. package/dist/api.js +7 -7
  4. package/dist/api.js.map +1 -1
  5. package/dist/app.js +6 -6
  6. package/dist/app.js.map +1 -1
  7. package/dist/client.d.ts +157 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +69 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/content.js +7 -7
  12. package/dist/content.js.map +1 -1
  13. package/dist/data.d.ts.map +1 -1
  14. package/dist/data.js +6 -6
  15. package/dist/data.js.map +1 -1
  16. package/dist/dataset.js +5 -5
  17. package/dist/dataset.js.map +1 -1
  18. package/dist/index.d.ts +92 -13
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +139 -15
  21. package/dist/index.js.map +1 -1
  22. package/dist/mcp.d.ts +1 -1
  23. package/dist/mcp.d.ts.map +1 -1
  24. package/dist/mcp.js +17 -10
  25. package/dist/mcp.js.map +1 -1
  26. package/dist/product.js +2 -2
  27. package/dist/product.js.map +1 -1
  28. package/dist/sdk.d.ts.map +1 -1
  29. package/dist/sdk.js +52 -16
  30. package/dist/sdk.js.map +1 -1
  31. package/dist/site.d.ts.map +1 -1
  32. package/dist/site.js +12 -8
  33. package/dist/site.js.map +1 -1
  34. package/dist/types.d.ts +830 -12
  35. package/dist/types.d.ts.map +1 -1
  36. package/dist/types.js +495 -2
  37. package/dist/types.js.map +1 -1
  38. package/dist/worker.d.ts +205 -0
  39. package/dist/worker.d.ts.map +1 -0
  40. package/dist/worker.js +356 -0
  41. package/dist/worker.js.map +1 -0
  42. package/package.json +29 -13
  43. package/src/api.ts +7 -7
  44. package/src/app.ts +6 -6
  45. package/src/client.ts +192 -0
  46. package/src/content.ts +7 -7
  47. package/src/data.ts +12 -7
  48. package/src/dataset.ts +5 -5
  49. package/src/index.ts +151 -15
  50. package/src/mcp.ts +18 -11
  51. package/src/product.ts +2 -2
  52. package/src/sdk.ts +54 -15
  53. package/src/site.ts +12 -8
  54. package/src/types.ts +821 -12
  55. package/src/worker.ts +525 -0
  56. package/test/product.test.ts +53 -198
  57. package/test/unified-types.test.ts +589 -0
  58. package/test/worker.test.ts +912 -0
  59. package/vitest.config.ts +42 -0
  60. package/wrangler.jsonc +36 -0
  61. package/.turbo/turbo-build.log +0 -5
  62. package/LICENSE +0 -21
  63. package/dist/features/define.d.ts +0 -63
  64. package/dist/features/define.d.ts.map +0 -1
  65. package/dist/features/define.js +0 -72
  66. package/dist/features/define.js.map +0 -1
  67. package/dist/features/flags.d.ts +0 -98
  68. package/dist/features/flags.d.ts.map +0 -1
  69. package/dist/features/flags.js +0 -145
  70. package/dist/features/flags.js.map +0 -1
  71. package/dist/features/toggles.d.ts +0 -75
  72. package/dist/features/toggles.d.ts.map +0 -1
  73. package/dist/features/toggles.js +0 -107
  74. package/dist/features/toggles.js.map +0 -1
  75. package/dist/tiers/define.d.ts +0 -63
  76. package/dist/tiers/define.d.ts.map +0 -1
  77. package/dist/tiers/define.js +0 -78
  78. package/dist/tiers/define.js.map +0 -1
  79. package/dist/tiers/entitlements.d.ts +0 -94
  80. package/dist/tiers/entitlements.d.ts.map +0 -1
  81. package/dist/tiers/entitlements.js +0 -94
  82. package/dist/tiers/entitlements.js.map +0 -1
  83. package/src/api.js +0 -128
  84. package/src/app.js +0 -106
  85. package/src/content.js +0 -77
  86. package/src/data.js +0 -106
  87. package/src/dataset.js +0 -49
  88. package/src/entities/ai.js +0 -858
  89. package/src/entities/content.js +0 -783
  90. package/src/entities/index.js +0 -88
  91. package/src/entities/interfaces.js +0 -929
  92. package/src/entities/lifecycle.js +0 -803
  93. package/src/entities/products.js +0 -797
  94. package/src/entities/web.js +0 -657
  95. package/src/features/define.ts +0 -130
  96. package/src/features/flags.ts +0 -247
  97. package/src/features/toggles.ts +0 -189
  98. package/src/index.js +0 -35
  99. package/src/mcp.js +0 -139
  100. package/src/pricing/billing.ts +0 -386
  101. package/src/pricing/plans.ts +0 -214
  102. package/src/product.js +0 -53
  103. package/src/registry.js +0 -31
  104. package/src/sdk.js +0 -127
  105. package/src/site.js +0 -112
  106. package/src/tiers/define.ts +0 -137
  107. package/src/tiers/entitlements.ts +0 -201
  108. package/src/types.js +0 -4
  109. package/test/analytics/events.test.ts +0 -319
  110. package/test/analytics/experiments.test.ts +0 -327
  111. package/test/features/define.test.ts +0 -187
  112. package/test/features/flags.test.ts +0 -259
  113. package/test/features/toggles.test.ts +0 -178
  114. package/test/lifecycle/stages.test.ts +0 -233
  115. package/test/lifecycle/transitions.test.ts +0 -207
  116. package/test/onboarding/flows.test.ts +0 -307
  117. package/test/pricing/billing.test.ts +0 -287
  118. package/test/pricing/plans.test.ts +0 -307
  119. package/test/roadmap/milestones.test.ts +0 -231
  120. package/test/roadmap/priorities.test.ts +0 -239
  121. package/test/tiers/define.test.ts +0 -192
  122. package/test/tiers/entitlements.test.ts +0 -220
@@ -1,287 +0,0 @@
1
- /**
2
- * Tests for Billing functionality
3
- * Phase 1: RED - These tests should FAIL initially
4
- */
5
-
6
- import { describe, it, expect, beforeEach } from 'vitest'
7
- import {
8
- BillingService,
9
- createBillingService,
10
- Subscription,
11
- Invoice,
12
- PaymentMethod,
13
- BillingEvent,
14
- } from '../../src/pricing/billing.js'
15
-
16
- describe('Billing', () => {
17
- describe('BillingService', () => {
18
- let billing: BillingService
19
-
20
- beforeEach(() => {
21
- billing = createBillingService()
22
- })
23
-
24
- describe('Subscriptions', () => {
25
- it('creates a new subscription', () => {
26
- const sub = billing.createSubscription({
27
- customerId: 'cust-123',
28
- planId: 'pro-monthly',
29
- startDate: new Date('2024-01-01'),
30
- })
31
-
32
- expect(sub.id).toBeDefined()
33
- expect(sub.customerId).toBe('cust-123')
34
- expect(sub.planId).toBe('pro-monthly')
35
- expect(sub.status).toBe('active')
36
- })
37
-
38
- it('creates subscription with trial', () => {
39
- const sub = billing.createSubscription({
40
- customerId: 'cust-456',
41
- planId: 'pro-monthly',
42
- startDate: new Date('2024-01-01'),
43
- trialDays: 14,
44
- })
45
-
46
- expect(sub.status).toBe('trialing')
47
- expect(sub.trialEnd).toBeDefined()
48
- })
49
-
50
- it('cancels subscription', () => {
51
- const sub = billing.createSubscription({
52
- customerId: 'cust-789',
53
- planId: 'pro-monthly',
54
- startDate: new Date('2024-01-01'),
55
- })
56
-
57
- const canceled = billing.cancelSubscription(sub.id, { immediate: false })
58
- expect(canceled.status).toBe('active')
59
- expect(canceled.cancelAtPeriodEnd).toBe(true)
60
- })
61
-
62
- it('cancels subscription immediately', () => {
63
- const sub = billing.createSubscription({
64
- customerId: 'cust-101',
65
- planId: 'pro-monthly',
66
- startDate: new Date('2024-01-01'),
67
- })
68
-
69
- const canceled = billing.cancelSubscription(sub.id, { immediate: true })
70
- expect(canceled.status).toBe('canceled')
71
- })
72
-
73
- it('upgrades subscription', () => {
74
- const sub = billing.createSubscription({
75
- customerId: 'cust-102',
76
- planId: 'pro-monthly',
77
- startDate: new Date('2024-01-01'),
78
- })
79
-
80
- const upgraded = billing.changeSubscription(sub.id, {
81
- newPlanId: 'enterprise-monthly',
82
- prorate: true,
83
- })
84
-
85
- expect(upgraded.planId).toBe('enterprise-monthly')
86
- })
87
-
88
- it('downgrades subscription at period end', () => {
89
- const sub = billing.createSubscription({
90
- customerId: 'cust-103',
91
- planId: 'enterprise-monthly',
92
- startDate: new Date('2024-01-01'),
93
- })
94
-
95
- const downgraded = billing.changeSubscription(sub.id, {
96
- newPlanId: 'pro-monthly',
97
- prorate: false,
98
- })
99
-
100
- expect(downgraded.scheduledPlanId).toBe('pro-monthly')
101
- })
102
-
103
- it('retrieves subscription by customer', () => {
104
- billing.createSubscription({
105
- customerId: 'cust-200',
106
- planId: 'pro-monthly',
107
- startDate: new Date('2024-01-01'),
108
- })
109
-
110
- const subs = billing.getSubscriptionsByCustomer('cust-200')
111
- expect(subs).toHaveLength(1)
112
- })
113
- })
114
-
115
- describe('Invoices', () => {
116
- it('generates invoice for subscription', () => {
117
- const sub = billing.createSubscription({
118
- customerId: 'cust-300',
119
- planId: 'pro-monthly',
120
- startDate: new Date('2024-01-01'),
121
- })
122
-
123
- const invoice = billing.generateInvoice(sub.id)
124
- expect(invoice.subscriptionId).toBe(sub.id)
125
- expect(invoice.status).toBe('draft')
126
- })
127
-
128
- it('calculates invoice total', () => {
129
- const sub = billing.createSubscription({
130
- customerId: 'cust-301',
131
- planId: 'pro-monthly',
132
- startDate: new Date('2024-01-01'),
133
- })
134
-
135
- const invoice = billing.generateInvoice(sub.id)
136
- expect(invoice.total).toBeGreaterThan(0)
137
- })
138
-
139
- it('applies discount to invoice', () => {
140
- const sub = billing.createSubscription({
141
- customerId: 'cust-302',
142
- planId: 'pro-monthly',
143
- startDate: new Date('2024-01-01'),
144
- })
145
-
146
- const invoice = billing.generateInvoice(sub.id, {
147
- couponCode: 'SAVE20',
148
- })
149
-
150
- expect(invoice.discountAmount).toBeGreaterThan(0)
151
- expect(invoice.total).toBeLessThan(invoice.subtotal)
152
- })
153
-
154
- it('adds usage charges to invoice', () => {
155
- const sub = billing.createSubscription({
156
- customerId: 'cust-303',
157
- planId: 'metered',
158
- startDate: new Date('2024-01-01'),
159
- })
160
-
161
- billing.recordUsage(sub.id, {
162
- metric: 'api-calls',
163
- quantity: 15000,
164
- timestamp: new Date(),
165
- })
166
-
167
- const invoice = billing.generateInvoice(sub.id)
168
- expect(invoice.usageCharges).toBeDefined()
169
- })
170
-
171
- it('marks invoice as paid', () => {
172
- const sub = billing.createSubscription({
173
- customerId: 'cust-304',
174
- planId: 'pro-monthly',
175
- startDate: new Date('2024-01-01'),
176
- })
177
-
178
- const invoice = billing.generateInvoice(sub.id)
179
- const paid = billing.markInvoicePaid(invoice.id, {
180
- paymentMethodId: 'pm-123',
181
- paidAt: new Date(),
182
- })
183
-
184
- expect(paid.status).toBe('paid')
185
- expect(paid.paidAt).toBeDefined()
186
- })
187
-
188
- it('retrieves invoices by customer', () => {
189
- const sub = billing.createSubscription({
190
- customerId: 'cust-305',
191
- planId: 'pro-monthly',
192
- startDate: new Date('2024-01-01'),
193
- })
194
-
195
- billing.generateInvoice(sub.id)
196
- billing.generateInvoice(sub.id)
197
-
198
- const invoices = billing.getInvoicesByCustomer('cust-305')
199
- expect(invoices.length).toBeGreaterThanOrEqual(2)
200
- })
201
- })
202
-
203
- describe('Payment Methods', () => {
204
- it('adds payment method', () => {
205
- const pm = billing.addPaymentMethod({
206
- customerId: 'cust-400',
207
- type: 'card',
208
- details: {
209
- last4: '4242',
210
- brand: 'visa',
211
- expMonth: 12,
212
- expYear: 2025,
213
- },
214
- })
215
-
216
- expect(pm.id).toBeDefined()
217
- expect(pm.type).toBe('card')
218
- })
219
-
220
- it('sets default payment method', () => {
221
- const pm1 = billing.addPaymentMethod({
222
- customerId: 'cust-401',
223
- type: 'card',
224
- details: { last4: '4242', brand: 'visa', expMonth: 12, expYear: 2025 },
225
- })
226
-
227
- const pm2 = billing.addPaymentMethod({
228
- customerId: 'cust-401',
229
- type: 'card',
230
- details: { last4: '5555', brand: 'mastercard', expMonth: 6, expYear: 2026 },
231
- })
232
-
233
- billing.setDefaultPaymentMethod('cust-401', pm2.id)
234
- const defaultPm = billing.getDefaultPaymentMethod('cust-401')
235
- expect(defaultPm?.id).toBe(pm2.id)
236
- })
237
-
238
- it('removes payment method', () => {
239
- const pm = billing.addPaymentMethod({
240
- customerId: 'cust-402',
241
- type: 'card',
242
- details: { last4: '4242', brand: 'visa', expMonth: 12, expYear: 2025 },
243
- })
244
-
245
- billing.removePaymentMethod(pm.id)
246
- const methods = billing.getPaymentMethods('cust-402')
247
- expect(methods).toHaveLength(0)
248
- })
249
- })
250
-
251
- describe('Events', () => {
252
- it('emits subscription created event', () => {
253
- const events: BillingEvent[] = []
254
- billing.on('subscription.created', (e) => events.push(e))
255
-
256
- billing.createSubscription({
257
- customerId: 'cust-500',
258
- planId: 'pro-monthly',
259
- startDate: new Date(),
260
- })
261
-
262
- expect(events).toHaveLength(1)
263
- expect(events[0].type).toBe('subscription.created')
264
- })
265
-
266
- it('emits invoice paid event', () => {
267
- const events: BillingEvent[] = []
268
- billing.on('invoice.paid', (e) => events.push(e))
269
-
270
- const sub = billing.createSubscription({
271
- customerId: 'cust-501',
272
- planId: 'pro-monthly',
273
- startDate: new Date(),
274
- })
275
-
276
- const invoice = billing.generateInvoice(sub.id)
277
- billing.markInvoicePaid(invoice.id, {
278
- paymentMethodId: 'pm-123',
279
- paidAt: new Date(),
280
- })
281
-
282
- expect(events).toHaveLength(1)
283
- expect(events[0].type).toBe('invoice.paid')
284
- })
285
- })
286
- })
287
- })
@@ -1,307 +0,0 @@
1
- /**
2
- * Tests for Pricing Plans
3
- * Phase 1: RED - These tests should FAIL initially
4
- */
5
-
6
- import { describe, it, expect } from 'vitest'
7
- import {
8
- PricingPlan,
9
- createPricingPlan,
10
- PlanRegistry,
11
- createPlanRegistry,
12
- BillingInterval,
13
- Currency,
14
- } from '../../src/pricing/plans.js'
15
-
16
- describe('Pricing Plans', () => {
17
- describe('PricingPlan()', () => {
18
- it('creates a monthly plan', () => {
19
- const plan = PricingPlan({
20
- id: 'pro-monthly',
21
- name: 'Pro Monthly',
22
- tierId: 'pro',
23
- price: 29,
24
- currency: 'USD',
25
- interval: 'monthly',
26
- })
27
-
28
- expect(plan.id).toBe('pro-monthly')
29
- expect(plan.price).toBe(29)
30
- expect(plan.currency).toBe('USD')
31
- expect(plan.interval).toBe('monthly')
32
- })
33
-
34
- it('creates a yearly plan with discount', () => {
35
- const plan = PricingPlan({
36
- id: 'pro-yearly',
37
- name: 'Pro Yearly',
38
- tierId: 'pro',
39
- price: 290,
40
- currency: 'USD',
41
- interval: 'yearly',
42
- discount: {
43
- percentage: 17,
44
- monthlyEquivalent: 24.17,
45
- },
46
- })
47
-
48
- expect(plan.interval).toBe('yearly')
49
- expect(plan.discount?.percentage).toBe(17)
50
- })
51
-
52
- it('creates a free plan', () => {
53
- const plan = PricingPlan({
54
- id: 'free',
55
- name: 'Free',
56
- tierId: 'free',
57
- price: 0,
58
- currency: 'USD',
59
- interval: 'monthly',
60
- })
61
-
62
- expect(plan.price).toBe(0)
63
- })
64
-
65
- it('supports custom billing cycles', () => {
66
- const plan = PricingPlan({
67
- id: 'quarterly',
68
- name: 'Quarterly Plan',
69
- tierId: 'pro',
70
- price: 75,
71
- currency: 'USD',
72
- interval: 'custom',
73
- intervalMonths: 3,
74
- })
75
-
76
- expect(plan.interval).toBe('custom')
77
- expect(plan.intervalMonths).toBe(3)
78
- })
79
-
80
- it('supports trial periods', () => {
81
- const plan = PricingPlan({
82
- id: 'with-trial',
83
- name: 'Pro with Trial',
84
- tierId: 'pro',
85
- price: 29,
86
- currency: 'USD',
87
- interval: 'monthly',
88
- trial: {
89
- days: 14,
90
- requiresPaymentMethod: false,
91
- },
92
- })
93
-
94
- expect(plan.trial?.days).toBe(14)
95
- expect(plan.trial?.requiresPaymentMethod).toBe(false)
96
- })
97
-
98
- it('supports multiple currencies', () => {
99
- const plan = PricingPlan({
100
- id: 'pro-eur',
101
- name: 'Pro EUR',
102
- tierId: 'pro',
103
- price: 27,
104
- currency: 'EUR',
105
- interval: 'monthly',
106
- })
107
-
108
- expect(plan.currency).toBe('EUR')
109
- })
110
-
111
- it('supports usage-based pricing', () => {
112
- const plan = PricingPlan({
113
- id: 'metered',
114
- name: 'Usage Based',
115
- tierId: 'pro',
116
- price: 0,
117
- currency: 'USD',
118
- interval: 'monthly',
119
- usageBased: {
120
- metric: 'api-calls',
121
- unitPrice: 0.001,
122
- includedUnits: 10000,
123
- },
124
- })
125
-
126
- expect(plan.usageBased?.metric).toBe('api-calls')
127
- expect(plan.usageBased?.unitPrice).toBe(0.001)
128
- })
129
-
130
- it('supports addons', () => {
131
- const plan = PricingPlan({
132
- id: 'with-addons',
133
- name: 'Customizable',
134
- tierId: 'pro',
135
- price: 29,
136
- currency: 'USD',
137
- interval: 'monthly',
138
- addons: [
139
- { id: 'extra-storage', price: 5 },
140
- { id: 'priority-support', price: 10 },
141
- ],
142
- })
143
-
144
- expect(plan.addons).toHaveLength(2)
145
- })
146
- })
147
-
148
- describe('createPricingPlan()', () => {
149
- it('validates price is non-negative', () => {
150
- expect(() =>
151
- createPricingPlan({
152
- id: 'invalid',
153
- name: 'Invalid',
154
- tierId: 'pro',
155
- price: -10,
156
- currency: 'USD',
157
- interval: 'monthly',
158
- })
159
- ).toThrow('Price must be non-negative')
160
- })
161
-
162
- it('validates interval months for custom interval', () => {
163
- expect(() =>
164
- createPricingPlan({
165
- id: 'invalid',
166
- name: 'Invalid',
167
- tierId: 'pro',
168
- price: 50,
169
- currency: 'USD',
170
- interval: 'custom',
171
- // Missing intervalMonths
172
- })
173
- ).toThrow('Custom interval requires intervalMonths')
174
- })
175
- })
176
-
177
- describe('PlanRegistry', () => {
178
- it('registers and retrieves plans', () => {
179
- const registry = createPlanRegistry()
180
-
181
- const plan = PricingPlan({
182
- id: 'basic',
183
- name: 'Basic',
184
- tierId: 'basic',
185
- price: 9,
186
- currency: 'USD',
187
- interval: 'monthly',
188
- })
189
-
190
- registry.register(plan)
191
- expect(registry.get('basic')).toEqual(plan)
192
- })
193
-
194
- it('lists plans by tier', () => {
195
- const registry = createPlanRegistry()
196
-
197
- registry.register(
198
- PricingPlan({
199
- id: 'pro-monthly',
200
- name: 'Pro Monthly',
201
- tierId: 'pro',
202
- price: 29,
203
- currency: 'USD',
204
- interval: 'monthly',
205
- })
206
- )
207
- registry.register(
208
- PricingPlan({
209
- id: 'pro-yearly',
210
- name: 'Pro Yearly',
211
- tierId: 'pro',
212
- price: 290,
213
- currency: 'USD',
214
- interval: 'yearly',
215
- })
216
- )
217
- registry.register(
218
- PricingPlan({
219
- id: 'free',
220
- name: 'Free',
221
- tierId: 'free',
222
- price: 0,
223
- currency: 'USD',
224
- interval: 'monthly',
225
- })
226
- )
227
-
228
- const proPlans = registry.listByTier('pro')
229
- expect(proPlans).toHaveLength(2)
230
- })
231
-
232
- it('lists plans by interval', () => {
233
- const registry = createPlanRegistry()
234
-
235
- registry.register(
236
- PricingPlan({
237
- id: 'p1',
238
- name: 'P1',
239
- tierId: 'pro',
240
- price: 29,
241
- currency: 'USD',
242
- interval: 'monthly',
243
- })
244
- )
245
- registry.register(
246
- PricingPlan({
247
- id: 'p2',
248
- name: 'P2',
249
- tierId: 'pro',
250
- price: 290,
251
- currency: 'USD',
252
- interval: 'yearly',
253
- })
254
- )
255
-
256
- const monthly = registry.listByInterval('monthly')
257
- expect(monthly).toHaveLength(1)
258
- })
259
-
260
- it('calculates monthly equivalent price', () => {
261
- const registry = createPlanRegistry()
262
-
263
- registry.register(
264
- PricingPlan({
265
- id: 'yearly',
266
- name: 'Yearly',
267
- tierId: 'pro',
268
- price: 240,
269
- currency: 'USD',
270
- interval: 'yearly',
271
- })
272
- )
273
-
274
- const monthly = registry.getMonthlyEquivalent('yearly')
275
- expect(monthly).toBe(20)
276
- })
277
-
278
- it('compares plan pricing', () => {
279
- const registry = createPlanRegistry()
280
-
281
- registry.register(
282
- PricingPlan({
283
- id: 'monthly',
284
- name: 'Monthly',
285
- tierId: 'pro',
286
- price: 29,
287
- currency: 'USD',
288
- interval: 'monthly',
289
- })
290
- )
291
- registry.register(
292
- PricingPlan({
293
- id: 'yearly',
294
- name: 'Yearly',
295
- tierId: 'pro',
296
- price: 290,
297
- currency: 'USD',
298
- interval: 'yearly',
299
- })
300
- )
301
-
302
- const savings = registry.calculateSavings('monthly', 'yearly')
303
- expect(savings.percentage).toBeCloseTo(17, 0)
304
- expect(savings.amount).toBeCloseTo(58, 0)
305
- })
306
- })
307
- })