@develemit/billing 0.2.1 → 0.4.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 CHANGED
@@ -197,6 +197,29 @@ Latency is measured with `performance.now()`, so `shadowLatencyMs` keeps
197
197
  sub-millisecond resolution — a cache-served shadow read reports e.g. `0.1`
198
198
  rather than a flat `0` that's indistinguishable from "never measured."
199
199
 
200
+ ## Reporting usage (metered plans)
201
+
202
+ ```ts
203
+ await billing.reportUsage({
204
+ subjectId: 'user_123',
205
+ quantity: 1,
206
+ timestamp: new Date(),
207
+ idempotencyKey: `delivery:${deliveryId}`,
208
+ });
209
+
210
+ const { usage } = await billing.getEntitlements('user_123');
211
+ // usage?.used, usage?.periodEnd — undefined on licensed plans and for
212
+ // subjects with no subscription
213
+ ```
214
+
215
+ **Idempotency contract.** The API dedupes on `(subject, idempotencyKey)`. If
216
+ you omit `idempotencyKey`, the SDK generates a random one for that call —
217
+ which is only safe when you never retry. **If you retry a failed report,
218
+ pass the same key every time; a fresh key is a new event and double-bills.**
219
+ Prefer a natural id you already own (a delivery id, a job id) so a retry
220
+ after a crash reuses it. Timestamps must be within the last 35 days and no
221
+ more than 5 minutes in the future.
222
+
200
223
  ## Behavior
201
224
 
202
225
  - `getEntitlements(subjectId)` caches per-subject for `entitlementsTtlMs`
@@ -207,6 +230,17 @@ rather than a flat `0` that's indistinguishable from "never measured."
207
230
  key, validation) — staleness never masks misconfiguration.
208
231
  - `createCheckout`, `portalUrl`, and `getSubscription` always call the API
209
232
  and throw `BillingApiError` on any failure.
233
+ - `startTrial({ subjectId, feature, durationDays? })` grants a time-boxed,
234
+ card-less trial entitlement for a subject in your own project (default 7
235
+ days, capped at 31) — no Stripe subscription involved; the entitlement
236
+ simply stops at `expiresAt`. One trial ever per subject+feature: repeat
237
+ calls return the original grant with `created: false`, even after it has
238
+ expired, so retried signups can't stack or restart a trial. A successful
239
+ call drops that subject's cached entitlements so the next
240
+ `getEntitlements` reflects the grant immediately.
241
+ - `reportUsage({ subjectId, quantity, timestamp, idempotencyKey? })` posts to
242
+ `/v1/usage`, returns the stored record, and drops that subject's cached
243
+ entitlements. It throws `BillingApiError` on any failure.
210
244
  - Every failure is a `BillingApiError` with `status` and `code`. Network
211
245
  failures use `status: 0, code: 'network_error'` so callers can tell
212
246
  "billing is unreachable" apart from "request was denied".
@@ -84,7 +84,8 @@ var replayOutcomeSchema = z.enum([
84
84
  "invalid",
85
85
  "unknown_subscription",
86
86
  "already_processed",
87
- "error"
87
+ "error",
88
+ "foreign_project"
88
89
  ]);
89
90
  var replayResponseSchema = z.object({
90
91
  outcome: replayOutcomeSchema
@@ -152,19 +153,31 @@ var subscriptionViewSchema = z2.discriminatedUnion("state", [
152
153
  activeSubscriptionViewSchema,
153
154
  noSubscriptionViewSchema
154
155
  ]);
156
+ var subscriptionCancelRequestSchema = z2.object({
157
+ subjectId: z2.string()
158
+ });
159
+ var subscriptionCancelResponseSchema = z2.object({
160
+ canceled: z2.literal(true),
161
+ providerSubscriptionId: z2.string()
162
+ });
155
163
 
156
164
  // ../shared-types/src/entitlements.ts
157
165
  var entitlementSourcesSchema = z3.object({
158
166
  features: z3.record(z3.string(), z3.enum(["subscription", "override"])),
159
167
  limits: z3.record(z3.string(), z3.enum(["subscription", "override"]))
160
168
  });
169
+ var meteredUsageSchema = z3.object({
170
+ used: z3.number(),
171
+ periodEnd: z3.string()
172
+ });
161
173
  var entitlementsResponseSchema = z3.object({
162
174
  plan: z3.string().nullable(),
163
175
  features: z3.record(z3.string(), z3.boolean()),
164
176
  limits: z3.record(z3.string(), z3.number()),
165
177
  status: subscriptionStatusSchema,
166
178
  source: z3.enum(["subscription", "override", "none"]),
167
- sources: entitlementSourcesSchema
179
+ sources: entitlementSourcesSchema,
180
+ usage: meteredUsageSchema.optional()
168
181
  });
169
182
 
170
183
  // ../shared-types/src/overrides.ts
@@ -242,6 +255,8 @@ var projectMetricsSchema = dashboardMetricsSchema.extend({
242
255
  mrrSeries: z5.array(z5.number())
243
256
  });
244
257
  var adminMetricsResponseSchema = z5.object({
258
+ // Which environment every total below describes — never a mix.
259
+ environment: z5.enum(["test", "live"]),
245
260
  ecosystem: dashboardMetricsSchema,
246
261
  // Shared x-axis labels for every project's mrrSeries (same calendar
247
262
  // months across the ecosystem) — empty when no project has snapshots yet.
@@ -290,7 +305,11 @@ var adminPriceSchema = z5.object({
290
305
  id: z5.string(),
291
306
  interval: z5.enum(["month", "year"]),
292
307
  currency: z5.string(),
293
- unitAmountCents: z5.number(),
308
+ // Null for a metered price (sprint 96) — no fixed amount to display yet.
309
+ unitAmountCents: z5.number().nullable(),
310
+ // Optional on input so callers built before sprint 96 still parse; always
311
+ // present on output via the default.
312
+ usageType: z5.enum(["licensed", "metered"]).default("licensed"),
294
313
  syncStatus: z5.enum(["synced", "pending", "drifted"]),
295
314
  syncedUnitAmountCents: z5.number().nullable()
296
315
  });
@@ -344,7 +363,8 @@ var adminDeadLetterGroupSchema = z5.object({
344
363
  count: z5.number(),
345
364
  sampleEventId: z5.string(),
346
365
  firstReceivedAt: z5.iso.datetime(),
347
- lastReceivedAt: z5.iso.datetime()
366
+ lastReceivedAt: z5.iso.datetime(),
367
+ environment: z5.enum(["test", "live"])
348
368
  });
349
369
  var adminDeadLetterGroupsResponseSchema = z5.object({
350
370
  groups: z5.array(adminDeadLetterGroupSchema)
@@ -353,7 +373,12 @@ var adminProjectDashboardResponseSchema = z5.object({
353
373
  metrics: projectMetricsSchema,
354
374
  monthLabels: z5.array(z5.string()),
355
375
  providerKind: z5.string(),
356
- plans: z5.array(adminPlanSchema)
376
+ plans: z5.array(adminPlanSchema),
377
+ // True when the caller gave no `environment` and the key named more than
378
+ // one row (sprint 66) — `metrics.environment` was picked by a
379
+ // deterministic fallback rather than requested explicitly, and the
380
+ // frontend labels it as such (sprint 68.5).
381
+ environmentDefaulted: z5.boolean()
357
382
  });
358
383
 
359
384
  // ../shared-types/src/checkout.ts
@@ -402,22 +427,95 @@ var registerProjectRequestSchema = z7.object({
402
427
  }
403
428
  });
404
429
 
405
- // ../shared-types/src/errors.ts
430
+ // ../shared-types/src/trials.ts
406
431
  import { z as z8 } from "zod";
407
- var errorEnvelopeSchema = z8.object({
408
- error: z8.object({
409
- code: z8.string(),
410
- message: z8.string()
432
+ var MAX_TRIAL_DURATION_DAYS = 31;
433
+ var DEFAULT_TRIAL_DURATION_DAYS = 7;
434
+ var startTrialRequestSchema = z8.object({
435
+ subjectId: z8.string().min(1),
436
+ feature: z8.string().min(1),
437
+ durationDays: z8.number().int().min(1).max(MAX_TRIAL_DURATION_DAYS).default(DEFAULT_TRIAL_DURATION_DAYS)
438
+ });
439
+ var trialGrantSchema = z8.object({
440
+ id: z8.string(),
441
+ subjectId: z8.string(),
442
+ feature: z8.string(),
443
+ expiresAt: z8.iso.datetime(),
444
+ createdAt: z8.iso.datetime()
445
+ });
446
+ var startTrialResponseSchema = z8.object({
447
+ trial: trialGrantSchema,
448
+ created: z8.boolean()
449
+ });
450
+
451
+ // ../shared-types/src/errors.ts
452
+ import { z as z9 } from "zod";
453
+ var errorEnvelopeSchema = z9.object({
454
+ error: z9.object({
455
+ code: z9.string(),
456
+ message: z9.string()
411
457
  })
412
458
  });
413
459
 
414
460
  // ../shared-types/src/webhook-secret.ts
415
- import { z as z9 } from "zod";
416
- var webhookSigningSecretSchema = z9.string().regex(/^whsec_.+/, "must be a non-empty whsec_-prefixed string");
461
+ import { z as z10 } from "zod";
462
+ var webhookSigningSecretSchema = z10.string().regex(/^whsec_.+/, "must be a non-empty whsec_-prefixed string");
417
463
 
418
464
  // ../shared-types/src/portal-return-url.ts
419
- import { z as z10 } from "zod";
420
- var portalReturnUrlSchema = z10.url();
465
+ import { z as z11 } from "zod";
466
+ var portalReturnUrlSchema = z11.url();
467
+
468
+ // ../shared-types/src/usage.ts
469
+ import { z as z12 } from "zod";
470
+ var recordUsageRequestSchema = z12.object({
471
+ subjectId: z12.string().min(1),
472
+ quantity: z12.number().int().positive(),
473
+ timestamp: z12.iso.datetime(),
474
+ idempotencyKey: z12.string().min(1)
475
+ });
476
+ var usageRecordSchema = z12.object({
477
+ id: z12.string(),
478
+ subjectId: z12.string(),
479
+ quantity: z12.number(),
480
+ eventTimestamp: z12.iso.datetime(),
481
+ idempotencyKey: z12.string(),
482
+ createdAt: z12.iso.datetime()
483
+ });
484
+ var listUsageResponseSchema = z12.object({
485
+ records: z12.array(usageRecordSchema),
486
+ total: z12.number().int().nonnegative(),
487
+ limit: z12.number().int().nonnegative(),
488
+ offset: z12.number().int().nonnegative()
489
+ });
490
+
491
+ // ../shared-types/src/admin-usage.ts
492
+ import { z as z13 } from "zod";
493
+ var usageIssueCauseSchema = z13.enum([
494
+ "unreportable",
495
+ "no_customer",
496
+ "no_meter",
497
+ "transport_failure",
498
+ "waiting"
499
+ ]);
500
+ var adminUsageIssueSchema = z13.object({
501
+ id: z13.string(),
502
+ projectId: z13.string(),
503
+ subjectId: z13.string(),
504
+ planKey: z13.string().nullable(),
505
+ quantity: z13.number(),
506
+ eventTimestamp: z13.iso.datetime(),
507
+ createdAt: z13.iso.datetime(),
508
+ state: z13.enum(["terminal", "retrying"]),
509
+ cause: usageIssueCauseSchema,
510
+ reason: z13.string(),
511
+ attempts: z13.number()
512
+ });
513
+ var adminUsageIssuesResponseSchema = z13.object({
514
+ environment: z13.enum(["test", "live"]),
515
+ issues: z13.array(adminUsageIssueSchema),
516
+ nextCursor: z13.string().nullable(),
517
+ approxTotal: z13.number()
518
+ });
421
519
 
422
520
  // src/errors.ts
423
521
  var BillingApiError = class extends Error {
@@ -486,10 +584,12 @@ export {
486
584
  entitlementsResponseSchema,
487
585
  checkoutResponseSchema,
488
586
  portalResponseSchema,
587
+ startTrialResponseSchema,
588
+ usageRecordSchema,
489
589
  BillingApiError,
490
590
  errorFromResponse,
491
591
  networkError,
492
592
  invalidResponseError,
493
593
  checkEntitlement
494
594
  };
495
- //# sourceMappingURL=chunk-3OSJ6UJT.js.map
595
+ //# sourceMappingURL=chunk-JKIQULCW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../shared-types/src/admin.ts","../../shared-types/src/event-log.ts","../../shared-types/src/entitlements.ts","../../shared-types/src/subscriptions.ts","../../shared-types/src/overrides.ts","../../shared-types/src/checkout.ts","../../shared-types/src/projects.ts","../../shared-types/src/trials.ts","../../shared-types/src/errors.ts","../../shared-types/src/webhook-secret.ts","../../shared-types/src/portal-return-url.ts","../../shared-types/src/usage.ts","../../shared-types/src/admin-usage.ts","../src/errors.ts","../src/guard.ts"],"sourcesContent":["import { z } from 'zod';\nimport {\n adminEventDetailSchema,\n adminEventSummarySchema,\n signatureCountSchema,\n wouldApplySchema,\n} from './event-log.js';\nimport { entitlementsResponseSchema } from './entitlements.js';\nimport { overrideRecordSchema } from './overrides.js';\nimport { subscriptionStatusSchema } from './subscriptions.js';\n\n// Per-project and ecosystem-wide subscription state counts. `grace` is\n// computed (never stored) — see @org/entitlements' resolveAccessStatus.\nexport const stateCountsSchema = z.object({\n trialing: z.number(),\n active: z.number(),\n past_due: z.number(),\n grace: z.number(),\n canceled: z.number(),\n unpaid: z.number(),\n});\nexport type StateCounts = z.infer<typeof stateCountsSchema>;\n\nconst dashboardMetricsSchema = z.object({\n mrrCents: z.number(),\n mrrPrevCents: z.number(),\n subjectsCount: z.number(),\n states: stateCountsSchema,\n deadLetterDepth: z.number(),\n oldestUnprocessedSec: z.number().nullable(),\n driftCount: z.number(),\n});\n\nexport const projectMetricsSchema = dashboardMetricsSchema.extend({\n projectId: z.string(),\n projectKey: z.string(),\n projectName: z.string(),\n subjectType: z.string(),\n environment: z.enum(['test', 'live']),\n envLocked: z.boolean(),\n mrrSeries: z.array(z.number()),\n});\nexport type ProjectMetrics = z.infer<typeof projectMetricsSchema>;\n\nexport const adminMetricsResponseSchema = z.object({\n // Which environment every total below describes — never a mix.\n environment: z.enum(['test', 'live']),\n ecosystem: dashboardMetricsSchema,\n // Shared x-axis labels for every project's mrrSeries (same calendar\n // months across the ecosystem) — empty when no project has snapshots yet.\n monthLabels: z.array(z.string()),\n projects: z.array(projectMetricsSchema),\n});\nexport type AdminMetricsResponse = z.infer<typeof adminMetricsResponseSchema>;\n\n// Cursor-based (data-display.md's \"Newer / Older\" contract): the page query\n// and the approximate total are the only two things a caller needs — no\n// offset, no page number.\nexport const adminEventsListResponseSchema = z.object({\n events: z.array(adminEventSummarySchema),\n nextCursor: z.string().nullable(),\n approxTotal: z.number(),\n signatureCounts: z.array(signatureCountSchema).optional(),\n});\nexport type AdminEventsListResponse = z.infer<\n typeof adminEventsListResponseSchema\n>;\n\nexport const adminEventDetailResponseSchema = z.object({\n event: adminEventDetailSchema,\n transition: z.object({\n current: z\n .object({\n state: subscriptionStatusSchema.exclude(['grace', 'none']),\n lastEventAt: z.iso.datetime().nullable(),\n })\n .nullable(),\n wouldApply: wouldApplySchema,\n }),\n});\nexport type AdminEventDetailResponse = z.infer<\n typeof adminEventDetailResponseSchema\n>;\n\nexport const adminSubjectSchema = z.object({\n id: z.string(),\n subjectType: z.string(),\n externalId: z.string(),\n providerCustomerId: z.string().nullable(),\n});\nexport type AdminSubject = z.infer<typeof adminSubjectSchema>;\n\n// Grants are the raw material entitlements are computed from (sprints\n// 12-14): a boolean flag or a numeric limit, keyed by feature name.\nexport const featureGrantsSchema = z.record(\n z.string(),\n z.union([z.boolean(), z.number()]),\n);\nexport type AdminFeatureGrants = z.infer<typeof featureGrantsSchema>;\n\n// The subject's most recent subscription's plan, independent of whether\n// that subscription currently grants access (unlike entitlements.plan,\n// which is null exactly when it doesn't) — sprint 40's plan-aware comp\n// reads this to restore the plan's real grants rather than a synthetic\n// flag. priceInterval is null when the plan has no price to derive one\n// from; comp falls back to a fixed cycle length in that case.\nexport const adminSubjectSubscriptionPlanSchema = z.object({\n key: z.string(),\n featureGrants: featureGrantsSchema,\n priceInterval: z.enum(['month', 'year']).nullable(),\n});\nexport type AdminSubjectSubscriptionPlan = z.infer<\n typeof adminSubjectSubscriptionPlanSchema\n>;\n\nexport const adminSubjectLookupResponseSchema = z.object({\n subject: adminSubjectSchema,\n entitlements: entitlementsResponseSchema,\n recentEvents: z.array(adminEventSummarySchema),\n activeOverrides: z.array(overrideRecordSchema),\n subscriptionPlan: adminSubjectSubscriptionPlanSchema.nullable(),\n});\nexport type AdminSubjectLookupResponse = z.infer<\n typeof adminSubjectLookupResponseSchema\n>;\n\nexport const adminPriceSchema = z.object({\n id: z.string(),\n interval: z.enum(['month', 'year']),\n currency: z.string(),\n // Null for a metered price (sprint 96) — no fixed amount to display yet.\n unitAmountCents: z.number().nullable(),\n // Optional on input so callers built before sprint 96 still parse; always\n // present on output via the default.\n usageType: z.enum(['licensed', 'metered']).default('licensed'),\n syncStatus: z.enum(['synced', 'pending', 'drifted']),\n syncedUnitAmountCents: z.number().nullable(),\n});\nexport type AdminPrice = z.infer<typeof adminPriceSchema>;\n\nexport const adminPlanSchema = z.object({\n id: z.string(),\n key: z.string(),\n name: z.string(),\n featureGrants: featureGrantsSchema,\n activeSubscriptions: z.number(),\n prices: z.array(adminPriceSchema),\n});\nexport type AdminPlan = z.infer<typeof adminPlanSchema>;\n\n// Statement descriptors are project-level, not per-plan (packages/db's\n// projects table), but the plan editor screen renders and edits the field\n// alongside the plans it applies to — so the response carries the project's\n// resolved descriptor config as a sibling of the plan list, not duplicated\n// per plan.\nexport const adminPlansResponseSchema = z.object({\n project: z.object({\n statementDescriptor: z.string().nullable(),\n statementDescriptorPrefix: z.string().nullable(),\n }),\n plans: z.array(adminPlanSchema),\n});\nexport type AdminPlansResponse = z.infer<typeof adminPlansResponseSchema>;\n\n// Never the raw secret — masked to last-4 (or null if never configured).\nexport const adminProviderResponseSchema = z.object({\n projectId: z.string(),\n providerKind: z.string(),\n environment: z.enum(['test', 'live']),\n envLocked: z.boolean(),\n secretKeyMasked: z.string().nullable(),\n publishableKeyMasked: z.string().nullable(),\n webhookEndpoint: z.string(),\n webhookSigningConfigured: z.boolean(),\n defaultPortalReturnUrl: z.string().nullable(),\n});\nexport type AdminProviderResponse = z.infer<typeof adminProviderResponseSchema>;\n\n// The overrides domain has no project_id column of its own (project scope\n// comes from a join through subjects), so the admin service tags each entry\n// with its project as it assembles the cross-project audit response.\nexport const adminAuditEntrySchema = overrideRecordSchema.extend({\n projectId: z.string(),\n});\nexport type AdminAuditEntry = z.infer<typeof adminAuditEntrySchema>;\n\nexport const adminAuditResponseSchema = z.object({\n entries: z.array(adminAuditEntrySchema),\n nextCursor: z.string().nullable(),\n approxTotal: z.number(),\n});\nexport type AdminAuditResponse = z.infer<typeof adminAuditResponseSchema>;\n\n// Parallel arrays, not one row per day, to match EventThroughput's own prop\n// shape (data-display.md chart 3) — the web layer passes these straight\n// through without reshaping.\nexport const adminThroughputResponseSchema = z.object({\n days: z.array(z.string()),\n processed: z.array(z.number()),\n failed: z.array(z.number()),\n});\nexport type AdminThroughputResponse = z.infer<\n typeof adminThroughputResponseSchema\n>;\n\n// No historical snapshot table exists for plan mix (unlike MRR's\n// mrr_snapshots — see packages/db/src/schema/mrr-snapshots.ts's own note\n// that nothing populates it beyond the dev seed). Sprint 38 scopes this to\n// the current month only rather than inventing a snapshot table: `months`\n// and `stacks` always carry exactly one entry.\nexport const adminPlanMixResponseSchema = z.object({\n months: z.array(z.string()),\n plans: z.array(z.object({ key: z.string(), name: z.string() })),\n stacks: z.array(z.array(z.number())),\n});\nexport type AdminPlanMixResponse = z.infer<typeof adminPlanMixResponseSchema>;\n\n// (project_id, error_signature) GROUP BY over the full dead-letter queue —\n// distinct from signatureCountSchema (event-log.ts), which groups by\n// signature alone within one already-project-scoped page and can't tell two\n// projects' identical error text apart.\nexport const adminDeadLetterGroupSchema = z.object({\n projectId: z.string(),\n signature: z.string(),\n count: z.number(),\n sampleEventId: z.string(),\n firstReceivedAt: z.iso.datetime(),\n lastReceivedAt: z.iso.datetime(),\n environment: z.enum(['test', 'live']),\n});\nexport type AdminDeadLetterGroup = z.infer<typeof adminDeadLetterGroupSchema>;\n\nexport const adminDeadLetterGroupsResponseSchema = z.object({\n groups: z.array(adminDeadLetterGroupSchema),\n});\nexport type AdminDeadLetterGroupsResponse = z.infer<\n typeof adminDeadLetterGroupsResponseSchema\n>;\n\n// One project's full overview-card payload in a single round trip — the\n// scoped counterpart to adminMetricsResponseSchema's all-projects bundle,\n// for screens that only ever render one project (project-overview.tsx).\nexport const adminProjectDashboardResponseSchema = z.object({\n metrics: projectMetricsSchema,\n monthLabels: z.array(z.string()),\n providerKind: z.string(),\n plans: z.array(adminPlanSchema),\n // True when the caller gave no `environment` and the key named more than\n // one row (sprint 66) — `metrics.environment` was picked by a\n // deterministic fallback rather than requested explicitly, and the\n // frontend labels it as such (sprint 68.5).\n environmentDefaulted: z.boolean(),\n});\nexport type AdminProjectDashboardResponse = z.infer<\n typeof adminProjectDashboardResponseSchema\n>;\n","import { z } from 'zod';\n\nexport const eventStatusSchema = z.enum([\n 'received',\n 'processed',\n 'failed',\n 'dead_letter',\n 'discarded',\n]);\nexport type EventStatus = z.infer<typeof eventStatusSchema>;\n\n// Matches @org/db's subscription_state enum — the five states the state\n// machine actually stores, not the computed 'grace'/'none' views.\nexport const subscriptionStateSchema = z.enum([\n 'trialing',\n 'active',\n 'past_due',\n 'canceled',\n 'unpaid',\n]);\nexport type SubscriptionStateContract = z.infer<typeof subscriptionStateSchema>;\n\nexport const adminEventSummarySchema = z.object({\n id: z.string(),\n projectId: z.string(),\n providerEventId: z.string(),\n type: z.string(),\n status: eventStatusSchema,\n attempts: z.number(),\n lastError: z.string().nullable(),\n errorSignature: z.string().nullable(),\n receivedAt: z.iso.datetime(),\n processedAt: z.iso.datetime().nullable(),\n // event_log has no subject/customer reference column (sprint 24's\n // repo-drizzle-subjects.ts documents the same gap the other direction) —\n // derived from the raw Stripe payload's well-known `data.object.customer`\n // path, so this is null for any non-Stripe-shaped payload.\n subjectRef: z.string().nullable(),\n});\nexport type AdminEventSummary = z.infer<typeof adminEventSummarySchema>;\n\nexport const adminEventDetailSchema = adminEventSummarySchema.extend({\n payload: z.record(z.string(), z.unknown()),\n discardReason: z.string().nullable(),\n discardedBy: z.string().nullable(),\n discardedAt: z.iso.datetime().nullable(),\n});\nexport type AdminEventDetail = z.infer<typeof adminEventDetailSchema>;\n\nexport const signatureCountSchema = z.object({\n signature: z.string(),\n count: z.number(),\n});\nexport type SignatureCount = z.infer<typeof signatureCountSchema>;\n\nexport const listEventsResponseSchema = z.object({\n events: z.array(adminEventSummarySchema),\n total: z.number(),\n limit: z.number(),\n offset: z.number(),\n signatureCounts: z.array(signatureCountSchema),\n});\nexport type ListEventsResponse = z.infer<typeof listEventsResponseSchema>;\n\n// Mirrors ApplyResult from apps/api's pure state machine, plus 'error' for\n// when the stored payload itself can't be replayed (e.g. missing provider\n// credentials) — dry-run degrades to this rather than throwing across the\n// HTTP boundary.\nexport const wouldApplySchema = z.discriminatedUnion('kind', [\n z.object({ kind: z.literal('create'), to: subscriptionStateSchema }),\n z.object({\n kind: z.literal('transition'),\n from: subscriptionStateSchema,\n to: subscriptionStateSchema,\n }),\n z.object({ kind: z.literal('stale') }),\n z.object({\n kind: z.literal('invalid'),\n from: subscriptionStateSchema,\n to: subscriptionStateSchema,\n }),\n z.object({ kind: z.literal('unknown_subscription') }),\n z.object({ kind: z.literal('noop'), reason: z.string() }),\n z.object({ kind: z.literal('error'), reason: z.string() }),\n]);\nexport type WouldApply = z.infer<typeof wouldApplySchema>;\n\nexport const dryRunReplayResponseSchema = z.object({\n event: adminEventDetailSchema,\n current: z\n .object({\n state: subscriptionStateSchema,\n lastEventAt: z.iso.datetime().nullable(),\n })\n .nullable(),\n wouldApply: wouldApplySchema,\n});\nexport type DryRunReplayResponse = z.infer<typeof dryRunReplayResponseSchema>;\n\nexport const replayOutcomeSchema = z.enum([\n 'created',\n 'transitioned',\n 'stale',\n 'noop',\n 'invalid',\n 'unknown_subscription',\n 'already_processed',\n 'error',\n 'foreign_project',\n]);\n\nexport const replayResponseSchema = z.object({\n outcome: replayOutcomeSchema,\n});\nexport type ReplayResponse = z.infer<typeof replayResponseSchema>;\n\nexport const discardEventRequestSchema = z.object({\n actor: z.string().min(1),\n reason: z.string(),\n});\nexport type DiscardEventRequest = z.infer<typeof discardEventRequestSchema>;\n\n// Operator-triggered, small-N batches (sprint 39): a hard ceiling so a bulk\n// replay can never process an unbounded number of events, whether in one\n// request or paged across several (sprint 48's progress UI). Shared so the\n// api's per-request clamp and the web client's paging loop can't drift.\nexport const BULK_REPLAY_CAP = 200;\n\n// Opaque-enough keyset cursor over (receivedAt, id), mirroring\n// processing-repo.ts's EventCursor — event_log's id is a random uuid, so\n// receivedAt provides the real chronological order and id only breaks ties.\nexport const replayGroupCursorSchema = z.object({\n receivedAt: z.iso.datetime(),\n id: z.string(),\n});\nexport type ReplayGroupCursor = z.infer<typeof replayGroupCursorSchema>;\n\n// A group is targeted either by its (project, signature) pair or by \"every\n// dead-lettered event in this project\" — never both, and never neither.\n// cursor/limit are optional so a bare {projectId, errorSignature|all} still\n// replays a single up-to-BULK_REPLAY_CAP batch exactly as before; the web\n// client's progress UI (sprint 48) pages through with them instead.\nexport const replayGroupRequestSchema = z\n .object({\n projectId: z.string().min(1),\n cursor: replayGroupCursorSchema.optional(),\n limit: z.number().int().positive().optional(),\n })\n .and(\n z.union([\n z.object({ errorSignature: z.string().min(1) }),\n z.object({ all: z.literal(true) }),\n ]),\n );\nexport type ReplayGroupRequest = z.infer<typeof replayGroupRequestSchema>;\n\nexport const replayGroupOutcomeEntrySchema = z.object({\n eventId: z.string(),\n outcome: replayOutcomeSchema,\n});\n\nexport const replayGroupResponseSchema = z.object({\n outcomes: z.array(replayGroupOutcomeEntrySchema),\n // Keyed by ProcessOutcome, but zod v4's record needs .partial() semantics\n // for an exhaustive enum key type, so this stays a plain string map — the\n // set of possible keys is still exactly replayOutcomeSchema's members.\n counts: z.record(z.string(), z.number()),\n // This call's batch (its own limit, or BULK_REPLAY_CAP by default) hit its\n // ceiling: more matching events remain beyond what was just replayed.\n // Paging with nextCursor continues; a non-paging caller reads this the\n // same way it always has, as \"replay again to finish draining it.\"\n truncated: z.boolean(),\n nextCursor: replayGroupCursorSchema.nullable(),\n});\nexport type ReplayGroupResponse = z.infer<typeof replayGroupResponseSchema>;\n","import { z } from 'zod';\n\nimport { subscriptionStatusSchema } from './subscriptions.js';\n\n// Additive alongside the aggregate `source` field below (kept for SDK\n// back-compat): every key in `features`/`limits` gets its own entry here,\n// so a caller no longer has to infer per-key provenance by cross-referencing\n// overrides itself.\nexport const entitlementSourcesSchema = z.object({\n features: z.record(z.string(), z.enum(['subscription', 'override'])),\n limits: z.record(z.string(), z.enum(['subscription', 'override'])),\n});\nexport type EntitlementSources = z.infer<typeof entitlementSourcesSchema>;\n\n// Kept in its own well-typed field rather than folded into `limits` — sprint\n// 79.1 is the cautionary tale for a wrong-typed value in that map 500ing the\n// endpoint in production. Absent entirely (not present with a null/zero\n// value) for a licensed plan or a subject with no subscription, so older\n// callers and existing licensed-plan responses stay byte-identical.\nexport const meteredUsageSchema = z.object({\n used: z.number(),\n periodEnd: z.string(),\n});\nexport type MeteredUsage = z.infer<typeof meteredUsageSchema>;\n\nexport const entitlementsResponseSchema = z.object({\n plan: z.string().nullable(),\n features: z.record(z.string(), z.boolean()),\n limits: z.record(z.string(), z.number()),\n status: subscriptionStatusSchema,\n source: z.enum(['subscription', 'override', 'none']),\n sources: entitlementSourcesSchema,\n usage: meteredUsageSchema.optional(),\n});\nexport type EntitlementsResponse = z.infer<typeof entitlementsResponseSchema>;\n","import { z } from 'zod';\n\n// `grace` and `none` are computed from @org/db's stored enum + graceDays, never stored themselves.\nexport const subscriptionStatusSchema = z.enum([\n 'trialing',\n 'active',\n 'past_due',\n 'grace',\n 'canceled',\n 'unpaid',\n 'none',\n]);\nexport type SubscriptionStatus = z.infer<typeof subscriptionStatusSchema>;\n\nconst activeSubscriptionViewSchema = z.object({\n state: subscriptionStatusSchema.exclude(['none']),\n planKey: z.string(),\n currentPeriodEnd: z.iso.datetime(),\n cancelAtPeriodEnd: z.boolean(),\n});\n\nconst noSubscriptionViewSchema = z.object({\n state: z.literal('none'),\n});\n\nexport const subscriptionViewSchema = z.discriminatedUnion('state', [\n activeSubscriptionViewSchema,\n noSubscriptionViewSchema,\n]);\nexport type SubscriptionView = z.infer<typeof subscriptionViewSchema>;\n\nexport const subscriptionCancelRequestSchema = z.object({\n subjectId: z.string(),\n});\nexport type SubscriptionCancelRequest = z.infer<\n typeof subscriptionCancelRequestSchema\n>;\n\nexport const subscriptionCancelResponseSchema = z.object({\n canceled: z.literal(true),\n providerSubscriptionId: z.string(),\n});\nexport type SubscriptionCancelResponse = z.infer<\n typeof subscriptionCancelResponseSchema\n>;\n","import { z } from 'zod';\n\n// Operator vocabulary (matches the dashboard's comp/extend/revoke buttons),\n// distinct from @org/entitlements' internal grant|revoke computation\n// vocabulary — apps/api's overrides domain translates between the two.\nexport const overrideKindSchema = z.enum(['comp', 'extend', 'revoke']);\nexport type OverrideKind = z.infer<typeof overrideKindSchema>;\n\nexport const overrideTargetSchema = z.discriminatedUnion('type', [\n z.object({ type: z.literal('feature'), feature: z.string().min(1) }),\n z.object({\n type: z.literal('limit'),\n limit: z.string().min(1),\n value: z.number(),\n }),\n]);\nexport type OverrideTarget = z.infer<typeof overrideTargetSchema>;\n\nexport const createOverrideRequestSchema = z.object({\n subjectId: z.string().min(1),\n kind: overrideKindSchema,\n target: overrideTargetSchema,\n actor: z.string().min(1),\n reason: z.string().min(4),\n expiresAt: z.iso.datetime().optional(),\n});\nexport type CreateOverrideRequest = z.infer<typeof createOverrideRequestSchema>;\n\n// Multi-target variant: one subject, one kind/actor/reason/expiresAt, several\n// targets applied atomically (e.g. comping every grant key a plan defines) —\n// see apps/api's overrides service for the all-or-nothing guarantee.\nexport const createBulkOverrideRequestSchema = z.object({\n subjectId: z.string().min(1),\n kind: overrideKindSchema,\n targets: z.array(overrideTargetSchema).min(1),\n actor: z.string().min(1),\n reason: z.string().min(4),\n expiresAt: z.iso.datetime().optional(),\n});\nexport type CreateBulkOverrideRequest = z.infer<\n typeof createBulkOverrideRequestSchema\n>;\n\nexport const overrideRecordSchema = z.object({\n id: z.string(),\n subjectId: z.string(),\n kind: overrideKindSchema,\n target: overrideTargetSchema,\n actor: z.string(),\n reason: z.string(),\n expiresAt: z.iso.datetime().nullable(),\n createdAt: z.iso.datetime(),\n});\nexport type OverrideRecord = z.infer<typeof overrideRecordSchema>;\n\nexport const bulkOverrideResponseSchema = z.object({\n overrides: z.array(overrideRecordSchema),\n});\nexport type BulkOverrideResponse = z.infer<typeof bulkOverrideResponseSchema>;\n\nexport const listOverridesResponseSchema = z.object({\n overrides: z.array(overrideRecordSchema),\n total: z.number(),\n limit: z.number(),\n offset: z.number(),\n});\nexport type ListOverridesResponse = z.infer<typeof listOverridesResponseSchema>;\n","import { z } from 'zod';\n\nexport const checkoutRequestSchema = z.object({\n planKey: z.string(),\n subjectId: z.string(),\n successUrl: z.url(),\n cancelUrl: z.url(),\n email: z.email().optional(),\n});\nexport type CheckoutRequest = z.infer<typeof checkoutRequestSchema>;\n\nexport const checkoutResponseSchema = z.object({\n url: z.url(),\n});\nexport type CheckoutResponse = z.infer<typeof checkoutResponseSchema>;\n\nexport const portalRequestSchema = z.object({\n subjectId: z.string(),\n returnUrl: z.url(),\n});\nexport type PortalRequest = z.infer<typeof portalRequestSchema>;\n\nexport const portalResponseSchema = z.object({\n url: z.url(),\n});\nexport type PortalResponse = z.infer<typeof portalResponseSchema>;\n","import { z } from 'zod';\n\n// The source of truth for a registration payload's shape — apps/api's\n// projects service validates against this directly (no parallel\n// hand-written type), and the admin UI can reuse it for form validation.\nexport const registerProjectRequestSchema = z\n .object({\n key: z.string().trim().min(1, 'is required'),\n name: z.string().trim().min(1, 'is required'),\n subjectType: z.string().trim().min(1, 'is required'),\n environment: z.enum(['test', 'live'], 'must be \"test\" or \"live\"'),\n envLocked: z.boolean().optional(),\n providerKind: z.string().trim().min(1, 'is required'),\n providerSecretKeyRef: z.string().optional(),\n providerPublishableKeyRef: z.string().optional(),\n providerPortalConfigRef: z.string().optional(),\n statementDescriptor: z.string().optional(),\n statementDescriptorPrefix: z.string().optional(),\n graceDays: z.number().min(0, 'must be >= 0').optional(),\n defaultPortalReturnUrl: z.url().optional(),\n })\n .superRefine((input, ctx) => {\n if (!input.statementDescriptor && !input.statementDescriptorPrefix) {\n ctx.addIssue({\n code: 'custom',\n path: ['statementDescriptor'],\n message: 'statementDescriptor or statementDescriptorPrefix is required',\n });\n }\n });\nexport type RegisterProjectRequest = z.infer<\n typeof registerProjectRequestSchema\n>;\n","import { z } from 'zod';\n\n// Cap on self-serve trials: a leaked or buggy project key can cost at most\n// one month of entitlement per subject, never a decade.\nexport const MAX_TRIAL_DURATION_DAYS = 31;\nexport const DEFAULT_TRIAL_DURATION_DAYS = 7;\n\nexport const startTrialRequestSchema = z.object({\n subjectId: z.string().min(1),\n feature: z.string().min(1),\n durationDays: z\n .number()\n .int()\n .min(1)\n .max(MAX_TRIAL_DURATION_DAYS)\n .default(DEFAULT_TRIAL_DURATION_DAYS),\n});\n// Input (what a consumer sends — durationDays optional) and output (what the\n// route hands the service — durationDays defaulted) diverge here, unlike the\n// other contracts in this package.\nexport type StartTrialRequest = z.input<typeof startTrialRequestSchema>;\nexport type ParsedStartTrialRequest = z.output<typeof startTrialRequestSchema>;\n\nexport const trialGrantSchema = z.object({\n id: z.string(),\n subjectId: z.string(),\n feature: z.string(),\n expiresAt: z.iso.datetime(),\n createdAt: z.iso.datetime(),\n});\nexport type TrialGrant = z.infer<typeof trialGrantSchema>;\n\n// `created: false` means a trial already existed for this subject+feature —\n// possibly one that has since expired (expiresAt in the past). A subject gets\n// one trial ever; retries return the original instead of stacking a new one.\nexport const startTrialResponseSchema = z.object({\n trial: trialGrantSchema,\n created: z.boolean(),\n});\nexport type StartTrialResponse = z.infer<typeof startTrialResponseSchema>;\n","import { z } from 'zod';\n\nexport const errorEnvelopeSchema = z.object({\n error: z.object({\n code: z.string(),\n message: z.string(),\n }),\n});\nexport type ErrorEnvelope = z.infer<typeof errorEnvelopeSchema>;\n","import { z } from 'zod';\n\nexport class InvalidWebhookSecretError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InvalidWebhookSecretError';\n }\n}\n\n// Stripe generates its own signing secret when a webhook endpoint is\n// created through its dashboard/API — this only validates the shape of a\n// value an operator copies in from there, it never generates one itself.\nconst webhookSigningSecretSchema = z\n .string()\n .regex(/^whsec_.+/, 'must be a non-empty whsec_-prefixed string');\n\nexport function resolveWebhookSigningSecret(value: string): string {\n const result = webhookSigningSecretSchema.safeParse(value);\n if (!result.success) {\n throw new InvalidWebhookSecretError(result.error.issues[0].message);\n }\n return result.data;\n}\n","import { z } from 'zod';\n\nexport class InvalidPortalReturnUrlError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InvalidPortalReturnUrlError';\n }\n}\n\nconst portalReturnUrlSchema = z.url();\n\nexport function resolveDefaultPortalReturnUrl(value: string): string {\n const result = portalReturnUrlSchema.safeParse(value);\n if (!result.success) {\n throw new InvalidPortalReturnUrlError(result.error.issues[0].message);\n }\n return result.data;\n}\n","import { z } from 'zod';\n\nexport const recordUsageRequestSchema = z.object({\n subjectId: z.string().min(1),\n quantity: z.number().int().positive(),\n timestamp: z.iso.datetime(),\n idempotencyKey: z.string().min(1),\n});\nexport type RecordUsageRequest = z.infer<typeof recordUsageRequestSchema>;\n\nexport const usageRecordSchema = z.object({\n id: z.string(),\n subjectId: z.string(),\n quantity: z.number(),\n eventTimestamp: z.iso.datetime(),\n idempotencyKey: z.string(),\n createdAt: z.iso.datetime(),\n});\nexport type UsageRecordResponse = z.infer<typeof usageRecordSchema>;\n\nexport const listUsageResponseSchema = z.object({\n records: z.array(usageRecordSchema),\n total: z.number().int().nonnegative(),\n limit: z.number().int().nonnegative(),\n offset: z.number().int().nonnegative(),\n});\nexport type ListUsageResponse = z.infer<typeof listUsageResponseSchema>;\n","import { z } from 'zod';\n\n// 'unreportable' is terminal (the sweep gave up); the rest are still-pending\n// rows the sweep has already touched, split by *why* they haven't landed.\n// 'waiting' means nothing is wrong that the row itself can show — it was\n// claimed and simply hasn't been reported yet.\nexport const usageIssueCauseSchema = z.enum([\n 'unreportable',\n 'no_customer',\n 'no_meter',\n 'transport_failure',\n 'waiting',\n]);\nexport type UsageIssueCause = z.infer<typeof usageIssueCauseSchema>;\n\nexport const adminUsageIssueSchema = z.object({\n id: z.string(),\n projectId: z.string(),\n subjectId: z.string(),\n planKey: z.string().nullable(),\n quantity: z.number(),\n eventTimestamp: z.iso.datetime(),\n createdAt: z.iso.datetime(),\n state: z.enum(['terminal', 'retrying']),\n cause: usageIssueCauseSchema,\n reason: z.string(),\n attempts: z.number(),\n});\nexport type AdminUsageIssue = z.infer<typeof adminUsageIssueSchema>;\n\n// Echoes the resolved environment like every ecosystem-scoped admin read\n// (sprints 104–106), so an omitted param can't be mistaken for \"all\".\nexport const adminUsageIssuesResponseSchema = z.object({\n environment: z.enum(['test', 'live']),\n issues: z.array(adminUsageIssueSchema),\n nextCursor: z.string().nullable(),\n approxTotal: z.number(),\n});\nexport type AdminUsageIssuesResponse = z.infer<\n typeof adminUsageIssuesResponseSchema\n>;\n","import { errorEnvelopeSchema } from '@org/shared-types';\n\n// Thrown for every failure path — API denials, transport failures, and\n// malformed responses alike — so consumers can branch on `status`/`code`\n// instead of catching different error shapes.\nexport class BillingApiError extends Error {\n readonly status: number;\n readonly code: string;\n\n constructor(status: number, code: string, message: string) {\n super(message);\n this.name = 'BillingApiError';\n this.status = status;\n this.code = code;\n }\n}\n\nexport async function errorFromResponse(\n response: Response,\n): Promise<BillingApiError> {\n let code = 'unknown_error';\n let message = `Request failed with status ${response.status}`;\n\n try {\n const body: unknown = await response.json();\n const parsed = errorEnvelopeSchema.safeParse(body);\n if (parsed.success) {\n code = parsed.data.error.code;\n message = parsed.data.error.message;\n }\n } catch {\n // Body wasn't JSON or didn't match the envelope — keep the defaults.\n }\n\n return new BillingApiError(response.status, code, message);\n}\n\n// Status 0 distinguishes \"couldn't reach the API\" from a real HTTP response,\n// so middleware (sprint 16) can fail open on outages without also failing\n// open on 4xx denials.\nexport function networkError(cause: unknown): BillingApiError {\n const message =\n cause instanceof Error ? cause.message : 'Network request failed';\n return new BillingApiError(0, 'network_error', message);\n}\n\nexport function invalidResponseError(message: string): BillingApiError {\n return new BillingApiError(502, 'invalid_response', message);\n}\n","import { BillingApiError } from './errors.js';\nimport type {\n CheckEntitlementInput,\n EntitlementsResult,\n GuardDecision,\n LimitCheck,\n} from './types.js';\n\nfunction isMisconfiguration(err: unknown): boolean {\n return (\n err instanceof BillingApiError && err.status >= 400 && err.status < 500\n );\n}\n\nfunction decideOnContent(\n entitlements: EntitlementsResult,\n feature: string | undefined,\n limit: LimitCheck | undefined,\n): GuardDecision {\n if (feature !== undefined) {\n return entitlements.features[feature]\n ? { decision: 'allow', entitlements }\n : { decision: 'deny', reason: `Feature \"${feature}\" is not entitled` };\n }\n\n if (limit !== undefined) {\n const max = entitlements.limits[limit.key];\n return max !== undefined && limit.usage < max\n ? { decision: 'allow', entitlements }\n : { decision: 'deny', reason: `Limit \"${limit.key}\" has been reached` };\n }\n\n return { decision: 'allow', entitlements };\n}\n\n// Framework-agnostic orchestration over BillingClient — Fastify (or any\n// other framework) middleware only needs to map GuardDecision to a\n// response. Keep this file free of any framework import.\nexport async function checkEntitlement(\n input: CheckEntitlementInput,\n): Promise<GuardDecision> {\n const { client, subjectId, feature, limit, onUnavailable } = input;\n\n let entitlements: EntitlementsResult;\n try {\n entitlements = await client.getEntitlements(subjectId);\n } catch (err) {\n if (isMisconfiguration(err)) {\n const message =\n err instanceof Error ? err.message : 'Billing request was rejected';\n return { decision: 'deny', reason: message, misconfigured: true };\n }\n return onUnavailable === 'open'\n ? { decision: 'unavailable-allow' }\n : { decision: 'unavailable-deny', reason: 'Billing is unavailable' };\n }\n\n // Fresh or stale, this is content-based — a stale entitlements payload is\n // the graceful-degradation path working, not an unavailability case.\n return decideOnContent(entitlements, feature, limit);\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z"]}
package/dist/fastify.cjs CHANGED
@@ -110,7 +110,8 @@ var replayOutcomeSchema = import_zod.z.enum([
110
110
  "invalid",
111
111
  "unknown_subscription",
112
112
  "already_processed",
113
- "error"
113
+ "error",
114
+ "foreign_project"
114
115
  ]);
115
116
  var replayResponseSchema = import_zod.z.object({
116
117
  outcome: replayOutcomeSchema
@@ -178,19 +179,31 @@ var subscriptionViewSchema = import_zod2.z.discriminatedUnion("state", [
178
179
  activeSubscriptionViewSchema,
179
180
  noSubscriptionViewSchema
180
181
  ]);
182
+ var subscriptionCancelRequestSchema = import_zod2.z.object({
183
+ subjectId: import_zod2.z.string()
184
+ });
185
+ var subscriptionCancelResponseSchema = import_zod2.z.object({
186
+ canceled: import_zod2.z.literal(true),
187
+ providerSubscriptionId: import_zod2.z.string()
188
+ });
181
189
 
182
190
  // ../shared-types/src/entitlements.ts
183
191
  var entitlementSourcesSchema = import_zod3.z.object({
184
192
  features: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.enum(["subscription", "override"])),
185
193
  limits: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.enum(["subscription", "override"]))
186
194
  });
195
+ var meteredUsageSchema = import_zod3.z.object({
196
+ used: import_zod3.z.number(),
197
+ periodEnd: import_zod3.z.string()
198
+ });
187
199
  var entitlementsResponseSchema = import_zod3.z.object({
188
200
  plan: import_zod3.z.string().nullable(),
189
201
  features: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.boolean()),
190
202
  limits: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.number()),
191
203
  status: subscriptionStatusSchema,
192
204
  source: import_zod3.z.enum(["subscription", "override", "none"]),
193
- sources: entitlementSourcesSchema
205
+ sources: entitlementSourcesSchema,
206
+ usage: meteredUsageSchema.optional()
194
207
  });
195
208
 
196
209
  // ../shared-types/src/overrides.ts
@@ -268,6 +281,8 @@ var projectMetricsSchema = dashboardMetricsSchema.extend({
268
281
  mrrSeries: import_zod5.z.array(import_zod5.z.number())
269
282
  });
270
283
  var adminMetricsResponseSchema = import_zod5.z.object({
284
+ // Which environment every total below describes — never a mix.
285
+ environment: import_zod5.z.enum(["test", "live"]),
271
286
  ecosystem: dashboardMetricsSchema,
272
287
  // Shared x-axis labels for every project's mrrSeries (same calendar
273
288
  // months across the ecosystem) — empty when no project has snapshots yet.
@@ -316,7 +331,11 @@ var adminPriceSchema = import_zod5.z.object({
316
331
  id: import_zod5.z.string(),
317
332
  interval: import_zod5.z.enum(["month", "year"]),
318
333
  currency: import_zod5.z.string(),
319
- unitAmountCents: import_zod5.z.number(),
334
+ // Null for a metered price (sprint 96) — no fixed amount to display yet.
335
+ unitAmountCents: import_zod5.z.number().nullable(),
336
+ // Optional on input so callers built before sprint 96 still parse; always
337
+ // present on output via the default.
338
+ usageType: import_zod5.z.enum(["licensed", "metered"]).default("licensed"),
320
339
  syncStatus: import_zod5.z.enum(["synced", "pending", "drifted"]),
321
340
  syncedUnitAmountCents: import_zod5.z.number().nullable()
322
341
  });
@@ -370,7 +389,8 @@ var adminDeadLetterGroupSchema = import_zod5.z.object({
370
389
  count: import_zod5.z.number(),
371
390
  sampleEventId: import_zod5.z.string(),
372
391
  firstReceivedAt: import_zod5.z.iso.datetime(),
373
- lastReceivedAt: import_zod5.z.iso.datetime()
392
+ lastReceivedAt: import_zod5.z.iso.datetime(),
393
+ environment: import_zod5.z.enum(["test", "live"])
374
394
  });
375
395
  var adminDeadLetterGroupsResponseSchema = import_zod5.z.object({
376
396
  groups: import_zod5.z.array(adminDeadLetterGroupSchema)
@@ -379,7 +399,12 @@ var adminProjectDashboardResponseSchema = import_zod5.z.object({
379
399
  metrics: projectMetricsSchema,
380
400
  monthLabels: import_zod5.z.array(import_zod5.z.string()),
381
401
  providerKind: import_zod5.z.string(),
382
- plans: import_zod5.z.array(adminPlanSchema)
402
+ plans: import_zod5.z.array(adminPlanSchema),
403
+ // True when the caller gave no `environment` and the key named more than
404
+ // one row (sprint 66) — `metrics.environment` was picked by a
405
+ // deterministic fallback rather than requested explicitly, and the
406
+ // frontend labels it as such (sprint 68.5).
407
+ environmentDefaulted: import_zod5.z.boolean()
383
408
  });
384
409
 
385
410
  // ../shared-types/src/checkout.ts
@@ -428,22 +453,95 @@ var registerProjectRequestSchema = import_zod7.z.object({
428
453
  }
429
454
  });
430
455
 
431
- // ../shared-types/src/errors.ts
456
+ // ../shared-types/src/trials.ts
432
457
  var import_zod8 = require("zod");
433
- var errorEnvelopeSchema = import_zod8.z.object({
434
- error: import_zod8.z.object({
435
- code: import_zod8.z.string(),
436
- message: import_zod8.z.string()
458
+ var MAX_TRIAL_DURATION_DAYS = 31;
459
+ var DEFAULT_TRIAL_DURATION_DAYS = 7;
460
+ var startTrialRequestSchema = import_zod8.z.object({
461
+ subjectId: import_zod8.z.string().min(1),
462
+ feature: import_zod8.z.string().min(1),
463
+ durationDays: import_zod8.z.number().int().min(1).max(MAX_TRIAL_DURATION_DAYS).default(DEFAULT_TRIAL_DURATION_DAYS)
464
+ });
465
+ var trialGrantSchema = import_zod8.z.object({
466
+ id: import_zod8.z.string(),
467
+ subjectId: import_zod8.z.string(),
468
+ feature: import_zod8.z.string(),
469
+ expiresAt: import_zod8.z.iso.datetime(),
470
+ createdAt: import_zod8.z.iso.datetime()
471
+ });
472
+ var startTrialResponseSchema = import_zod8.z.object({
473
+ trial: trialGrantSchema,
474
+ created: import_zod8.z.boolean()
475
+ });
476
+
477
+ // ../shared-types/src/errors.ts
478
+ var import_zod9 = require("zod");
479
+ var errorEnvelopeSchema = import_zod9.z.object({
480
+ error: import_zod9.z.object({
481
+ code: import_zod9.z.string(),
482
+ message: import_zod9.z.string()
437
483
  })
438
484
  });
439
485
 
440
486
  // ../shared-types/src/webhook-secret.ts
441
- var import_zod9 = require("zod");
442
- var webhookSigningSecretSchema = import_zod9.z.string().regex(/^whsec_.+/, "must be a non-empty whsec_-prefixed string");
487
+ var import_zod10 = require("zod");
488
+ var webhookSigningSecretSchema = import_zod10.z.string().regex(/^whsec_.+/, "must be a non-empty whsec_-prefixed string");
443
489
 
444
490
  // ../shared-types/src/portal-return-url.ts
445
- var import_zod10 = require("zod");
446
- var portalReturnUrlSchema = import_zod10.z.url();
491
+ var import_zod11 = require("zod");
492
+ var portalReturnUrlSchema = import_zod11.z.url();
493
+
494
+ // ../shared-types/src/usage.ts
495
+ var import_zod12 = require("zod");
496
+ var recordUsageRequestSchema = import_zod12.z.object({
497
+ subjectId: import_zod12.z.string().min(1),
498
+ quantity: import_zod12.z.number().int().positive(),
499
+ timestamp: import_zod12.z.iso.datetime(),
500
+ idempotencyKey: import_zod12.z.string().min(1)
501
+ });
502
+ var usageRecordSchema = import_zod12.z.object({
503
+ id: import_zod12.z.string(),
504
+ subjectId: import_zod12.z.string(),
505
+ quantity: import_zod12.z.number(),
506
+ eventTimestamp: import_zod12.z.iso.datetime(),
507
+ idempotencyKey: import_zod12.z.string(),
508
+ createdAt: import_zod12.z.iso.datetime()
509
+ });
510
+ var listUsageResponseSchema = import_zod12.z.object({
511
+ records: import_zod12.z.array(usageRecordSchema),
512
+ total: import_zod12.z.number().int().nonnegative(),
513
+ limit: import_zod12.z.number().int().nonnegative(),
514
+ offset: import_zod12.z.number().int().nonnegative()
515
+ });
516
+
517
+ // ../shared-types/src/admin-usage.ts
518
+ var import_zod13 = require("zod");
519
+ var usageIssueCauseSchema = import_zod13.z.enum([
520
+ "unreportable",
521
+ "no_customer",
522
+ "no_meter",
523
+ "transport_failure",
524
+ "waiting"
525
+ ]);
526
+ var adminUsageIssueSchema = import_zod13.z.object({
527
+ id: import_zod13.z.string(),
528
+ projectId: import_zod13.z.string(),
529
+ subjectId: import_zod13.z.string(),
530
+ planKey: import_zod13.z.string().nullable(),
531
+ quantity: import_zod13.z.number(),
532
+ eventTimestamp: import_zod13.z.iso.datetime(),
533
+ createdAt: import_zod13.z.iso.datetime(),
534
+ state: import_zod13.z.enum(["terminal", "retrying"]),
535
+ cause: usageIssueCauseSchema,
536
+ reason: import_zod13.z.string(),
537
+ attempts: import_zod13.z.number()
538
+ });
539
+ var adminUsageIssuesResponseSchema = import_zod13.z.object({
540
+ environment: import_zod13.z.enum(["test", "live"]),
541
+ issues: import_zod13.z.array(adminUsageIssueSchema),
542
+ nextCursor: import_zod13.z.string().nullable(),
543
+ approxTotal: import_zod13.z.number()
544
+ });
447
545
 
448
546
  // src/errors.ts
449
547
  var BillingApiError = class extends Error {