@kernhq/module-billing 0.2.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.
Files changed (46) hide show
  1. package/LICENSE +662 -0
  2. package/dist/contract.d.ts +965 -0
  3. package/dist/contract.d.ts.map +1 -0
  4. package/dist/contract.js +265 -0
  5. package/dist/contract.js.map +1 -0
  6. package/dist/server/index.d.ts +11 -0
  7. package/dist/server/index.d.ts.map +1 -0
  8. package/dist/server/index.js +165 -0
  9. package/dist/server/index.js.map +1 -0
  10. package/dist/server/router.d.ts +697 -0
  11. package/dist/server/router.d.ts.map +1 -0
  12. package/dist/server/router.js +126 -0
  13. package/dist/server/router.js.map +1 -0
  14. package/dist/server/schema.d.ts +1030 -0
  15. package/dist/server/schema.d.ts.map +1 -0
  16. package/dist/server/schema.js +137 -0
  17. package/dist/server/schema.js.map +1 -0
  18. package/dist/server/services/entitlements.d.ts +3 -0
  19. package/dist/server/services/entitlements.d.ts.map +1 -0
  20. package/dist/server/services/entitlements.js +68 -0
  21. package/dist/server/services/entitlements.js.map +1 -0
  22. package/dist/server/services/plans.d.ts +20 -0
  23. package/dist/server/services/plans.d.ts.map +1 -0
  24. package/dist/server/services/plans.js +122 -0
  25. package/dist/server/services/plans.js.map +1 -0
  26. package/dist/server/services/stripe.d.ts +42 -0
  27. package/dist/server/services/stripe.d.ts.map +1 -0
  28. package/dist/server/services/stripe.js +267 -0
  29. package/dist/server/services/stripe.js.map +1 -0
  30. package/dist/server/services/subscriptions.d.ts +35 -0
  31. package/dist/server/services/subscriptions.d.ts.map +1 -0
  32. package/dist/server/services/subscriptions.js +193 -0
  33. package/dist/server/services/subscriptions.js.map +1 -0
  34. package/dist/server/services/usage.d.ts +40 -0
  35. package/dist/server/services/usage.d.ts.map +1 -0
  36. package/dist/server/services/usage.js +98 -0
  37. package/dist/server/services/usage.js.map +1 -0
  38. package/migrations/0000_init.sql +82 -0
  39. package/migrations/0001_rls.sql +18 -0
  40. package/migrations/meta/0000_snapshot.json +580 -0
  41. package/migrations/meta/_journal.json +20 -0
  42. package/package.json +73 -0
  43. package/src/client/api.ts +15 -0
  44. package/src/client/format.test.ts +64 -0
  45. package/src/client/index.ts +81 -0
  46. package/src/contract.ts +311 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,265 @@
1
+ import { baseContract, defineEvent, definePermissions, Id, PageInput, page, WorkspaceId, } from '@kernhq/contracts';
2
+ import { z } from 'zod';
3
+ export const MODULE_ID = 'billing';
4
+ /**
5
+ * The limits a plan may set.
6
+ *
7
+ * These keys mirror `Entitlement` in `@kernhq/kernel` exactly, and that is the point: the kernel
8
+ * declares what can be limited, this module decides the values, and every key has one place in core
9
+ * that enforces it. A plan can therefore be edited freely by an instance admin without ever being
10
+ * able to promise something nothing checks.
11
+ *
12
+ * `null` means unlimited, everywhere.
13
+ */
14
+ export const PlanLimits = z.object({
15
+ /** billable seats; members with the `guest` role never consume one */
16
+ seats: z.number().int().positive().nullable().default(null),
17
+ storageBytes: z.number().int().nonnegative().nullable().default(null),
18
+ /** module ids this plan allows to be switched on; `null` = every module the instance ships */
19
+ modules: z.array(z.string()).nullable().default(null),
20
+ sso: z.boolean().default(true),
21
+ auditRetentionDays: z.number().int().positive().nullable().default(null),
22
+ apiRateLimit: z.number().int().positive().nullable().default(null),
23
+ });
24
+ /**
25
+ * A patch over `PlanLimits`, for comping one limit without touching the rest.
26
+ *
27
+ * Written out rather than derived with `.partial()`, because `.partial()` keeps the field defaults:
28
+ * parsing `{ seats: 50 }` through it returns every other key at its default too, so spreading the
29
+ * result silently resets limits the admin never mentioned. Absent here means absent.
30
+ */
31
+ export const PlanLimitsPatch = z.object({
32
+ seats: z.number().int().positive().nullable().optional(),
33
+ storageBytes: z.number().int().nonnegative().nullable().optional(),
34
+ modules: z.array(z.string()).nullable().optional(),
35
+ sso: z.boolean().optional(),
36
+ auditRetentionDays: z.number().int().positive().nullable().optional(),
37
+ apiRateLimit: z.number().int().positive().nullable().optional(),
38
+ });
39
+ export const BillingInterval = z.enum(['month', 'year']);
40
+ export const Plan = z.object({
41
+ id: Id,
42
+ /** stable identifier used in URLs and by the marketing site; never reused */
43
+ slug: z
44
+ .string()
45
+ .min(2)
46
+ .max(48)
47
+ .regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/),
48
+ name: z.string().min(1).max(80),
49
+ description: z.string().max(300).default(''),
50
+ /** in the currency's smallest unit, so 800 is $8.00 — never a float */
51
+ priceMinor: z.number().int().nonnegative(),
52
+ currency: z.string().length(3).default('usd'),
53
+ interval: BillingInterval.default('month'),
54
+ /** true when `priceMinor` is charged per seat rather than per workspace */
55
+ perSeat: z.boolean().default(true),
56
+ trialDays: z.number().int().nonnegative().default(0),
57
+ limits: PlanLimits,
58
+ /** the price object in Stripe; null until the plan is wired to one */
59
+ stripePriceId: z.string().nullable().default(null),
60
+ /** what the marketing site lists under the plan */
61
+ highlights: z.array(z.string()).default([]),
62
+ published: z.boolean().default(false),
63
+ order: z.number().int().default(100),
64
+ createdAt: z.string(),
65
+ updatedAt: z.string(),
66
+ });
67
+ /**
68
+ * What a stranger may see. Served unauthenticated so the marketing site can render prices that come
69
+ * from the same row the instance actually charges against — no internal ids, no Stripe ids, and
70
+ * published plans only.
71
+ */
72
+ export const PublicPlan = Plan.pick({
73
+ slug: true,
74
+ name: true,
75
+ description: true,
76
+ priceMinor: true,
77
+ currency: true,
78
+ interval: true,
79
+ perSeat: true,
80
+ trialDays: true,
81
+ highlights: true,
82
+ order: true,
83
+ }).extend({ limits: PlanLimits });
84
+ export const UpsertPlan = Plan.omit({ id: true, createdAt: true, updatedAt: true }).extend({
85
+ id: Id.optional(),
86
+ });
87
+ /**
88
+ * `trialing` and `active` are the two states that entitle a workspace to its plan.
89
+ * `past_due` still does — there is a grace period — and `suspended` does not.
90
+ * `canceled` keeps the row so the history and the Stripe ids survive a resubscribe.
91
+ */
92
+ export const SubscriptionStatus = z.enum(['trialing', 'active', 'past_due', 'canceled', 'suspended']);
93
+ export const Subscription = z.object({
94
+ workspaceId: WorkspaceId,
95
+ planId: Id.nullable(),
96
+ planName: z.string().nullable(),
97
+ planSlug: z.string().nullable(),
98
+ status: SubscriptionStatus,
99
+ seatsPurchased: z.number().int().nonnegative(),
100
+ trialEndsAt: z.string().nullable(),
101
+ currentPeriodEnd: z.string().nullable(),
102
+ cancelAtPeriodEnd: z.boolean(),
103
+ /** set once the workspace has a Stripe customer; null on a comped or manually managed workspace */
104
+ stripeCustomerId: z.string().nullable(),
105
+ stripeSubscriptionId: z.string().nullable(),
106
+ });
107
+ export const Usage = z.object({
108
+ seats: z.number().int().nonnegative(),
109
+ storageBytes: z.number().int().nonnegative(),
110
+ updatedAt: z.string(),
111
+ });
112
+ /** Everything the workspace's own billing screen needs, in one round trip. */
113
+ export const WorkspaceBilling = z.object({
114
+ subscription: Subscription.nullable(),
115
+ usage: Usage,
116
+ limits: PlanLimits,
117
+ /** false while past due or suspended */
118
+ active: z.boolean(),
119
+ /** whether this instance can take a payment at all — false when no Stripe key is configured */
120
+ paymentsEnabled: z.boolean(),
121
+ });
122
+ export const Invoice = z.object({
123
+ id: Id,
124
+ workspaceId: WorkspaceId,
125
+ number: z.string().nullable(),
126
+ status: z.string(),
127
+ totalMinor: z.number().int(),
128
+ currency: z.string(),
129
+ periodStart: z.string().nullable(),
130
+ periodEnd: z.string().nullable(),
131
+ hostedUrl: z.string().nullable(),
132
+ pdfUrl: z.string().nullable(),
133
+ createdAt: z.string(),
134
+ });
135
+ /** One row of the instance console's list of every workspace on the instance. */
136
+ export const AdminWorkspaceRow = z.object({
137
+ workspaceId: WorkspaceId,
138
+ workspaceName: z.string(),
139
+ workspaceSlug: z.string(),
140
+ planName: z.string().nullable(),
141
+ planSlug: z.string().nullable(),
142
+ status: SubscriptionStatus.nullable(),
143
+ seatsUsed: z.number().int().nonnegative(),
144
+ seatsPurchased: z.number().int().nonnegative(),
145
+ storageBytes: z.number().int().nonnegative(),
146
+ trialEndsAt: z.string().nullable(),
147
+ currentPeriodEnd: z.string().nullable(),
148
+ /** what this workspace bills per month, in minor units; annual plans are divided by twelve */
149
+ monthlyMinor: z.number().int().nonnegative(),
150
+ currency: z.string(),
151
+ /** true when an admin has overridden any limit by hand */
152
+ overridden: z.boolean(),
153
+ stripeCustomerId: z.string().nullable(),
154
+ });
155
+ const ws = z.object({ workspaceId: WorkspaceId });
156
+ export const billingContract = {
157
+ plans: {
158
+ list: baseContract
159
+ .route({ method: 'GET', path: '/plans', tags: ['billing'] })
160
+ .input(z.object({ includeUnpublished: z.boolean().default(false) }))
161
+ .output(z.array(Plan)),
162
+ /**
163
+ * Unauthenticated on purpose: this is what kernaio.com and any other instance's marketing page
164
+ * reads, so that a price is edited in one place and true in both.
165
+ */
166
+ public: baseContract
167
+ .route({ method: 'GET', path: '/plans/public', tags: ['billing'] })
168
+ .input(z.object({}))
169
+ .output(z.array(PublicPlan)),
170
+ upsert: baseContract
171
+ .route({ method: 'POST', path: '/plans', tags: ['billing'] })
172
+ .input(UpsertPlan)
173
+ .output(Plan),
174
+ setPublished: baseContract
175
+ .route({ method: 'POST', path: '/plans/{id}/published', tags: ['billing'] })
176
+ .input(z.object({ id: Id, published: z.boolean() }))
177
+ .output(Plan),
178
+ archive: baseContract
179
+ .route({ method: 'DELETE', path: '/plans/{id}', tags: ['billing'] })
180
+ .input(z.object({ id: Id }))
181
+ .output(z.object({ ok: z.literal(true) })),
182
+ },
183
+ subscription: {
184
+ get: baseContract
185
+ .route({ method: 'GET', path: '/subscription', tags: ['billing'] })
186
+ .input(ws)
187
+ .output(WorkspaceBilling),
188
+ invoices: baseContract
189
+ .route({ method: 'GET', path: '/subscription/invoices', tags: ['billing'] })
190
+ .input(ws.extend(PageInput.shape))
191
+ .output(page(Invoice)),
192
+ /** Stripe Checkout for a new subscription or a plan change; returns a URL to send the user to. */
193
+ checkout: baseContract
194
+ .route({ method: 'POST', path: '/subscription/checkout', tags: ['billing'] })
195
+ .input(ws.extend({ planSlug: z.string(), seats: z.number().int().positive().optional() }))
196
+ .output(z.object({ url: z.string() })),
197
+ /** Stripe's own billing portal: payment method, cancellation, invoice download. */
198
+ portal: baseContract
199
+ .route({ method: 'POST', path: '/subscription/portal', tags: ['billing'] })
200
+ .input(ws.extend({ returnPath: z.string().default('/') }))
201
+ .output(z.object({ url: z.string() })),
202
+ },
203
+ admin: {
204
+ workspaces: baseContract
205
+ .route({ method: 'GET', path: '/admin/workspaces', tags: ['billing'] })
206
+ .input(z.object({ q: z.string().optional(), status: SubscriptionStatus.optional() }).extend(PageInput.shape))
207
+ .output(page(AdminWorkspaceRow)),
208
+ setPlan: baseContract
209
+ .route({ method: 'POST', path: '/admin/workspaces/{workspaceId}/plan', tags: ['billing'] })
210
+ .input(ws.extend({ planId: Id.nullable(), seatsPurchased: z.number().int().nonnegative().optional() }))
211
+ .output(Subscription),
212
+ /**
213
+ * Comp an account without inventing a plan for it. `null` clears the override and the plan's own
214
+ * limit applies again.
215
+ */
216
+ override: baseContract
217
+ .route({ method: 'POST', path: '/admin/workspaces/{workspaceId}/override', tags: ['billing'] })
218
+ .input(ws.extend({ limits: PlanLimitsPatch.nullable() }))
219
+ .output(Subscription),
220
+ extendTrial: baseContract
221
+ .route({ method: 'POST', path: '/admin/workspaces/{workspaceId}/trial', tags: ['billing'] })
222
+ .input(ws.extend({ days: z.number().int().positive().max(365) }))
223
+ .output(Subscription),
224
+ setStatus: baseContract
225
+ .route({ method: 'POST', path: '/admin/workspaces/{workspaceId}/status', tags: ['billing'] })
226
+ .input(ws.extend({ status: z.enum(['active', 'suspended']) }))
227
+ .output(Subscription),
228
+ },
229
+ };
230
+ export const billingEvents = {
231
+ /**
232
+ * Emitted whenever anything changes what a workspace is allowed to do. The kernel listens on
233
+ * `billing.subscription.*` and drops its entitlement cache, so a customer who has just paid does
234
+ * not wait out a TTL for the seat they bought.
235
+ */
236
+ subscriptionChanged: defineEvent('billing.subscription.changed', z.object({
237
+ workspaceId: WorkspaceId,
238
+ status: SubscriptionStatus,
239
+ planSlug: z.string().nullable(),
240
+ })),
241
+ subscriptionSuspended: defineEvent('billing.subscription.suspended', z.object({ workspaceId: WorkspaceId, reason: z.string() })),
242
+ /** A plan was published or unpublished — what the marketing site shows has changed. */
243
+ catalogueChanged: defineEvent('billing.catalogue.changed', z.object({ planSlug: z.string() })),
244
+ };
245
+ export const BILLING_PERMISSIONS = {
246
+ view: 'billing.subscription.view',
247
+ manage: 'billing.subscription.manage',
248
+ };
249
+ export const billingPermissions = definePermissions([
250
+ {
251
+ key: BILLING_PERMISSIONS.view,
252
+ label: 'View the plan and what it costs',
253
+ scope: 'workspace',
254
+ defaultRoles: ['owner', 'admin'],
255
+ dangerous: false,
256
+ },
257
+ {
258
+ key: BILLING_PERMISSIONS.manage,
259
+ label: 'Change the plan and the payment method',
260
+ scope: 'workspace',
261
+ defaultRoles: ['owner'],
262
+ dangerous: true,
263
+ },
264
+ ]);
265
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ export { billingRouter } from './router.js';
3
+ export * from './schema.js';
4
+ export * as billingEntitlements from './services/entitlements.js';
5
+ export * as billingPlans from './services/plans.js';
6
+ export * as billingStripe from './services/stripe.js';
7
+ export * as billingSubscriptions from './services/subscriptions.js';
8
+ export * as billingUsage from './services/usage.js';
9
+ export declare const billingModule: import("@kernhq/kernel").ServerModule<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
10
+ export default billingModule;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AASvB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,cAAc,aAAa,CAAA;AAC3B,OAAO,KAAK,mBAAmB,MAAM,4BAA4B,CAAA;AACjE,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAA;AACnD,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAA;AACrD,OAAO,KAAK,oBAAoB,MAAM,6BAA6B,CAAA;AACnE,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAA;AAiBnD,eAAO,MAAM,aAAa,gHA4IxB,CAAA;AAEF,eAAe,aAAa,CAAA"}
@@ -0,0 +1,165 @@
1
+ import { dirname, join } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { WorkspaceId } from '@kernhq/contracts';
4
+ import { defineModule, defineServerModule, KernError, packageVersion } from '@kernhq/kernel';
5
+ import { and, eq, isNotNull, lte } from 'drizzle-orm';
6
+ import { z } from 'zod';
7
+ import { billingContract, billingEvents, billingPermissions, MODULE_ID } from '../contract.js';
8
+ import { billingRouter } from './router.js';
9
+ import { schema, subscriptions } from './schema.js';
10
+ import * as entitlements from './services/entitlements.js';
11
+ import * as stripeSvc from './services/stripe.js';
12
+ import * as subsSvc from './services/subscriptions.js';
13
+ import * as usageSvc from './services/usage.js';
14
+ export { billingRouter } from './router.js';
15
+ export * from './schema.js';
16
+ export * as billingEntitlements from './services/entitlements.js';
17
+ export * as billingPlans from './services/plans.js';
18
+ export * as billingStripe from './services/stripe.js';
19
+ export * as billingSubscriptions from './services/subscriptions.js';
20
+ export * as billingUsage from './services/usage.js';
21
+ /**
22
+ * `procedures` is the service-to-service surface, reachable only over `kernel.call`. It runs with
23
+ * elevated access, so it must never be reachable by an end user: everything a person does goes
24
+ * through the oRPC router and its permission middleware.
25
+ */
26
+ function requireService(principal) {
27
+ if (principal.kind !== 'service' && !principal.instanceAdmin)
28
+ throw KernError.forbidden();
29
+ }
30
+ /** Workspaces this instance knows about, asked of core — billing only ever stores ids. */
31
+ async function allWorkspaceIds(kernel) {
32
+ const rows = await kernel.call('core.workspaces.list', { limit: 10_000 });
33
+ return rows.map((r) => r.id);
34
+ }
35
+ export const billingModule = defineServerModule({
36
+ definition: defineModule({
37
+ id: MODULE_ID,
38
+ name: 'Billing',
39
+ version: packageVersion(import.meta.url),
40
+ description: 'Plans, entitlements and subscriptions — what lets an instance sell seats on itself',
41
+ icon: 'credit-card',
42
+ permissions: billingPermissions,
43
+ events: billingEvents,
44
+ }),
45
+ schema,
46
+ migrationsFolder: join(dirname(fileURLToPath(import.meta.url)), '../../migrations'),
47
+ contract: billingContract,
48
+ router: billingRouter,
49
+ procedures: {
50
+ /**
51
+ * The one the kernel calls. Its mere presence on the broker is what switches limits on for the
52
+ * whole instance — `kernel.entitlements` checks `broker.has()` and treats an absent procedure as
53
+ * unlimited, which is what every self-hosted Kern does on every request.
54
+ */
55
+ 'entitlements.get': {
56
+ input: z.object({ workspaceId: WorkspaceId }),
57
+ handler: async (input, { kernel, principal }) => {
58
+ requireService(principal);
59
+ return entitlements.resolve(kernel, input.workspaceId);
60
+ },
61
+ },
62
+ /** Recount one workspace from core's tables. Used by the nightly job and by support. */
63
+ 'usage.reconcile': {
64
+ input: z.object({ workspaceId: WorkspaceId }),
65
+ handler: async (input, { kernel, principal }) => {
66
+ requireService(principal);
67
+ return usageSvc.reconcile(kernel, input.workspaceId);
68
+ },
69
+ },
70
+ },
71
+ subscriptions: {
72
+ /**
73
+ * Seats follow membership, and only for members who cost money — a guest is invited to look at
74
+ * one thing and must not put the workspace over its plan.
75
+ *
76
+ * All three events do the same thing: recount. `core.member.removed` does not say what role the
77
+ * person had and `core.member.updated` does not say what role they had before, so neither can be
78
+ * turned into a safe delta. Core counts non-guest memberships for one workspace, which is one
79
+ * indexed query.
80
+ */
81
+ 'core.member.*': async (e, kernel) => {
82
+ const p = e.payload;
83
+ if (!p.workspaceId)
84
+ return;
85
+ const seats = await usageSvc.recountSeats(kernel, p.workspaceId);
86
+ await stripeSvc.syncSeats(kernel, p.workspaceId, seats);
87
+ },
88
+ 'core.file.ready': async (e, kernel) => {
89
+ const p = e.payload;
90
+ if (typeof p.size !== 'number')
91
+ return;
92
+ await usageSvc.bump(kernel, p.workspaceId, { storageBytes: p.size });
93
+ },
94
+ 'core.file.deleted': async (e, kernel) => {
95
+ const p = e.payload;
96
+ await usageSvc.bump(kernel, p.workspaceId, { storageBytes: -p.size });
97
+ },
98
+ /**
99
+ * A brand-new workspace starts on the default plan if the instance has one, so a cloud signup is
100
+ * entitled to something before anybody has touched the admin console. An instance with no
101
+ * default plan — every self-hosted one — gets no row, which resolves to unlimited.
102
+ */
103
+ 'core.workspace.created': async (e, kernel) => {
104
+ const p = e.payload;
105
+ const slug = process.env.KERN_DEFAULT_PLAN_SLUG;
106
+ if (!slug)
107
+ return;
108
+ const { bySlug } = await import('./services/plans.js');
109
+ const plan = await bySlug(kernel, slug);
110
+ if (!plan) {
111
+ kernel.log.warn({ slug }, 'billing: KERN_DEFAULT_PLAN_SLUG names a plan that does not exist');
112
+ return;
113
+ }
114
+ const trialEndsAt = new Date();
115
+ trialEndsAt.setUTCDate(trialEndsAt.getUTCDate() + plan.trialDays);
116
+ await subsSvc.upsert(kernel, p.workspaceId, {
117
+ planId: plan.id,
118
+ status: plan.trialDays > 0 ? 'trialing' : 'active',
119
+ trialEndsAt: plan.trialDays > 0 ? trialEndsAt : null,
120
+ });
121
+ },
122
+ },
123
+ jobs: [
124
+ {
125
+ name: 'billing.reconcile-usage',
126
+ // nightly; counters move on events all day and this is what proves they were right
127
+ cron: '17 3 * * *',
128
+ handler: async (_input, { kernel }) => {
129
+ for (const workspaceId of await allWorkspaceIds(kernel)) {
130
+ try {
131
+ const { drift } = await usageSvc.reconcile(kernel, workspaceId);
132
+ // Logged, never silently corrected: a counter that keeps needing correction means an
133
+ // event is being missed, and quietly fixing the number every night is how that goes
134
+ // unnoticed for a year.
135
+ if (drift.seats !== 0 || drift.storageBytes !== 0)
136
+ kernel.log.warn({ workspaceId, drift }, 'billing: usage counters had drifted');
137
+ }
138
+ catch (err) {
139
+ kernel.log.warn({ err: String(err), workspaceId }, 'billing: reconcile failed');
140
+ }
141
+ }
142
+ },
143
+ },
144
+ {
145
+ name: 'billing.close-grace-periods',
146
+ cron: '7 * * * *',
147
+ handler: async (_input, { kernel }) => {
148
+ const due = await kernel.database.db
149
+ .select({ workspaceId: subscriptions.workspaceId })
150
+ .from(subscriptions)
151
+ .where(and(eq(subscriptions.status, 'past_due'), isNotNull(subscriptions.graceEndsAt), lte(subscriptions.graceEndsAt, new Date())));
152
+ for (const row of due) {
153
+ await subsSvc.upsert(kernel, row.workspaceId, { status: 'suspended', graceEndsAt: null });
154
+ await kernel.emit(billingEvents.subscriptionSuspended, {
155
+ workspaceId: row.workspaceId,
156
+ reason: 'the grace period after a failed payment ended',
157
+ }, { workspaceId: row.workspaceId });
158
+ kernel.log.info({ workspaceId: row.workspaceId }, 'billing: grace period ended, workspace suspended');
159
+ }
160
+ },
161
+ },
162
+ ],
163
+ });
164
+ export default billingModule;
165
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}