@farthershore/product 0.5.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,151 +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.capabilities?.length) options.capabilities = file.capabilities;
149
- if (file.plans?.length) options.plans = file.plans;
150
- if (file.actions?.length) options.actions = file.actions;
151
- if (file.runtime?.rollout_key !== void 0)
152
- options.rolloutKey = file.runtime.rollout_key;
153
- if (file.runtime?.required_flags?.length)
154
- options.requiredFlags = file.runtime.required_flags;
155
- options.routes = file.routes.map((route) => ({
156
- match: `${route.match.method ?? "*"} ${route.match.path}`,
157
- ...route.metering?.reports?.length ? { reports: route.metering.reports } : {},
158
- ...route.metering?.defaults && Object.keys(route.metering.defaults).length ? {
159
- costs: Object.entries(route.metering.defaults).map(
160
- ([meter, value]) => ({ kind: "meter_cost", meter, value })
161
- )
162
- } : {},
163
- ...route.metering?.estimates && Object.keys(route.metering.estimates).length ? { estimates: route.metering.estimates } : {},
164
- ...route.metering?.onStatusCodes !== void 0 ? { onStatusCodes: route.metering.onStatusCodes } : {},
165
- ...route.unmetered !== void 0 ? { unmetered: route.unmetered } : {},
166
- ...route.inheritDefaultMeters !== void 0 ? { inheritDefaultMeters: route.inheritDefaultMeters } : {},
167
- ...route.action !== void 0 ? { action: route.action } : {}
168
- }));
169
- lines.push(`product.feature(${lit(file.feature)}, ${lit(options, 0)});`);
170
- }
171
- }
172
- if (product.frontend !== void 0) {
173
- lines.push("");
174
- 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)});`);
175
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) {
176
203
  const entitlements = product.entitlements ?? [];
177
- if (entitlements.length) {
178
- lines.push("");
179
- for (const entitlement of entitlements) {
180
- const { key, ...rest } = entitlement;
181
- lines.push(`product.entitlement(${lit(key)}, ${lit(rest, 0)});`);
182
- }
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)});`);
183
209
  }
210
+ }
211
+ function emitWorkflows(lines, product) {
184
212
  const workflows = product.workflows ?? [];
185
- if (workflows.length) {
186
- lines.push("");
187
- for (const workflow of workflows) {
188
- const { key, ...rest } = workflow;
189
- lines.push(`product.workflow(${lit(key)}, ${lit(rest, 0)});`);
190
- }
191
- }
192
- if (product.migrations?.length) {
193
- lines.push("");
194
- 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)});`);
195
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) {
196
226
  const plans = product.plans ?? [];
197
- if (plans.length) {
198
- lines.push("");
199
- for (const plan of plans) {
200
- lines.push(
201
- `product.plan(${lit(plan.key)}, ${lit(planOptions(plan), 0)});`
202
- );
203
- }
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)});`);
204
231
  }
232
+ }
233
+ function emitProductPatch(lines, product) {
205
234
  const patch = productPatch(product);
206
- if (Object.keys(patch).length) {
207
- lines.push("");
208
- lines.push(`product.raw.productPatch(${lit(patch, 0)});`);
209
- }
235
+ if (!Object.keys(patch).length) return;
210
236
  lines.push("");
211
- lines.push("export default product;");
212
- lines.push("");
213
- return lines.join("\n");
237
+ lines.push(`product.raw.productPatch(${lit(patch, 0)});`);
214
238
  }
215
239
  function productOptions(product) {
216
240
  const block = product.product;
@@ -239,8 +263,6 @@ function productOptions(product) {
239
263
  const billing = product.billing;
240
264
  if (billing) {
241
265
  const handled = {};
242
- if (billing.gracePeriodDays !== void 0)
243
- handled.gracePeriodDays = billing.gracePeriodDays;
244
266
  if (billing.applyLimitUpgradesInstantly !== void 0)
245
267
  handled.applyLimitUpgradesInstantly = billing.applyLimitUpgradesInstantly;
246
268
  if (Object.keys(handled).length) options.billing = handled;
@@ -254,45 +276,59 @@ function customerContextOptions(context) {
254
276
  ...context.portal_auth !== void 0 ? { customerAuth: context.portal_auth } : {}
255
277
  };
256
278
  }
257
- function planOptions(plan) {
258
- const options = { name: plan.name };
259
- if (plan.description !== void 0) options.description = plan.description;
260
- if (plan.details !== void 0) options.details = plan.details;
261
- 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) {
262
296
  const fee = plan.recurring_fee_cents;
263
297
  const interval = plan.billing_interval;
264
298
  const free = plan.free;
299
+ const rawPrice = {};
265
300
  if (fee !== void 0 && interval !== void 0 && free !== true && fee % 1 === 0) {
266
- options.price = {
267
- __price: interval === "year" ? "yearly" : "monthly",
268
- 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
269
308
  };
270
- if (free !== void 0) raw.free = free;
271
- } else if (free === true && fee === 0 && interval === "month") {
272
- options.price = { __price: "free" };
273
- } else {
274
- if (fee !== void 0) raw.recurring_fee_cents = fee;
275
- if (interval !== void 0) raw.billing_interval = interval;
276
- if (free !== void 0) raw.free = free;
277
309
  }
278
- if (plan.meters !== void 0) options.meters = plan.meters;
279
- if (plan.grants !== void 0) options.grants = plan.grants;
280
- if (plan.trial_days !== void 0) options.trialDays = plan.trial_days;
281
- if (plan.max_monthly_spend_cents !== void 0)
282
- options.maxMonthlySpendCents = plan.max_monthly_spend_cents;
283
- if (plan.min_monthly_spend_cents !== void 0)
284
- options.minMonthlySpendCents = plan.min_monthly_spend_cents;
285
- if (plan.limits !== void 0) options.limits = plan.limits;
286
- if (plan.featureGates !== void 0) options.featureGates = plan.featureGates;
287
- if (plan.capability_limits !== void 0)
288
- options.capabilityLimits = plan.capability_limits;
289
- if (plan.capabilities !== void 0) options.capabilities = plan.capabilities;
290
- if (plan.overageBehavior !== void 0)
291
- options.overageBehavior = plan.overageBehavior;
292
- if (plan.selfServeEnabled !== void 0)
293
- options.selfServeEnabled = plan.selfServeEnabled;
294
- if (plan.legacy !== void 0) options.legacy = plan.legacy;
295
- 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
+ }
296
332
  for (const [key, value] of Object.entries(plan)) {
297
333
  if (!PLAN_HANDLED_KEYS.has(key)) raw[key] = value;
298
334
  }
@@ -357,5 +393,6 @@ function identifier(key) {
357
393
  return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
358
394
  }
359
395
  export {
360
- generateManifestSource
396
+ generateManifestSource,
397
+ generatePlanStatement
361
398
  };