@develemit/billing 0.1.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/README.md +138 -0
- package/dist/chunk-3OSJ6UJT.js +495 -0
- package/dist/chunk-3OSJ6UJT.js.map +1 -0
- package/dist/fastify.cjs +556 -0
- package/dist/fastify.cjs.map +1 -0
- package/dist/fastify.d.cts +26 -0
- package/dist/fastify.d.ts +26 -0
- package/dist/fastify.js +71 -0
- package/dist/fastify.js.map +1 -0
- package/dist/index.cjs +625 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/dist/types-D_vVr3D2.d.cts +116 -0
- package/dist/types-D_vVr3D2.d.ts +116 -0
- package/package.json +39 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
BillingApiError: () => BillingApiError,
|
|
24
|
+
checkEntitlement: () => checkEntitlement,
|
|
25
|
+
createClient: () => createClient
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// ../shared-types/src/admin.ts
|
|
30
|
+
var import_zod5 = require("zod");
|
|
31
|
+
|
|
32
|
+
// ../shared-types/src/event-log.ts
|
|
33
|
+
var import_zod = require("zod");
|
|
34
|
+
var eventStatusSchema = import_zod.z.enum([
|
|
35
|
+
"received",
|
|
36
|
+
"processed",
|
|
37
|
+
"failed",
|
|
38
|
+
"dead_letter",
|
|
39
|
+
"discarded"
|
|
40
|
+
]);
|
|
41
|
+
var subscriptionStateSchema = import_zod.z.enum([
|
|
42
|
+
"trialing",
|
|
43
|
+
"active",
|
|
44
|
+
"past_due",
|
|
45
|
+
"canceled",
|
|
46
|
+
"unpaid"
|
|
47
|
+
]);
|
|
48
|
+
var adminEventSummarySchema = import_zod.z.object({
|
|
49
|
+
id: import_zod.z.string(),
|
|
50
|
+
projectId: import_zod.z.string(),
|
|
51
|
+
providerEventId: import_zod.z.string(),
|
|
52
|
+
type: import_zod.z.string(),
|
|
53
|
+
status: eventStatusSchema,
|
|
54
|
+
attempts: import_zod.z.number(),
|
|
55
|
+
lastError: import_zod.z.string().nullable(),
|
|
56
|
+
errorSignature: import_zod.z.string().nullable(),
|
|
57
|
+
receivedAt: import_zod.z.iso.datetime(),
|
|
58
|
+
processedAt: import_zod.z.iso.datetime().nullable(),
|
|
59
|
+
// event_log has no subject/customer reference column (sprint 24's
|
|
60
|
+
// repo-drizzle-subjects.ts documents the same gap the other direction) —
|
|
61
|
+
// derived from the raw Stripe payload's well-known `data.object.customer`
|
|
62
|
+
// path, so this is null for any non-Stripe-shaped payload.
|
|
63
|
+
subjectRef: import_zod.z.string().nullable()
|
|
64
|
+
});
|
|
65
|
+
var adminEventDetailSchema = adminEventSummarySchema.extend({
|
|
66
|
+
payload: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()),
|
|
67
|
+
discardReason: import_zod.z.string().nullable(),
|
|
68
|
+
discardedBy: import_zod.z.string().nullable(),
|
|
69
|
+
discardedAt: import_zod.z.iso.datetime().nullable()
|
|
70
|
+
});
|
|
71
|
+
var signatureCountSchema = import_zod.z.object({
|
|
72
|
+
signature: import_zod.z.string(),
|
|
73
|
+
count: import_zod.z.number()
|
|
74
|
+
});
|
|
75
|
+
var listEventsResponseSchema = import_zod.z.object({
|
|
76
|
+
events: import_zod.z.array(adminEventSummarySchema),
|
|
77
|
+
total: import_zod.z.number(),
|
|
78
|
+
limit: import_zod.z.number(),
|
|
79
|
+
offset: import_zod.z.number(),
|
|
80
|
+
signatureCounts: import_zod.z.array(signatureCountSchema)
|
|
81
|
+
});
|
|
82
|
+
var wouldApplySchema = import_zod.z.discriminatedUnion("kind", [
|
|
83
|
+
import_zod.z.object({ kind: import_zod.z.literal("create"), to: subscriptionStateSchema }),
|
|
84
|
+
import_zod.z.object({
|
|
85
|
+
kind: import_zod.z.literal("transition"),
|
|
86
|
+
from: subscriptionStateSchema,
|
|
87
|
+
to: subscriptionStateSchema
|
|
88
|
+
}),
|
|
89
|
+
import_zod.z.object({ kind: import_zod.z.literal("stale") }),
|
|
90
|
+
import_zod.z.object({
|
|
91
|
+
kind: import_zod.z.literal("invalid"),
|
|
92
|
+
from: subscriptionStateSchema,
|
|
93
|
+
to: subscriptionStateSchema
|
|
94
|
+
}),
|
|
95
|
+
import_zod.z.object({ kind: import_zod.z.literal("unknown_subscription") }),
|
|
96
|
+
import_zod.z.object({ kind: import_zod.z.literal("noop"), reason: import_zod.z.string() }),
|
|
97
|
+
import_zod.z.object({ kind: import_zod.z.literal("error"), reason: import_zod.z.string() })
|
|
98
|
+
]);
|
|
99
|
+
var dryRunReplayResponseSchema = import_zod.z.object({
|
|
100
|
+
event: adminEventDetailSchema,
|
|
101
|
+
current: import_zod.z.object({
|
|
102
|
+
state: subscriptionStateSchema,
|
|
103
|
+
lastEventAt: import_zod.z.iso.datetime().nullable()
|
|
104
|
+
}).nullable(),
|
|
105
|
+
wouldApply: wouldApplySchema
|
|
106
|
+
});
|
|
107
|
+
var replayOutcomeSchema = import_zod.z.enum([
|
|
108
|
+
"created",
|
|
109
|
+
"transitioned",
|
|
110
|
+
"stale",
|
|
111
|
+
"noop",
|
|
112
|
+
"invalid",
|
|
113
|
+
"unknown_subscription",
|
|
114
|
+
"already_processed",
|
|
115
|
+
"error"
|
|
116
|
+
]);
|
|
117
|
+
var replayResponseSchema = import_zod.z.object({
|
|
118
|
+
outcome: replayOutcomeSchema
|
|
119
|
+
});
|
|
120
|
+
var discardEventRequestSchema = import_zod.z.object({
|
|
121
|
+
actor: import_zod.z.string().min(1),
|
|
122
|
+
reason: import_zod.z.string()
|
|
123
|
+
});
|
|
124
|
+
var replayGroupCursorSchema = import_zod.z.object({
|
|
125
|
+
receivedAt: import_zod.z.iso.datetime(),
|
|
126
|
+
id: import_zod.z.string()
|
|
127
|
+
});
|
|
128
|
+
var replayGroupRequestSchema = import_zod.z.object({
|
|
129
|
+
projectId: import_zod.z.string().min(1),
|
|
130
|
+
cursor: replayGroupCursorSchema.optional(),
|
|
131
|
+
limit: import_zod.z.number().int().positive().optional()
|
|
132
|
+
}).and(
|
|
133
|
+
import_zod.z.union([
|
|
134
|
+
import_zod.z.object({ errorSignature: import_zod.z.string().min(1) }),
|
|
135
|
+
import_zod.z.object({ all: import_zod.z.literal(true) })
|
|
136
|
+
])
|
|
137
|
+
);
|
|
138
|
+
var replayGroupOutcomeEntrySchema = import_zod.z.object({
|
|
139
|
+
eventId: import_zod.z.string(),
|
|
140
|
+
outcome: replayOutcomeSchema
|
|
141
|
+
});
|
|
142
|
+
var replayGroupResponseSchema = import_zod.z.object({
|
|
143
|
+
outcomes: import_zod.z.array(replayGroupOutcomeEntrySchema),
|
|
144
|
+
// Keyed by ProcessOutcome, but zod v4's record needs .partial() semantics
|
|
145
|
+
// for an exhaustive enum key type, so this stays a plain string map — the
|
|
146
|
+
// set of possible keys is still exactly replayOutcomeSchema's members.
|
|
147
|
+
counts: import_zod.z.record(import_zod.z.string(), import_zod.z.number()),
|
|
148
|
+
// This call's batch (its own limit, or BULK_REPLAY_CAP by default) hit its
|
|
149
|
+
// ceiling: more matching events remain beyond what was just replayed.
|
|
150
|
+
// Paging with nextCursor continues; a non-paging caller reads this the
|
|
151
|
+
// same way it always has, as "replay again to finish draining it."
|
|
152
|
+
truncated: import_zod.z.boolean(),
|
|
153
|
+
nextCursor: replayGroupCursorSchema.nullable()
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// ../shared-types/src/entitlements.ts
|
|
157
|
+
var import_zod3 = require("zod");
|
|
158
|
+
|
|
159
|
+
// ../shared-types/src/subscriptions.ts
|
|
160
|
+
var import_zod2 = require("zod");
|
|
161
|
+
var subscriptionStatusSchema = import_zod2.z.enum([
|
|
162
|
+
"trialing",
|
|
163
|
+
"active",
|
|
164
|
+
"past_due",
|
|
165
|
+
"grace",
|
|
166
|
+
"canceled",
|
|
167
|
+
"unpaid",
|
|
168
|
+
"none"
|
|
169
|
+
]);
|
|
170
|
+
var activeSubscriptionViewSchema = import_zod2.z.object({
|
|
171
|
+
state: subscriptionStatusSchema.exclude(["none"]),
|
|
172
|
+
planKey: import_zod2.z.string(),
|
|
173
|
+
currentPeriodEnd: import_zod2.z.iso.datetime(),
|
|
174
|
+
cancelAtPeriodEnd: import_zod2.z.boolean()
|
|
175
|
+
});
|
|
176
|
+
var noSubscriptionViewSchema = import_zod2.z.object({
|
|
177
|
+
state: import_zod2.z.literal("none")
|
|
178
|
+
});
|
|
179
|
+
var subscriptionViewSchema = import_zod2.z.discriminatedUnion("state", [
|
|
180
|
+
activeSubscriptionViewSchema,
|
|
181
|
+
noSubscriptionViewSchema
|
|
182
|
+
]);
|
|
183
|
+
|
|
184
|
+
// ../shared-types/src/entitlements.ts
|
|
185
|
+
var entitlementSourcesSchema = import_zod3.z.object({
|
|
186
|
+
features: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.enum(["subscription", "override"])),
|
|
187
|
+
limits: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.enum(["subscription", "override"]))
|
|
188
|
+
});
|
|
189
|
+
var entitlementsResponseSchema = import_zod3.z.object({
|
|
190
|
+
plan: import_zod3.z.string().nullable(),
|
|
191
|
+
features: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.boolean()),
|
|
192
|
+
limits: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.number()),
|
|
193
|
+
status: subscriptionStatusSchema,
|
|
194
|
+
source: import_zod3.z.enum(["subscription", "override", "none"]),
|
|
195
|
+
sources: entitlementSourcesSchema
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// ../shared-types/src/overrides.ts
|
|
199
|
+
var import_zod4 = require("zod");
|
|
200
|
+
var overrideKindSchema = import_zod4.z.enum(["comp", "extend", "revoke"]);
|
|
201
|
+
var overrideTargetSchema = import_zod4.z.discriminatedUnion("type", [
|
|
202
|
+
import_zod4.z.object({ type: import_zod4.z.literal("feature"), feature: import_zod4.z.string().min(1) }),
|
|
203
|
+
import_zod4.z.object({
|
|
204
|
+
type: import_zod4.z.literal("limit"),
|
|
205
|
+
limit: import_zod4.z.string().min(1),
|
|
206
|
+
value: import_zod4.z.number()
|
|
207
|
+
})
|
|
208
|
+
]);
|
|
209
|
+
var createOverrideRequestSchema = import_zod4.z.object({
|
|
210
|
+
subjectId: import_zod4.z.string().min(1),
|
|
211
|
+
kind: overrideKindSchema,
|
|
212
|
+
target: overrideTargetSchema,
|
|
213
|
+
actor: import_zod4.z.string().min(1),
|
|
214
|
+
reason: import_zod4.z.string().min(4),
|
|
215
|
+
expiresAt: import_zod4.z.iso.datetime().optional()
|
|
216
|
+
});
|
|
217
|
+
var createBulkOverrideRequestSchema = import_zod4.z.object({
|
|
218
|
+
subjectId: import_zod4.z.string().min(1),
|
|
219
|
+
kind: overrideKindSchema,
|
|
220
|
+
targets: import_zod4.z.array(overrideTargetSchema).min(1),
|
|
221
|
+
actor: import_zod4.z.string().min(1),
|
|
222
|
+
reason: import_zod4.z.string().min(4),
|
|
223
|
+
expiresAt: import_zod4.z.iso.datetime().optional()
|
|
224
|
+
});
|
|
225
|
+
var overrideRecordSchema = import_zod4.z.object({
|
|
226
|
+
id: import_zod4.z.string(),
|
|
227
|
+
subjectId: import_zod4.z.string(),
|
|
228
|
+
kind: overrideKindSchema,
|
|
229
|
+
target: overrideTargetSchema,
|
|
230
|
+
actor: import_zod4.z.string(),
|
|
231
|
+
reason: import_zod4.z.string(),
|
|
232
|
+
expiresAt: import_zod4.z.iso.datetime().nullable(),
|
|
233
|
+
createdAt: import_zod4.z.iso.datetime()
|
|
234
|
+
});
|
|
235
|
+
var bulkOverrideResponseSchema = import_zod4.z.object({
|
|
236
|
+
overrides: import_zod4.z.array(overrideRecordSchema)
|
|
237
|
+
});
|
|
238
|
+
var listOverridesResponseSchema = import_zod4.z.object({
|
|
239
|
+
overrides: import_zod4.z.array(overrideRecordSchema),
|
|
240
|
+
total: import_zod4.z.number(),
|
|
241
|
+
limit: import_zod4.z.number(),
|
|
242
|
+
offset: import_zod4.z.number()
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// ../shared-types/src/admin.ts
|
|
246
|
+
var stateCountsSchema = import_zod5.z.object({
|
|
247
|
+
trialing: import_zod5.z.number(),
|
|
248
|
+
active: import_zod5.z.number(),
|
|
249
|
+
past_due: import_zod5.z.number(),
|
|
250
|
+
grace: import_zod5.z.number(),
|
|
251
|
+
canceled: import_zod5.z.number(),
|
|
252
|
+
unpaid: import_zod5.z.number()
|
|
253
|
+
});
|
|
254
|
+
var dashboardMetricsSchema = import_zod5.z.object({
|
|
255
|
+
mrrCents: import_zod5.z.number(),
|
|
256
|
+
mrrPrevCents: import_zod5.z.number(),
|
|
257
|
+
subjectsCount: import_zod5.z.number(),
|
|
258
|
+
states: stateCountsSchema,
|
|
259
|
+
deadLetterDepth: import_zod5.z.number(),
|
|
260
|
+
oldestUnprocessedSec: import_zod5.z.number().nullable(),
|
|
261
|
+
driftCount: import_zod5.z.number()
|
|
262
|
+
});
|
|
263
|
+
var projectMetricsSchema = dashboardMetricsSchema.extend({
|
|
264
|
+
projectId: import_zod5.z.string(),
|
|
265
|
+
projectKey: import_zod5.z.string(),
|
|
266
|
+
projectName: import_zod5.z.string(),
|
|
267
|
+
subjectType: import_zod5.z.string(),
|
|
268
|
+
environment: import_zod5.z.enum(["test", "live"]),
|
|
269
|
+
envLocked: import_zod5.z.boolean(),
|
|
270
|
+
mrrSeries: import_zod5.z.array(import_zod5.z.number())
|
|
271
|
+
});
|
|
272
|
+
var adminMetricsResponseSchema = import_zod5.z.object({
|
|
273
|
+
ecosystem: dashboardMetricsSchema,
|
|
274
|
+
// Shared x-axis labels for every project's mrrSeries (same calendar
|
|
275
|
+
// months across the ecosystem) — empty when no project has snapshots yet.
|
|
276
|
+
monthLabels: import_zod5.z.array(import_zod5.z.string()),
|
|
277
|
+
projects: import_zod5.z.array(projectMetricsSchema)
|
|
278
|
+
});
|
|
279
|
+
var adminEventsListResponseSchema = import_zod5.z.object({
|
|
280
|
+
events: import_zod5.z.array(adminEventSummarySchema),
|
|
281
|
+
nextCursor: import_zod5.z.string().nullable(),
|
|
282
|
+
approxTotal: import_zod5.z.number(),
|
|
283
|
+
signatureCounts: import_zod5.z.array(signatureCountSchema).optional()
|
|
284
|
+
});
|
|
285
|
+
var adminEventDetailResponseSchema = import_zod5.z.object({
|
|
286
|
+
event: adminEventDetailSchema,
|
|
287
|
+
transition: import_zod5.z.object({
|
|
288
|
+
current: import_zod5.z.object({
|
|
289
|
+
state: subscriptionStatusSchema.exclude(["grace", "none"]),
|
|
290
|
+
lastEventAt: import_zod5.z.iso.datetime().nullable()
|
|
291
|
+
}).nullable(),
|
|
292
|
+
wouldApply: wouldApplySchema
|
|
293
|
+
})
|
|
294
|
+
});
|
|
295
|
+
var adminSubjectSchema = import_zod5.z.object({
|
|
296
|
+
id: import_zod5.z.string(),
|
|
297
|
+
subjectType: import_zod5.z.string(),
|
|
298
|
+
externalId: import_zod5.z.string(),
|
|
299
|
+
providerCustomerId: import_zod5.z.string().nullable()
|
|
300
|
+
});
|
|
301
|
+
var featureGrantsSchema = import_zod5.z.record(
|
|
302
|
+
import_zod5.z.string(),
|
|
303
|
+
import_zod5.z.union([import_zod5.z.boolean(), import_zod5.z.number()])
|
|
304
|
+
);
|
|
305
|
+
var adminSubjectSubscriptionPlanSchema = import_zod5.z.object({
|
|
306
|
+
key: import_zod5.z.string(),
|
|
307
|
+
featureGrants: featureGrantsSchema,
|
|
308
|
+
priceInterval: import_zod5.z.enum(["month", "year"]).nullable()
|
|
309
|
+
});
|
|
310
|
+
var adminSubjectLookupResponseSchema = import_zod5.z.object({
|
|
311
|
+
subject: adminSubjectSchema,
|
|
312
|
+
entitlements: entitlementsResponseSchema,
|
|
313
|
+
recentEvents: import_zod5.z.array(adminEventSummarySchema),
|
|
314
|
+
activeOverrides: import_zod5.z.array(overrideRecordSchema),
|
|
315
|
+
subscriptionPlan: adminSubjectSubscriptionPlanSchema.nullable()
|
|
316
|
+
});
|
|
317
|
+
var adminPriceSchema = import_zod5.z.object({
|
|
318
|
+
id: import_zod5.z.string(),
|
|
319
|
+
interval: import_zod5.z.enum(["month", "year"]),
|
|
320
|
+
currency: import_zod5.z.string(),
|
|
321
|
+
unitAmountCents: import_zod5.z.number(),
|
|
322
|
+
syncStatus: import_zod5.z.enum(["synced", "pending", "drifted"]),
|
|
323
|
+
syncedUnitAmountCents: import_zod5.z.number().nullable()
|
|
324
|
+
});
|
|
325
|
+
var adminPlanSchema = import_zod5.z.object({
|
|
326
|
+
id: import_zod5.z.string(),
|
|
327
|
+
key: import_zod5.z.string(),
|
|
328
|
+
name: import_zod5.z.string(),
|
|
329
|
+
featureGrants: featureGrantsSchema,
|
|
330
|
+
activeSubscriptions: import_zod5.z.number(),
|
|
331
|
+
prices: import_zod5.z.array(adminPriceSchema)
|
|
332
|
+
});
|
|
333
|
+
var adminPlansResponseSchema = import_zod5.z.object({
|
|
334
|
+
project: import_zod5.z.object({
|
|
335
|
+
statementDescriptor: import_zod5.z.string().nullable(),
|
|
336
|
+
statementDescriptorPrefix: import_zod5.z.string().nullable()
|
|
337
|
+
}),
|
|
338
|
+
plans: import_zod5.z.array(adminPlanSchema)
|
|
339
|
+
});
|
|
340
|
+
var adminProviderResponseSchema = import_zod5.z.object({
|
|
341
|
+
projectId: import_zod5.z.string(),
|
|
342
|
+
providerKind: import_zod5.z.string(),
|
|
343
|
+
environment: import_zod5.z.enum(["test", "live"]),
|
|
344
|
+
envLocked: import_zod5.z.boolean(),
|
|
345
|
+
secretKeyMasked: import_zod5.z.string().nullable(),
|
|
346
|
+
publishableKeyMasked: import_zod5.z.string().nullable(),
|
|
347
|
+
webhookEndpoint: import_zod5.z.string(),
|
|
348
|
+
webhookSigningConfigured: import_zod5.z.boolean(),
|
|
349
|
+
defaultPortalReturnUrl: import_zod5.z.string().nullable()
|
|
350
|
+
});
|
|
351
|
+
var adminAuditEntrySchema = overrideRecordSchema.extend({
|
|
352
|
+
projectId: import_zod5.z.string()
|
|
353
|
+
});
|
|
354
|
+
var adminAuditResponseSchema = import_zod5.z.object({
|
|
355
|
+
entries: import_zod5.z.array(adminAuditEntrySchema),
|
|
356
|
+
nextCursor: import_zod5.z.string().nullable(),
|
|
357
|
+
approxTotal: import_zod5.z.number()
|
|
358
|
+
});
|
|
359
|
+
var adminThroughputResponseSchema = import_zod5.z.object({
|
|
360
|
+
days: import_zod5.z.array(import_zod5.z.string()),
|
|
361
|
+
processed: import_zod5.z.array(import_zod5.z.number()),
|
|
362
|
+
failed: import_zod5.z.array(import_zod5.z.number())
|
|
363
|
+
});
|
|
364
|
+
var adminPlanMixResponseSchema = import_zod5.z.object({
|
|
365
|
+
months: import_zod5.z.array(import_zod5.z.string()),
|
|
366
|
+
plans: import_zod5.z.array(import_zod5.z.object({ key: import_zod5.z.string(), name: import_zod5.z.string() })),
|
|
367
|
+
stacks: import_zod5.z.array(import_zod5.z.array(import_zod5.z.number()))
|
|
368
|
+
});
|
|
369
|
+
var adminDeadLetterGroupSchema = import_zod5.z.object({
|
|
370
|
+
projectId: import_zod5.z.string(),
|
|
371
|
+
signature: import_zod5.z.string(),
|
|
372
|
+
count: import_zod5.z.number(),
|
|
373
|
+
sampleEventId: import_zod5.z.string(),
|
|
374
|
+
firstReceivedAt: import_zod5.z.iso.datetime(),
|
|
375
|
+
lastReceivedAt: import_zod5.z.iso.datetime()
|
|
376
|
+
});
|
|
377
|
+
var adminDeadLetterGroupsResponseSchema = import_zod5.z.object({
|
|
378
|
+
groups: import_zod5.z.array(adminDeadLetterGroupSchema)
|
|
379
|
+
});
|
|
380
|
+
var adminProjectDashboardResponseSchema = import_zod5.z.object({
|
|
381
|
+
metrics: projectMetricsSchema,
|
|
382
|
+
monthLabels: import_zod5.z.array(import_zod5.z.string()),
|
|
383
|
+
providerKind: import_zod5.z.string(),
|
|
384
|
+
plans: import_zod5.z.array(adminPlanSchema)
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// ../shared-types/src/checkout.ts
|
|
388
|
+
var import_zod6 = require("zod");
|
|
389
|
+
var checkoutRequestSchema = import_zod6.z.object({
|
|
390
|
+
planKey: import_zod6.z.string(),
|
|
391
|
+
subjectId: import_zod6.z.string(),
|
|
392
|
+
successUrl: import_zod6.z.url(),
|
|
393
|
+
cancelUrl: import_zod6.z.url(),
|
|
394
|
+
email: import_zod6.z.email().optional()
|
|
395
|
+
});
|
|
396
|
+
var checkoutResponseSchema = import_zod6.z.object({
|
|
397
|
+
url: import_zod6.z.url()
|
|
398
|
+
});
|
|
399
|
+
var portalRequestSchema = import_zod6.z.object({
|
|
400
|
+
subjectId: import_zod6.z.string(),
|
|
401
|
+
returnUrl: import_zod6.z.url()
|
|
402
|
+
});
|
|
403
|
+
var portalResponseSchema = import_zod6.z.object({
|
|
404
|
+
url: import_zod6.z.url()
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// ../shared-types/src/projects.ts
|
|
408
|
+
var import_zod7 = require("zod");
|
|
409
|
+
var registerProjectRequestSchema = import_zod7.z.object({
|
|
410
|
+
key: import_zod7.z.string().trim().min(1, "is required"),
|
|
411
|
+
name: import_zod7.z.string().trim().min(1, "is required"),
|
|
412
|
+
subjectType: import_zod7.z.string().trim().min(1, "is required"),
|
|
413
|
+
environment: import_zod7.z.enum(["test", "live"], 'must be "test" or "live"'),
|
|
414
|
+
envLocked: import_zod7.z.boolean().optional(),
|
|
415
|
+
providerKind: import_zod7.z.string().trim().min(1, "is required"),
|
|
416
|
+
providerSecretKeyRef: import_zod7.z.string().optional(),
|
|
417
|
+
providerPublishableKeyRef: import_zod7.z.string().optional(),
|
|
418
|
+
providerPortalConfigRef: import_zod7.z.string().optional(),
|
|
419
|
+
statementDescriptor: import_zod7.z.string().optional(),
|
|
420
|
+
statementDescriptorPrefix: import_zod7.z.string().optional(),
|
|
421
|
+
graceDays: import_zod7.z.number().min(0, "must be >= 0").optional(),
|
|
422
|
+
defaultPortalReturnUrl: import_zod7.z.url().optional()
|
|
423
|
+
}).superRefine((input, ctx) => {
|
|
424
|
+
if (!input.statementDescriptor && !input.statementDescriptorPrefix) {
|
|
425
|
+
ctx.addIssue({
|
|
426
|
+
code: "custom",
|
|
427
|
+
path: ["statementDescriptor"],
|
|
428
|
+
message: "statementDescriptor or statementDescriptorPrefix is required"
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// ../shared-types/src/errors.ts
|
|
434
|
+
var import_zod8 = require("zod");
|
|
435
|
+
var errorEnvelopeSchema = import_zod8.z.object({
|
|
436
|
+
error: import_zod8.z.object({
|
|
437
|
+
code: import_zod8.z.string(),
|
|
438
|
+
message: import_zod8.z.string()
|
|
439
|
+
})
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// ../shared-types/src/webhook-secret.ts
|
|
443
|
+
var import_zod9 = require("zod");
|
|
444
|
+
var webhookSigningSecretSchema = import_zod9.z.string().regex(/^whsec_.+/, "must be a non-empty whsec_-prefixed string");
|
|
445
|
+
|
|
446
|
+
// ../shared-types/src/portal-return-url.ts
|
|
447
|
+
var import_zod10 = require("zod");
|
|
448
|
+
var portalReturnUrlSchema = import_zod10.z.url();
|
|
449
|
+
|
|
450
|
+
// src/cache.ts
|
|
451
|
+
var TtlCache = class {
|
|
452
|
+
constructor(now = Date.now) {
|
|
453
|
+
this.now = now;
|
|
454
|
+
}
|
|
455
|
+
now;
|
|
456
|
+
store = /* @__PURE__ */ new Map();
|
|
457
|
+
get(key) {
|
|
458
|
+
return this.store.get(key);
|
|
459
|
+
}
|
|
460
|
+
set(key, value) {
|
|
461
|
+
this.store.set(key, { value, fetchedAt: this.now() });
|
|
462
|
+
}
|
|
463
|
+
getFresh(key, ttlMs) {
|
|
464
|
+
const entry = this.store.get(key);
|
|
465
|
+
if (!entry) return void 0;
|
|
466
|
+
return this.now() - entry.fetchedAt < ttlMs ? entry.value : void 0;
|
|
467
|
+
}
|
|
468
|
+
getStale(key) {
|
|
469
|
+
return this.store.get(key)?.value;
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// src/errors.ts
|
|
474
|
+
var BillingApiError = class extends Error {
|
|
475
|
+
status;
|
|
476
|
+
code;
|
|
477
|
+
constructor(status, code, message) {
|
|
478
|
+
super(message);
|
|
479
|
+
this.name = "BillingApiError";
|
|
480
|
+
this.status = status;
|
|
481
|
+
this.code = code;
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
async function errorFromResponse(response) {
|
|
485
|
+
let code = "unknown_error";
|
|
486
|
+
let message = `Request failed with status ${response.status}`;
|
|
487
|
+
try {
|
|
488
|
+
const body = await response.json();
|
|
489
|
+
const parsed = errorEnvelopeSchema.safeParse(body);
|
|
490
|
+
if (parsed.success) {
|
|
491
|
+
code = parsed.data.error.code;
|
|
492
|
+
message = parsed.data.error.message;
|
|
493
|
+
}
|
|
494
|
+
} catch {
|
|
495
|
+
}
|
|
496
|
+
return new BillingApiError(response.status, code, message);
|
|
497
|
+
}
|
|
498
|
+
function networkError(cause) {
|
|
499
|
+
const message = cause instanceof Error ? cause.message : "Network request failed";
|
|
500
|
+
return new BillingApiError(0, "network_error", message);
|
|
501
|
+
}
|
|
502
|
+
function invalidResponseError(message) {
|
|
503
|
+
return new BillingApiError(502, "invalid_response", message);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// src/client.ts
|
|
507
|
+
var DEFAULT_ENTITLEMENTS_TTL_MS = 5e3;
|
|
508
|
+
async function requestJson(fetchImpl, url, apiKey, init) {
|
|
509
|
+
let response;
|
|
510
|
+
try {
|
|
511
|
+
response = await fetchImpl(url, {
|
|
512
|
+
...init,
|
|
513
|
+
headers: {
|
|
514
|
+
...init?.headers,
|
|
515
|
+
Authorization: `Bearer ${apiKey}`,
|
|
516
|
+
...init?.body ? { "Content-Type": "application/json" } : {}
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
} catch (cause) {
|
|
520
|
+
throw networkError(cause);
|
|
521
|
+
}
|
|
522
|
+
if (!response.ok) {
|
|
523
|
+
throw await errorFromResponse(response);
|
|
524
|
+
}
|
|
525
|
+
return response.json();
|
|
526
|
+
}
|
|
527
|
+
function parseOrThrow(schema, data) {
|
|
528
|
+
const parsed = schema.safeParse(data);
|
|
529
|
+
if (!parsed.success) {
|
|
530
|
+
throw invalidResponseError(
|
|
531
|
+
`Response failed validation: ${parsed.error.message}`
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
return parsed.data;
|
|
535
|
+
}
|
|
536
|
+
function createClient(options) {
|
|
537
|
+
const { apiKey, baseUrl } = options;
|
|
538
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
539
|
+
const entitlementsTtlMs = options.entitlementsTtlMs ?? DEFAULT_ENTITLEMENTS_TTL_MS;
|
|
540
|
+
const entitlementsCache = new TtlCache();
|
|
541
|
+
async function getEntitlements(subjectId) {
|
|
542
|
+
const fresh = entitlementsCache.getFresh(subjectId, entitlementsTtlMs);
|
|
543
|
+
if (fresh) return fresh;
|
|
544
|
+
try {
|
|
545
|
+
const data = await requestJson(
|
|
546
|
+
fetchImpl,
|
|
547
|
+
`${baseUrl}/v1/entitlements/${encodeURIComponent(subjectId)}`,
|
|
548
|
+
apiKey
|
|
549
|
+
);
|
|
550
|
+
const parsed = parseOrThrow(entitlementsResponseSchema, data);
|
|
551
|
+
entitlementsCache.set(subjectId, parsed);
|
|
552
|
+
return parsed;
|
|
553
|
+
} catch (err) {
|
|
554
|
+
const isClientError = err instanceof BillingApiError && err.status >= 400 && err.status < 500;
|
|
555
|
+
if (isClientError) throw err;
|
|
556
|
+
const stale = entitlementsCache.getStale(subjectId);
|
|
557
|
+
if (stale) return { ...stale, stale: true };
|
|
558
|
+
throw err;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
async function createCheckout(input) {
|
|
562
|
+
const data = await requestJson(
|
|
563
|
+
fetchImpl,
|
|
564
|
+
`${baseUrl}/v1/checkout`,
|
|
565
|
+
apiKey,
|
|
566
|
+
{
|
|
567
|
+
method: "POST",
|
|
568
|
+
body: JSON.stringify(input)
|
|
569
|
+
}
|
|
570
|
+
);
|
|
571
|
+
return parseOrThrow(checkoutResponseSchema, data);
|
|
572
|
+
}
|
|
573
|
+
async function portalUrl(input) {
|
|
574
|
+
const data = await requestJson(fetchImpl, `${baseUrl}/v1/portal`, apiKey, {
|
|
575
|
+
method: "POST",
|
|
576
|
+
body: JSON.stringify(input)
|
|
577
|
+
});
|
|
578
|
+
return parseOrThrow(portalResponseSchema, data);
|
|
579
|
+
}
|
|
580
|
+
async function getSubscription(subjectId) {
|
|
581
|
+
const data = await requestJson(
|
|
582
|
+
fetchImpl,
|
|
583
|
+
`${baseUrl}/v1/subscriptions/${encodeURIComponent(subjectId)}`,
|
|
584
|
+
apiKey
|
|
585
|
+
);
|
|
586
|
+
return parseOrThrow(subscriptionViewSchema, data);
|
|
587
|
+
}
|
|
588
|
+
return { getEntitlements, createCheckout, portalUrl, getSubscription };
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// src/guard.ts
|
|
592
|
+
function isMisconfiguration(err) {
|
|
593
|
+
return err instanceof BillingApiError && err.status >= 400 && err.status < 500;
|
|
594
|
+
}
|
|
595
|
+
function decideOnContent(entitlements, feature, limit) {
|
|
596
|
+
if (feature !== void 0) {
|
|
597
|
+
return entitlements.features[feature] ? { decision: "allow", entitlements } : { decision: "deny", reason: `Feature "${feature}" is not entitled` };
|
|
598
|
+
}
|
|
599
|
+
if (limit !== void 0) {
|
|
600
|
+
const max = entitlements.limits[limit.key];
|
|
601
|
+
return max !== void 0 && limit.usage < max ? { decision: "allow", entitlements } : { decision: "deny", reason: `Limit "${limit.key}" has been reached` };
|
|
602
|
+
}
|
|
603
|
+
return { decision: "allow", entitlements };
|
|
604
|
+
}
|
|
605
|
+
async function checkEntitlement(input) {
|
|
606
|
+
const { client, subjectId, feature, limit, onUnavailable } = input;
|
|
607
|
+
let entitlements;
|
|
608
|
+
try {
|
|
609
|
+
entitlements = await client.getEntitlements(subjectId);
|
|
610
|
+
} catch (err) {
|
|
611
|
+
if (isMisconfiguration(err)) {
|
|
612
|
+
const message = err instanceof Error ? err.message : "Billing request was rejected";
|
|
613
|
+
return { decision: "deny", reason: message, misconfigured: true };
|
|
614
|
+
}
|
|
615
|
+
return onUnavailable === "open" ? { decision: "unavailable-allow" } : { decision: "unavailable-deny", reason: "Billing is unavailable" };
|
|
616
|
+
}
|
|
617
|
+
return decideOnContent(entitlements, feature, limit);
|
|
618
|
+
}
|
|
619
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
620
|
+
0 && (module.exports = {
|
|
621
|
+
BillingApiError,
|
|
622
|
+
checkEntitlement,
|
|
623
|
+
createClient
|
|
624
|
+
});
|
|
625
|
+
//# sourceMappingURL=index.cjs.map
|