digital-products 2.1.3 → 2.4.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/.turbo/turbo-build.log +4 -5
  2. package/CHANGELOG.md +17 -0
  3. package/README.md +2 -0
  4. package/dist/api.js +7 -7
  5. package/dist/api.js.map +1 -1
  6. package/dist/app.js +6 -6
  7. package/dist/app.js.map +1 -1
  8. package/dist/client.d.ts +157 -0
  9. package/dist/client.d.ts.map +1 -0
  10. package/dist/client.js +69 -0
  11. package/dist/client.js.map +1 -0
  12. package/dist/content.js +7 -7
  13. package/dist/content.js.map +1 -1
  14. package/dist/data.d.ts.map +1 -1
  15. package/dist/data.js +6 -6
  16. package/dist/data.js.map +1 -1
  17. package/dist/dataset.js +5 -5
  18. package/dist/dataset.js.map +1 -1
  19. package/dist/index.d.ts +92 -13
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +139 -15
  22. package/dist/index.js.map +1 -1
  23. package/dist/mcp.d.ts +1 -1
  24. package/dist/mcp.d.ts.map +1 -1
  25. package/dist/mcp.js +17 -10
  26. package/dist/mcp.js.map +1 -1
  27. package/dist/product.js +2 -2
  28. package/dist/product.js.map +1 -1
  29. package/dist/sdk.d.ts.map +1 -1
  30. package/dist/sdk.js +52 -16
  31. package/dist/sdk.js.map +1 -1
  32. package/dist/site.d.ts.map +1 -1
  33. package/dist/site.js +12 -8
  34. package/dist/site.js.map +1 -1
  35. package/dist/types.d.ts +830 -12
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/types.js +495 -2
  38. package/dist/types.js.map +1 -1
  39. package/dist/worker.d.ts +205 -0
  40. package/dist/worker.d.ts.map +1 -0
  41. package/dist/worker.js +356 -0
  42. package/dist/worker.js.map +1 -0
  43. package/package.json +29 -13
  44. package/src/api.ts +7 -7
  45. package/src/app.ts +6 -6
  46. package/src/client.ts +192 -0
  47. package/src/content.ts +7 -7
  48. package/src/data.ts +12 -7
  49. package/src/dataset.ts +5 -5
  50. package/src/index.ts +151 -15
  51. package/src/mcp.ts +18 -11
  52. package/src/product.ts +2 -2
  53. package/src/sdk.ts +54 -15
  54. package/src/site.ts +12 -8
  55. package/src/types.ts +821 -12
  56. package/src/worker.ts +525 -0
  57. package/test/product.test.ts +53 -198
  58. package/test/unified-types.test.ts +589 -0
  59. package/test/worker.test.ts +912 -0
  60. package/vitest.config.ts +42 -0
  61. package/wrangler.jsonc +36 -0
  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,214 +0,0 @@
1
- /**
2
- * Pricing Plans
3
- * Product pricing and billing plans
4
- */
5
-
6
- /**
7
- * Billing interval
8
- */
9
- export type BillingInterval = 'monthly' | 'yearly' | 'custom'
10
-
11
- /**
12
- * Currency type
13
- */
14
- export type Currency = 'USD' | 'EUR' | 'GBP' | 'CAD' | 'AUD' | 'JPY' | string
15
-
16
- /**
17
- * Plan discount
18
- */
19
- export interface PlanDiscount {
20
- percentage: number
21
- monthlyEquivalent: number
22
- }
23
-
24
- /**
25
- * Trial configuration
26
- */
27
- export interface TrialConfig {
28
- days: number
29
- requiresPaymentMethod: boolean
30
- }
31
-
32
- /**
33
- * Usage-based pricing
34
- */
35
- export interface UsageBasedPricing {
36
- metric: string
37
- unitPrice: number
38
- includedUnits: number
39
- }
40
-
41
- /**
42
- * Plan addon
43
- */
44
- export interface PlanAddon {
45
- id: string
46
- price: number
47
- name?: string
48
- }
49
-
50
- /**
51
- * Pricing plan definition
52
- */
53
- export interface PricingPlanDefinition {
54
- /** Unique identifier */
55
- id: string
56
- /** Human-readable name */
57
- name: string
58
- /** Associated tier ID */
59
- tierId: string
60
- /** Price */
61
- price: number
62
- /** Currency */
63
- currency: Currency
64
- /** Billing interval */
65
- interval: BillingInterval
66
- /** Custom interval in months */
67
- intervalMonths?: number
68
- /** Discount info */
69
- discount?: PlanDiscount
70
- /** Trial configuration */
71
- trial?: TrialConfig
72
- /** Usage-based pricing */
73
- usageBased?: UsageBasedPricing
74
- /** Available addons */
75
- addons?: PlanAddon[]
76
- /** Description */
77
- description?: string
78
- /** Metadata */
79
- metadata?: Record<string, unknown>
80
- }
81
-
82
- /**
83
- * Create a pricing plan
84
- */
85
- export function PricingPlan(config: PricingPlanDefinition): PricingPlanDefinition {
86
- return {
87
- id: config.id,
88
- name: config.name,
89
- tierId: config.tierId,
90
- price: config.price,
91
- currency: config.currency,
92
- interval: config.interval,
93
- intervalMonths: config.intervalMonths,
94
- discount: config.discount,
95
- trial: config.trial,
96
- usageBased: config.usageBased,
97
- addons: config.addons,
98
- description: config.description,
99
- metadata: config.metadata,
100
- }
101
- }
102
-
103
- /**
104
- * Create and validate a pricing plan
105
- */
106
- export function createPricingPlan(config: PricingPlanDefinition): PricingPlanDefinition {
107
- if (config.price < 0) {
108
- throw new Error('Price must be non-negative')
109
- }
110
-
111
- if (config.interval === 'custom' && !config.intervalMonths) {
112
- throw new Error('Custom interval requires intervalMonths')
113
- }
114
-
115
- return PricingPlan(config)
116
- }
117
-
118
- /**
119
- * Savings calculation result
120
- */
121
- export interface SavingsResult {
122
- percentage: number
123
- amount: number
124
- }
125
-
126
- /**
127
- * Plan registry interface
128
- */
129
- export interface PlanRegistry {
130
- /** Register a plan */
131
- register(plan: PricingPlanDefinition): void
132
- /** Get a plan by ID */
133
- get(id: string): PricingPlanDefinition | undefined
134
- /** List all plans */
135
- list(): PricingPlanDefinition[]
136
- /** List plans by tier */
137
- listByTier(tierId: string): PricingPlanDefinition[]
138
- /** List plans by interval */
139
- listByInterval(interval: BillingInterval): PricingPlanDefinition[]
140
- /** Get monthly equivalent price */
141
- getMonthlyEquivalent(planId: string): number
142
- /** Calculate savings between plans */
143
- calculateSavings(fromPlanId: string, toPlanId: string): SavingsResult
144
- /** Clear registry */
145
- clear(): void
146
- }
147
-
148
- /**
149
- * Create a plan registry
150
- */
151
- export function createPlanRegistry(): PlanRegistry {
152
- const plans = new Map<string, PricingPlanDefinition>()
153
-
154
- const getMonths = (plan: PricingPlanDefinition): number => {
155
- if (plan.interval === 'monthly') return 1
156
- if (plan.interval === 'yearly') return 12
157
- return plan.intervalMonths ?? 1
158
- }
159
-
160
- return {
161
- register(plan: PricingPlanDefinition): void {
162
- plans.set(plan.id, plan)
163
- },
164
-
165
- get(id: string): PricingPlanDefinition | undefined {
166
- return plans.get(id)
167
- },
168
-
169
- list(): PricingPlanDefinition[] {
170
- return Array.from(plans.values())
171
- },
172
-
173
- listByTier(tierId: string): PricingPlanDefinition[] {
174
- return Array.from(plans.values()).filter((p) => p.tierId === tierId)
175
- },
176
-
177
- listByInterval(interval: BillingInterval): PricingPlanDefinition[] {
178
- return Array.from(plans.values()).filter((p) => p.interval === interval)
179
- },
180
-
181
- getMonthlyEquivalent(planId: string): number {
182
- const plan = plans.get(planId)
183
- if (!plan) return 0
184
-
185
- const months = getMonths(plan)
186
- return plan.price / months
187
- },
188
-
189
- calculateSavings(fromPlanId: string, toPlanId: string): SavingsResult {
190
- const fromPlan = plans.get(fromPlanId)
191
- const toPlan = plans.get(toPlanId)
192
-
193
- if (!fromPlan || !toPlan) {
194
- return { percentage: 0, amount: 0 }
195
- }
196
-
197
- const fromMonthly = fromPlan.price / getMonths(fromPlan)
198
- const toMonthly = toPlan.price / getMonths(toPlan)
199
-
200
- // Annualized comparison
201
- const fromYearly = fromMonthly * 12
202
- const toYearly = toMonthly * 12
203
-
204
- const amount = fromYearly - toYearly
205
- const percentage = (amount / fromYearly) * 100
206
-
207
- return { percentage, amount }
208
- },
209
-
210
- clear(): void {
211
- plans.clear()
212
- },
213
- }
214
- }
package/src/product.js DELETED
@@ -1,53 +0,0 @@
1
- /**
2
- * Generic Product() constructor
3
- */
4
- import { registry } from './registry.js';
5
- /**
6
- * Create a generic digital product definition
7
- *
8
- * @example
9
- * ```ts
10
- * const product = Product({
11
- * id: 'my-product',
12
- * name: 'My Product',
13
- * description: 'A digital product',
14
- * version: '1.0.0',
15
- * })
16
- * ```
17
- */
18
- export function Product(config) {
19
- const product = {
20
- id: config.id,
21
- name: config.name,
22
- description: config.description,
23
- version: config.version,
24
- metadata: config.metadata,
25
- tags: config.tags,
26
- status: config.status || 'active',
27
- };
28
- return product;
29
- }
30
- /**
31
- * Create and register a product in one step
32
- *
33
- * @example
34
- * ```ts
35
- * const product = createProduct({
36
- * id: 'my-product',
37
- * name: 'My Product',
38
- * description: 'A digital product',
39
- * version: '1.0.0',
40
- * })
41
- * ```
42
- */
43
- export function createProduct(config) {
44
- const product = Product(config);
45
- return product;
46
- }
47
- /**
48
- * Create and register any product definition
49
- */
50
- export function registerProduct(product) {
51
- registry.register(product);
52
- return product;
53
- }
package/src/registry.js DELETED
@@ -1,31 +0,0 @@
1
- /**
2
- * Product registry implementation
3
- */
4
- /**
5
- * In-memory product registry
6
- */
7
- class InMemoryProductRegistry {
8
- products = new Map();
9
- register(product) {
10
- this.products.set(product.id, product);
11
- }
12
- get(id) {
13
- return this.products.get(id);
14
- }
15
- list() {
16
- return Array.from(this.products.values());
17
- }
18
- listByType(type) {
19
- return this.list().filter((p) => p.type === type);
20
- }
21
- remove(id) {
22
- return this.products.delete(id);
23
- }
24
- clear() {
25
- this.products.clear();
26
- }
27
- }
28
- /**
29
- * Global product registry instance
30
- */
31
- export const registry = new InMemoryProductRegistry();
package/src/sdk.js DELETED
@@ -1,127 +0,0 @@
1
- /**
2
- * SDK() - Define a software development kit
3
- */
4
- import { registerProduct } from './product.js';
5
- /**
6
- * Create an SDK definition
7
- *
8
- * @example
9
- * ```ts
10
- * const mySDK = SDK({
11
- * id: 'my-sdk',
12
- * name: 'My SDK',
13
- * description: 'JavaScript SDK for My API',
14
- * version: '1.0.0',
15
- * language: 'typescript',
16
- * api: 'my-api',
17
- * exports: [
18
- * Export('function', 'createClient', 'Create an API client', {
19
- * parameters: {
20
- * apiKey: 'API key for authentication',
21
- * baseUrl: 'Optional base URL',
22
- * },
23
- * returns: 'API client instance',
24
- * }),
25
- * Export('class', 'APIClient', 'Main API client', {
26
- * methods: [
27
- * Export('function', 'get', 'GET request', {
28
- * parameters: { path: 'Request path' },
29
- * returns: 'Response data',
30
- * }),
31
- * Export('function', 'post', 'POST request', {
32
- * parameters: { path: 'Request path', data: 'Request body' },
33
- * returns: 'Response data',
34
- * }),
35
- * ],
36
- * }),
37
- * ],
38
- * install: 'npm install my-sdk',
39
- * examples: [
40
- * Example(
41
- * 'Basic Usage',
42
- * 'Create a client and make a request',
43
- * `import { createClient } from 'my-sdk'
44
- *
45
- * const client = createClient({ apiKey: 'YOUR_API_KEY' })
46
- * const users = await client.get('/users')
47
- * console.log(users)`
48
- * ),
49
- * ],
50
- * })
51
- * ```
52
- */
53
- export function SDK(config) {
54
- const sdk = {
55
- type: 'sdk',
56
- id: config.id,
57
- name: config.name,
58
- description: config.description,
59
- version: config.version,
60
- language: config.language,
61
- api: config.api,
62
- exports: config.exports,
63
- install: config.install,
64
- docs: config.docs,
65
- examples: config.examples,
66
- metadata: config.metadata,
67
- tags: config.tags,
68
- status: config.status || 'active',
69
- };
70
- return registerProduct(sdk);
71
- }
72
- /**
73
- * Helper to create an SDK export
74
- *
75
- * @example
76
- * ```ts
77
- * const fn = Export('function', 'calculateTotal', 'Calculate order total', {
78
- * parameters: {
79
- * items: ['Array of order items'],
80
- * taxRate: 'Tax rate (number)',
81
- * },
82
- * returns: 'Total amount (number)',
83
- * })
84
- *
85
- * const cls = Export('class', 'OrderManager', 'Manage orders', {
86
- * methods: [
87
- * Export('function', 'create', 'Create order', {
88
- * parameters: { order: 'Order data' },
89
- * returns: 'Created order',
90
- * }),
91
- * ],
92
- * })
93
- * ```
94
- */
95
- export function Export(type, name, description, options) {
96
- return {
97
- type,
98
- name,
99
- description,
100
- parameters: options?.parameters,
101
- returns: options?.returns,
102
- methods: options?.methods,
103
- };
104
- }
105
- /**
106
- * Helper to create an SDK example
107
- *
108
- * @example
109
- * ```ts
110
- * const example = Example(
111
- * 'Authentication',
112
- * 'How to authenticate with the API',
113
- * `const client = createClient({
114
- * apiKey: process.env.API_KEY,
115
- * })`,
116
- * '{ authenticated: true }'
117
- * )
118
- * ```
119
- */
120
- export function Example(title, description, code, output) {
121
- return {
122
- title,
123
- description,
124
- code,
125
- output,
126
- };
127
- }
package/src/site.js DELETED
@@ -1,112 +0,0 @@
1
- /**
2
- * Site() - Define a website
3
- */
4
- import { registerProduct } from './product.js';
5
- /**
6
- * Create a site definition
7
- *
8
- * @example
9
- * ```ts
10
- * const docsSite = Site({
11
- * id: 'docs',
12
- * name: 'Documentation Site',
13
- * description: 'Product documentation',
14
- * version: '1.0.0',
15
- * generator: 'fumadocs',
16
- * structure: {
17
- * home: '/docs/index.mdx',
18
- * docs: [
19
- * '/docs/getting-started.mdx',
20
- * '/docs/api-reference.mdx',
21
- * ],
22
- * },
23
- * navigation: [
24
- * Nav('Home', '/'),
25
- * Nav('Docs', '/docs', {
26
- * children: [
27
- * Nav('Getting Started', '/docs/getting-started'),
28
- * Nav('API Reference', '/docs/api-reference'),
29
- * ],
30
- * }),
31
- * ],
32
- * seo: {
33
- * titleTemplate: '%s | My Product',
34
- * description: 'Official documentation for My Product',
35
- * keywords: ['docs', 'api', 'reference'],
36
- * },
37
- * analytics: {
38
- * provider: 'plausible',
39
- * id: 'docs.example.com',
40
- * },
41
- * })
42
- * ```
43
- */
44
- export function Site(config) {
45
- const site = {
46
- type: 'site',
47
- id: config.id,
48
- name: config.name,
49
- description: config.description,
50
- version: config.version,
51
- generator: config.generator || 'next',
52
- structure: config.structure,
53
- navigation: config.navigation,
54
- seo: config.seo,
55
- analytics: config.analytics,
56
- deployment: config.deployment,
57
- metadata: config.metadata,
58
- tags: config.tags,
59
- status: config.status || 'active',
60
- };
61
- return registerProduct(site);
62
- }
63
- /**
64
- * Helper to create a navigation item
65
- *
66
- * @example
67
- * ```ts
68
- * const nav = Nav('Documentation', '/docs', {
69
- * icon: 'book',
70
- * children: [
71
- * Nav('Getting Started', '/docs/getting-started'),
72
- * Nav('API Reference', '/docs/api'),
73
- * ],
74
- * })
75
- * ```
76
- */
77
- export function Nav(label, href, options) {
78
- return {
79
- label,
80
- href,
81
- ...options,
82
- };
83
- }
84
- /**
85
- * Helper to configure SEO
86
- *
87
- * @example
88
- * ```ts
89
- * const seo = SEO({
90
- * titleTemplate: '%s | My Site',
91
- * description: 'My awesome site',
92
- * keywords: ['keyword1', 'keyword2'],
93
- * ogImage: '/og-image.png',
94
- * twitterCard: 'summary_large_image',
95
- * })
96
- * ```
97
- */
98
- export function SEO(config) {
99
- return config;
100
- }
101
- /**
102
- * Helper to configure analytics
103
- *
104
- * @example
105
- * ```ts
106
- * const analytics = Analytics('google', 'G-XXXXXXXXXX')
107
- * const analytics = Analytics('plausible', 'example.com')
108
- * ```
109
- */
110
- export function Analytics(provider, id, config) {
111
- return { provider, id, config };
112
- }
@@ -1,137 +0,0 @@
1
- /**
2
- * Tier Definition
3
- * Product tier primitives
4
- */
5
-
6
- /**
7
- * Tier level type
8
- */
9
- export type TierLevel = number
10
-
11
- /**
12
- * Tier definition
13
- */
14
- export interface TierDefinition {
15
- /** Unique identifier */
16
- id: string
17
- /** Human-readable name */
18
- name: string
19
- /** Tier level (higher = more features) */
20
- level: TierLevel
21
- /** Description */
22
- description?: string
23
- /** Custom pricing flag */
24
- customPricing?: boolean
25
- /** Feature limits */
26
- limits?: Record<string, number | string>
27
- /** Included features */
28
- features?: string[]
29
- /** Metadata */
30
- metadata?: Record<string, unknown>
31
- }
32
-
33
- /**
34
- * Create a tier definition
35
- */
36
- export function Tier(config: TierDefinition): TierDefinition {
37
- return {
38
- id: config.id,
39
- name: config.name,
40
- level: config.level,
41
- description: config.description,
42
- customPricing: config.customPricing,
43
- limits: config.limits,
44
- features: config.features,
45
- metadata: config.metadata,
46
- }
47
- }
48
-
49
- /**
50
- * Create and validate a tier definition
51
- */
52
- export function defineTier(config: TierDefinition): TierDefinition {
53
- if (!config.id || config.id.trim() === '') {
54
- throw new Error('Tier ID is required')
55
- }
56
-
57
- if (config.level < 0) {
58
- throw new Error('Tier level must be non-negative')
59
- }
60
-
61
- return Tier(config)
62
- }
63
-
64
- /**
65
- * Tier registry interface
66
- */
67
- export interface TierRegistry {
68
- /** Register a tier */
69
- register(tier: TierDefinition): void
70
- /** Get a tier by ID */
71
- get(id: string): TierDefinition | undefined
72
- /** List all tiers */
73
- list(): TierDefinition[]
74
- /** List tiers sorted by level */
75
- listSorted(): TierDefinition[]
76
- /** Compare two tiers */
77
- compare(tierA: string, tierB: string): number
78
- /** Check if tier has access to another tier's features */
79
- hasAccessTo(currentTier: string, requiredTier: string): boolean
80
- /** Get upgrade path from current tier */
81
- getUpgradePath(currentTier: string): string[]
82
- /** Clear registry */
83
- clear(): void
84
- }
85
-
86
- /**
87
- * Create a tier registry
88
- */
89
- export function createTierRegistry(): TierRegistry {
90
- const tiers = new Map<string, TierDefinition>()
91
-
92
- return {
93
- register(tier: TierDefinition): void {
94
- tiers.set(tier.id, tier)
95
- },
96
-
97
- get(id: string): TierDefinition | undefined {
98
- return tiers.get(id)
99
- },
100
-
101
- list(): TierDefinition[] {
102
- return Array.from(tiers.values())
103
- },
104
-
105
- listSorted(): TierDefinition[] {
106
- return Array.from(tiers.values()).sort((a, b) => a.level - b.level)
107
- },
108
-
109
- compare(tierA: string, tierB: string): number {
110
- const a = tiers.get(tierA)
111
- const b = tiers.get(tierB)
112
- if (!a || !b) return 0
113
- return a.level - b.level
114
- },
115
-
116
- hasAccessTo(currentTier: string, requiredTier: string): boolean {
117
- const current = tiers.get(currentTier)
118
- const required = tiers.get(requiredTier)
119
- if (!current || !required) return false
120
- return current.level >= required.level
121
- },
122
-
123
- getUpgradePath(currentTier: string): string[] {
124
- const current = tiers.get(currentTier)
125
- if (!current) return []
126
-
127
- return Array.from(tiers.values())
128
- .filter((t) => t.level > current.level)
129
- .sort((a, b) => a.level - b.level)
130
- .map((t) => t.id)
131
- },
132
-
133
- clear(): void {
134
- tiers.clear()
135
- },
136
- }
137
- }