atmn 1.1.25 → 2.0.1

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 (117) hide show
  1. package/README.md +120 -0
  2. package/dist/bin.js +23318 -0
  3. package/dist/index.js +2946 -0
  4. package/dist/tsconfig.tsbuildinfo +1 -1
  5. package/package.json +28 -74
  6. package/src/actions/api/callApi.ts +280 -0
  7. package/src/actions/api/registerApiCommands.ts +121 -0
  8. package/src/actions/env/fetchOrgInfo.ts +32 -0
  9. package/src/actions/env/types/orgInfo.ts +18 -0
  10. package/src/actions/env.ts +94 -0
  11. package/src/actions/init/runInit.ts +401 -0
  12. package/src/actions/login/keyless.ts +135 -0
  13. package/src/actions/login.ts +144 -0
  14. package/src/actions/pull/appendPlanVersionFixture.ts +373 -0
  15. package/src/actions/pull/applyPreview.ts +553 -0
  16. package/src/actions/pull/applySettingsPreview.ts +114 -0
  17. package/src/actions/pull/changedFixtureKeys.ts +88 -0
  18. package/src/actions/pull/listSourceFiles.ts +29 -0
  19. package/src/actions/pull/locateFixture.ts +78 -0
  20. package/src/actions/pull/resolveCollectionTarget.ts +198 -0
  21. package/src/actions/pull/rewriteConfig.ts +57 -0
  22. package/src/actions/pull/scaffoldConfig.ts +118 -0
  23. package/src/actions/pull.ts +399 -0
  24. package/src/actions/push/backfillInternalIds.ts +394 -0
  25. package/src/actions/push/deprecatedFields.ts +55 -0
  26. package/src/actions/push.ts +294 -0
  27. package/src/actions/reset/runReset.ts +58 -0
  28. package/src/actions/sandbox/createSandbox.ts +83 -0
  29. package/src/actions/sandbox/deleteSandbox.ts +91 -0
  30. package/src/actions/sandbox/listSandboxes.ts +28 -0
  31. package/src/actions/sandbox/types/sandboxClient.ts +16 -0
  32. package/src/actions/sandbox/useSandbox.ts +157 -0
  33. package/src/actions/sandbox/withSandboxScopeHint.ts +27 -0
  34. package/src/actions/skills/skills.ts +246 -0
  35. package/src/auth/announceAuthorizationUrl.ts +26 -0
  36. package/src/auth/browser/openSystemBrowser.ts +7 -0
  37. package/src/auth/browser/tryOpenBrowser.ts +17 -0
  38. package/src/auth/browser/watchLauncher.ts +46 -0
  39. package/src/auth/buildAuthorizationUrl.ts +36 -0
  40. package/src/auth/callbackPages.ts +126 -0
  41. package/src/auth/createOrgApiKeys.ts +46 -0
  42. package/src/auth/keyless.ts +119 -0
  43. package/src/auth/oauthConfig.ts +63 -0
  44. package/src/auth/runOAuthFlow.ts +230 -0
  45. package/src/auth/types/browserOpener.ts +5 -0
  46. package/src/auth/types/impersonationTokens.ts +23 -0
  47. package/src/auth/types/oauthTokens.ts +13 -0
  48. package/src/auth/types/orgApiKeys.ts +6 -0
  49. package/src/bin.ts +9 -0
  50. package/src/cli.ts +648 -0
  51. package/src/config/configPackageName.ts +9 -0
  52. package/src/config/legacyConfig.ts +25 -0
  53. package/src/config/loadConfig.ts +231 -0
  54. package/src/env/assertSandboxTarget.ts +20 -0
  55. package/src/env/loadEnv.ts +184 -0
  56. package/src/env/resolveTarget.ts +134 -0
  57. package/src/env/sandboxKeyName.ts +18 -0
  58. package/src/generated/apiRoutes.ts +3937 -0
  59. package/src/generated/client.ts +52579 -0
  60. package/src/generated/emit.ts +1188 -0
  61. package/src/generated/emitRuntime.ts +522 -0
  62. package/src/generated/features.ts +146 -0
  63. package/src/generated/labels.ts +29 -0
  64. package/src/generated/licenses.ts +292 -0
  65. package/src/generated/lintRules.ts +2247 -0
  66. package/src/generated/lintRuntime.ts +865 -0
  67. package/src/generated/plans.ts +1653 -0
  68. package/src/generated/referralPrograms.ts +22 -0
  69. package/src/generated/rewards.ts +58 -0
  70. package/src/generated/settings.ts +21 -0
  71. package/src/generated/skills.ts +305 -0
  72. package/src/generated/variants.ts +949 -0
  73. package/src/generated/wire.ts +334 -0
  74. package/src/http/autumnFetch.ts +30 -0
  75. package/src/index.ts +20 -0
  76. package/src/project/chooseConfigDir.ts +41 -0
  77. package/src/project/resolveProject.ts +115 -0
  78. package/src/project/rootMarker.ts +40 -0
  79. package/src/prompt/prompt.ts +186 -0
  80. package/src/prompt/select.ts +162 -0
  81. package/src/render/renderEnv.ts +77 -0
  82. package/src/render/renderPreview.ts +945 -0
  83. package/src/render/renderSandboxes.ts +92 -0
  84. package/src/render/stripTerminalControls.ts +19 -0
  85. package/src/repo/findRepoRoot.ts +79 -0
  86. package/src/surgery/appendPropertyEdit.ts +67 -0
  87. package/src/surgery/appendToArray.ts +87 -0
  88. package/src/surgery/appendToBinding.ts +19 -0
  89. package/src/surgery/appendToCollection.ts +40 -0
  90. package/src/surgery/appendToFixtureArray.ts +71 -0
  91. package/src/surgery/arrayBinding.ts +30 -0
  92. package/src/surgery/deleteFixtureLiteral.ts +81 -0
  93. package/src/surgery/deleteReference.ts +48 -0
  94. package/src/surgery/ensureBuilderImport.ts +65 -0
  95. package/src/surgery/findFixture.ts +238 -0
  96. package/src/surgery/fixtureEdit.ts +156 -0
  97. package/src/surgery/fixtureLocation.ts +32 -0
  98. package/src/surgery/insertCollection.ts +86 -0
  99. package/src/surgery/insertFirstProperty.ts +73 -0
  100. package/src/surgery/patchFixtureProperty.ts +152 -0
  101. package/src/surgery/patchSingletonProperty.ts +221 -0
  102. package/src/surgery/replaceFixture.ts +28 -0
  103. package/src/surgery/setFixtureProperty.ts +55 -0
  104. package/src/surgery/staticFixtureRule.ts +48 -0
  105. package/src/version.ts +5 -0
  106. package/dist/cli.js +0 -146296
  107. package/dist/compose/index.js +0 -122
  108. package/dist/src/compose/builders/builderFunctions.d.ts +0 -84
  109. package/dist/src/compose/builders/rewardFunctions.d.ts +0 -5
  110. package/dist/src/compose/builders/variantFunctions.d.ts +0 -2
  111. package/dist/src/compose/index.d.ts +0 -19
  112. package/dist/src/compose/models/featureModels.d.ts +0 -262
  113. package/dist/src/compose/models/index.d.ts +0 -3
  114. package/dist/src/compose/models/planModels.d.ts +0 -562
  115. package/dist/src/compose/models/rewardModels.d.ts +0 -52
  116. package/dist/src/compose/models/variantModels.d.ts +0 -34
  117. package/readme.md +0 -186
package/dist/index.js ADDED
@@ -0,0 +1,2946 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // src/generated/features.ts
5
+ var feature = (input) => input;
6
+ // src/generated/licenses.ts
7
+ var license = (input) => input;
8
+ // src/generated/plans.ts
9
+ var plan = (input) => input;
10
+ // src/generated/referralPrograms.ts
11
+ var referralProgram = (input) => input;
12
+ // src/generated/rewards.ts
13
+ var coupon = (input) => ({ coupon: input });
14
+ var featureGrant = (input) => ({
15
+ featureGrant: input
16
+ });
17
+ // src/generated/variants.ts
18
+ var variant = (input) => input;
19
+ // src/generated/lintRules.ts
20
+ var LINT_RULES = {
21
+ features: {
22
+ label: "feature",
23
+ idField: "featureId",
24
+ required: ["featureId", "name", "type"],
25
+ fields: {
26
+ type: {
27
+ enum: ["boolean", "metered", "credit_system", "ai_credit_system"]
28
+ },
29
+ defaultMarkup: {
30
+ minimum: -100
31
+ },
32
+ internalId: {
33
+ minLength: 1
34
+ }
35
+ },
36
+ rules: [
37
+ {
38
+ kind: "requiredWhen",
39
+ when: "type",
40
+ equals: "metered",
41
+ require: ["consumable"],
42
+ because: "Omitting it silently creates a non-consumable feature, which never resets."
43
+ },
44
+ {
45
+ kind: "unique",
46
+ field: "featureId",
47
+ because: "Two features claiming one id race to define the same row."
48
+ },
49
+ {
50
+ kind: "unique",
51
+ field: "internalId",
52
+ because: "A stable id names exactly one row; two fixtures cannot both be it."
53
+ }
54
+ ]
55
+ },
56
+ "features.creditSchema": {
57
+ variants: {
58
+ on: "tierBehavior",
59
+ byValue: {
60
+ graduated: {
61
+ required: ["meteredFeatureId", "tierBehavior", "tiers"],
62
+ fields: {
63
+ meteredFeatureId: {
64
+ minLength: 1
65
+ },
66
+ billingUnits: {
67
+ exclusiveMinimum: 0
68
+ },
69
+ tierBehavior: {
70
+ enum: ["graduated"]
71
+ },
72
+ tiers: {
73
+ minItems: 1
74
+ }
75
+ }
76
+ }
77
+ },
78
+ fallback: {
79
+ required: ["creditCost", "meteredFeatureId"],
80
+ fields: {
81
+ meteredFeatureId: {
82
+ minLength: 1
83
+ },
84
+ billingUnits: {
85
+ exclusiveMinimum: 0
86
+ },
87
+ creditCost: {
88
+ minimum: 0
89
+ }
90
+ }
91
+ }
92
+ }
93
+ },
94
+ "features.creditSchema.dimensions": {
95
+ keys: {
96
+ minLength: 1,
97
+ maxLength: 64
98
+ }
99
+ },
100
+ "features.creditSchema.dimensions.*": {
101
+ variants: {
102
+ on: "tierBehavior",
103
+ byValue: {
104
+ graduated: {
105
+ required: ["match", "tierBehavior", "tiers"],
106
+ fields: {
107
+ priority: {
108
+ minimum: -9007199254740991,
109
+ maximum: 9007199254740991
110
+ },
111
+ tierBehavior: {
112
+ enum: ["graduated"]
113
+ },
114
+ tiers: {
115
+ minItems: 1
116
+ }
117
+ }
118
+ }
119
+ },
120
+ fallback: {
121
+ required: ["creditCost", "match"],
122
+ fields: {
123
+ priority: {
124
+ minimum: -9007199254740991,
125
+ maximum: 9007199254740991
126
+ },
127
+ creditCost: {
128
+ minimum: 0
129
+ }
130
+ }
131
+ }
132
+ }
133
+ },
134
+ "features.creditSchema.dimensions.*.tiers": {
135
+ required: ["creditCost", "to"],
136
+ fields: {
137
+ to: {
138
+ exclusiveMinimum: 0
139
+ },
140
+ creditCost: {
141
+ minimum: 0
142
+ }
143
+ }
144
+ },
145
+ "features.creditSchema.multipliers": {
146
+ keys: {
147
+ minLength: 1,
148
+ maxLength: 64
149
+ }
150
+ },
151
+ "features.creditSchema.multipliers.*": {
152
+ required: ["match"],
153
+ fields: {
154
+ factor: {
155
+ exclusiveMinimum: 0
156
+ }
157
+ }
158
+ },
159
+ "features.creditSchema.tiers": {
160
+ required: ["creditCost", "to"],
161
+ fields: {
162
+ to: {
163
+ exclusiveMinimum: 0
164
+ },
165
+ creditCost: {
166
+ minimum: 0
167
+ }
168
+ }
169
+ },
170
+ "features.display": {
171
+ required: ["plural", "singular"]
172
+ },
173
+ "features.modelMarkups": {
174
+ keys: {
175
+ pattern: ".+\\/.+"
176
+ }
177
+ },
178
+ "features.modelMarkups.*": {
179
+ fields: {
180
+ markup: {
181
+ minimum: -100
182
+ },
183
+ inputCost: {
184
+ minimum: 0
185
+ },
186
+ outputCost: {
187
+ minimum: 0
188
+ }
189
+ }
190
+ },
191
+ "features.providerMarkups.*": {
192
+ required: ["markup"],
193
+ fields: {
194
+ markup: {
195
+ minimum: -100
196
+ }
197
+ }
198
+ },
199
+ plans: {
200
+ label: "plan",
201
+ idField: "planId",
202
+ required: ["planId", "versionSlug"],
203
+ fields: {
204
+ planId: {
205
+ minLength: 1,
206
+ pattern: "^[a-zA-Z0-9_-]+$"
207
+ },
208
+ newPlanId: {
209
+ minLength: 1,
210
+ pattern: "^[a-zA-Z0-9_-]+$"
211
+ },
212
+ internalId: {
213
+ minLength: 1
214
+ },
215
+ name: {
216
+ minLength: 1
217
+ },
218
+ version: {
219
+ minimum: 1,
220
+ maximum: 9007199254740991
221
+ },
222
+ versionSlug: {
223
+ minLength: 1,
224
+ pattern: "^[a-zA-Z0-9_-]+$"
225
+ },
226
+ newVersionSlug: {
227
+ minLength: 1,
228
+ pattern: "^[a-zA-Z0-9_-]+$"
229
+ },
230
+ versioning: {
231
+ enum: ["existing", "new_version", "all_versions"]
232
+ },
233
+ baseVariantId: {
234
+ minLength: 1,
235
+ pattern: "^[a-zA-Z0-9_-]+$"
236
+ }
237
+ },
238
+ rules: [
239
+ {
240
+ kind: "unique",
241
+ field: "internalId",
242
+ because: "A stable id names exactly one row; two fixtures cannot both be it."
243
+ },
244
+ {
245
+ kind: "unique",
246
+ field: "planId",
247
+ alongside: "versionSlug",
248
+ because: "A plan id plus a version slug names exactly one version."
249
+ },
250
+ {
251
+ kind: "linkedOnce",
252
+ groupBy: "planId",
253
+ namedBy: "versionSlug",
254
+ absentMeans: "v1",
255
+ collection: "variants",
256
+ identity: "variantPlanId",
257
+ pins: ["versionSlug", "version"],
258
+ because: "When versioning a base plan with variants linked, you also need to version the variant, and relink the new version to the new variant version."
259
+ },
260
+ {
261
+ kind: "exactlyOneActive",
262
+ groupBy: "planId",
263
+ field: "active",
264
+ label: "Plan",
265
+ because: "Every version of a plan lives in plans; mark the one customers can buy active: true and the rest active: false."
266
+ }
267
+ ]
268
+ },
269
+ "plans.billingControls.autoTopups": {
270
+ required: ["featureId", "quantity", "threshold"],
271
+ fields: {
272
+ quantity: {
273
+ minimum: 1
274
+ }
275
+ }
276
+ },
277
+ "plans.billingControls.autoTopups.purchaseLimit": {
278
+ required: ["interval", "limit"],
279
+ fields: {
280
+ interval: {
281
+ enum: ["hour", "day", "week", "month"]
282
+ },
283
+ intervalCount: {
284
+ minimum: 1
285
+ },
286
+ limit: {
287
+ minimum: 1
288
+ },
289
+ count: {
290
+ minimum: 0
291
+ }
292
+ }
293
+ },
294
+ "plans.billingControls.overageAllowed": {
295
+ required: ["featureId"]
296
+ },
297
+ "plans.billingControls.spendLimits": {
298
+ fields: {
299
+ limitType: {
300
+ enum: ["absolute", "usage_percentage"]
301
+ },
302
+ overageLimit: {
303
+ minimum: 0
304
+ }
305
+ }
306
+ },
307
+ "plans.billingControls.usageAlerts": {
308
+ required: ["threshold", "thresholdType"],
309
+ fields: {
310
+ threshold: {
311
+ minimum: 0
312
+ },
313
+ thresholdType: {
314
+ enum: [
315
+ "usage",
316
+ "usage_percentage",
317
+ "remaining",
318
+ "remaining_percentage"
319
+ ]
320
+ },
321
+ basis: {
322
+ enum: ["balance", "included", "recurring", "usage_limit"]
323
+ }
324
+ }
325
+ },
326
+ "plans.billingControls.usageAlerts.filter": {
327
+ required: ["properties"]
328
+ },
329
+ "plans.billingControls.usageAlerts.filter.properties": {
330
+ keys: {
331
+ minLength: 1,
332
+ maxLength: 64
333
+ }
334
+ },
335
+ "plans.billingControls.usageLimits": {
336
+ required: ["featureId", "interval", "limit"],
337
+ fields: {
338
+ limit: {
339
+ minimum: 0
340
+ },
341
+ interval: {
342
+ enum: ["day", "week", "month", "year"]
343
+ },
344
+ anchor: {
345
+ enum: ["billing_cycle", "utc"]
346
+ }
347
+ }
348
+ },
349
+ "plans.billingControls.usageLimits.filter": {
350
+ required: ["properties"]
351
+ },
352
+ "plans.billingControls.usageLimits.filter.properties": {
353
+ keys: {
354
+ minLength: 1,
355
+ maxLength: 64
356
+ }
357
+ },
358
+ "plans.freeTrial": {
359
+ required: ["durationLength"],
360
+ fields: {
361
+ durationType: {
362
+ enum: ["day", "month", "year"]
363
+ },
364
+ onEnd: {
365
+ enum: ["bill", "revert"]
366
+ }
367
+ }
368
+ },
369
+ "plans.items": {
370
+ label: "item",
371
+ idField: "featureId",
372
+ required: ["featureId"],
373
+ fields: {
374
+ included: {
375
+ maximum: 10000000000000
376
+ }
377
+ },
378
+ rules: [
379
+ {
380
+ kind: "exists",
381
+ field: "featureId",
382
+ in: "features",
383
+ matching: "featureId",
384
+ because: "A plan item meters a feature this config does not declare."
385
+ },
386
+ {
387
+ kind: "targetHas",
388
+ when: "featureOverride",
389
+ field: "featureId",
390
+ in: "features",
391
+ matching: "featureId",
392
+ target: "type",
393
+ equals: "credit_system",
394
+ because: "featureOverride is only honoured on classic credit-system features."
395
+ },
396
+ {
397
+ kind: "targetLacks",
398
+ field: "featureId",
399
+ in: "features",
400
+ matching: "featureId",
401
+ target: "archived",
402
+ label: "Feature",
403
+ parentGuard: "archived",
404
+ parentIdField: "planId",
405
+ parentLabel: "plan",
406
+ because: "An archived feature should not gain new customers through a live plan."
407
+ }
408
+ ]
409
+ },
410
+ "plans.items.expiry": {
411
+ required: ["duration", "length"],
412
+ fields: {
413
+ duration: {
414
+ enum: ["day", "week", "month", "year"]
415
+ }
416
+ }
417
+ },
418
+ "plans.items.featureOverride.creditSchema": {
419
+ variants: {
420
+ on: "tierBehavior",
421
+ byValue: {
422
+ graduated: {
423
+ required: ["meteredFeatureId", "tierBehavior", "tiers"],
424
+ fields: {
425
+ meteredFeatureId: {
426
+ minLength: 1
427
+ },
428
+ billingUnits: {
429
+ exclusiveMinimum: 0
430
+ },
431
+ tierBehavior: {
432
+ enum: ["graduated"]
433
+ },
434
+ tiers: {
435
+ minItems: 1
436
+ }
437
+ }
438
+ }
439
+ },
440
+ fallback: {
441
+ required: ["creditCost", "meteredFeatureId"],
442
+ fields: {
443
+ meteredFeatureId: {
444
+ minLength: 1
445
+ },
446
+ billingUnits: {
447
+ exclusiveMinimum: 0
448
+ },
449
+ creditCost: {
450
+ minimum: 0
451
+ }
452
+ }
453
+ }
454
+ }
455
+ },
456
+ "plans.items.featureOverride.creditSchema.dimensions": {
457
+ keys: {
458
+ minLength: 1,
459
+ maxLength: 64
460
+ }
461
+ },
462
+ "plans.items.featureOverride.creditSchema.dimensions.*": {
463
+ variants: {
464
+ on: "tierBehavior",
465
+ byValue: {
466
+ graduated: {
467
+ required: ["match", "tierBehavior", "tiers"],
468
+ fields: {
469
+ priority: {
470
+ minimum: -9007199254740991,
471
+ maximum: 9007199254740991
472
+ },
473
+ tierBehavior: {
474
+ enum: ["graduated"]
475
+ },
476
+ tiers: {
477
+ minItems: 1
478
+ }
479
+ }
480
+ }
481
+ },
482
+ fallback: {
483
+ required: ["creditCost", "match"],
484
+ fields: {
485
+ priority: {
486
+ minimum: -9007199254740991,
487
+ maximum: 9007199254740991
488
+ },
489
+ creditCost: {
490
+ minimum: 0
491
+ }
492
+ }
493
+ }
494
+ }
495
+ },
496
+ "plans.items.featureOverride.creditSchema.dimensions.*.tiers": {
497
+ required: ["creditCost", "to"],
498
+ fields: {
499
+ to: {
500
+ exclusiveMinimum: 0
501
+ },
502
+ creditCost: {
503
+ minimum: 0
504
+ }
505
+ }
506
+ },
507
+ "plans.items.featureOverride.creditSchema.multipliers": {
508
+ keys: {
509
+ minLength: 1,
510
+ maxLength: 64
511
+ }
512
+ },
513
+ "plans.items.featureOverride.creditSchema.multipliers.*": {
514
+ required: ["match"],
515
+ fields: {
516
+ factor: {
517
+ exclusiveMinimum: 0
518
+ }
519
+ }
520
+ },
521
+ "plans.items.featureOverride.creditSchema.tiers": {
522
+ required: ["creditCost", "to"],
523
+ fields: {
524
+ to: {
525
+ exclusiveMinimum: 0
526
+ },
527
+ creditCost: {
528
+ minimum: 0
529
+ }
530
+ }
531
+ },
532
+ "plans.items.featureOverride.markups": {
533
+ fields: {
534
+ defaultMarkup: {
535
+ minimum: -100
536
+ }
537
+ }
538
+ },
539
+ "plans.items.featureOverride.markups.modelMarkups": {
540
+ keys: {
541
+ pattern: ".+\\/.+"
542
+ }
543
+ },
544
+ "plans.items.featureOverride.markups.modelMarkups.*": {
545
+ fields: {
546
+ markup: {
547
+ minimum: -100
548
+ },
549
+ inputCost: {
550
+ minimum: 0
551
+ },
552
+ outputCost: {
553
+ minimum: 0
554
+ }
555
+ }
556
+ },
557
+ "plans.items.featureOverride.markups.providerMarkups.*": {
558
+ required: ["markup"],
559
+ fields: {
560
+ markup: {
561
+ minimum: -100
562
+ }
563
+ }
564
+ },
565
+ "plans.items.price": {
566
+ label: "price",
567
+ required: ["billingMethod", "interval"],
568
+ fields: {
569
+ tierBehavior: {
570
+ enum: ["graduated", "volume"]
571
+ },
572
+ interval: {
573
+ enum: ["one_off", "week", "month", "quarter", "semi_annual", "year"]
574
+ },
575
+ billingMethod: {
576
+ enum: ["prepaid", "usage_based"]
577
+ },
578
+ allocatedBilling: {
579
+ enum: ["arrear", "prorated_legacy"]
580
+ }
581
+ },
582
+ rules: [
583
+ {
584
+ kind: "valueWhen",
585
+ when: "tierBehavior",
586
+ equals: "volume",
587
+ field: "billingMethod",
588
+ mustBe: "prepaid",
589
+ because: "Volume tiers are prepaid-only."
590
+ }
591
+ ]
592
+ },
593
+ "plans.items.price.additionalCurrencies": {
594
+ required: ["amount", "currency"]
595
+ },
596
+ "plans.items.price.processors.stripe": {
597
+ required: ["priceId"]
598
+ },
599
+ "plans.items.price.tiers": {
600
+ required: ["to"]
601
+ },
602
+ "plans.items.price.tiers.additionalCurrencies": {
603
+ required: ["currency"]
604
+ },
605
+ "plans.items.proration": {
606
+ required: ["onDecrease", "onIncrease"],
607
+ fields: {
608
+ onIncrease: {
609
+ enum: [
610
+ "bill_immediately",
611
+ "prorate_immediately",
612
+ "prorate_next_cycle",
613
+ "bill_next_cycle"
614
+ ]
615
+ },
616
+ onDecrease: {
617
+ enum: [
618
+ "prorate",
619
+ "prorate_immediately",
620
+ "prorate_next_cycle",
621
+ "none",
622
+ "no_prorations"
623
+ ]
624
+ }
625
+ }
626
+ },
627
+ "plans.items.reset": {
628
+ required: ["interval"],
629
+ fields: {
630
+ interval: {
631
+ enum: [
632
+ "one_off",
633
+ "minute",
634
+ "hour",
635
+ "day",
636
+ "week",
637
+ "month",
638
+ "quarter",
639
+ "semi_annual",
640
+ "year"
641
+ ]
642
+ }
643
+ }
644
+ },
645
+ "plans.items.rollover": {
646
+ required: ["expiryDurationType"],
647
+ fields: {
648
+ expiryDurationType: {
649
+ enum: ["month", "forever"]
650
+ }
651
+ }
652
+ },
653
+ "plans.items.thresholdBilling": {
654
+ required: ["threshold"],
655
+ fields: {
656
+ threshold: {
657
+ exclusiveMinimum: 0
658
+ }
659
+ }
660
+ },
661
+ "plans.licenses": {
662
+ label: "license",
663
+ idField: "licensePlanId",
664
+ required: ["licensePlanId", "versionSlug"],
665
+ fields: {
666
+ included: {
667
+ minimum: 0,
668
+ maximum: 9007199254740991
669
+ }
670
+ }
671
+ },
672
+ "plans.licenses.customize.addItems": {
673
+ required: ["featureId"],
674
+ fields: {
675
+ included: {
676
+ maximum: 10000000000000
677
+ }
678
+ }
679
+ },
680
+ "plans.licenses.customize.addItems.expiry": {
681
+ required: ["duration", "length"],
682
+ fields: {
683
+ duration: {
684
+ enum: ["day", "week", "month", "year"]
685
+ }
686
+ }
687
+ },
688
+ "plans.licenses.customize.addItems.featureOverride.creditSchema": {
689
+ variants: {
690
+ on: "tierBehavior",
691
+ byValue: {
692
+ graduated: {
693
+ required: ["meteredFeatureId", "tierBehavior", "tiers"],
694
+ fields: {
695
+ meteredFeatureId: {
696
+ minLength: 1
697
+ },
698
+ billingUnits: {
699
+ exclusiveMinimum: 0
700
+ },
701
+ tierBehavior: {
702
+ enum: ["graduated"]
703
+ },
704
+ tiers: {
705
+ minItems: 1
706
+ }
707
+ }
708
+ }
709
+ },
710
+ fallback: {
711
+ required: ["creditCost", "meteredFeatureId"],
712
+ fields: {
713
+ meteredFeatureId: {
714
+ minLength: 1
715
+ },
716
+ billingUnits: {
717
+ exclusiveMinimum: 0
718
+ },
719
+ creditCost: {
720
+ minimum: 0
721
+ }
722
+ }
723
+ }
724
+ }
725
+ },
726
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.dimensions": {
727
+ keys: {
728
+ minLength: 1,
729
+ maxLength: 64
730
+ }
731
+ },
732
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.dimensions.*": {
733
+ variants: {
734
+ on: "tierBehavior",
735
+ byValue: {
736
+ graduated: {
737
+ required: ["match", "tierBehavior", "tiers"],
738
+ fields: {
739
+ priority: {
740
+ minimum: -9007199254740991,
741
+ maximum: 9007199254740991
742
+ },
743
+ tierBehavior: {
744
+ enum: ["graduated"]
745
+ },
746
+ tiers: {
747
+ minItems: 1
748
+ }
749
+ }
750
+ }
751
+ },
752
+ fallback: {
753
+ required: ["creditCost", "match"],
754
+ fields: {
755
+ priority: {
756
+ minimum: -9007199254740991,
757
+ maximum: 9007199254740991
758
+ },
759
+ creditCost: {
760
+ minimum: 0
761
+ }
762
+ }
763
+ }
764
+ }
765
+ },
766
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.dimensions.*.tiers": {
767
+ required: ["creditCost", "to"],
768
+ fields: {
769
+ to: {
770
+ exclusiveMinimum: 0
771
+ },
772
+ creditCost: {
773
+ minimum: 0
774
+ }
775
+ }
776
+ },
777
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.multipliers": {
778
+ keys: {
779
+ minLength: 1,
780
+ maxLength: 64
781
+ }
782
+ },
783
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.multipliers.*": {
784
+ required: ["match"],
785
+ fields: {
786
+ factor: {
787
+ exclusiveMinimum: 0
788
+ }
789
+ }
790
+ },
791
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.tiers": {
792
+ required: ["creditCost", "to"],
793
+ fields: {
794
+ to: {
795
+ exclusiveMinimum: 0
796
+ },
797
+ creditCost: {
798
+ minimum: 0
799
+ }
800
+ }
801
+ },
802
+ "plans.licenses.customize.addItems.featureOverride.markups": {
803
+ fields: {
804
+ defaultMarkup: {
805
+ minimum: -100
806
+ }
807
+ }
808
+ },
809
+ "plans.licenses.customize.addItems.featureOverride.markups.modelMarkups": {
810
+ keys: {
811
+ pattern: ".+\\/.+"
812
+ }
813
+ },
814
+ "plans.licenses.customize.addItems.featureOverride.markups.modelMarkups.*": {
815
+ fields: {
816
+ markup: {
817
+ minimum: -100
818
+ },
819
+ inputCost: {
820
+ minimum: 0
821
+ },
822
+ outputCost: {
823
+ minimum: 0
824
+ }
825
+ }
826
+ },
827
+ "plans.licenses.customize.addItems.featureOverride.markups.providerMarkups.*": {
828
+ required: ["markup"],
829
+ fields: {
830
+ markup: {
831
+ minimum: -100
832
+ }
833
+ }
834
+ },
835
+ "plans.licenses.customize.addItems.price": {
836
+ required: ["billingMethod", "interval"],
837
+ fields: {
838
+ tierBehavior: {
839
+ enum: ["graduated", "volume"]
840
+ },
841
+ interval: {
842
+ enum: ["one_off", "week", "month", "quarter", "semi_annual", "year"]
843
+ },
844
+ billingMethod: {
845
+ enum: ["prepaid", "usage_based"]
846
+ },
847
+ allocatedBilling: {
848
+ enum: ["arrear", "prorated_legacy"]
849
+ }
850
+ }
851
+ },
852
+ "plans.licenses.customize.addItems.price.additionalCurrencies": {
853
+ required: ["amount", "currency"]
854
+ },
855
+ "plans.licenses.customize.addItems.price.tiers": {
856
+ required: ["to"]
857
+ },
858
+ "plans.licenses.customize.addItems.price.tiers.additionalCurrencies": {
859
+ required: ["currency"]
860
+ },
861
+ "plans.licenses.customize.addItems.proration": {
862
+ required: ["onDecrease", "onIncrease"],
863
+ fields: {
864
+ onIncrease: {
865
+ enum: [
866
+ "bill_immediately",
867
+ "prorate_immediately",
868
+ "prorate_next_cycle",
869
+ "bill_next_cycle"
870
+ ]
871
+ },
872
+ onDecrease: {
873
+ enum: [
874
+ "prorate",
875
+ "prorate_immediately",
876
+ "prorate_next_cycle",
877
+ "none",
878
+ "no_prorations"
879
+ ]
880
+ }
881
+ }
882
+ },
883
+ "plans.licenses.customize.addItems.reset": {
884
+ required: ["interval"],
885
+ fields: {
886
+ interval: {
887
+ enum: [
888
+ "one_off",
889
+ "minute",
890
+ "hour",
891
+ "day",
892
+ "week",
893
+ "month",
894
+ "quarter",
895
+ "semi_annual",
896
+ "year"
897
+ ]
898
+ }
899
+ }
900
+ },
901
+ "plans.licenses.customize.addItems.rollover": {
902
+ required: ["expiryDurationType"],
903
+ fields: {
904
+ expiryDurationType: {
905
+ enum: ["month", "forever"]
906
+ }
907
+ }
908
+ },
909
+ "plans.licenses.customize.addItems.thresholdBilling": {
910
+ required: ["threshold"],
911
+ fields: {
912
+ threshold: {
913
+ exclusiveMinimum: 0
914
+ }
915
+ }
916
+ },
917
+ "plans.licenses.customize.price": {
918
+ required: ["amount", "interval"],
919
+ fields: {
920
+ interval: {
921
+ enum: ["one_off", "week", "month", "quarter", "semi_annual", "year"]
922
+ }
923
+ }
924
+ },
925
+ "plans.licenses.customize.price.additionalCurrencies": {
926
+ required: ["amount", "currency"]
927
+ },
928
+ "plans.licenses.customize.removeItems": {
929
+ fields: {
930
+ billingMethod: {
931
+ enum: ["prepaid", "usage_based"]
932
+ },
933
+ interval: {
934
+ enum: [
935
+ "one_off",
936
+ "week",
937
+ "month",
938
+ "quarter",
939
+ "semi_annual",
940
+ "year",
941
+ "minute",
942
+ "hour",
943
+ "day"
944
+ ]
945
+ },
946
+ intervalCount: {
947
+ minimum: -9007199254740991,
948
+ maximum: 9007199254740991,
949
+ exclusiveMinimum: 0
950
+ },
951
+ included: {
952
+ maximum: 10000000000000
953
+ }
954
+ }
955
+ },
956
+ "plans.price": {
957
+ required: ["amount", "interval"],
958
+ fields: {
959
+ interval: {
960
+ enum: ["one_off", "week", "month", "quarter", "semi_annual", "year"]
961
+ }
962
+ }
963
+ },
964
+ "plans.price.additionalCurrencies": {
965
+ required: ["amount", "currency"]
966
+ },
967
+ "plans.price.processors.stripe": {
968
+ required: ["priceId"]
969
+ },
970
+ "plans.processors.revenuecat": {
971
+ required: ["products"]
972
+ },
973
+ "plans.processors.revenuecat.products": {
974
+ required: ["productId"]
975
+ },
976
+ "plans.processors.revenuecat.products.featureQuantities": {
977
+ required: ["featureId"],
978
+ fields: {
979
+ quantity: {
980
+ minimum: 0
981
+ }
982
+ }
983
+ },
984
+ "plans.processors.stripe": {
985
+ required: ["productId"]
986
+ },
987
+ "plans.propagate.licenseParents": {
988
+ required: ["planId"],
989
+ fields: {
990
+ planId: {
991
+ minLength: 1,
992
+ pattern: "^[a-zA-Z0-9_-]+$"
993
+ },
994
+ version: {
995
+ minimum: 1,
996
+ maximum: 9007199254740991
997
+ },
998
+ versionSlug: {
999
+ minLength: 1,
1000
+ pattern: "^[a-zA-Z0-9_-]+$"
1001
+ },
1002
+ newVersionSlug: {
1003
+ minLength: 1,
1004
+ pattern: "^[a-zA-Z0-9_-]+$"
1005
+ }
1006
+ }
1007
+ },
1008
+ "plans.propagate.variants": {
1009
+ required: ["planId"],
1010
+ fields: {
1011
+ planId: {
1012
+ minLength: 1,
1013
+ pattern: "^[a-zA-Z0-9_-]+$"
1014
+ },
1015
+ version: {
1016
+ minimum: 1,
1017
+ maximum: 9007199254740991
1018
+ },
1019
+ versionSlug: {
1020
+ minLength: 1,
1021
+ pattern: "^[a-zA-Z0-9_-]+$"
1022
+ },
1023
+ newVersionSlug: {
1024
+ minLength: 1,
1025
+ pattern: "^[a-zA-Z0-9_-]+$"
1026
+ }
1027
+ }
1028
+ },
1029
+ "plans.variants": {
1030
+ label: "variant",
1031
+ idField: "variantPlanId",
1032
+ required: ["variantPlanId", "versionSlug"],
1033
+ fields: {
1034
+ variantPlanId: {
1035
+ minLength: 1,
1036
+ pattern: "^[a-zA-Z0-9_-]+$"
1037
+ },
1038
+ internalId: {
1039
+ minLength: 1
1040
+ },
1041
+ version: {
1042
+ minimum: 1,
1043
+ maximum: 9007199254740991
1044
+ },
1045
+ versionSlug: {
1046
+ minLength: 1,
1047
+ pattern: "^[a-zA-Z0-9_-]+$"
1048
+ },
1049
+ name: {
1050
+ minLength: 1
1051
+ },
1052
+ newPlanId: {
1053
+ minLength: 1,
1054
+ pattern: "^[a-zA-Z0-9_-]+$"
1055
+ },
1056
+ newVersionSlug: {
1057
+ minLength: 1,
1058
+ pattern: "^[a-zA-Z0-9_-]+$"
1059
+ },
1060
+ baseVariantId: {
1061
+ minLength: 1,
1062
+ pattern: "^[a-zA-Z0-9_-]+$"
1063
+ }
1064
+ }
1065
+ },
1066
+ "plans.variants.customize.addItems": {
1067
+ required: ["featureId"],
1068
+ fields: {
1069
+ included: {
1070
+ maximum: 10000000000000
1071
+ }
1072
+ }
1073
+ },
1074
+ "plans.variants.customize.addItems.expiry": {
1075
+ required: ["duration", "length"],
1076
+ fields: {
1077
+ duration: {
1078
+ enum: ["day", "week", "month", "year"]
1079
+ }
1080
+ }
1081
+ },
1082
+ "plans.variants.customize.addItems.featureOverride.creditSchema": {
1083
+ variants: {
1084
+ on: "tierBehavior",
1085
+ byValue: {
1086
+ graduated: {
1087
+ required: ["meteredFeatureId", "tierBehavior", "tiers"],
1088
+ fields: {
1089
+ meteredFeatureId: {
1090
+ minLength: 1
1091
+ },
1092
+ billingUnits: {
1093
+ exclusiveMinimum: 0
1094
+ },
1095
+ tierBehavior: {
1096
+ enum: ["graduated"]
1097
+ },
1098
+ tiers: {
1099
+ minItems: 1
1100
+ }
1101
+ }
1102
+ }
1103
+ },
1104
+ fallback: {
1105
+ required: ["creditCost", "meteredFeatureId"],
1106
+ fields: {
1107
+ meteredFeatureId: {
1108
+ minLength: 1
1109
+ },
1110
+ billingUnits: {
1111
+ exclusiveMinimum: 0
1112
+ },
1113
+ creditCost: {
1114
+ minimum: 0
1115
+ }
1116
+ }
1117
+ }
1118
+ }
1119
+ },
1120
+ "plans.variants.customize.addItems.featureOverride.creditSchema.dimensions": {
1121
+ keys: {
1122
+ minLength: 1,
1123
+ maxLength: 64
1124
+ }
1125
+ },
1126
+ "plans.variants.customize.addItems.featureOverride.creditSchema.dimensions.*": {
1127
+ variants: {
1128
+ on: "tierBehavior",
1129
+ byValue: {
1130
+ graduated: {
1131
+ required: ["match", "tierBehavior", "tiers"],
1132
+ fields: {
1133
+ priority: {
1134
+ minimum: -9007199254740991,
1135
+ maximum: 9007199254740991
1136
+ },
1137
+ tierBehavior: {
1138
+ enum: ["graduated"]
1139
+ },
1140
+ tiers: {
1141
+ minItems: 1
1142
+ }
1143
+ }
1144
+ }
1145
+ },
1146
+ fallback: {
1147
+ required: ["creditCost", "match"],
1148
+ fields: {
1149
+ priority: {
1150
+ minimum: -9007199254740991,
1151
+ maximum: 9007199254740991
1152
+ },
1153
+ creditCost: {
1154
+ minimum: 0
1155
+ }
1156
+ }
1157
+ }
1158
+ }
1159
+ },
1160
+ "plans.variants.customize.addItems.featureOverride.creditSchema.dimensions.*.tiers": {
1161
+ required: ["creditCost", "to"],
1162
+ fields: {
1163
+ to: {
1164
+ exclusiveMinimum: 0
1165
+ },
1166
+ creditCost: {
1167
+ minimum: 0
1168
+ }
1169
+ }
1170
+ },
1171
+ "plans.variants.customize.addItems.featureOverride.creditSchema.multipliers": {
1172
+ keys: {
1173
+ minLength: 1,
1174
+ maxLength: 64
1175
+ }
1176
+ },
1177
+ "plans.variants.customize.addItems.featureOverride.creditSchema.multipliers.*": {
1178
+ required: ["match"],
1179
+ fields: {
1180
+ factor: {
1181
+ exclusiveMinimum: 0
1182
+ }
1183
+ }
1184
+ },
1185
+ "plans.variants.customize.addItems.featureOverride.creditSchema.tiers": {
1186
+ required: ["creditCost", "to"],
1187
+ fields: {
1188
+ to: {
1189
+ exclusiveMinimum: 0
1190
+ },
1191
+ creditCost: {
1192
+ minimum: 0
1193
+ }
1194
+ }
1195
+ },
1196
+ "plans.variants.customize.addItems.featureOverride.markups": {
1197
+ fields: {
1198
+ defaultMarkup: {
1199
+ minimum: -100
1200
+ }
1201
+ }
1202
+ },
1203
+ "plans.variants.customize.addItems.featureOverride.markups.modelMarkups": {
1204
+ keys: {
1205
+ pattern: ".+\\/.+"
1206
+ }
1207
+ },
1208
+ "plans.variants.customize.addItems.featureOverride.markups.modelMarkups.*": {
1209
+ fields: {
1210
+ markup: {
1211
+ minimum: -100
1212
+ },
1213
+ inputCost: {
1214
+ minimum: 0
1215
+ },
1216
+ outputCost: {
1217
+ minimum: 0
1218
+ }
1219
+ }
1220
+ },
1221
+ "plans.variants.customize.addItems.featureOverride.markups.providerMarkups.*": {
1222
+ required: ["markup"],
1223
+ fields: {
1224
+ markup: {
1225
+ minimum: -100
1226
+ }
1227
+ }
1228
+ },
1229
+ "plans.variants.customize.addItems.price": {
1230
+ required: ["billingMethod", "interval"],
1231
+ fields: {
1232
+ tierBehavior: {
1233
+ enum: ["graduated", "volume"]
1234
+ },
1235
+ interval: {
1236
+ enum: ["one_off", "week", "month", "quarter", "semi_annual", "year"]
1237
+ },
1238
+ billingMethod: {
1239
+ enum: ["prepaid", "usage_based"]
1240
+ },
1241
+ allocatedBilling: {
1242
+ enum: ["arrear", "prorated_legacy"]
1243
+ }
1244
+ }
1245
+ },
1246
+ "plans.variants.customize.addItems.price.additionalCurrencies": {
1247
+ required: ["amount", "currency"]
1248
+ },
1249
+ "plans.variants.customize.addItems.price.tiers": {
1250
+ required: ["to"]
1251
+ },
1252
+ "plans.variants.customize.addItems.price.tiers.additionalCurrencies": {
1253
+ required: ["currency"]
1254
+ },
1255
+ "plans.variants.customize.addItems.proration": {
1256
+ required: ["onDecrease", "onIncrease"],
1257
+ fields: {
1258
+ onIncrease: {
1259
+ enum: [
1260
+ "bill_immediately",
1261
+ "prorate_immediately",
1262
+ "prorate_next_cycle",
1263
+ "bill_next_cycle"
1264
+ ]
1265
+ },
1266
+ onDecrease: {
1267
+ enum: [
1268
+ "prorate",
1269
+ "prorate_immediately",
1270
+ "prorate_next_cycle",
1271
+ "none",
1272
+ "no_prorations"
1273
+ ]
1274
+ }
1275
+ }
1276
+ },
1277
+ "plans.variants.customize.addItems.reset": {
1278
+ required: ["interval"],
1279
+ fields: {
1280
+ interval: {
1281
+ enum: [
1282
+ "one_off",
1283
+ "minute",
1284
+ "hour",
1285
+ "day",
1286
+ "week",
1287
+ "month",
1288
+ "quarter",
1289
+ "semi_annual",
1290
+ "year"
1291
+ ]
1292
+ }
1293
+ }
1294
+ },
1295
+ "plans.variants.customize.addItems.rollover": {
1296
+ required: ["expiryDurationType"],
1297
+ fields: {
1298
+ expiryDurationType: {
1299
+ enum: ["month", "forever"]
1300
+ }
1301
+ }
1302
+ },
1303
+ "plans.variants.customize.addItems.thresholdBilling": {
1304
+ required: ["threshold"],
1305
+ fields: {
1306
+ threshold: {
1307
+ exclusiveMinimum: 0
1308
+ }
1309
+ }
1310
+ },
1311
+ "plans.variants.customize.billingControls.autoTopups": {
1312
+ required: ["featureId", "quantity", "threshold"],
1313
+ fields: {
1314
+ quantity: {
1315
+ minimum: 1
1316
+ }
1317
+ }
1318
+ },
1319
+ "plans.variants.customize.billingControls.autoTopups.purchaseLimit": {
1320
+ required: ["interval", "limit"],
1321
+ fields: {
1322
+ interval: {
1323
+ enum: ["hour", "day", "week", "month"]
1324
+ },
1325
+ intervalCount: {
1326
+ minimum: 1
1327
+ },
1328
+ limit: {
1329
+ minimum: 1
1330
+ },
1331
+ count: {
1332
+ minimum: 0
1333
+ }
1334
+ }
1335
+ },
1336
+ "plans.variants.customize.billingControls.overageAllowed": {
1337
+ required: ["featureId"]
1338
+ },
1339
+ "plans.variants.customize.billingControls.spendLimits": {
1340
+ fields: {
1341
+ limitType: {
1342
+ enum: ["absolute", "usage_percentage"]
1343
+ },
1344
+ overageLimit: {
1345
+ minimum: 0
1346
+ }
1347
+ }
1348
+ },
1349
+ "plans.variants.customize.billingControls.usageAlerts": {
1350
+ required: ["threshold", "thresholdType"],
1351
+ fields: {
1352
+ threshold: {
1353
+ minimum: 0
1354
+ },
1355
+ thresholdType: {
1356
+ enum: [
1357
+ "usage",
1358
+ "usage_percentage",
1359
+ "remaining",
1360
+ "remaining_percentage"
1361
+ ]
1362
+ },
1363
+ basis: {
1364
+ enum: ["balance", "included", "recurring", "usage_limit"]
1365
+ }
1366
+ }
1367
+ },
1368
+ "plans.variants.customize.billingControls.usageAlerts.filter": {
1369
+ required: ["properties"]
1370
+ },
1371
+ "plans.variants.customize.billingControls.usageAlerts.filter.properties": {
1372
+ keys: {
1373
+ minLength: 1,
1374
+ maxLength: 64
1375
+ }
1376
+ },
1377
+ "plans.variants.customize.billingControls.usageLimits": {
1378
+ required: ["featureId", "interval", "limit"],
1379
+ fields: {
1380
+ limit: {
1381
+ minimum: 0
1382
+ },
1383
+ interval: {
1384
+ enum: ["day", "week", "month", "year"]
1385
+ },
1386
+ anchor: {
1387
+ enum: ["billing_cycle", "utc"]
1388
+ }
1389
+ }
1390
+ },
1391
+ "plans.variants.customize.billingControls.usageLimits.filter": {
1392
+ required: ["properties"]
1393
+ },
1394
+ "plans.variants.customize.billingControls.usageLimits.filter.properties": {
1395
+ keys: {
1396
+ minLength: 1,
1397
+ maxLength: 64
1398
+ }
1399
+ },
1400
+ "plans.variants.customize.freeTrial": {
1401
+ required: ["durationLength"],
1402
+ fields: {
1403
+ durationType: {
1404
+ enum: ["day", "month", "year"]
1405
+ },
1406
+ onEnd: {
1407
+ enum: ["bill", "revert"]
1408
+ }
1409
+ }
1410
+ },
1411
+ "plans.variants.customize.items": {
1412
+ required: ["featureId"],
1413
+ fields: {
1414
+ included: {
1415
+ maximum: 10000000000000
1416
+ }
1417
+ }
1418
+ },
1419
+ "plans.variants.customize.items.expiry": {
1420
+ required: ["duration", "length"],
1421
+ fields: {
1422
+ duration: {
1423
+ enum: ["day", "week", "month", "year"]
1424
+ }
1425
+ }
1426
+ },
1427
+ "plans.variants.customize.items.featureOverride.creditSchema": {
1428
+ variants: {
1429
+ on: "tierBehavior",
1430
+ byValue: {
1431
+ graduated: {
1432
+ required: ["meteredFeatureId", "tierBehavior", "tiers"],
1433
+ fields: {
1434
+ meteredFeatureId: {
1435
+ minLength: 1
1436
+ },
1437
+ billingUnits: {
1438
+ exclusiveMinimum: 0
1439
+ },
1440
+ tierBehavior: {
1441
+ enum: ["graduated"]
1442
+ },
1443
+ tiers: {
1444
+ minItems: 1
1445
+ }
1446
+ }
1447
+ }
1448
+ },
1449
+ fallback: {
1450
+ required: ["creditCost", "meteredFeatureId"],
1451
+ fields: {
1452
+ meteredFeatureId: {
1453
+ minLength: 1
1454
+ },
1455
+ billingUnits: {
1456
+ exclusiveMinimum: 0
1457
+ },
1458
+ creditCost: {
1459
+ minimum: 0
1460
+ }
1461
+ }
1462
+ }
1463
+ }
1464
+ },
1465
+ "plans.variants.customize.items.featureOverride.creditSchema.dimensions": {
1466
+ keys: {
1467
+ minLength: 1,
1468
+ maxLength: 64
1469
+ }
1470
+ },
1471
+ "plans.variants.customize.items.featureOverride.creditSchema.dimensions.*": {
1472
+ variants: {
1473
+ on: "tierBehavior",
1474
+ byValue: {
1475
+ graduated: {
1476
+ required: ["match", "tierBehavior", "tiers"],
1477
+ fields: {
1478
+ priority: {
1479
+ minimum: -9007199254740991,
1480
+ maximum: 9007199254740991
1481
+ },
1482
+ tierBehavior: {
1483
+ enum: ["graduated"]
1484
+ },
1485
+ tiers: {
1486
+ minItems: 1
1487
+ }
1488
+ }
1489
+ }
1490
+ },
1491
+ fallback: {
1492
+ required: ["creditCost", "match"],
1493
+ fields: {
1494
+ priority: {
1495
+ minimum: -9007199254740991,
1496
+ maximum: 9007199254740991
1497
+ },
1498
+ creditCost: {
1499
+ minimum: 0
1500
+ }
1501
+ }
1502
+ }
1503
+ }
1504
+ },
1505
+ "plans.variants.customize.items.featureOverride.creditSchema.dimensions.*.tiers": {
1506
+ required: ["creditCost", "to"],
1507
+ fields: {
1508
+ to: {
1509
+ exclusiveMinimum: 0
1510
+ },
1511
+ creditCost: {
1512
+ minimum: 0
1513
+ }
1514
+ }
1515
+ },
1516
+ "plans.variants.customize.items.featureOverride.creditSchema.multipliers": {
1517
+ keys: {
1518
+ minLength: 1,
1519
+ maxLength: 64
1520
+ }
1521
+ },
1522
+ "plans.variants.customize.items.featureOverride.creditSchema.multipliers.*": {
1523
+ required: ["match"],
1524
+ fields: {
1525
+ factor: {
1526
+ exclusiveMinimum: 0
1527
+ }
1528
+ }
1529
+ },
1530
+ "plans.variants.customize.items.featureOverride.creditSchema.tiers": {
1531
+ required: ["creditCost", "to"],
1532
+ fields: {
1533
+ to: {
1534
+ exclusiveMinimum: 0
1535
+ },
1536
+ creditCost: {
1537
+ minimum: 0
1538
+ }
1539
+ }
1540
+ },
1541
+ "plans.variants.customize.items.featureOverride.markups": {
1542
+ fields: {
1543
+ defaultMarkup: {
1544
+ minimum: -100
1545
+ }
1546
+ }
1547
+ },
1548
+ "plans.variants.customize.items.featureOverride.markups.modelMarkups": {
1549
+ keys: {
1550
+ pattern: ".+\\/.+"
1551
+ }
1552
+ },
1553
+ "plans.variants.customize.items.featureOverride.markups.modelMarkups.*": {
1554
+ fields: {
1555
+ markup: {
1556
+ minimum: -100
1557
+ },
1558
+ inputCost: {
1559
+ minimum: 0
1560
+ },
1561
+ outputCost: {
1562
+ minimum: 0
1563
+ }
1564
+ }
1565
+ },
1566
+ "plans.variants.customize.items.featureOverride.markups.providerMarkups.*": {
1567
+ required: ["markup"],
1568
+ fields: {
1569
+ markup: {
1570
+ minimum: -100
1571
+ }
1572
+ }
1573
+ },
1574
+ "plans.variants.customize.items.price": {
1575
+ required: ["billingMethod", "interval"],
1576
+ fields: {
1577
+ tierBehavior: {
1578
+ enum: ["graduated", "volume"]
1579
+ },
1580
+ interval: {
1581
+ enum: ["one_off", "week", "month", "quarter", "semi_annual", "year"]
1582
+ },
1583
+ billingMethod: {
1584
+ enum: ["prepaid", "usage_based"]
1585
+ },
1586
+ allocatedBilling: {
1587
+ enum: ["arrear", "prorated_legacy"]
1588
+ }
1589
+ }
1590
+ },
1591
+ "plans.variants.customize.items.price.additionalCurrencies": {
1592
+ required: ["amount", "currency"]
1593
+ },
1594
+ "plans.variants.customize.items.price.tiers": {
1595
+ required: ["to"]
1596
+ },
1597
+ "plans.variants.customize.items.price.tiers.additionalCurrencies": {
1598
+ required: ["currency"]
1599
+ },
1600
+ "plans.variants.customize.items.proration": {
1601
+ required: ["onDecrease", "onIncrease"],
1602
+ fields: {
1603
+ onIncrease: {
1604
+ enum: [
1605
+ "bill_immediately",
1606
+ "prorate_immediately",
1607
+ "prorate_next_cycle",
1608
+ "bill_next_cycle"
1609
+ ]
1610
+ },
1611
+ onDecrease: {
1612
+ enum: [
1613
+ "prorate",
1614
+ "prorate_immediately",
1615
+ "prorate_next_cycle",
1616
+ "none",
1617
+ "no_prorations"
1618
+ ]
1619
+ }
1620
+ }
1621
+ },
1622
+ "plans.variants.customize.items.reset": {
1623
+ required: ["interval"],
1624
+ fields: {
1625
+ interval: {
1626
+ enum: [
1627
+ "one_off",
1628
+ "minute",
1629
+ "hour",
1630
+ "day",
1631
+ "week",
1632
+ "month",
1633
+ "quarter",
1634
+ "semi_annual",
1635
+ "year"
1636
+ ]
1637
+ }
1638
+ }
1639
+ },
1640
+ "plans.variants.customize.items.rollover": {
1641
+ required: ["expiryDurationType"],
1642
+ fields: {
1643
+ expiryDurationType: {
1644
+ enum: ["month", "forever"]
1645
+ }
1646
+ }
1647
+ },
1648
+ "plans.variants.customize.items.thresholdBilling": {
1649
+ required: ["threshold"],
1650
+ fields: {
1651
+ threshold: {
1652
+ exclusiveMinimum: 0
1653
+ }
1654
+ }
1655
+ },
1656
+ "plans.variants.customize.price": {
1657
+ required: ["amount", "interval"],
1658
+ fields: {
1659
+ interval: {
1660
+ enum: ["one_off", "week", "month", "quarter", "semi_annual", "year"]
1661
+ }
1662
+ }
1663
+ },
1664
+ "plans.variants.customize.price.additionalCurrencies": {
1665
+ required: ["amount", "currency"]
1666
+ },
1667
+ "plans.variants.customize.removeItems": {
1668
+ fields: {
1669
+ billingMethod: {
1670
+ enum: ["prepaid", "usage_based"]
1671
+ },
1672
+ interval: {
1673
+ enum: [
1674
+ "one_off",
1675
+ "week",
1676
+ "month",
1677
+ "quarter",
1678
+ "semi_annual",
1679
+ "year",
1680
+ "minute",
1681
+ "hour",
1682
+ "day"
1683
+ ]
1684
+ },
1685
+ intervalCount: {
1686
+ minimum: -9007199254740991,
1687
+ maximum: 9007199254740991,
1688
+ exclusiveMinimum: 0
1689
+ },
1690
+ included: {
1691
+ maximum: 10000000000000
1692
+ }
1693
+ }
1694
+ },
1695
+ "plans.variants.customize.removeLicenses": {
1696
+ required: ["licensePlanId"]
1697
+ },
1698
+ "plans.variants.customize.upsertLicenses": {
1699
+ required: ["licensePlanId"],
1700
+ fields: {
1701
+ included: {
1702
+ minimum: 0,
1703
+ maximum: 9007199254740991
1704
+ }
1705
+ }
1706
+ },
1707
+ "plans.variants.customize.upsertLicenses.customize.addItems": {
1708
+ required: ["featureId"],
1709
+ fields: {
1710
+ included: {
1711
+ maximum: 10000000000000
1712
+ }
1713
+ }
1714
+ },
1715
+ "plans.variants.customize.upsertLicenses.customize.addItems.expiry": {
1716
+ required: ["duration", "length"],
1717
+ fields: {
1718
+ duration: {
1719
+ enum: ["day", "week", "month", "year"]
1720
+ }
1721
+ }
1722
+ },
1723
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema": {
1724
+ variants: {
1725
+ on: "tierBehavior",
1726
+ byValue: {
1727
+ graduated: {
1728
+ required: ["meteredFeatureId", "tierBehavior", "tiers"],
1729
+ fields: {
1730
+ meteredFeatureId: {
1731
+ minLength: 1
1732
+ },
1733
+ billingUnits: {
1734
+ exclusiveMinimum: 0
1735
+ },
1736
+ tierBehavior: {
1737
+ enum: ["graduated"]
1738
+ },
1739
+ tiers: {
1740
+ minItems: 1
1741
+ }
1742
+ }
1743
+ }
1744
+ },
1745
+ fallback: {
1746
+ required: ["creditCost", "meteredFeatureId"],
1747
+ fields: {
1748
+ meteredFeatureId: {
1749
+ minLength: 1
1750
+ },
1751
+ billingUnits: {
1752
+ exclusiveMinimum: 0
1753
+ },
1754
+ creditCost: {
1755
+ minimum: 0
1756
+ }
1757
+ }
1758
+ }
1759
+ }
1760
+ },
1761
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.dimensions": {
1762
+ keys: {
1763
+ minLength: 1,
1764
+ maxLength: 64
1765
+ }
1766
+ },
1767
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.dimensions.*": {
1768
+ variants: {
1769
+ on: "tierBehavior",
1770
+ byValue: {
1771
+ graduated: {
1772
+ required: ["match", "tierBehavior", "tiers"],
1773
+ fields: {
1774
+ priority: {
1775
+ minimum: -9007199254740991,
1776
+ maximum: 9007199254740991
1777
+ },
1778
+ tierBehavior: {
1779
+ enum: ["graduated"]
1780
+ },
1781
+ tiers: {
1782
+ minItems: 1
1783
+ }
1784
+ }
1785
+ }
1786
+ },
1787
+ fallback: {
1788
+ required: ["creditCost", "match"],
1789
+ fields: {
1790
+ priority: {
1791
+ minimum: -9007199254740991,
1792
+ maximum: 9007199254740991
1793
+ },
1794
+ creditCost: {
1795
+ minimum: 0
1796
+ }
1797
+ }
1798
+ }
1799
+ }
1800
+ },
1801
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.dimensions.*.tiers": {
1802
+ required: ["creditCost"],
1803
+ fields: {
1804
+ creditCost: {
1805
+ minimum: 0
1806
+ }
1807
+ }
1808
+ },
1809
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.multipliers": {
1810
+ keys: {
1811
+ minLength: 1,
1812
+ maxLength: 64
1813
+ }
1814
+ },
1815
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.multipliers.*": {
1816
+ required: ["match"],
1817
+ fields: {
1818
+ factor: {
1819
+ exclusiveMinimum: 0
1820
+ }
1821
+ }
1822
+ },
1823
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.tiers": {
1824
+ required: ["creditCost", "to"],
1825
+ fields: {
1826
+ to: {
1827
+ exclusiveMinimum: 0
1828
+ },
1829
+ creditCost: {
1830
+ minimum: 0
1831
+ }
1832
+ }
1833
+ },
1834
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.markups": {
1835
+ fields: {
1836
+ defaultMarkup: {
1837
+ minimum: -100
1838
+ }
1839
+ }
1840
+ },
1841
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.markups.modelMarkups": {
1842
+ keys: {
1843
+ pattern: ".+\\/.+"
1844
+ }
1845
+ },
1846
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.markups.modelMarkups.*": {
1847
+ fields: {
1848
+ markup: {
1849
+ minimum: -100
1850
+ },
1851
+ inputCost: {
1852
+ minimum: 0
1853
+ },
1854
+ outputCost: {
1855
+ minimum: 0
1856
+ }
1857
+ }
1858
+ },
1859
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.markups.providerMarkups.*": {
1860
+ required: ["markup"],
1861
+ fields: {
1862
+ markup: {
1863
+ minimum: -100
1864
+ }
1865
+ }
1866
+ },
1867
+ "plans.variants.customize.upsertLicenses.customize.addItems.price": {
1868
+ required: ["billingMethod", "interval"],
1869
+ fields: {
1870
+ tierBehavior: {
1871
+ enum: ["graduated", "volume"]
1872
+ },
1873
+ interval: {
1874
+ enum: ["one_off", "week", "month", "quarter", "semi_annual", "year"]
1875
+ },
1876
+ billingMethod: {
1877
+ enum: ["prepaid", "usage_based"]
1878
+ },
1879
+ allocatedBilling: {
1880
+ enum: ["arrear", "prorated_legacy"]
1881
+ }
1882
+ }
1883
+ },
1884
+ "plans.variants.customize.upsertLicenses.customize.addItems.price.additionalCurrencies": {
1885
+ required: ["amount", "currency"]
1886
+ },
1887
+ "plans.variants.customize.upsertLicenses.customize.addItems.price.tiers": {
1888
+ required: ["to"]
1889
+ },
1890
+ "plans.variants.customize.upsertLicenses.customize.addItems.price.tiers.additionalCurrencies": {
1891
+ required: ["currency"]
1892
+ },
1893
+ "plans.variants.customize.upsertLicenses.customize.addItems.proration": {
1894
+ required: ["onDecrease", "onIncrease"],
1895
+ fields: {
1896
+ onIncrease: {
1897
+ enum: [
1898
+ "bill_immediately",
1899
+ "prorate_immediately",
1900
+ "prorate_next_cycle",
1901
+ "bill_next_cycle"
1902
+ ]
1903
+ },
1904
+ onDecrease: {
1905
+ enum: [
1906
+ "prorate",
1907
+ "prorate_immediately",
1908
+ "prorate_next_cycle",
1909
+ "none",
1910
+ "no_prorations"
1911
+ ]
1912
+ }
1913
+ }
1914
+ },
1915
+ "plans.variants.customize.upsertLicenses.customize.addItems.reset": {
1916
+ required: ["interval"],
1917
+ fields: {
1918
+ interval: {
1919
+ enum: [
1920
+ "one_off",
1921
+ "minute",
1922
+ "hour",
1923
+ "day",
1924
+ "week",
1925
+ "month",
1926
+ "quarter",
1927
+ "semi_annual",
1928
+ "year"
1929
+ ]
1930
+ }
1931
+ }
1932
+ },
1933
+ "plans.variants.customize.upsertLicenses.customize.addItems.rollover": {
1934
+ required: ["expiryDurationType"],
1935
+ fields: {
1936
+ expiryDurationType: {
1937
+ enum: ["month", "forever"]
1938
+ }
1939
+ }
1940
+ },
1941
+ "plans.variants.customize.upsertLicenses.customize.addItems.thresholdBilling": {
1942
+ required: ["threshold"],
1943
+ fields: {
1944
+ threshold: {
1945
+ exclusiveMinimum: 0
1946
+ }
1947
+ }
1948
+ },
1949
+ "plans.variants.customize.upsertLicenses.customize.price": {
1950
+ required: ["amount", "interval"],
1951
+ fields: {
1952
+ interval: {
1953
+ enum: ["one_off", "week", "month", "quarter", "semi_annual", "year"]
1954
+ }
1955
+ }
1956
+ },
1957
+ "plans.variants.customize.upsertLicenses.customize.price.additionalCurrencies": {
1958
+ required: ["amount", "currency"]
1959
+ },
1960
+ "plans.variants.customize.upsertLicenses.customize.removeItems": {
1961
+ fields: {
1962
+ billingMethod: {
1963
+ enum: ["prepaid", "usage_based"]
1964
+ },
1965
+ interval: {
1966
+ enum: [
1967
+ "one_off",
1968
+ "week",
1969
+ "month",
1970
+ "quarter",
1971
+ "semi_annual",
1972
+ "year",
1973
+ "minute",
1974
+ "hour",
1975
+ "day"
1976
+ ]
1977
+ },
1978
+ intervalCount: {
1979
+ minimum: -9007199254740991,
1980
+ maximum: 9007199254740991,
1981
+ exclusiveMinimum: 0
1982
+ },
1983
+ included: {
1984
+ maximum: 10000000000000
1985
+ }
1986
+ }
1987
+ },
1988
+ "plans.variants.processors.revenuecat": {
1989
+ required: ["products"]
1990
+ },
1991
+ "plans.variants.processors.revenuecat.products": {
1992
+ required: ["productId"]
1993
+ },
1994
+ "plans.variants.processors.revenuecat.products.featureQuantities": {
1995
+ required: ["featureId"],
1996
+ fields: {
1997
+ quantity: {
1998
+ minimum: 0
1999
+ }
2000
+ }
2001
+ },
2002
+ "plans.variants.processors.stripe": {
2003
+ required: ["productId"]
2004
+ },
2005
+ referralPrograms: {
2006
+ label: "referral program",
2007
+ idField: "id",
2008
+ required: ["id", "receivedBy", "redeemOn", "rewardId"],
2009
+ fields: {
2010
+ id: {
2011
+ minLength: 1
2012
+ },
2013
+ rewardId: {
2014
+ minLength: 1
2015
+ },
2016
+ redeemOn: {
2017
+ enum: ["customer_creation", "checkout"]
2018
+ },
2019
+ receivedBy: {
2020
+ enum: ["referrer", "all"]
2021
+ },
2022
+ maxRedemptions: {
2023
+ minimum: -9007199254740991,
2024
+ maximum: 9007199254740991,
2025
+ exclusiveMinimum: 0
2026
+ },
2027
+ internalId: {
2028
+ minLength: 1
2029
+ }
2030
+ },
2031
+ rules: [
2032
+ {
2033
+ kind: "unique",
2034
+ field: "id",
2035
+ because: "Two referral programs claiming one id race to define the same row."
2036
+ },
2037
+ {
2038
+ kind: "unique",
2039
+ field: "internalId",
2040
+ because: "A stable id names exactly one row; two fixtures cannot both be it."
2041
+ },
2042
+ {
2043
+ kind: "exists",
2044
+ field: "rewardId",
2045
+ in: "rewards",
2046
+ matching: ["coupon.id", "featureGrant.id"],
2047
+ because: "A referral program grants a reward this config does not declare."
2048
+ },
2049
+ {
2050
+ kind: "exists",
2051
+ field: "planIds",
2052
+ in: "plans",
2053
+ matching: "planId",
2054
+ because: "A referral program triggers on checkout of a plan this config does not declare."
2055
+ }
2056
+ ]
2057
+ },
2058
+ removeFeatures: {
2059
+ required: ["featureId"]
2060
+ },
2061
+ removePlans: {
2062
+ required: ["planId"],
2063
+ fields: {
2064
+ version: {
2065
+ minimum: 1,
2066
+ maximum: 9007199254740991
2067
+ }
2068
+ }
2069
+ },
2070
+ rewards: {
2071
+ label: "reward",
2072
+ rules: [
2073
+ {
2074
+ kind: "unique",
2075
+ field: ["coupon.id", "featureGrant.id"],
2076
+ because: "Two rewards claiming one id race to define the same row."
2077
+ },
2078
+ {
2079
+ kind: "unique",
2080
+ field: ["coupon.internalId", "featureGrant.internalId"],
2081
+ because: "A stable id names exactly one row; two fixtures cannot both be it."
2082
+ }
2083
+ ]
2084
+ },
2085
+ "rewards.coupon": {
2086
+ label: "coupon",
2087
+ idField: "id",
2088
+ required: [
2089
+ "duration",
2090
+ "id",
2091
+ "name",
2092
+ "planIds",
2093
+ "promoCodes",
2094
+ "type",
2095
+ "value"
2096
+ ],
2097
+ fields: {
2098
+ id: {
2099
+ minLength: 1
2100
+ },
2101
+ name: {
2102
+ minLength: 1
2103
+ },
2104
+ planIds: {
2105
+ minItems: 1
2106
+ },
2107
+ internalId: {
2108
+ minLength: 1
2109
+ },
2110
+ type: {
2111
+ enum: ["percentage_discount", "fixed_discount"]
2112
+ },
2113
+ value: {
2114
+ exclusiveMinimum: 0
2115
+ }
2116
+ },
2117
+ rules: [
2118
+ {
2119
+ kind: "exists",
2120
+ field: "planIds",
2121
+ in: "plans",
2122
+ matching: "planId",
2123
+ because: "A coupon discounts a plan this config does not declare."
2124
+ }
2125
+ ]
2126
+ },
2127
+ "rewards.coupon.duration": {
2128
+ required: ["length", "type"],
2129
+ fields: {
2130
+ type: {
2131
+ enum: ["one_off", "months", "forever"]
2132
+ },
2133
+ length: {
2134
+ minimum: -9007199254740991,
2135
+ maximum: 9007199254740991,
2136
+ exclusiveMinimum: 0
2137
+ }
2138
+ }
2139
+ },
2140
+ "rewards.coupon.promoCodes": {
2141
+ required: ["code"],
2142
+ fields: {
2143
+ code: {
2144
+ minLength: 1
2145
+ },
2146
+ globalMaxRedemption: {
2147
+ minimum: -9007199254740991,
2148
+ maximum: 9007199254740991,
2149
+ exclusiveMinimum: 0
2150
+ }
2151
+ }
2152
+ },
2153
+ "rewards.featureGrant": {
2154
+ label: "feature grant",
2155
+ idField: "id",
2156
+ required: ["grants", "id", "name", "promoCodes"],
2157
+ fields: {
2158
+ id: {
2159
+ minLength: 1
2160
+ },
2161
+ name: {
2162
+ minLength: 1
2163
+ },
2164
+ grants: {
2165
+ minItems: 1
2166
+ },
2167
+ promoCodes: {
2168
+ minItems: 1
2169
+ },
2170
+ internalId: {
2171
+ minLength: 1
2172
+ }
2173
+ }
2174
+ },
2175
+ "rewards.featureGrant.grants": {
2176
+ label: "grant",
2177
+ idField: "featureId",
2178
+ required: ["expiry", "featureId", "included"],
2179
+ fields: {
2180
+ featureId: {
2181
+ minLength: 1
2182
+ },
2183
+ included: {
2184
+ minimum: 0
2185
+ }
2186
+ },
2187
+ rules: [
2188
+ {
2189
+ kind: "exists",
2190
+ field: "featureId",
2191
+ in: "features",
2192
+ matching: "featureId",
2193
+ because: "A feature grant awards a feature this config does not declare."
2194
+ }
2195
+ ]
2196
+ },
2197
+ "rewards.featureGrant.grants.expiry": {
2198
+ required: ["length", "type"],
2199
+ fields: {
2200
+ type: {
2201
+ enum: ["day", "week", "month", "year"]
2202
+ },
2203
+ length: {
2204
+ minimum: -9007199254740991,
2205
+ maximum: 9007199254740991,
2206
+ exclusiveMinimum: 0
2207
+ }
2208
+ }
2209
+ },
2210
+ "rewards.featureGrant.promoCodes": {
2211
+ required: ["code", "maxUses"],
2212
+ fields: {
2213
+ code: {
2214
+ minLength: 1
2215
+ },
2216
+ maxUses: {
2217
+ minimum: -9007199254740991,
2218
+ maximum: 9007199254740991,
2219
+ exclusiveMinimum: 0
2220
+ }
2221
+ }
2222
+ }
2223
+ };
2224
+
2225
+ // src/generated/lintRuntime.ts
2226
+ class ConfigError extends Error {
2227
+ issues;
2228
+ constructor(issues) {
2229
+ super([
2230
+ `${issues.length} problem${issues.length === 1 ? "" : "s"} in your config:`,
2231
+ "",
2232
+ ...issues.map((issue) => ` ${issue.path}
2233
+ ${issue.message}`)
2234
+ ].join(`
2235
+ `));
2236
+ this.name = "ConfigError";
2237
+ this.issues = issues;
2238
+ }
2239
+ }
2240
+ var isEntry = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
2241
+ var valueAtPath = ({
2242
+ entry,
2243
+ path
2244
+ }) => {
2245
+ let current = entry;
2246
+ for (const segment of path.split(".")) {
2247
+ if (!isEntry(current))
2248
+ return;
2249
+ current = current[segment];
2250
+ }
2251
+ return current;
2252
+ };
2253
+ var firstValueAtPaths = ({
2254
+ entry,
2255
+ paths
2256
+ }) => {
2257
+ for (const path of typeof paths === "string" ? [paths] : paths) {
2258
+ const value = valueAtPath({ entry, path });
2259
+ if (value !== undefined)
2260
+ return value;
2261
+ }
2262
+ return;
2263
+ };
2264
+ var show = (value) => JSON.stringify(value);
2265
+ var list = (values) => values.map(show).join(", ");
2266
+ var regexCache = new Map;
2267
+ var regexFor = (pattern) => {
2268
+ const cached = regexCache.get(pattern);
2269
+ if (cached)
2270
+ return cached;
2271
+ const compiled = new RegExp(pattern);
2272
+ regexCache.set(pattern, compiled);
2273
+ return compiled;
2274
+ };
2275
+ var constraintFailures = ({
2276
+ name,
2277
+ value,
2278
+ constraints
2279
+ }) => {
2280
+ const failures = [];
2281
+ const c = constraints;
2282
+ if (c.enum && !c.enum.includes(value)) {
2283
+ failures.push(`${name} must be one of ${list(c.enum)} — got ${show(value)}.`);
2284
+ }
2285
+ if (typeof value === "number") {
2286
+ if (c.minimum !== undefined && value < c.minimum)
2287
+ failures.push(`${name} must be at least ${c.minimum} — got ${value}.`);
2288
+ if (c.maximum !== undefined && value > c.maximum)
2289
+ failures.push(`${name} must be at most ${c.maximum} — got ${value}.`);
2290
+ if (c.exclusiveMinimum !== undefined && value <= c.exclusiveMinimum)
2291
+ failures.push(`${name} must be greater than ${c.exclusiveMinimum} — got ${value}.`);
2292
+ if (c.exclusiveMaximum !== undefined && value >= c.exclusiveMaximum)
2293
+ failures.push(`${name} must be less than ${c.exclusiveMaximum} — got ${value}.`);
2294
+ }
2295
+ if (typeof value === "string") {
2296
+ if (c.minLength !== undefined && value.length < c.minLength) {
2297
+ failures.push(c.minLength === 1 ? `${name} must not be empty.` : `${name} must be at least ${c.minLength} characters — got ${value.length}.`);
2298
+ }
2299
+ if (c.maxLength !== undefined && value.length > c.maxLength)
2300
+ failures.push(`${name} must be at most ${c.maxLength} characters — got ${value.length}.`);
2301
+ if (c.pattern !== undefined && !regexFor(c.pattern).test(value))
2302
+ failures.push(`${name} must match ${c.pattern} — got ${show(value)}.`);
2303
+ }
2304
+ if (Array.isArray(value)) {
2305
+ if (c.minItems !== undefined && value.length < c.minItems)
2306
+ failures.push(`${name} must have at least ${c.minItems} ${c.minItems === 1 ? "entry" : "entries"}.`);
2307
+ if (c.maxItems !== undefined && value.length > c.maxItems)
2308
+ failures.push(`${name} must have at most ${c.maxItems} entries.`);
2309
+ }
2310
+ return failures;
2311
+ };
2312
+ var checkShape = ({
2313
+ entry,
2314
+ shape,
2315
+ at,
2316
+ issues
2317
+ }) => {
2318
+ for (const field of shape.required ?? []) {
2319
+ if (entry[field] === undefined)
2320
+ issues.push({ path: at, message: `${field} is required.` });
2321
+ }
2322
+ for (const [field, constraints] of Object.entries(shape.fields ?? {})) {
2323
+ if (entry[field] === undefined)
2324
+ continue;
2325
+ for (const message of constraintFailures({
2326
+ name: field,
2327
+ value: entry[field],
2328
+ constraints
2329
+ })) {
2330
+ issues.push({ path: at, message });
2331
+ }
2332
+ }
2333
+ };
2334
+ var checkVariants = ({
2335
+ entry,
2336
+ variants,
2337
+ at,
2338
+ issues
2339
+ }) => {
2340
+ const selector = entry[variants.on];
2341
+ if (selector === undefined) {
2342
+ if (variants.fallback) {
2343
+ checkShape({ entry, shape: variants.fallback, at, issues });
2344
+ } else {
2345
+ issues.push({ path: at, message: `${variants.on} is required.` });
2346
+ }
2347
+ return;
2348
+ }
2349
+ const chosen = typeof selector === "string" ? variants.byValue[selector] : undefined;
2350
+ if (!chosen) {
2351
+ issues.push({
2352
+ path: at,
2353
+ message: `${variants.on} must be one of ${list(Object.keys(variants.byValue))} — got ${show(selector)}.`
2354
+ });
2355
+ return;
2356
+ }
2357
+ checkShape({ entry, shape: chosen, at, issues });
2358
+ };
2359
+ var crumbFor = ({
2360
+ node,
2361
+ key,
2362
+ entry,
2363
+ index
2364
+ }) => {
2365
+ const label = node?.label ?? key;
2366
+ const id = node?.idField ? entry[node.idField] : undefined;
2367
+ return typeof id === "string" && id ? `${label} ${show(id)}` : `${label}[${index}]`;
2368
+ };
2369
+ var render = (trail) => trail.length === 0 ? "config" : trail.join(" › ");
2370
+ var setFields = ({
2371
+ entry,
2372
+ fields
2373
+ }) => fields.filter((field) => entry[field] !== undefined);
2374
+ var joinNames = (names) => names.length <= 1 ? names.join("") : `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
2375
+ var COMPARE = {
2376
+ "<": { holds: (a, b) => a < b, words: "less than" },
2377
+ "<=": { holds: (a, b) => a <= b, words: "at most" },
2378
+ ">": { holds: (a, b) => a > b, words: "greater than" },
2379
+ ">=": { holds: (a, b) => a >= b, words: "at least" }
2380
+ };
2381
+ var entryRuleFailures = ({
2382
+ entry,
2383
+ rule,
2384
+ document,
2385
+ parent
2386
+ }) => {
2387
+ switch (rule.kind) {
2388
+ case "requiredWhen": {
2389
+ if (entry[rule.when] !== rule.equals)
2390
+ return [];
2391
+ return rule.require.filter((field) => entry[field] === undefined).map((field) => `${field} is required when ${rule.when} is ${show(rule.equals)}. ${rule.because}`);
2392
+ }
2393
+ case "forbiddenWhen": {
2394
+ if (entry[rule.when] !== rule.equals)
2395
+ return [];
2396
+ return setFields({ entry, fields: rule.forbid }).map((field) => `${field} cannot be set when ${rule.when} is ${show(rule.equals)}. ${rule.because}`);
2397
+ }
2398
+ case "mutex": {
2399
+ const set = setFields({ entry, fields: rule.fields });
2400
+ if (set.length <= 1)
2401
+ return [];
2402
+ return [`${joinNames(set)} cannot be set together. ${rule.because}`];
2403
+ }
2404
+ case "exactlyOne": {
2405
+ const set = setFields({ entry, fields: rule.fields });
2406
+ if (set.length === 1)
2407
+ return [];
2408
+ if (set.length === 0)
2409
+ return [
2410
+ `One of ${joinNames(rule.fields)} is required. ${rule.because}`
2411
+ ];
2412
+ return [`${joinNames(set)} cannot be set together. ${rule.because}`];
2413
+ }
2414
+ case "exists": {
2415
+ const value = valueAtPath({ entry, path: rule.field });
2416
+ const target = document[rule.in];
2417
+ if (value === undefined || value === null || !Array.isArray(target))
2418
+ return [];
2419
+ const names = (wanted) => target.some((candidate) => isEntry(candidate) && firstValueAtPaths({ entry: candidate, paths: rule.matching }) === wanted);
2420
+ const missing = (Array.isArray(value) ? value : [value]).filter((wanted) => !names(wanted));
2421
+ return missing.map((wanted) => `${rule.field} ${show(wanted)} is not in ${rule.in}. ${rule.because}`);
2422
+ }
2423
+ case "compare": {
2424
+ const a = entry[rule.field];
2425
+ const b = entry[rule.than];
2426
+ if (typeof a !== "number" || typeof b !== "number")
2427
+ return [];
2428
+ const { holds, words } = COMPARE[rule.op];
2429
+ return holds(a, b) ? [] : [
2430
+ `${rule.field} must be ${words} ${rule.than} — got ${a} and ${b}. ${rule.because}`
2431
+ ];
2432
+ }
2433
+ case "valueWhen": {
2434
+ if (entry[rule.when] !== rule.equals)
2435
+ return [];
2436
+ const value = entry[rule.field];
2437
+ if (value === undefined || value === rule.mustBe)
2438
+ return [];
2439
+ return [
2440
+ `${rule.field} must be ${show(rule.mustBe)} when ${rule.when} is ${show(rule.equals)}. ${rule.because}`
2441
+ ];
2442
+ }
2443
+ case "targetHas": {
2444
+ if (entry[rule.when] === undefined)
2445
+ return [];
2446
+ const target = document[rule.in];
2447
+ if (!Array.isArray(target))
2448
+ return [];
2449
+ const row = target.find((candidate) => isEntry(candidate) && candidate[rule.matching] === entry[rule.field]);
2450
+ if (!row || row[rule.target] === rule.equals)
2451
+ return [];
2452
+ return [
2453
+ `${rule.when} needs ${rule.in} ${show(entry[rule.field])} to have ${rule.target} ${show(rule.equals)} — got ${show(row[rule.target])}. ${rule.because}`
2454
+ ];
2455
+ }
2456
+ case "targetLacks": {
2457
+ const target = document[rule.in];
2458
+ if (!Array.isArray(target))
2459
+ return [];
2460
+ const row = target.find((candidate) => isEntry(candidate) && candidate[rule.matching] === entry[rule.field]);
2461
+ if (!row || row[rule.target] !== true)
2462
+ return [];
2463
+ if (parent?.[rule.parentGuard] === true)
2464
+ return [];
2465
+ return [
2466
+ `${rule.label} ${show(entry[rule.field])} is ${rule.target}. Unarchive it, or archive ${rule.parentLabel} ${show(parent?.[rule.parentIdField])}. ${rule.because}`
2467
+ ];
2468
+ }
2469
+ case "unique":
2470
+ case "linkedOnce":
2471
+ case "exactlyOneActive":
2472
+ return [];
2473
+ }
2474
+ };
2475
+ var checkUnique = ({
2476
+ entries,
2477
+ rule,
2478
+ node,
2479
+ key,
2480
+ trail,
2481
+ issues
2482
+ }) => {
2483
+ const seen = new Set;
2484
+ for (const [index, entry] of entries.entries()) {
2485
+ if (!isEntry(entry))
2486
+ continue;
2487
+ const value = firstValueAtPaths({ entry, paths: rule.field });
2488
+ if (typeof value !== "string")
2489
+ continue;
2490
+ const fieldName = typeof rule.field === "string" ? rule.field : rule.field.join(" / ");
2491
+ const pair = rule.alongside === undefined ? undefined : entry[rule.alongside];
2492
+ if (rule.alongside !== undefined && typeof pair !== "string")
2493
+ continue;
2494
+ const composite = rule.alongside === undefined ? value : `${value}@${pair}`;
2495
+ if (seen.has(composite)) {
2496
+ const label = rule.alongside === undefined ? `${fieldName} ${show(value)}` : `${fieldName} ${show(value)} with ${rule.alongside} ${show(pair)}`;
2497
+ issues.push({
2498
+ path: render([...trail, crumbFor({ node, key, entry, index })]),
2499
+ message: `${label} is used more than once. ${rule.because}`
2500
+ });
2501
+ }
2502
+ seen.add(composite);
2503
+ }
2504
+ };
2505
+ var pinOf = ({
2506
+ entry,
2507
+ pins
2508
+ }) => {
2509
+ for (const pin of pins) {
2510
+ const value = entry[pin];
2511
+ if (typeof value === "string")
2512
+ return { key: `${pin}:${value}`, display: value };
2513
+ if (typeof value === "number")
2514
+ return { key: `${pin}:${value}`, display: `v${value}` };
2515
+ }
2516
+ return;
2517
+ };
2518
+ var checkLinkedOnce = ({
2519
+ entries,
2520
+ rule,
2521
+ node,
2522
+ key,
2523
+ trail,
2524
+ issues
2525
+ }) => {
2526
+ const ownerByLink = new Map;
2527
+ for (const [index, entry] of entries.entries()) {
2528
+ if (!isEntry(entry))
2529
+ continue;
2530
+ const group = entry[rule.groupBy];
2531
+ const links = entry[rule.collection];
2532
+ if (typeof group !== "string" || !Array.isArray(links))
2533
+ continue;
2534
+ const owner = pinOf({ entry, pins: [rule.namedBy] })?.display ?? rule.absentMeans;
2535
+ for (const link of links) {
2536
+ if (!isEntry(link))
2537
+ continue;
2538
+ const id = link[rule.identity];
2539
+ if (typeof id !== "string")
2540
+ continue;
2541
+ const pin = pinOf({ entry: link, pins: rule.pins });
2542
+ const label = pin === undefined ? id : `${id} ${pin.display}`;
2543
+ const composite = `${group} ${id} ${pin?.key ?? "latest"}`;
2544
+ const previous = ownerByLink.get(composite);
2545
+ if (previous === undefined) {
2546
+ ownerByLink.set(composite, { owner, index });
2547
+ continue;
2548
+ }
2549
+ const at = render([...trail, crumbFor({ node, key, entry, index })]);
2550
+ if (previous.index === index) {
2551
+ issues.push({
2552
+ path: at,
2553
+ message: `${label} is linked twice from ${group} ${owner}. ${rule.because}`
2554
+ });
2555
+ continue;
2556
+ }
2557
+ if (previous.owner === owner)
2558
+ continue;
2559
+ issues.push({
2560
+ path: at,
2561
+ message: `${label} is linked from ${group} ${previous.owner} and ${group} ${owner}. ${rule.because}`
2562
+ });
2563
+ }
2564
+ }
2565
+ };
2566
+ var checkExactlyOneActive = ({
2567
+ entries,
2568
+ rule,
2569
+ node,
2570
+ key,
2571
+ trail,
2572
+ issues
2573
+ }) => {
2574
+ const rowsByGroup = new Map;
2575
+ for (const [index, entry] of entries.entries()) {
2576
+ if (!isEntry(entry))
2577
+ continue;
2578
+ const group = entry[rule.groupBy];
2579
+ if (typeof group !== "string")
2580
+ continue;
2581
+ rowsByGroup.set(group, [
2582
+ ...rowsByGroup.get(group) ?? [],
2583
+ { entry, index, active: entry[rule.field] === true }
2584
+ ]);
2585
+ }
2586
+ for (const [group, members] of rowsByGroup) {
2587
+ const active = members.filter((member) => member.active);
2588
+ if (active.length === 1)
2589
+ continue;
2590
+ const at = active.length === 0 ? members[0] : active[1];
2591
+ if (at === undefined)
2592
+ continue;
2593
+ const versions = `${members.length} version${members.length === 1 ? "" : "s"}`;
2594
+ const count = active.length === 0 ? "none is active" : `${active.length} are active`;
2595
+ issues.push({
2596
+ path: render([
2597
+ ...trail,
2598
+ crumbFor({ node, key, entry: at.entry, index: at.index })
2599
+ ]),
2600
+ message: `${rule.label} ${show(group)} has ${versions} and ${count}. ${rule.because}${renameHint({ active, members })}`
2601
+ });
2602
+ }
2603
+ };
2604
+ var renameHint = ({
2605
+ active,
2606
+ members
2607
+ }) => {
2608
+ if (active.length !== 0)
2609
+ return "";
2610
+ const everyRowIsKnown = members.every((member) => typeof member.entry.internalId === "string");
2611
+ if (!everyRowIsKnown)
2612
+ return "";
2613
+ return " If you are renaming a plan, change the planId on every one of its versions, not just some.";
2614
+ };
2615
+ var checkCollection = ({
2616
+ entries,
2617
+ node,
2618
+ key,
2619
+ trail,
2620
+ issues
2621
+ }) => {
2622
+ for (const rule of node.rules ?? []) {
2623
+ if (rule.kind === "unique")
2624
+ checkUnique({ entries, rule, node, key, trail, issues });
2625
+ if (rule.kind === "linkedOnce")
2626
+ checkLinkedOnce({ entries, rule, node, key, trail, issues });
2627
+ if (rule.kind === "exactlyOneActive")
2628
+ checkExactlyOneActive({ entries, rule, node, key, trail, issues });
2629
+ }
2630
+ };
2631
+ var checkEntry = ({
2632
+ entry,
2633
+ node,
2634
+ at,
2635
+ walk,
2636
+ parent
2637
+ }) => {
2638
+ checkShape({ entry, shape: node, at, issues: walk.issues });
2639
+ if (node.variants) {
2640
+ checkVariants({ entry, variants: node.variants, at, issues: walk.issues });
2641
+ }
2642
+ for (const rule of node.rules ?? []) {
2643
+ for (const message of entryRuleFailures({
2644
+ entry,
2645
+ rule,
2646
+ document: walk.document,
2647
+ parent
2648
+ })) {
2649
+ walk.issues.push({ path: at, message });
2650
+ }
2651
+ }
2652
+ };
2653
+ var walkEntry = ({
2654
+ entry,
2655
+ path,
2656
+ trail,
2657
+ walk,
2658
+ parent
2659
+ }) => {
2660
+ const node = walk.rules[path];
2661
+ if (node)
2662
+ checkEntry({ entry, node, at: render(trail), walk, parent });
2663
+ for (const [key, child] of Object.entries(entry)) {
2664
+ walkValue({
2665
+ value: child,
2666
+ path: path ? `${path}.${key}` : key,
2667
+ key,
2668
+ trail,
2669
+ walk,
2670
+ parent: entry
2671
+ });
2672
+ }
2673
+ };
2674
+ var walkValue = ({
2675
+ value,
2676
+ path,
2677
+ key,
2678
+ trail,
2679
+ walk,
2680
+ parent
2681
+ }) => {
2682
+ if (walk.hints.frozenPaths.has(path))
2683
+ return;
2684
+ if (Array.isArray(value)) {
2685
+ const node = walk.rules[path];
2686
+ if (node) {
2687
+ checkCollection({
2688
+ entries: value,
2689
+ node,
2690
+ key,
2691
+ trail,
2692
+ issues: walk.issues
2693
+ });
2694
+ }
2695
+ for (const [index, entry] of value.entries()) {
2696
+ if (!isEntry(entry))
2697
+ continue;
2698
+ walkEntry({
2699
+ entry,
2700
+ path,
2701
+ trail: [...trail, crumbFor({ node, key, entry, index })],
2702
+ walk,
2703
+ parent
2704
+ });
2705
+ }
2706
+ return;
2707
+ }
2708
+ if (!isEntry(value))
2709
+ return;
2710
+ if (walk.hints.recordPaths.has(path)) {
2711
+ const keys = walk.rules[path]?.keys;
2712
+ for (const [recordKey, child] of Object.entries(value)) {
2713
+ if (keys) {
2714
+ for (const message of constraintFailures({
2715
+ name: `${key} key ${show(recordKey)}`,
2716
+ value: recordKey,
2717
+ constraints: keys
2718
+ })) {
2719
+ walk.issues.push({ path: render(trail), message });
2720
+ }
2721
+ }
2722
+ walkValue({
2723
+ value: child,
2724
+ path: `${path}.*`,
2725
+ key: `${key}[${show(recordKey)}]`,
2726
+ trail,
2727
+ walk,
2728
+ parent
2729
+ });
2730
+ }
2731
+ return;
2732
+ }
2733
+ walkEntry({ entry: value, path, trail: [...trail, key], walk, parent });
2734
+ };
2735
+ var lintDocument = ({
2736
+ document,
2737
+ rules,
2738
+ hints
2739
+ }) => {
2740
+ const walk = { document, rules, hints, issues: [] };
2741
+ walkEntry({ entry: document, path: "", trail: [], walk });
2742
+ return walk.issues;
2743
+ };
2744
+
2745
+ // src/generated/wire.ts
2746
+ var isOperatorKey = (key) => key.startsWith("$");
2747
+ var toSnakeCase = (key) => isOperatorKey(key) ? key : key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
2748
+ var toCamelCase = (key) => isOperatorKey(key) ? key : key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
2749
+ var clearOmittedRelationshipCustomizes = (row) => {
2750
+ if (row === null || typeof row !== "object")
2751
+ return row;
2752
+ const source = row;
2753
+ const normalize = (entries) => Array.isArray(entries) ? entries.map((entry) => entry !== null && typeof entry === "object" ? {
2754
+ ...entry,
2755
+ customize: entry.customize ?? null
2756
+ } : entry) : entries;
2757
+ return {
2758
+ ...source,
2759
+ ...source.licenses !== undefined ? { licenses: normalize(source.licenses) } : {},
2760
+ ...source.variants !== undefined ? { variants: normalize(source.variants) } : {}
2761
+ };
2762
+ };
2763
+ var toWire = ({
2764
+ value,
2765
+ path,
2766
+ hints
2767
+ }) => {
2768
+ if (hints.frozenPaths.has(path))
2769
+ return value;
2770
+ if (Array.isArray(value)) {
2771
+ return value.map((entry) => toWire({ value: entry, path, hints }));
2772
+ }
2773
+ if (value === null || typeof value !== "object")
2774
+ return value;
2775
+ const source = value;
2776
+ if (hints.recordPaths.has(path)) {
2777
+ return Object.fromEntries(Object.entries(source).map(([key, entry]) => [
2778
+ key,
2779
+ toWire({ value: entry, path: `${path}.*`, hints })
2780
+ ]));
2781
+ }
2782
+ return Object.fromEntries(Object.entries(source).map(([key, entry]) => {
2783
+ const childPath = path ? `${path}.${key}` : key;
2784
+ return [
2785
+ hints.renamedPaths.get(childPath) ?? toSnakeCase(key),
2786
+ toWire({ value: entry, path: childPath, hints })
2787
+ ];
2788
+ }));
2789
+ };
2790
+ var toFixture = ({
2791
+ value,
2792
+ path,
2793
+ hints
2794
+ }) => {
2795
+ if (hints.frozenPaths.has(path))
2796
+ return value;
2797
+ if (Array.isArray(value)) {
2798
+ return value.map((entry) => toFixture({ value: entry, path, hints }));
2799
+ }
2800
+ if (value === null || typeof value !== "object")
2801
+ return value;
2802
+ const source = value;
2803
+ if (hints.recordPaths.has(path)) {
2804
+ return Object.fromEntries(Object.entries(source).map(([key, entry]) => [
2805
+ key,
2806
+ toFixture({ value: entry, path: `${path}.*`, hints })
2807
+ ]));
2808
+ }
2809
+ return Object.fromEntries(Object.entries(source).map(([key, entry]) => {
2810
+ const name = hints.renamedWirePaths.get(path ? `${path}.${key}` : key) ?? toCamelCase(key);
2811
+ return [
2812
+ name,
2813
+ toFixture({
2814
+ value: entry,
2815
+ path: path ? `${path}.${name}` : name,
2816
+ hints
2817
+ })
2818
+ ];
2819
+ }));
2820
+ };
2821
+ var hintsOf = (hints) => ({
2822
+ recordPaths: new Set(hints.recordPaths),
2823
+ frozenPaths: new Set(hints.frozenPaths),
2824
+ renamedPaths: new Map(Object.entries(hints.renamedPaths)),
2825
+ renamedWirePaths: new Map(Object.entries(hints.renamedPaths).map(([fixturePath, wireKey]) => {
2826
+ const segments = fixturePath.split(".");
2827
+ const parent = segments.slice(0, -1);
2828
+ return [
2829
+ [...parent, wireKey].join("."),
2830
+ segments[segments.length - 1] ?? ""
2831
+ ];
2832
+ }))
2833
+ });
2834
+ var CATALOG_HINTS = hintsOf({
2835
+ recordPaths: [
2836
+ "features.creditSchema.dimensions",
2837
+ "features.creditSchema.dimensions.*.match",
2838
+ "features.creditSchema.multipliers",
2839
+ "features.creditSchema.multipliers.*.match",
2840
+ "features.modelMarkups",
2841
+ "features.providerMarkups",
2842
+ "plans.billingControls.usageAlerts.filter.properties",
2843
+ "plans.billingControls.usageLimits.filter.properties",
2844
+ "plans.items.featureOverride.creditSchema.dimensions",
2845
+ "plans.items.featureOverride.creditSchema.dimensions.*.match",
2846
+ "plans.items.featureOverride.creditSchema.multipliers",
2847
+ "plans.items.featureOverride.creditSchema.multipliers.*.match",
2848
+ "plans.items.featureOverride.markups.modelMarkups",
2849
+ "plans.items.featureOverride.markups.providerMarkups",
2850
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.dimensions",
2851
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.dimensions.*.match",
2852
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.multipliers",
2853
+ "plans.licenses.customize.addItems.featureOverride.creditSchema.multipliers.*.match",
2854
+ "plans.licenses.customize.addItems.featureOverride.markups.modelMarkups",
2855
+ "plans.licenses.customize.addItems.featureOverride.markups.providerMarkups",
2856
+ "plans.variants.customize.addItems.featureOverride.creditSchema.dimensions",
2857
+ "plans.variants.customize.addItems.featureOverride.creditSchema.dimensions.*.match",
2858
+ "plans.variants.customize.addItems.featureOverride.creditSchema.multipliers",
2859
+ "plans.variants.customize.addItems.featureOverride.creditSchema.multipliers.*.match",
2860
+ "plans.variants.customize.addItems.featureOverride.markups.modelMarkups",
2861
+ "plans.variants.customize.addItems.featureOverride.markups.providerMarkups",
2862
+ "plans.variants.customize.billingControls.usageAlerts.filter.properties",
2863
+ "plans.variants.customize.billingControls.usageLimits.filter.properties",
2864
+ "plans.variants.customize.items.featureOverride.creditSchema.dimensions",
2865
+ "plans.variants.customize.items.featureOverride.creditSchema.dimensions.*.match",
2866
+ "plans.variants.customize.items.featureOverride.creditSchema.multipliers",
2867
+ "plans.variants.customize.items.featureOverride.creditSchema.multipliers.*.match",
2868
+ "plans.variants.customize.items.featureOverride.markups.modelMarkups",
2869
+ "plans.variants.customize.items.featureOverride.markups.providerMarkups",
2870
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.dimensions",
2871
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.dimensions.*.match",
2872
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.multipliers",
2873
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.multipliers.*.match",
2874
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.markups.modelMarkups",
2875
+ "plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.markups.providerMarkups"
2876
+ ],
2877
+ frozenPaths: [
2878
+ "plans.licenses.metadata",
2879
+ "plans.metadata",
2880
+ "plans.variants.customize.upsertLicenses.metadata"
2881
+ ],
2882
+ renamedPaths: { "settings.paydownOverages": "persist_free_overage" }
2883
+ });
2884
+ var stated = (config) => ({
2885
+ ...config.features !== undefined ? { features: config.features } : {},
2886
+ ...config.plans !== undefined ? {
2887
+ plans: config.plans.map(clearOmittedRelationshipCustomizes),
2888
+ skip_version_deletions: false
2889
+ } : {},
2890
+ ...config.rewards !== undefined ? { rewards: config.rewards } : {},
2891
+ ...config.referralPrograms !== undefined ? { referralPrograms: config.referralPrograms } : {},
2892
+ ...config.settings !== undefined ? { settings: config.settings } : {}
2893
+ });
2894
+ var SINGLETON_KEYS = ["settings"];
2895
+ var CONFIG_KEYS = [
2896
+ "features",
2897
+ "plans",
2898
+ "rewards",
2899
+ "referralPrograms",
2900
+ "settings"
2901
+ ];
2902
+ var unknownKeyIssue = (key) => key === "planVersions" ? {
2903
+ path: key,
2904
+ message: "planVersions is gone: every version is now a row in plans, with versionSlug and active. Rebuild the config from your org with `atmn pull --overwrite --yes` (commit first), or move the rows into plans."
2905
+ } : {
2906
+ path: key,
2907
+ message: `${key} is not a config field. The fields are ${CONFIG_KEYS.join(", ")}.`
2908
+ };
2909
+ var splitWire = (document) => ({
2910
+ catalog: Object.fromEntries(Object.entries(document).filter(([key]) => !SINGLETON_KEYS.includes(key))),
2911
+ singletons: {
2912
+ settings: document.settings === undefined ? undefined : { config: document.settings }
2913
+ }
2914
+ });
2915
+ var atmn = (config) => {
2916
+ const unknownKeys = Object.keys(config).filter((key) => !CONFIG_KEYS.includes(key));
2917
+ if (unknownKeys.length > 0)
2918
+ throw new ConfigError(unknownKeys.map(unknownKeyIssue));
2919
+ const document = stated(config);
2920
+ const issues = lintDocument({
2921
+ document,
2922
+ rules: LINT_RULES,
2923
+ hints: CATALOG_HINTS
2924
+ });
2925
+ if (issues.length > 0)
2926
+ throw new ConfigError(issues);
2927
+ return {
2928
+ ...toWire({
2929
+ value: document,
2930
+ path: "",
2931
+ hints: CATALOG_HINTS
2932
+ }),
2933
+ skip_deletions: false,
2934
+ migration: { draft: true }
2935
+ };
2936
+ };
2937
+ export {
2938
+ variant,
2939
+ referralProgram,
2940
+ plan,
2941
+ license,
2942
+ featureGrant,
2943
+ feature,
2944
+ coupon,
2945
+ atmn
2946
+ };