UNPKG

prices-as-code

Version:

Prices as Code (PaC) - Define your product pricing schemas with type-safe definitions

188 lines (187 loc) 5.68 kB
import { z } from 'zod'; /** * Base Types */ /** * Common metadata schema used across all providers */ export const MetadataSchema = z.record(z.string().or(z.number()).or(z.boolean()).or(z.array(z.string()))); /** * Base product schema shared across all providers */ export const BaseProductSchema = z.object({ id: z.string().optional(), name: z.string(), description: z.string().optional(), metadata: MetadataSchema.optional().default({}), }); /** * Common price intervals */ export const PriceIntervalSchema = z.enum(['day', 'week', 'month', 'year']); /** * Base recurring price schema */ export const BaseRecurringSchema = z.object({ interval: PriceIntervalSchema, intervalCount: z.number().optional().default(1), }); /** * Base price schema shared across all providers */ export const BasePriceSchema = z.object({ id: z.string().optional(), name: z.string(), unitAmount: z.number(), currency: z.string().length(3), // ISO 4217 currency code type: z.enum(['one_time', 'recurring']).default('one_time'), recurring: BaseRecurringSchema.optional(), active: z.boolean().optional().default(true), productId: z.string().optional(), // Reference to product ID metadata: MetadataSchema.optional().default({}), }); /** * Stripe Provider Schemas */ /** * Stripe-specific product schema */ export const StripeProductSchema = BaseProductSchema.extend({ features: z.array(z.string()).optional(), highlight: z.boolean().optional(), provider: z.literal('stripe'), key: z.string().optional(), // Well-known ID for reference }); /** * Stripe-specific recurring schema */ export const StripeRecurringSchema = BaseRecurringSchema.extend({ interval: z.enum(['day', 'week', 'month', 'year']), usageType: z.enum(['licensed', 'metered']).optional(), aggregateUsage: z .enum(['sum', 'last_during_period', 'last_ever', 'max']) .optional(), trialPeriodDays: z.number().optional(), }); /** * Stripe-specific price schema */ export const StripePriceSchema = BasePriceSchema.extend({ nickname: z.string(), // Stripe-specific field recurring: StripeRecurringSchema.optional(), provider: z.literal('stripe'), key: z.string().optional(), // Well-known ID for reference taxBehavior: z.enum(['inclusive', 'exclusive', 'unspecified']).optional(), billingScheme: z.enum(['per_unit', 'tiered']).optional(), productKey: z.string().optional(), // Reference by key instead of ID }); /** * Union types for providers */ export const ProductSchema = z.discriminatedUnion('provider', [ StripeProductSchema, ]); export const PriceSchema = z.discriminatedUnion('provider', [ StripePriceSchema, ]); /** * Configuration schema for all providers */ export const ConfigSchema = z.object({ products: z.array(ProductSchema), prices: z.array(PriceSchema), }); /** * Provider-specific client options */ export const StripeOptionsSchema = z.object({ secretKey: z.string(), apiVersion: z.string().optional(), }); /** * Provider union type */ export const ProviderOptionsSchema = z.discriminatedUnion('provider', [ z.object({ provider: z.literal('stripe'), options: StripeOptionsSchema }), ]); /** * Global options */ export const PaCOptionsSchema = z.object({ configPath: z.string().optional(), providers: z.array(ProviderOptionsSchema), writeBack: z.boolean().optional().default(false), format: z.enum(['yaml', 'json', 'ts']).optional().default('yaml'), }); /** * Generate options */ export const GenerateOptionsSchema = z.object({ configPath: z.string(), format: z.enum(['yaml', 'json', 'ts']).optional().default('yaml'), provider: z.enum(['stripe']).optional().default('stripe'), productTiers: z.array(z.string()).optional().default(['basic', 'pro', 'enterprise']), intervals: z.array(z.enum(['month', 'year'])).optional().default(['month', 'year']), currency: z.string().length(3).optional().default('usd'), includeMetadata: z.boolean().optional().default(true), includeFeatures: z.boolean().optional().default(true), }); /** * Result of synchronization */ export const SyncResultSchema = z.object({ config: ConfigSchema, configUpdated: z.boolean(), }); /** * Result of pull operation */ export const PullResultSchema = z.object({ config: ConfigSchema, configPath: z.string(), }); /** * Result of generate operation */ export const GenerateResultSchema = z.object({ config: ConfigSchema, configPath: z.string(), }); /** * Private/internal types for Recurly support (not exposed in public API) */ /** * Recurly-specific product schema */ export const RecurlyProductSchema = BaseProductSchema.extend({ provider: z.literal('recurly'), code: z.string(), // Recurly-specific identifier taxCode: z.string().optional(), taxExempt: z.boolean().optional(), }); /** * Recurly-specific recurring schema */ export const RecurlyRecurringSchema = BaseRecurringSchema.extend({ intervalLength: z.number().min(1), intervalUnit: z.enum(['days', 'months']), trialLength: z.number().optional(), trialUnit: z.enum(['days', 'months']).optional(), }); /** * Recurly-specific price schema */ export const RecurlyPriceSchema = BasePriceSchema.extend({ provider: z.literal('recurly'), code: z.string(), // Recurly-specific identifier taxInclusive: z.boolean().optional(), recurring: RecurlyRecurringSchema.optional(), productCode: z.string(), // Reference to product code }); /** * Recurly client options */ export const RecurlyOptionsSchema = z.object({ apiKey: z.string(), subdomain: z.string().optional(), });