@farthershore/product 0.6.0 → 0.6.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.
package/dist/codegen.js CHANGED
@@ -14,10 +14,7 @@ var PRODUCT_BLOCK_KEYS = /* @__PURE__ */ new Set([
14
14
  ]);
15
15
  var GATEWAY_KEYS = /* @__PURE__ */ new Set(["authHeader", "upstreamAuth"]);
16
16
  var METERING_KEYS = /* @__PURE__ */ new Set(["meters", "billOn4xx"]);
17
- var BILLING_KEYS = /* @__PURE__ */ new Set([
18
- "gracePeriodDays",
19
- "applyLimitUpgradesInstantly"
20
- ]);
17
+ var BILLING_KEYS = /* @__PURE__ */ new Set(["applyLimitUpgradesInstantly"]);
21
18
  var TOP_LEVEL_HANDLED = /* @__PURE__ */ new Set([
22
19
  "product",
23
20
  "gateway",
@@ -43,6 +40,7 @@ var PLAN_HANDLED_KEYS = /* @__PURE__ */ new Set([
43
40
  "free",
44
41
  "meters",
45
42
  "grants",
43
+ "creditPolicy",
46
44
  "trial_days",
47
45
  "max_monthly_spend_cents",
48
46
  "min_monthly_spend_cents",
@@ -55,6 +53,9 @@ var PLAN_HANDLED_KEYS = /* @__PURE__ */ new Set([
55
53
  "legacy",
56
54
  "archive"
57
55
  ]);
56
+ function generatePlanStatement(plan) {
57
+ return `product.plan(${lit(plan.key)}, ${lit(planOptions(plan), 0)});`;
58
+ }
58
59
  function generateManifestSource(ir) {
59
60
  const lines = [];
60
61
  const product = ir.product;
@@ -66,150 +67,174 @@ function generateManifestSource(ir) {
66
67
  0
67
68
  )});`
68
69
  );
70
+ emitMeters(lines, product);
71
+ emitResources(lines, product);
72
+ emitSurfaces(lines, product);
73
+ emitCapabilities(lines, ir);
74
+ emitPolicies(lines, ir);
75
+ emitFeatures(lines, ir);
76
+ emitFrontend(lines, product);
77
+ emitEntitlements(lines, product);
78
+ emitWorkflows(lines, product);
79
+ emitMigrations(lines, product);
80
+ emitPlans(lines, product);
81
+ emitProductPatch(lines, product);
82
+ lines.push("");
83
+ lines.push("export default product;");
84
+ lines.push("");
85
+ return lines.join("\n");
86
+ }
87
+ function emitMeters(lines, product) {
69
88
  const meters = product.metering?.meters ?? [];
70
- if (meters.length) {
71
- lines.push("");
72
- for (const meter of meters) {
73
- const { key, ...rest } = meter;
74
- lines.push(`product.meter(${lit(key)}, ${lit(rest, 0)});`);
75
- }
89
+ if (!meters.length) return;
90
+ lines.push("");
91
+ for (const meter of meters) {
92
+ const { key, ...rest } = meter;
93
+ lines.push(`product.meter(${lit(key)}, ${lit(rest, 0)});`);
76
94
  }
95
+ }
96
+ function emitResources(lines, product) {
77
97
  const resources = product.resources ?? [];
78
- if (resources.length) {
79
- lines.push("");
80
- for (const resource of resources) {
81
- const { name, ...rest } = resource;
82
- lines.push(`product.resource(${lit(name)}, ${lit(rest, 0)});`);
83
- }
98
+ if (!resources.length) return;
99
+ lines.push("");
100
+ for (const resource of resources) {
101
+ const { name, ...rest } = resource;
102
+ lines.push(`product.resource(${lit(name)}, ${lit(rest, 0)});`);
84
103
  }
104
+ }
105
+ function emitSurfaces(lines, product) {
85
106
  const surfaces = product.surfaces ?? [];
86
- if (surfaces.length) {
87
- lines.push("");
88
- for (const surface of surfaces) {
89
- const { type, key, ...rest } = surface;
90
- lines.push(`product.surface(${lit(type)}, ${lit({ key, ...rest }, 0)});`);
91
- }
107
+ if (!surfaces.length) return;
108
+ lines.push("");
109
+ for (const surface of surfaces) {
110
+ const { type, key, ...rest } = surface;
111
+ lines.push(`product.surface(${lit(type)}, ${lit({ key, ...rest }, 0)});`);
92
112
  }
93
- if (ir.capabilities.length) {
94
- lines.push("");
95
- for (const cap of ir.capabilities) {
96
- const options = {};
97
- if (cap.description !== void 0) options.description = cap.description;
98
- if (cap.mutation_class !== void 0)
99
- options.mutationClass = cap.mutation_class;
100
- if (cap.includes_features?.length)
101
- options.includesFeatures = cap.includes_features;
102
- if (cap.includes_policies?.length)
103
- options.includesPolicies = cap.includes_policies;
104
- if (cap.includes_capabilities?.length)
105
- options.includesCapabilities = cap.includes_capabilities;
106
- lines.push(
107
- `product.capability(${lit(cap.capability)}, ${lit(options, 0)});`
108
- );
109
- }
113
+ }
114
+ function emitCapabilities(lines, ir) {
115
+ if (!ir.capabilities.length) return;
116
+ lines.push("");
117
+ for (const cap of ir.capabilities) {
118
+ const options = {};
119
+ if (cap.description !== void 0) options.description = cap.description;
120
+ if (cap.mutation_class !== void 0)
121
+ options.mutationClass = cap.mutation_class;
122
+ if (cap.includes_features?.length)
123
+ options.includesFeatures = cap.includes_features;
124
+ if (cap.includes_policies?.length)
125
+ options.includesPolicies = cap.includes_policies;
126
+ if (cap.includes_capabilities?.length)
127
+ options.includesCapabilities = cap.includes_capabilities;
128
+ lines.push(
129
+ `product.capability(${lit(cap.capability)}, ${lit(options, 0)});`
130
+ );
110
131
  }
111
- if (ir.policies.length) {
112
- lines.push("");
113
- for (const policy of ir.policies) {
114
- const options = {
115
- type: policy.type,
116
- config: policy.config
132
+ }
133
+ function emitPolicies(lines, ir) {
134
+ if (!ir.policies.length) return;
135
+ lines.push("");
136
+ for (const policy of ir.policies) {
137
+ const options = {
138
+ type: policy.type,
139
+ config: policy.config
140
+ };
141
+ if (policy.description !== void 0)
142
+ options.description = policy.description;
143
+ if (policy.mutation_class !== void 0)
144
+ options.mutationClass = policy.mutation_class;
145
+ if (policy.cacheProfile !== void 0)
146
+ options.cacheProfile = policy.cacheProfile;
147
+ if (policy.compatible_with !== void 0) {
148
+ const cw = policy.compatible_with;
149
+ options.compatibleWith = {
150
+ ...cw.route_types ? { routeTypes: cw.route_types } : {},
151
+ ...cw.meters ? { meters: cw.meters } : {},
152
+ ...cw.auth_modes ? { authModes: cw.auth_modes } : {}
117
153
  };
118
- if (policy.description !== void 0)
119
- options.description = policy.description;
120
- if (policy.mutation_class !== void 0)
121
- options.mutationClass = policy.mutation_class;
122
- if (policy.cacheProfile !== void 0)
123
- options.cacheProfile = policy.cacheProfile;
124
- if (policy.compatible_with !== void 0) {
125
- const cw = policy.compatible_with;
126
- options.compatibleWith = {
127
- ...cw.route_types ? { routeTypes: cw.route_types } : {},
128
- ...cw.meters ? { meters: cw.meters } : {},
129
- ...cw.auth_modes ? { authModes: cw.auth_modes } : {}
130
- };
131
- }
132
- lines.push(`product.policy(${lit(policy.name)}, ${lit(options, 0)});`);
133
154
  }
155
+ lines.push(`product.policy(${lit(policy.name)}, ${lit(options, 0)});`);
134
156
  }
135
- if (ir.routes.length) {
136
- lines.push("");
137
- for (const file of ir.routes) {
138
- const options = {};
139
- if (file.description !== void 0)
140
- options.description = file.description;
141
- if (file.mutation_class !== void 0)
142
- options.mutationClass = file.mutation_class;
143
- if (file.cacheProfile !== void 0)
144
- options.cacheProfile = file.cacheProfile;
145
- if (file.upstream !== void 0)
146
- options.upstreamOrigin = file.upstream.override_origin;
147
- if (file.policies?.length) options.policies = file.policies;
148
- if (file.plans?.length) options.plans = file.plans;
149
- if (file.actions?.length) options.actions = file.actions;
150
- if (file.runtime?.rollout_key !== void 0)
151
- options.rolloutKey = file.runtime.rollout_key;
152
- if (file.runtime?.required_flags?.length)
153
- options.requiredFlags = file.runtime.required_flags;
154
- options.routes = file.routes.map((route) => ({
155
- match: `${route.match.method ?? "*"} ${route.match.path}`,
156
- ...route.metering?.reports?.length ? { reports: route.metering.reports } : {},
157
- ...route.metering?.defaults && Object.keys(route.metering.defaults).length ? {
158
- costs: Object.entries(route.metering.defaults).map(
159
- ([meter, value]) => ({ kind: "meter_cost", meter, value })
160
- )
161
- } : {},
162
- ...route.metering?.estimates && Object.keys(route.metering.estimates).length ? { estimates: route.metering.estimates } : {},
163
- ...route.metering?.onStatusCodes !== void 0 ? { onStatusCodes: route.metering.onStatusCodes } : {},
164
- ...route.unmetered !== void 0 ? { unmetered: route.unmetered } : {},
165
- ...route.inheritDefaultMeters !== void 0 ? { inheritDefaultMeters: route.inheritDefaultMeters } : {},
166
- ...route.action !== void 0 ? { action: route.action } : {}
167
- }));
168
- lines.push(`product.feature(${lit(file.feature)}, ${lit(options, 0)});`);
169
- }
170
- }
171
- if (product.frontend !== void 0) {
172
- lines.push("");
173
- lines.push(`product.frontend.manifest(${lit(product.frontend, 0)});`);
157
+ }
158
+ function emitFeatures(lines, ir) {
159
+ if (!ir.routes.length) return;
160
+ lines.push("");
161
+ for (const file of ir.routes) {
162
+ const options = {};
163
+ if (file.description !== void 0) options.description = file.description;
164
+ if (file.mutation_class !== void 0)
165
+ options.mutationClass = file.mutation_class;
166
+ if (file.cacheProfile !== void 0)
167
+ options.cacheProfile = file.cacheProfile;
168
+ if (file.upstream !== void 0)
169
+ options.upstreamOrigin = file.upstream.override_origin;
170
+ if (file.policies?.length) options.policies = file.policies;
171
+ if (file.plans?.length) options.plans = file.plans;
172
+ if (file.actions?.length) options.actions = file.actions;
173
+ if (file.runtime?.rollout_key !== void 0)
174
+ options.rolloutKey = file.runtime.rollout_key;
175
+ if (file.runtime?.required_flags?.length)
176
+ options.requiredFlags = file.runtime.required_flags;
177
+ options.routes = file.routes.map(featureRoute);
178
+ lines.push(`product.feature(${lit(file.feature)}, ${lit(options, 0)});`);
174
179
  }
180
+ }
181
+ function featureRoute(route) {
182
+ return {
183
+ match: `${route.match.method ?? "*"} ${route.match.path}`,
184
+ ...route.metering?.reports?.length ? { reports: route.metering.reports } : {},
185
+ ...route.metering?.defaults && Object.keys(route.metering.defaults).length ? {
186
+ costs: Object.entries(route.metering.defaults).map(
187
+ ([meter, value]) => ({ kind: "meter_cost", meter, value })
188
+ )
189
+ } : {},
190
+ ...route.metering?.estimates && Object.keys(route.metering.estimates).length ? { estimates: route.metering.estimates } : {},
191
+ ...route.metering?.onStatusCodes !== void 0 ? { onStatusCodes: route.metering.onStatusCodes } : {},
192
+ ...route.unmetered !== void 0 ? { unmetered: route.unmetered } : {},
193
+ ...route.inheritDefaultMeters !== void 0 ? { inheritDefaultMeters: route.inheritDefaultMeters } : {},
194
+ ...route.action !== void 0 ? { action: route.action } : {}
195
+ };
196
+ }
197
+ function emitFrontend(lines, product) {
198
+ if (product.frontend === void 0) return;
199
+ lines.push("");
200
+ lines.push(`product.frontend.manifest(${lit(product.frontend, 0)});`);
201
+ }
202
+ function emitEntitlements(lines, product) {
175
203
  const entitlements = product.entitlements ?? [];
176
- if (entitlements.length) {
177
- lines.push("");
178
- for (const entitlement of entitlements) {
179
- const { key, ...rest } = entitlement;
180
- lines.push(`product.entitlement(${lit(key)}, ${lit(rest, 0)});`);
181
- }
204
+ if (!entitlements.length) return;
205
+ lines.push("");
206
+ for (const entitlement of entitlements) {
207
+ const { key, ...rest } = entitlement;
208
+ lines.push(`product.entitlement(${lit(key)}, ${lit(rest, 0)});`);
182
209
  }
210
+ }
211
+ function emitWorkflows(lines, product) {
183
212
  const workflows = product.workflows ?? [];
184
- if (workflows.length) {
185
- lines.push("");
186
- for (const workflow of workflows) {
187
- const { key, ...rest } = workflow;
188
- lines.push(`product.workflow(${lit(key)}, ${lit(rest, 0)});`);
189
- }
190
- }
191
- if (product.migrations?.length) {
192
- lines.push("");
193
- lines.push(`product.lifecycle.migrations(${lit(product.migrations, 0)});`);
213
+ if (!workflows.length) return;
214
+ lines.push("");
215
+ for (const workflow of workflows) {
216
+ const { key, ...rest } = workflow;
217
+ lines.push(`product.workflow(${lit(key)}, ${lit(rest, 0)});`);
194
218
  }
219
+ }
220
+ function emitMigrations(lines, product) {
221
+ if (!product.migrations?.length) return;
222
+ lines.push("");
223
+ lines.push(`product.lifecycle.migrations(${lit(product.migrations, 0)});`);
224
+ }
225
+ function emitPlans(lines, product) {
195
226
  const plans = product.plans ?? [];
196
- if (plans.length) {
197
- lines.push("");
198
- for (const plan of plans) {
199
- lines.push(
200
- `product.plan(${lit(plan.key)}, ${lit(planOptions(plan), 0)});`
201
- );
202
- }
227
+ if (!plans.length) return;
228
+ lines.push("");
229
+ for (const plan of plans) {
230
+ lines.push(`product.plan(${lit(plan.key)}, ${lit(planOptions(plan), 0)});`);
203
231
  }
232
+ }
233
+ function emitProductPatch(lines, product) {
204
234
  const patch = productPatch(product);
205
- if (Object.keys(patch).length) {
206
- lines.push("");
207
- lines.push(`product.raw.productPatch(${lit(patch, 0)});`);
208
- }
235
+ if (!Object.keys(patch).length) return;
209
236
  lines.push("");
210
- lines.push("export default product;");
211
- lines.push("");
212
- return lines.join("\n");
237
+ lines.push(`product.raw.productPatch(${lit(patch, 0)});`);
213
238
  }
214
239
  function productOptions(product) {
215
240
  const block = product.product;
@@ -238,8 +263,6 @@ function productOptions(product) {
238
263
  const billing = product.billing;
239
264
  if (billing) {
240
265
  const handled = {};
241
- if (billing.gracePeriodDays !== void 0)
242
- handled.gracePeriodDays = billing.gracePeriodDays;
243
266
  if (billing.applyLimitUpgradesInstantly !== void 0)
244
267
  handled.applyLimitUpgradesInstantly = billing.applyLimitUpgradesInstantly;
245
268
  if (Object.keys(handled).length) options.billing = handled;
@@ -253,45 +276,59 @@ function customerContextOptions(context) {
253
276
  ...context.portal_auth !== void 0 ? { customerAuth: context.portal_auth } : {}
254
277
  };
255
278
  }
256
- function planOptions(plan) {
257
- const options = { name: plan.name };
258
- if (plan.description !== void 0) options.description = plan.description;
259
- if (plan.details !== void 0) options.details = plan.details;
260
- const raw = {};
279
+ var PLAN_OPTION_FIELDS = [
280
+ ["meters", "meters"],
281
+ ["grants", "grants"],
282
+ ["creditPolicy", "creditPolicy"],
283
+ ["trial_days", "trialDays"],
284
+ ["max_monthly_spend_cents", "maxMonthlySpendCents"],
285
+ ["min_monthly_spend_cents", "minMonthlySpendCents"],
286
+ ["limits", "limits"],
287
+ ["featureGates", "featureGates"],
288
+ ["capability_limits", "capabilityLimits"],
289
+ ["capabilities", "capabilities"],
290
+ ["overageBehavior", "overageBehavior"],
291
+ ["selfServeEnabled", "selfServeEnabled"],
292
+ ["legacy", "legacy"],
293
+ ["archive", "archive"]
294
+ ];
295
+ function planPrice(plan) {
261
296
  const fee = plan.recurring_fee_cents;
262
297
  const interval = plan.billing_interval;
263
298
  const free = plan.free;
299
+ const rawPrice = {};
264
300
  if (fee !== void 0 && interval !== void 0 && free !== true && fee % 1 === 0) {
265
- options.price = {
266
- __price: interval === "year" ? "yearly" : "monthly",
267
- amount: fee / 100
301
+ if (free !== void 0) rawPrice.free = free;
302
+ return {
303
+ price: {
304
+ __price: interval === "year" ? "yearly" : "monthly",
305
+ amount: fee / 100
306
+ },
307
+ rawPrice
268
308
  };
269
- if (free !== void 0) raw.free = free;
270
- } else if (free === true && fee === 0 && interval === "month") {
271
- options.price = { __price: "free" };
272
- } else {
273
- if (fee !== void 0) raw.recurring_fee_cents = fee;
274
- if (interval !== void 0) raw.billing_interval = interval;
275
- if (free !== void 0) raw.free = free;
276
309
  }
277
- if (plan.meters !== void 0) options.meters = plan.meters;
278
- if (plan.grants !== void 0) options.grants = plan.grants;
279
- if (plan.trial_days !== void 0) options.trialDays = plan.trial_days;
280
- if (plan.max_monthly_spend_cents !== void 0)
281
- options.maxMonthlySpendCents = plan.max_monthly_spend_cents;
282
- if (plan.min_monthly_spend_cents !== void 0)
283
- options.minMonthlySpendCents = plan.min_monthly_spend_cents;
284
- if (plan.limits !== void 0) options.limits = plan.limits;
285
- if (plan.featureGates !== void 0) options.featureGates = plan.featureGates;
286
- if (plan.capability_limits !== void 0)
287
- options.capabilityLimits = plan.capability_limits;
288
- if (plan.capabilities !== void 0) options.capabilities = plan.capabilities;
289
- if (plan.overageBehavior !== void 0)
290
- options.overageBehavior = plan.overageBehavior;
291
- if (plan.selfServeEnabled !== void 0)
292
- options.selfServeEnabled = plan.selfServeEnabled;
293
- if (plan.legacy !== void 0) options.legacy = plan.legacy;
294
- if (plan.archive !== void 0) options.archive = plan.archive;
310
+ if (free === true && fee === 0 && interval === "month") {
311
+ return { price: { __price: "free" }, rawPrice };
312
+ }
313
+ if (fee !== void 0) rawPrice.recurring_fee_cents = fee;
314
+ if (interval !== void 0) rawPrice.billing_interval = interval;
315
+ if (free !== void 0) rawPrice.free = free;
316
+ return { rawPrice };
317
+ }
318
+ function planOptions(plan) {
319
+ if (plan.name === void 0 || plan.name === null) {
320
+ throw new Error(`plan "${plan.key}" is missing a required name`);
321
+ }
322
+ const options = { name: plan.name };
323
+ if (plan.description !== void 0) options.description = plan.description;
324
+ if (plan.details !== void 0) options.details = plan.details;
325
+ const { price, rawPrice } = planPrice(plan);
326
+ const raw = { ...rawPrice };
327
+ if (price !== void 0) options.price = price;
328
+ for (const [field, optionKey] of PLAN_OPTION_FIELDS) {
329
+ const value = plan[field];
330
+ if (value !== void 0) options[optionKey] = value;
331
+ }
295
332
  for (const [key, value] of Object.entries(plan)) {
296
333
  if (!PLAN_HANDLED_KEYS.has(key)) raw[key] = value;
297
334
  }
@@ -356,5 +393,6 @@ function identifier(key) {
356
393
  return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
357
394
  }
358
395
  export {
359
- generateManifestSource
396
+ generateManifestSource,
397
+ generatePlanStatement
360
398
  };