feat(db): mesh data model — meshes, members, invites, audit log
- pgSchema "mesh" with 4 tables isolating the peer mesh domain - Enums: visibility, transport, tier, role - audit_log is metadata-only (E2E encryption enforced at broker/client) - Cascade on mesh delete, soft-delete via archivedAt/revokedAt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
69
packages/billing/src/config/schema.ts
Normal file
69
packages/billing/src/config/schema.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import * as z from "zod";
|
||||
|
||||
import {
|
||||
BillingDiscountType,
|
||||
BillingModel,
|
||||
PricingPlanType,
|
||||
RecurringInterval,
|
||||
} from "../types";
|
||||
|
||||
export const discountSchema = z.object({
|
||||
code: z.string(),
|
||||
type: z.enum(BillingDiscountType),
|
||||
off: z.number(),
|
||||
appliesTo: z.array(z.string()),
|
||||
});
|
||||
|
||||
const customPriceSchema = z.union([
|
||||
z.object({
|
||||
custom: z.literal(true),
|
||||
label: z.string(),
|
||||
href: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
custom: z.literal(false).optional().default(false),
|
||||
amount: z.number(),
|
||||
}),
|
||||
]);
|
||||
|
||||
const sharedPriceSchema = z.intersection(
|
||||
customPriceSchema,
|
||||
z.object({
|
||||
id: z.string(),
|
||||
currency: z.string().optional(),
|
||||
}),
|
||||
);
|
||||
|
||||
const priceTypeSchema = z.discriminatedUnion("type", [
|
||||
z.object({
|
||||
type: z.literal(BillingModel.ONE_TIME),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal(BillingModel.RECURRING),
|
||||
interval: z.enum(RecurringInterval),
|
||||
trialDays: z.number().optional(),
|
||||
}),
|
||||
]);
|
||||
|
||||
export const priceSchema = z.intersection(sharedPriceSchema, priceTypeSchema);
|
||||
|
||||
export const planSchema = z.object({
|
||||
id: z.enum(PricingPlanType),
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
badge: z.string().nullable().default(null),
|
||||
prices: z.array(priceSchema),
|
||||
});
|
||||
|
||||
export const billingConfigSchema = z.object({
|
||||
plans: z.array(planSchema).refine(
|
||||
(plans) => {
|
||||
const types = new Set(plans.map((plan) => plan.id));
|
||||
return types.size === plans.length;
|
||||
},
|
||||
{
|
||||
message: "You can't have two plans with the same id!",
|
||||
},
|
||||
),
|
||||
discounts: z.array(discountSchema).optional().default([]),
|
||||
});
|
||||
Reference in New Issue
Block a user