owostack 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +28 -3
- package/dist/index.js +190 -23
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CheckResult, PlanFeatureEntry, ResetInterval, CreditSystemDefinition, AddEntityResult, RemoveEntityResult, ListEntitiesResult, MeteredFeatureConfig, TrackResult, CatalogEntry, SyncPayload, Currency, PlanInterval, PlanDefinition, OwostackConfig, BillingUsageParams, BillingUsageResult, InvoiceParams, InvoiceResult, InvoicesParams, InvoicesResult, PayInvoiceParams, PayInvoiceResult, WalletResult, WalletSetupResult, WalletRemoveResult, SyncResult, AttachParams, AttachResult, CheckParams, TrackParams, AddonParams, AddonResult, CustomerParams, CustomerResult, AddEntityParams, RemoveEntityParams, ListEntitiesParams, PlansParams, PlansResult, PublicPlan } from '@owostack/types';
|
|
2
|
-
export { AddEntityParams, AddEntityResult, AddonParams, AddonResult, AttachParams, AttachResult, BillingFeatureUsage, BillingUsageParams, BillingUsageResult, BooleanFeatureConfig, CardInfo, CatalogEntry, CheckCode, CheckParams, CheckResult, CustomerData, CustomerParams, CustomerResult, Invoice, InvoiceLineItem, InvoiceParams, InvoiceResult, InvoicesParams, InvoicesResult, ListEntitiesParams, ListEntitiesResult, MeteredFeatureConfig, OverageDetails, OwostackConfig, PayInvoiceParams, PayInvoiceResult, PaymentMethodInfo, PlanCredits, PlanDefinition, PlanFeatureEntry, PlansParams, PlansResult, PublicPlan, PublicPlanFeature, RemoveEntityParams, RemoveEntityResult, ResponseDetails, SyncChanges, SyncPayload, SyncResult, TrackCode, TrackParams, TrackResult, WalletRemoveResult, WalletResult, WalletSetupResult } from '@owostack/types';
|
|
1
|
+
import { CheckResult, PlanFeatureEntry, ResetInterval, CreditSystemDefinition, AddEntityResult, RemoveEntityResult, ListEntitiesResult, MeteredFeatureConfig, TrackResult, PricingTier, CatalogEntry, SyncPayload, Currency, CreditPackDefinition, PlanInterval, PlanDefinition, OwostackConfig, BillingUsageParams, BillingUsageResult, InvoiceParams, InvoiceResult, InvoicesParams, InvoicesResult, PayInvoiceParams, PayInvoiceResult, WalletResult, WalletSetupResult, WalletRemoveResult, SyncResult, AttachParams, AttachResult, CheckParams, TrackParams, AddonParams, AddonResult, CustomerParams, CustomerResult, AddEntityParams, RemoveEntityParams, ListEntitiesParams, PlansParams, PlansResult, PublicPlan } from '@owostack/types';
|
|
2
|
+
export { AddEntityParams, AddEntityResult, AddonParams, AddonResult, AttachParams, AttachResult, BillingFeatureUsage, BillingTierBreakdown, BillingUsageParams, BillingUsageResult, BooleanFeatureConfig, CardInfo, CatalogEntry, CheckCode, CheckParams, CheckResult, CurrentPricingTier, CustomerData, CustomerParams, CustomerResult, Invoice, InvoiceLineItem, InvoiceParams, InvoiceResult, InvoicesParams, InvoicesResult, ListEntitiesParams, ListEntitiesResult, MeteredFeatureConfig, OverageDetails, OwostackConfig, PayInvoiceParams, PayInvoiceResult, PaymentMethodInfo, PlanCredits, PlanDefinition, PlanFeatureEntry, PlansParams, PlansResult, PricingDetails, PricingTier, PublicPlan, PublicPlanFeature, RatingModel, RemoveEntityParams, RemoveEntityResult, ResponseDetails, SyncChanges, SyncPayload, SyncResult, TrackCode, TrackParams, TrackResult, WalletRemoveResult, WalletResult, WalletSetupResult } from '@owostack/types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* BooleanHandle — returned by boolean().
|
|
@@ -37,6 +37,15 @@ interface MeteredHandle {
|
|
|
37
37
|
limit(value: number, config?: Omit<MeteredFeatureConfig, "limit">): PlanFeatureEntry;
|
|
38
38
|
included(value: number, config?: Omit<MeteredFeatureConfig, "limit">): PlanFeatureEntry;
|
|
39
39
|
unlimited(config?: Omit<MeteredFeatureConfig, "limit">): PlanFeatureEntry;
|
|
40
|
+
perUnit(unitPrice: number, config?: {
|
|
41
|
+
reset?: ResetInterval;
|
|
42
|
+
}): PlanFeatureEntry;
|
|
43
|
+
graduated(tiers: PricingTier[], config?: {
|
|
44
|
+
reset?: ResetInterval;
|
|
45
|
+
}): PlanFeatureEntry;
|
|
46
|
+
volume(tiers: PricingTier[], config?: {
|
|
47
|
+
reset?: ResetInterval;
|
|
48
|
+
}): PlanFeatureEntry;
|
|
40
49
|
config(opts: MeteredFeatureConfig): PlanFeatureEntry;
|
|
41
50
|
(creditCost: number): {
|
|
42
51
|
feature: string;
|
|
@@ -133,7 +142,23 @@ declare function plan(slug: string, config: {
|
|
|
133
142
|
trialDays?: number;
|
|
134
143
|
provider?: string;
|
|
135
144
|
metadata?: Record<string, unknown>;
|
|
145
|
+
autoEnable?: boolean;
|
|
146
|
+
isAddon?: boolean;
|
|
136
147
|
}): PlanDefinition;
|
|
148
|
+
/**
|
|
149
|
+
* Create a credit pack definition.
|
|
150
|
+
* Credit packs are one-time purchases that add credits to a customer's balance.
|
|
151
|
+
*/
|
|
152
|
+
declare function creditPack(slug: string, config: {
|
|
153
|
+
name: string;
|
|
154
|
+
description?: string;
|
|
155
|
+
credits: number;
|
|
156
|
+
price: number;
|
|
157
|
+
currency: Currency;
|
|
158
|
+
creditSystem: string;
|
|
159
|
+
provider?: string;
|
|
160
|
+
metadata?: Record<string, unknown>;
|
|
161
|
+
}): CreditPackDefinition;
|
|
137
162
|
/**
|
|
138
163
|
* Extract SyncPayload from catalog.
|
|
139
164
|
*/
|
|
@@ -446,4 +471,4 @@ declare class OwostackError extends Error {
|
|
|
446
471
|
constructor(code: string, message: string);
|
|
447
472
|
}
|
|
448
473
|
|
|
449
|
-
export { BooleanHandle, CreditSystemHandle, EntityHandle, type MeteredHandle, Owostack, OwostackError, boolean, buildSyncPayload, creditSystem, entity, metered, plan };
|
|
474
|
+
export { BooleanHandle, CreditSystemHandle, EntityHandle, type MeteredHandle, Owostack, OwostackError, boolean, buildSyncPayload, creditPack, creditSystem, entity, metered, plan };
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,74 @@ var BooleanHandle = class {
|
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
+
function validateUnitPrice(unitPrice, methodName) {
|
|
49
|
+
if (!Number.isFinite(unitPrice) || unitPrice < 0) {
|
|
50
|
+
throw new Error(`${methodName}() requires a non-negative unit price.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function validatePricingTiers(tiers, methodName) {
|
|
54
|
+
if (!Array.isArray(tiers) || tiers.length === 0) {
|
|
55
|
+
throw new Error(`${methodName}() requires at least one pricing tier.`);
|
|
56
|
+
}
|
|
57
|
+
let previousUpTo = 0;
|
|
58
|
+
for (let index = 0; index < tiers.length; index += 1) {
|
|
59
|
+
const tier = tiers[index];
|
|
60
|
+
const hasUnitPrice = tier.unitPrice !== void 0;
|
|
61
|
+
const hasFlatFee = tier.flatFee !== void 0;
|
|
62
|
+
if (!hasUnitPrice && !hasFlatFee) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`${methodName}() tier ${index + 1} must define unitPrice, flatFee, or both.`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if (hasUnitPrice && (!Number.isFinite(tier.unitPrice) || tier.unitPrice < 0)) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`${methodName}() tier ${index + 1} must have a non-negative unitPrice.`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (tier.flatFee !== void 0 && (!Number.isFinite(tier.flatFee) || tier.flatFee < 0)) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`${methodName}() tier ${index + 1} must have a non-negative flatFee.`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
if (tier.upTo === null) {
|
|
78
|
+
if (index !== tiers.length - 1) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`${methodName}() only allows the last tier to use upTo: null.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (!Number.isFinite(tier.upTo) || tier.upTo <= previousUpTo) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`${methodName}() tiers must be in ascending order by upTo.`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
previousUpTo = tier.upTo;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function validateMeteredFeaturePricing(config, featureSlug) {
|
|
94
|
+
if (!config) return;
|
|
95
|
+
if (config.pricePerUnit !== void 0) {
|
|
96
|
+
validateUnitPrice(config.pricePerUnit, `${featureSlug} pricePerUnit`);
|
|
97
|
+
}
|
|
98
|
+
const ratingModel = config.ratingModel || "package";
|
|
99
|
+
if (ratingModel === "graduated" || ratingModel === "volume") {
|
|
100
|
+
validatePricingTiers(config.tiers || [], ratingModel);
|
|
101
|
+
} else if (config.tiers && config.tiers.length > 0) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`Feature '${featureSlug}' cannot define tiers with ratingModel "package".`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (config.usageModel === "usage_based" && ratingModel === "package" && config.pricePerUnit === void 0) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Feature '${featureSlug}' must define pricePerUnit for usage-based package pricing.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function normalizeUsageBasedOverage(usageModel, overage) {
|
|
113
|
+
if (usageModel === "usage_based") return "charge";
|
|
114
|
+
return overage;
|
|
115
|
+
}
|
|
48
116
|
function metered(slug, opts) {
|
|
49
117
|
const callable = (creditCost) => ({ feature: slug, creditCost });
|
|
50
118
|
const handleProps = {
|
|
@@ -92,6 +160,61 @@ function metered(slug, opts) {
|
|
|
92
160
|
config: { limit: null, reset: "monthly", overage: "block", ...config }
|
|
93
161
|
};
|
|
94
162
|
},
|
|
163
|
+
perUnit(unitPrice, config) {
|
|
164
|
+
validateUnitPrice(unitPrice, "perUnit");
|
|
165
|
+
return {
|
|
166
|
+
_type: "plan_feature",
|
|
167
|
+
slug,
|
|
168
|
+
featureType: "metered",
|
|
169
|
+
name: opts?.name,
|
|
170
|
+
enabled: true,
|
|
171
|
+
config: {
|
|
172
|
+
limit: null,
|
|
173
|
+
reset: config?.reset || "monthly",
|
|
174
|
+
usageModel: "usage_based",
|
|
175
|
+
ratingModel: "package",
|
|
176
|
+
pricePerUnit: unitPrice,
|
|
177
|
+
billingUnits: 1,
|
|
178
|
+
overage: "charge"
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
graduated(tiers, config) {
|
|
183
|
+
validatePricingTiers(tiers, "graduated");
|
|
184
|
+
return {
|
|
185
|
+
_type: "plan_feature",
|
|
186
|
+
slug,
|
|
187
|
+
featureType: "metered",
|
|
188
|
+
name: opts?.name,
|
|
189
|
+
enabled: true,
|
|
190
|
+
config: {
|
|
191
|
+
limit: null,
|
|
192
|
+
reset: config?.reset || "monthly",
|
|
193
|
+
usageModel: "usage_based",
|
|
194
|
+
ratingModel: "graduated",
|
|
195
|
+
tiers: tiers.map((tier) => ({ ...tier })),
|
|
196
|
+
overage: "charge"
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
volume(tiers, config) {
|
|
201
|
+
validatePricingTiers(tiers, "volume");
|
|
202
|
+
return {
|
|
203
|
+
_type: "plan_feature",
|
|
204
|
+
slug,
|
|
205
|
+
featureType: "metered",
|
|
206
|
+
name: opts?.name,
|
|
207
|
+
enabled: true,
|
|
208
|
+
config: {
|
|
209
|
+
limit: null,
|
|
210
|
+
reset: config?.reset || "monthly",
|
|
211
|
+
usageModel: "usage_based",
|
|
212
|
+
ratingModel: "volume",
|
|
213
|
+
tiers: tiers.map((tier) => ({ ...tier })),
|
|
214
|
+
overage: "charge"
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
},
|
|
95
218
|
config(configOpts) {
|
|
96
219
|
const isEnabled = configOpts.enabled !== false;
|
|
97
220
|
return {
|
|
@@ -258,6 +381,13 @@ function plan(slug, config) {
|
|
|
258
381
|
...config
|
|
259
382
|
};
|
|
260
383
|
}
|
|
384
|
+
function creditPack(slug, config) {
|
|
385
|
+
return {
|
|
386
|
+
_type: "credit_pack",
|
|
387
|
+
slug,
|
|
388
|
+
...config
|
|
389
|
+
};
|
|
390
|
+
}
|
|
261
391
|
function slugToName(slug) {
|
|
262
392
|
return slug.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
263
393
|
}
|
|
@@ -273,7 +403,9 @@ function buildSyncPayload(catalog, defaultProvider) {
|
|
|
273
403
|
slug: f.slug,
|
|
274
404
|
type: f.featureType,
|
|
275
405
|
name: f.name || slugToName(f.slug),
|
|
276
|
-
...handle instanceof EntityHandle && {
|
|
406
|
+
...handle instanceof EntityHandle && {
|
|
407
|
+
meterType: "non_consumable"
|
|
408
|
+
}
|
|
277
409
|
});
|
|
278
410
|
}
|
|
279
411
|
}
|
|
@@ -310,34 +442,67 @@ function buildSyncPayload(catalog, defaultProvider) {
|
|
|
310
442
|
trialDays: p.trialDays ?? void 0,
|
|
311
443
|
provider: p.provider ?? void 0,
|
|
312
444
|
metadata: p.metadata ?? void 0,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
// Boolean features have no reset interval
|
|
319
|
-
...f.featureType !== "boolean" && {
|
|
320
|
-
reset: f.config?.reset || "monthly"
|
|
321
|
-
},
|
|
322
|
-
...f.config?.overage && { overage: f.config.overage },
|
|
323
|
-
...f.config?.overagePrice !== void 0 && {
|
|
324
|
-
overagePrice: f.config.overagePrice
|
|
325
|
-
},
|
|
326
|
-
...f.config?.maxOverageUnits !== void 0 && {
|
|
327
|
-
maxOverageUnits: f.config.maxOverageUnits
|
|
328
|
-
},
|
|
329
|
-
...f.config?.billingUnits !== void 0 && {
|
|
330
|
-
billingUnits: f.config.billingUnits
|
|
331
|
-
},
|
|
332
|
-
...f.config?.creditCost !== void 0 && {
|
|
333
|
-
creditCost: f.config.creditCost
|
|
445
|
+
autoEnable: p.autoEnable ?? void 0,
|
|
446
|
+
isAddon: p.isAddon ?? void 0,
|
|
447
|
+
features: p.features.map((f) => {
|
|
448
|
+
if (f.featureType !== "boolean") {
|
|
449
|
+
validateMeteredFeaturePricing(f.config, f.slug);
|
|
334
450
|
}
|
|
335
|
-
|
|
451
|
+
return {
|
|
452
|
+
slug: f.slug,
|
|
453
|
+
enabled: f.enabled,
|
|
454
|
+
// Boolean features have no limit concept (null), metered features use limit from config
|
|
455
|
+
limit: f.featureType === "boolean" ? null : f.config?.limit ?? null,
|
|
456
|
+
// Boolean features have no reset interval
|
|
457
|
+
...f.featureType !== "boolean" && {
|
|
458
|
+
reset: f.config?.reset || "monthly"
|
|
459
|
+
},
|
|
460
|
+
...f.config?.usageModel && { usageModel: f.config.usageModel },
|
|
461
|
+
...f.config?.pricePerUnit !== void 0 && {
|
|
462
|
+
pricePerUnit: f.config.pricePerUnit
|
|
463
|
+
},
|
|
464
|
+
...f.config?.ratingModel && { ratingModel: f.config.ratingModel },
|
|
465
|
+
...f.config?.tiers && { tiers: f.config.tiers },
|
|
466
|
+
...normalizeUsageBasedOverage(
|
|
467
|
+
f.config?.usageModel,
|
|
468
|
+
f.config?.overage
|
|
469
|
+
) && {
|
|
470
|
+
overage: normalizeUsageBasedOverage(
|
|
471
|
+
f.config?.usageModel,
|
|
472
|
+
f.config?.overage
|
|
473
|
+
)
|
|
474
|
+
},
|
|
475
|
+
...f.config?.overagePrice !== void 0 && {
|
|
476
|
+
overagePrice: f.config.overagePrice
|
|
477
|
+
},
|
|
478
|
+
...f.config?.maxOverageUnits !== void 0 && {
|
|
479
|
+
maxOverageUnits: f.config.maxOverageUnits
|
|
480
|
+
},
|
|
481
|
+
...f.config?.billingUnits !== void 0 && {
|
|
482
|
+
billingUnits: f.config.billingUnits
|
|
483
|
+
},
|
|
484
|
+
...f.config?.creditCost !== void 0 && {
|
|
485
|
+
creditCost: f.config.creditCost
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
})
|
|
489
|
+
}));
|
|
490
|
+
const creditPacks = catalog.filter((e) => e._type === "credit_pack").map((cp) => ({
|
|
491
|
+
slug: cp.slug,
|
|
492
|
+
name: cp.name,
|
|
493
|
+
description: cp.description ?? void 0,
|
|
494
|
+
credits: cp.credits,
|
|
495
|
+
price: cp.price,
|
|
496
|
+
currency: cp.currency,
|
|
497
|
+
creditSystem: cp.creditSystem,
|
|
498
|
+
provider: cp.provider ?? void 0,
|
|
499
|
+
metadata: cp.metadata ?? void 0
|
|
336
500
|
}));
|
|
337
501
|
return {
|
|
338
502
|
defaultProvider,
|
|
339
503
|
features: Array.from(featureMap.values()),
|
|
340
504
|
creditSystems,
|
|
505
|
+
creditPacks,
|
|
341
506
|
plans
|
|
342
507
|
};
|
|
343
508
|
}
|
|
@@ -428,6 +593,7 @@ var Owostack = class {
|
|
|
428
593
|
success: true,
|
|
429
594
|
features: { created: [], updated: [], unchanged: [] },
|
|
430
595
|
creditSystems: { created: [], updated: [], unchanged: [] },
|
|
596
|
+
creditPacks: { created: [], updated: [], unchanged: [] },
|
|
431
597
|
plans: { created: [], updated: [], unchanged: [] },
|
|
432
598
|
warnings: ["No catalog entries to sync."]
|
|
433
599
|
};
|
|
@@ -809,6 +975,7 @@ export {
|
|
|
809
975
|
OwostackError,
|
|
810
976
|
boolean,
|
|
811
977
|
buildSyncPayload,
|
|
978
|
+
creditPack,
|
|
812
979
|
creditSystem,
|
|
813
980
|
entity,
|
|
814
981
|
metered,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "owostack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Core SDK for Owostack billing infrastructure",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"payments"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@owostack/types": "0.
|
|
33
|
+
"@owostack/types": "0.3.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"tsup": "^8.3.6",
|