From 3d0e4f94f2c2e29795b13fffa71c6ecce687a0cf Mon Sep 17 00:00:00 2001 From: John Yeo Date: Mon, 29 Sep 2025 11:15:23 +0100 Subject: [PATCH] wip --- bun.lock | 14 +- server/src/index.ts | 37 +- .../src/internal/api/entitled/checkRouter.ts | 22 +- shared/api/customer.ts | 131 ++ shared/archives/orgModels_old.ts | 2 +- shared/db/schema.ts | 145 +- shared/models/attachModels/attachBody.ts | 8 +- shared/models/attachModels/checkoutModels.ts | 2 +- .../chatResultModels/chatResultFeature.ts | 2 +- shared/models/cusModels/cusModels.ts | 59 +- .../cusResModels/cusFeatureResponse.ts | 2 +- .../cusResModels/cusProductResponse.ts | 2 +- .../cusResModels/cusReferralsResponse.ts | 2 +- .../cusResModels/upcomingInvoiceResponse.ts | 2 +- shared/models/cusModels/cusResponseModels.ts | 16 +- .../cusModels/entityModels/entityModels.ts | 4 +- .../cusModels/entityModels/entityResModels.ts | 7 +- .../invoiceModels/invoiceItemModels.ts | 2 +- .../cusModels/invoiceModels/invoiceModels.ts | 2 +- .../invoiceModels/invoiceResponseModels.ts | 2 +- .../cusEntModels/cusEntModels.ts | 3 +- .../cusEntModels/cusEntRelations.ts | 5 +- .../cusEntModels/cusEntTable.ts | 17 +- .../cusEntModels/cusEntWithProduct.ts | 2 +- .../cusEntModels/replaceableSchema.ts | 2 +- .../rolloverModels/rolloverModels.ts | 2 +- .../rolloverModels/rolloverRelations.ts | 2 +- .../rolloverModels/rolloverTable.ts | 12 +- .../cusPriceModels/cusPriceModels.ts | 2 +- .../cusProductModels/cusProductModels.ts | 22 +- shared/models/eventModels/eventModels.ts | 2 +- .../featureConfig/creditConfig.ts | 2 +- .../featureConfig/meteredConfig.ts | 2 +- shared/models/featureModels/featureModels.ts | 2 +- .../models/featureModels/featureResModels.ts | 2 +- .../models/migrationModels/migrationModels.ts | 2 +- shared/models/orgModels/frontendOrg.ts | 2 +- shared/models/orgModels/orgConfig.ts | 2 +- shared/models/otherModels/metadataModels.ts | 2 +- .../productModels/entModels/entModels.ts | 4 +- .../freeTrialModels/freeTrialModels.ts | 2 +- .../priceConfig/fixedPriceConfig.ts | 2 +- .../priceConfig/usagePriceConfig.ts | 2 +- .../productModels/priceModels/priceModels.ts | 10 +- shared/models/productModels/productModels.ts | 8 +- .../productItemModels/checkProdItemModels.ts | 2 +- .../productItemModels/featureItem.ts | 4 +- .../productItemModels/featurePriceItem.ts | 2 +- .../productItemModels/priceItem.ts | 2 +- .../prodItemResponseModels.ts | 6 +- .../productItemModels/productItemModels.ts | 5 +- .../productV2Models/productResponseModels.ts | 2 +- .../models/productV2Models/productV2Models.ts | 2 +- .../referralModels/referralModels.ts | 2 +- .../rewardModels/rewardModels/rewardModels.ts | 2 +- .../rewardModels/rewardResponseModels.ts | 2 +- .../rewardProgramModels.ts | 2 +- shared/models/subModels/subModels.ts | 2 +- shared/openapi.yaml | 1445 +++++++++++++++++ shared/package.json | 5 +- .../productItemUtils/mapToItem.ts | 18 +- 61 files changed, 1820 insertions(+), 261 deletions(-) create mode 100644 shared/api/customer.ts create mode 100644 shared/openapi.yaml diff --git a/bun.lock b/bun.lock index 1f6c6c2e5..7d69fb359 100644 --- a/bun.lock +++ b/bun.lock @@ -124,9 +124,13 @@ "drizzle-kit": "^0.31.1", "drizzle-orm": "^0.43.1", "drizzle-zod": "^0.8.2", + "js-yaml": "^4.1.0", + "yaml": "^2.8.1", + "zod-openapi": "^5.4.1", }, "devDependencies": { "@types/bun": "latest", + "@types/js-yaml": "^4.0.9", "@types/node": "^24.0.3", "@typescript/native-preview": "^7.0.0-dev.20250731.1", "cross-env": "^7.0.3", @@ -1079,7 +1083,7 @@ "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], - "@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="], + "@types/bun": ["@types/bun@1.2.22", "", { "dependencies": { "bun-types": "1.2.22" } }, "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA=="], "@types/bunyan": ["@types/bunyan@1.8.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ=="], @@ -1129,6 +1133,8 @@ "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], + "@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="], + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], "@types/lodash": ["@types/lodash@4.17.20", "", {}, "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA=="], @@ -2663,6 +2669,8 @@ "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + "yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], @@ -2681,6 +2689,8 @@ "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "zod-openapi": ["zod-openapi@5.4.1", "", { "peerDependencies": { "zod": "^3.25.74 || ^4.0.0" } }, "sha512-deZCmezGJhi2urw7l8LWYCJEUaAb/Azo14c0wncCM7L7u7hz+1d4v3r4Uav7x4+zVkJj/ZYlCu6lwT0QQttW6g=="], + "zod-to-json-schema": ["zod-to-json-schema@3.24.6", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg=="], "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], @@ -3041,7 +3051,7 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "@types/bun/bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="], + "@types/bun/bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA=="], "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], diff --git a/server/src/index.ts b/server/src/index.ts index 9d941881b..4e46facf8 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -1,31 +1,28 @@ import { config } from "dotenv"; + config(); import "./instrumentation.js"; -import { trace, context } from "@opentelemetry/api"; - -import http from "http"; -import cluster from "cluster"; -import os from "os"; -import mainRouter from "./internal/mainRouter.js"; -import express from "express"; -import cors from "cors"; - -import webhooksRouter from "./external/webhooks/webhooksRouter.js"; - -import { apiRouter } from "./internal/api/apiRouter.js"; -import { QueueManager } from "./queue/QueueManager.js"; import { AppEnv } from "@autumn/shared"; +import { context, trace } from "@opentelemetry/api"; +import { toNodeHandler } from "better-auth/node"; +import cluster from "cluster"; +import cors from "cors"; +import express from "express"; +import http from "http"; +import os from "os"; +import { client, db } from "./db/initDrizzle.js"; import { CacheManager } from "./external/caching/CacheManager.js"; +import { ClickHouseManager } from "./external/clickhouse/ClickHouseManager.js"; import { logger } from "./external/logtail/logtailUtils.js"; import { createPosthogCli } from "./external/posthog/createPosthogCli.js"; -import { generateId } from "./utils/genUtils.js"; -import { subscribeToOrgUpdates } from "./external/supabase/subscribeToOrgUpdates.js"; -import { client, db } from "./db/initDrizzle.js"; -import { toNodeHandler } from "better-auth/node"; +import webhooksRouter from "./external/webhooks/webhooksRouter.js"; +import { apiRouter } from "./internal/api/apiRouter.js"; +import mainRouter from "./internal/mainRouter.js"; +import { QueueManager } from "./queue/QueueManager.js"; import { auth } from "./utils/auth.js"; +import { generateId } from "./utils/genUtils.js"; import { checkEnvVars } from "./utils/initUtils.js"; -import { ClickHouseManager } from "./external/clickhouse/ClickHouseManager.js"; const tracer = trace.getTracer("express"); @@ -171,13 +168,13 @@ if (process.env.NODE_ENV === "development") { init(); registerShutdownHandlers(); } else { - let numCPUs = os.cpus().length; + const numCPUs = os.cpus().length; if (cluster.isPrimary) { console.log(`Master ${process.pid} is running`); console.log("Number of CPUs", numCPUs); - let numWorkers = 7; + const numWorkers = 7; for (let i = 0; i < numWorkers; i++) { cluster.fork(); diff --git a/server/src/internal/api/entitled/checkRouter.ts b/server/src/internal/api/entitled/checkRouter.ts index 8f95afaf5..f180249c7 100644 --- a/server/src/internal/api/entitled/checkRouter.ts +++ b/server/src/internal/api/entitled/checkRouter.ts @@ -1,25 +1,23 @@ -import { ErrCode } from "@/errors/errCodes.js"; -import RecaseError, { handleRequestError } from "@/utils/errorUtils.js"; import { APIVersion, type Feature, FeatureType } from "@autumn/shared"; - import { Router } from "express"; import { StatusCodes } from "http-status-codes"; -import { handleEventSent } from "../events/eventRouter.js"; +import { ErrCode } from "@/errors/errCodes.js"; +import RecaseError, { handleRequestError } from "@/utils/errorUtils.js"; import { notNullish } from "@/utils/genUtils.js"; - -import { handleProductCheck } from "./handlers/handleProductCheck.js"; -import { getBooleanEntitledResult } from "./checkUtils.js"; -import { getCheckPreview } from "./getCheckPreview.js"; import { orgToVersion } from "@/utils/versionUtils.js"; +import { handleEventSent } from "../events/eventRouter.js"; import { getCheckData } from "./checkUtils/getCheckData.js"; import { getV1CheckResponse } from "./checkUtils/getV1CheckResponse.js"; import { getV2CheckResponse } from "./checkUtils/getV2CheckResponse.js"; +import { getBooleanEntitledResult } from "./checkUtils.js"; +import { getCheckPreview } from "./getCheckPreview.js"; +import { handleProductCheck } from "./handlers/handleProductCheck.js"; export const checkRouter: Router = Router(); checkRouter.post("", async (req: any, res: any) => { try { - let { + const { customer_id, feature_id, product_id, @@ -71,7 +69,7 @@ checkRouter.post("", async (req: any, res: any) => { let quantity = 1; if (notNullish(requiredBalance)) { - let floatQuantity = parseFloat(requiredBalance); + const floatQuantity = parseFloat(requiredBalance); if (isNaN(floatQuantity)) { throw new RecaseError({ @@ -93,7 +91,7 @@ checkRouter.post("", async (req: any, res: any) => { allFeatures, } = await getCheckData({ req }); - let apiVersion = orgToVersion({ + const apiVersion = orgToVersion({ org, reqApiVersion: req.apiVersion, }); @@ -171,7 +169,7 @@ checkRouter.post("", async (req: any, res: any) => { } } - let preview = undefined; + let preview; if (req.body.with_preview) { try { preview = await getCheckPreview({ diff --git a/shared/api/customer.ts b/shared/api/customer.ts new file mode 100644 index 000000000..34cb9cdf8 --- /dev/null +++ b/shared/api/customer.ts @@ -0,0 +1,131 @@ +import { writeFileSync } from "node:fs"; +import yaml from "yaml"; +import { z } from "zod/v4"; +import { createDocument } from "zod-openapi"; +import { AttachBodySchema } from "../models/attachModels/attachBody.js"; +import { CusResponseSchema } from "../models/cusModels/cusResponseModels.js"; + +const customerId = z.string().meta({ + description: "Your internal ID for the customer", + example: "cus_123", + id: "customerId", +}); + +const featureId = z.string().meta({ + description: "Feature ID as defined in the dashboard (eg. 'messages')", + example: "messages", + id: "featureId", +}); + +const AttachResult = z + .object({ + message: z.string().meta({ + description: "A short description on the result of the operation", + example: "Successfully downgraded from Product A to Product B", + id: "message", + }), + product_ids: z.array(z.string()).meta({ + description: "The IDs of the products that were attached", + example: ["pro", "one_off"], + id: "productIds", + }), + customer_id: customerId, + }) + .meta({ id: "AttachResult" }); + +const attachDefinition = { + // requestParams: { path: z.object({ customerId }) }, + requestBody: { + content: { + "application/json": { schema: AttachBodySchema }, + }, + }, + responses: { + "200": { + description: "200 OK", + content: { + "application/json": { schema: AttachResult }, + }, + }, + }, +}; + +// Define Customer schema as a reusable component +const CustomerV1 = CusResponseSchema.meta({ id: "Customer" }); + +const document = createDocument({ + openapi: "3.1.0", + info: { + title: "My API", + version: "1.0.0", + }, + security: [ + { + secretKey: [], + }, + ], + components: { + securitySchemes: { + secretKey: { + type: "http", + scheme: "bearer", + bearerFormat: "JWT", + }, + }, + }, + paths: { + "/customers/{customerId}": { + get: { + requestParams: { path: z.object({ customerId }) }, + responses: { + "200": { + description: "200 OK", + content: { + "application/json": { schema: CustomerV1 }, + }, + }, + }, + }, + }, + "/customers/{customerId}/features/{featureId}": { + patch: { + tags: ["customers.features"], + requestParams: { path: z.object({ customerId, featureId }) }, + "x-speakeasy-name-override": "update", + requestBody: { + content: { + "application/json": { + schema: z.object({ + usage: z.number(), + }), + }, + }, + }, + responses: { + "200": { + description: "200 OK", + content: { + "application/json": { + schema: z.object({ + usage: z.number(), + }), + }, + }, + }, + }, + }, + }, + "/core/attach": { post: attachDefinition }, + }, +}); + +// Export to YAML file during build +if (process.env.NODE_ENV !== "production") { + try { + const yamlContent = yaml.stringify(document); + writeFileSync("./openapi.yaml", yamlContent, "utf8"); + console.log("OpenAPI document exported to openapi-customer.yaml"); + } catch (error) { + console.error("Failed to export OpenAPI document:", error); + } +} diff --git a/shared/archives/orgModels_old.ts b/shared/archives/orgModels_old.ts index 524c3ebf9..8676a0839 100644 --- a/shared/archives/orgModels_old.ts +++ b/shared/archives/orgModels_old.ts @@ -1,6 +1,6 @@ // Old File -import { z } from "zod"; +import { z } from "zod/v4"; import { OrgConfigSchema } from "../models/orgModels/orgConfig.js"; export const StripeConfigSchema = z.object({ diff --git a/shared/db/schema.ts b/shared/db/schema.ts index 9fcaeae6a..2fab2a7b0 100644 --- a/shared/db/schema.ts +++ b/shared/db/schema.ts @@ -1,89 +1,78 @@ /* TABLES */ -import { organizations } from "../models/orgModels/orgTable.js"; -import { chatResults } from "../models/chatResultModels/chatResultTable.js"; -import { features } from "../models/featureModels/featureTable.js"; - -// Customer Tables -import { customers } from "../models/cusModels/cusTable.js"; -import { entities } from "../models/cusModels/entityModels/entityTable.js"; - -// Product Tables -import { products } from "../models/productModels/productTable.js"; -import { prices } from "../models/productModels/priceModels/priceTable.js"; -import { entitlements } from "../models/productModels/entModels/entTable.js"; -import { freeTrials } from "../models/productModels/freeTrialModels/freeTrialTable.js"; -import { rollovers } from "../models/cusProductModels/cusEntModels/rolloverModels/rolloverTable.js"; -import { rolloverRelations } from "../models/cusProductModels/cusEntModels/rolloverModels/rolloverRelations.js"; - -// CusProduct Tables -import { customerProducts } from "../models/cusProductModels/cusProductTable.js"; -import { customerPrices } from "../models/cusProductModels/cusPriceModels/cusPriceTable.js"; -import { customerEntitlements } from "../models/cusProductModels/cusEntModels/cusEntTable.js"; - -// Other Tables -import { apiKeys } from "../models/devModels/apiKeyTable.js"; -import { metadata } from "../models/otherModels/metadataTable.js"; -import { subscriptions } from "../models/subModels/subTable.js"; -import { invoices } from "../models/cusModels/invoiceModels/invoiceTable.js"; -import { invoiceRelations } from "../models/cusModels/invoiceModels/invoiceRelations.js"; - -// Reward Tables -import { rewards } from "../models/rewardModels/rewardModels/rewardTable.js"; -import { rewardPrograms } from "../models/rewardModels/rewardProgramModels/rewardProgramTable.js"; -import { referralCodes } from "../models/rewardModels/referralModels/referralCodeTable.js"; -import { rewardRedemptions } from "../models/rewardModels/referralModels/rewardRedemptionTable.js"; - -// Migration Tables -import { migrationJobs } from "../models/migrationModels/migrationJobTable.js"; -import { migrationErrors } from "../models/migrationModels/migrationErrorTable.js"; - -/* RELATIONS */ -import { organizationsRelations } from "../models/orgModels/orgRelations.js"; -import { featureRelations } from "../models/featureModels/featureRelations.js"; - -// Customer Relations -import { customersRelations } from "../models/cusModels/cusRelations.js"; -import { entitiesRelations } from "../models/cusModels/entityModels/entityRelations.js"; - -// Product Relations -import { entitlementsRelations } from "../models/productModels/entModels/entRelations.js"; -import { priceRelations } from "../models/productModels/priceModels/priceRelations.js"; -import { productRelations } from "../models/productModels/productRelations.js"; -import { freeTrialRelations } from "../models/productModels/freeTrialModels/freeTrialRelations.js"; - -// CusProduct Relations -import { customerProductsRelations } from "../models/cusProductModels/cusProductRelations.js"; -import { customerPricesRelations } from "../models/cusProductModels/cusPriceModels/cusPriceRelations.js"; -import { customerEntitlementsRelations } from "../models/cusProductModels/cusEntModels/cusEntRelations.js"; -import { apiKeyRelations } from "../models/devModels/apiKeyRelations.js"; -import { replaceableRelations } from "../models/cusProductModels/cusEntModels/replaceableRelations.js"; - -// Reward Relations -import { rewardProgramRelations } from "../models/rewardModels/rewardProgramModels/rewardProgramRelations.js"; -import { referralCodeRelations } from "../models/rewardModels/referralModels/referralCodeRelations.js"; -import { rewardRedemptionRelations } from "../models/rewardModels/referralModels/rewardRedemptionRelations.js"; - -// Migration Relations -import { migrationErrorRelations } from "../models/migrationModels/migrationErrorRelations.js"; // Analytics Tables import { actions } from "../models/analyticsModels/actionTable.js"; -import { events } from "../models/eventModels/eventTable.js"; -import { replaceables } from "../models/cusProductModels/cusEntModels/replaceableTable.js"; +import { chatResults } from "../models/chatResultModels/chatResultTable.js"; +// Customer Relations +import { customersRelations } from "../models/cusModels/cusRelations.js"; +// Customer Tables +import { customers } from "../models/cusModels/cusTable.js"; +import { entitiesRelations } from "../models/cusModels/entityModels/entityRelations.js"; +import { entities } from "../models/cusModels/entityModels/entityTable.js"; +import { invoiceRelations } from "../models/cusModels/invoiceModels/invoiceRelations.js"; +import { invoices } from "../models/cusModels/invoiceModels/invoiceTable.js"; +import { customerEntitlementsRelations } from "../models/cusProductModels/cusEntModels/cusEntRelations.js"; +import { customerEntitlements } from "../models/cusProductModels/cusEntModels/cusEntTable.js"; +import { replaceableRelations } from "../models/cusProductModels/cusEntModels/replaceableRelations.js"; +import { replaceables } from "../models/cusProductModels/cusEntModels/replaceableTable.js"; +import { rolloverRelations } from "../models/cusProductModels/cusEntModels/rolloverModels/rolloverRelations.js"; +import { rollovers } from "../models/cusProductModels/cusEntModels/rolloverModels/rolloverTable.js"; +import { customerPricesRelations } from "../models/cusProductModels/cusPriceModels/cusPriceRelations.js"; +import { customerPrices } from "../models/cusProductModels/cusPriceModels/cusPriceTable.js"; +// CusProduct Relations +import { customerProductsRelations } from "../models/cusProductModels/cusProductRelations.js"; +// CusProduct Tables +import { customerProducts } from "../models/cusProductModels/cusProductTable.js"; +import { apiKeyRelations } from "../models/devModels/apiKeyRelations.js"; +// Other Tables +import { apiKeys } from "../models/devModels/apiKeyTable.js"; +import { events } from "../models/eventModels/eventTable.js"; +import { featureRelations } from "../models/featureModels/featureRelations.js"; +import { features } from "../models/featureModels/featureTable.js"; +// Migration Relations +import { migrationErrorRelations } from "../models/migrationModels/migrationErrorRelations.js"; +import { migrationErrors } from "../models/migrationModels/migrationErrorTable.js"; +// Migration Tables +import { migrationJobs } from "../models/migrationModels/migrationJobTable.js"; +/* RELATIONS */ +import { organizationsRelations } from "../models/orgModels/orgRelations.js"; +import { organizations } from "../models/orgModels/orgTable.js"; +import { metadata } from "../models/otherModels/metadataTable.js"; + +// Product Relations +import { entitlementsRelations } from "../models/productModels/entModels/entRelations.js"; +import { entitlements } from "../models/productModels/entModels/entTable.js"; +import { freeTrialRelations } from "../models/productModels/freeTrialModels/freeTrialRelations.js"; +import { freeTrials } from "../models/productModels/freeTrialModels/freeTrialTable.js"; +import { priceRelations } from "../models/productModels/priceModels/priceRelations.js"; +import { prices } from "../models/productModels/priceModels/priceTable.js"; +import { productRelations } from "../models/productModels/productRelations.js"; +// Product Tables +import { products } from "../models/productModels/productTable.js"; +import { referralCodeRelations } from "../models/rewardModels/referralModels/referralCodeRelations.js"; +import { referralCodes } from "../models/rewardModels/referralModels/referralCodeTable.js"; +import { rewardRedemptionRelations } from "../models/rewardModels/referralModels/rewardRedemptionRelations.js"; +import { rewardRedemptions } from "../models/rewardModels/referralModels/rewardRedemptionTable.js"; +// Reward Tables +import { rewards } from "../models/rewardModels/rewardModels/rewardTable.js"; +// Reward Relations +import { rewardProgramRelations } from "../models/rewardModels/rewardProgramModels/rewardProgramRelations.js"; +import { rewardPrograms } from "../models/rewardModels/rewardProgramModels/rewardProgramTable.js"; +import { subscriptions } from "../models/subModels/subTable.js"; import { - user, - session, - account, - verification, - member, - invitation, -} from "./auth-schema.js"; -import { - userRelations, - memberRelations, inviteRelations, + memberRelations, + userRelations, } from "./auth-relations.js"; +import { + account, + invitation, + member, + session, + user, + verification, +} from "./auth-schema.js"; export { // Tables diff --git a/shared/models/attachModels/attachBody.ts b/shared/models/attachModels/attachBody.ts index 18ff2bc25..50510cd6c 100644 --- a/shared/models/attachModels/attachBody.ts +++ b/shared/models/attachModels/attachBody.ts @@ -1,8 +1,8 @@ -import { z } from "zod"; -import { FeatureOptionsSchema } from "../cusProductModels/cusProductModels.js"; -import { ProductItemSchema } from "../productV2Models/productItemModels/productItemModels.js"; -import { CreateFreeTrialSchema } from "../productModels/freeTrialModels/freeTrialModels.js"; +import { z } from "zod/v4"; import { notNullish } from "../../utils/utils.js"; +import { FeatureOptionsSchema } from "../cusProductModels/cusProductModels.js"; +import { CreateFreeTrialSchema } from "../productModels/freeTrialModels/freeTrialModels.js"; +import { ProductItemSchema } from "../productV2Models/productItemModels/productItemModels.js"; export const ProductOptions = z.object({ product_id: z.string(), diff --git a/shared/models/attachModels/checkoutModels.ts b/shared/models/attachModels/checkoutModels.ts index b5bf0d404..ac016ca3b 100644 --- a/shared/models/attachModels/checkoutModels.ts +++ b/shared/models/attachModels/checkoutModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { FeatureOptionsSchema } from "../cusProductModels/cusProductModels.js"; import { ProductItemResponseSchema } from "../productV2Models/productItemModels/prodItemResponseModels.js"; import { ProductResponseSchema } from "../productV2Models/productResponseModels.js"; diff --git a/shared/models/chatResultModels/chatResultFeature.ts b/shared/models/chatResultModels/chatResultFeature.ts index a7d46f3bf..d571bc8e2 100644 --- a/shared/models/chatResultModels/chatResultFeature.ts +++ b/shared/models/chatResultModels/chatResultFeature.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; export const ChatFeatureCreditSchema = z.object({ metered_feature_id: z.string().nonempty(), diff --git a/shared/models/cusModels/cusModels.ts b/shared/models/cusModels/cusModels.ts index dddc7fabc..839efffcb 100644 --- a/shared/models/cusModels/cusModels.ts +++ b/shared/models/cusModels/cusModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { AppEnv } from "../genModels/genEnums.js"; export const CustomerSchema = z.object({ @@ -21,43 +21,36 @@ export const CreateCustomerSchema = z.object({ .string() .refine( (val) => { - if (val === null) return true; // Allow null/undefined - + if (val === "") return false; + if (val.includes("@")) return false; + if (val.includes(" ")) return false; + if (val.includes(".")) return false; return /^[a-zA-Z0-9_-]+$/.test(val); }, - (val) => { - if (val === "") return { message: "can't be an empty string" }; - - // Check for specific invalid characters and provide targeted messages - if (val.includes("@")) { - return { - message: - "ID cannot contain @ symbol. Use only letters, numbers, underscores, and hyphens.", - }; - } - if (val.includes(" ")) { - return { - message: - "ID cannot contain spaces. Use only letters, numbers, underscores, and hyphens.", - }; - } - if (val.includes(".")) { - return { - message: - "ID cannot contain periods. Use only letters, numbers, underscores, and hyphens.", - }; - } - if (/[^a-zA-Z0-9_-]/.test(val)) { - const invalidChar = val.match(/[^a-zA-Z0-9_-]/)?.[0]; + { + error: (issue) => { + const input = issue.input as string; + if (input === "") return { message: "can't be an empty string" }; + if (input.includes("@")) + return { + message: + "ID cannot contain @ symbol. Use only letters, numbers, underscores, and hyphens.", + }; + if (input.includes(" ")) + return { + message: + "ID cannot contain spaces. Use only letters, numbers, underscores, and hyphens.", + }; + if (input.includes(".")) + return { + message: + "ID cannot contain periods. Use only letters, numbers, underscores, and hyphens.", + }; + const invalidChar = input.match(/[^a-zA-Z0-9_-]/)?.[0]; return { message: `ID cannot contain '${invalidChar}'. Use only letters, numbers, underscores, and hyphens.`, }; - } - - return { - message: - "ID must contain only letters, numbers, underscores, and hyphens.", - }; + }, }, ) .nullish(), diff --git a/shared/models/cusModels/cusResModels/cusFeatureResponse.ts b/shared/models/cusModels/cusResModels/cusFeatureResponse.ts index fcaee7bd1..52f212e67 100644 --- a/shared/models/cusModels/cusResModels/cusFeatureResponse.ts +++ b/shared/models/cusModels/cusResModels/cusFeatureResponse.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { EntInterval } from "../../productModels/entModels/entEnums.js"; import { ProductItemFeatureType } from "../../productV2Models/productItemModels/productItemModels.js"; diff --git a/shared/models/cusModels/cusResModels/cusProductResponse.ts b/shared/models/cusModels/cusResModels/cusProductResponse.ts index 45b25eebe..cdb396199 100644 --- a/shared/models/cusModels/cusResModels/cusProductResponse.ts +++ b/shared/models/cusModels/cusResModels/cusProductResponse.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { CusProductStatus } from "../../cusProductModels/cusProductEnums.js"; import { ProductItemResponseSchema } from "../../productV2Models/productItemModels/prodItemResponseModels.js"; diff --git a/shared/models/cusModels/cusResModels/cusReferralsResponse.ts b/shared/models/cusModels/cusResModels/cusReferralsResponse.ts index af313c8d4..2e1b52d42 100644 --- a/shared/models/cusModels/cusResModels/cusReferralsResponse.ts +++ b/shared/models/cusModels/cusResModels/cusReferralsResponse.ts @@ -1,4 +1,4 @@ -import z from "zod"; +import { z } from "zod/v4"; export const CusReferralResponseSchema = z.object({ program_id: z.string(), diff --git a/shared/models/cusModels/cusResModels/upcomingInvoiceResponse.ts b/shared/models/cusModels/cusResModels/upcomingInvoiceResponse.ts index 1dfe31127..a3e09ef57 100644 --- a/shared/models/cusModels/cusResModels/upcomingInvoiceResponse.ts +++ b/shared/models/cusModels/cusResModels/upcomingInvoiceResponse.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { DiscountResponseSchema } from "../../rewardModels/rewardModels/rewardResponseModels.js"; export const UpcomingInvoiceResponseSchema = z.object({ diff --git a/shared/models/cusModels/cusResponseModels.ts b/shared/models/cusModels/cusResponseModels.ts index 119ede667..a808e462c 100644 --- a/shared/models/cusModels/cusResponseModels.ts +++ b/shared/models/cusModels/cusResponseModels.ts @@ -1,4 +1,5 @@ -import { z } from "zod"; +import { z } from "zod/v4"; + import { AppEnv } from "../genModels/genEnums.js"; import { RewardResponseSchema } from "../rewardModels/rewardModels/rewardResponseModels.js"; import { CusProductResponseSchema } from "./cusResModels/cusProductResponse.js"; @@ -17,8 +18,17 @@ export const CusResponseSchema = z.object({ // Internal fields autumn_id: z.string().nullish(), - id: z.string().nullable(), - created_at: z.number(), + id: z.string().nullable().meta({ + description: "Your internal ID for the customer", + example: "cus_123", + }), + + created_at: z.number().meta({ + description: + "The date and time the customer was created in milliseconds since epoch", + example: 1717000000, + }), + name: z.string().nullable(), email: z.string().nullable(), fingerprint: z.string().nullable(), diff --git a/shared/models/cusModels/entityModels/entityModels.ts b/shared/models/cusModels/entityModels/entityModels.ts index 9113f8c86..514fe4559 100644 --- a/shared/models/cusModels/entityModels/entityModels.ts +++ b/shared/models/cusModels/entityModels/entityModels.ts @@ -1,5 +1,5 @@ -import { z } from "zod"; -import { Feature } from "../../featureModels/featureModels.js"; +import { z } from "zod/v4"; +import type { Feature } from "../../featureModels/featureModels.js"; export const EntitySchema = z.object({ id: z.string(), diff --git a/shared/models/cusModels/entityModels/entityResModels.ts b/shared/models/cusModels/entityModels/entityResModels.ts index 8bdc17311..d2f9dbcb8 100644 --- a/shared/models/cusModels/entityModels/entityResModels.ts +++ b/shared/models/cusModels/entityModels/entityResModels.ts @@ -1,9 +1,8 @@ +import { z } from "zod/v4"; import { AppEnv } from "../../genModels/genEnums.js"; - -import { z } from "zod"; -import { InvoiceResponseSchema } from "../invoiceModels/invoiceResponseModels.js"; -import { CusProductResponseSchema } from "../cusResModels/cusProductResponse.js"; import { CusEntResponseV2Schema } from "../cusResModels/cusFeatureResponse.js"; +import { CusProductResponseSchema } from "../cusResModels/cusProductResponse.js"; +import { InvoiceResponseSchema } from "../invoiceModels/invoiceResponseModels.js"; export const EntityResponseSchema = z.object({ id: z.string().nullable(), diff --git a/shared/models/cusModels/invoiceModels/invoiceItemModels.ts b/shared/models/cusModels/invoiceModels/invoiceItemModels.ts index 7552b6f69..dee31a913 100644 --- a/shared/models/cusModels/invoiceModels/invoiceItemModels.ts +++ b/shared/models/cusModels/invoiceModels/invoiceItemModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; const InvoiceItemSchema = z.object({ id: z.string(), diff --git a/shared/models/cusModels/invoiceModels/invoiceModels.ts b/shared/models/cusModels/invoiceModels/invoiceModels.ts index 88e9ec7a3..cd3b94cbc 100644 --- a/shared/models/cusModels/invoiceModels/invoiceModels.ts +++ b/shared/models/cusModels/invoiceModels/invoiceModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; export enum InvoiceStatus { Draft = "draft", diff --git a/shared/models/cusModels/invoiceModels/invoiceResponseModels.ts b/shared/models/cusModels/invoiceModels/invoiceResponseModels.ts index cff72fa86..e674b4229 100644 --- a/shared/models/cusModels/invoiceModels/invoiceResponseModels.ts +++ b/shared/models/cusModels/invoiceModels/invoiceResponseModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; export const InvoiceItemResponseSchema = z.object({ description: z.string(), diff --git a/shared/models/cusProductModels/cusEntModels/cusEntModels.ts b/shared/models/cusProductModels/cusEntModels/cusEntModels.ts index 0f41ec99c..63fd838f9 100644 --- a/shared/models/cusProductModels/cusEntModels/cusEntModels.ts +++ b/shared/models/cusProductModels/cusEntModels/cusEntModels.ts @@ -1,6 +1,5 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { EntitlementWithFeatureSchema } from "../../productModels/entModels/entModels.js"; -import { Replaceable } from "./replaceableTable.js"; import { ReplaceableSchema } from "./replaceableSchema.js"; import { RolloverSchema } from "./rolloverModels/rolloverTable.js"; diff --git a/shared/models/cusProductModels/cusEntModels/cusEntRelations.ts b/shared/models/cusProductModels/cusEntModels/cusEntRelations.ts index 369003470..763986c49 100644 --- a/shared/models/cusProductModels/cusEntModels/cusEntRelations.ts +++ b/shared/models/cusProductModels/cusEntModels/cusEntRelations.ts @@ -1,10 +1,9 @@ import { relations } from "drizzle-orm"; - -import { entitlements } from "../../productModels/entModels/entTable.js"; import { customers } from "../../cusModels/cusTable.js"; import { features } from "../../featureModels/featureTable.js"; -import { customerEntitlements } from "./cusEntTable.js"; +import { entitlements } from "../../productModels/entModels/entTable.js"; import { customerProducts } from "../cusProductTable.js"; +import { customerEntitlements } from "./cusEntTable.js"; import { replaceables } from "./replaceableTable.js"; import { rollovers } from "./rolloverModels/rolloverTable.js"; diff --git a/shared/models/cusProductModels/cusEntModels/cusEntTable.ts b/shared/models/cusProductModels/cusEntModels/cusEntTable.ts index 5f483c535..f1a356b01 100644 --- a/shared/models/cusProductModels/cusEntModels/cusEntTable.ts +++ b/shared/models/cusProductModels/cusEntModels/cusEntTable.ts @@ -1,20 +1,17 @@ import { - pgTable, - numeric, boolean, foreignKey, - unique, - text, - jsonb, index, + jsonb, + numeric, + pgTable, + text, } from "drizzle-orm/pg-core"; - -import { features } from "../../featureModels/featureTable.js"; - import { collatePgColumn } from "../../../db/utils.js"; -import { EntityBalance } from "./cusEntModels.js"; +import { features } from "../../featureModels/featureTable.js"; +import { entitlements } from "../../productModels/entModels/entTable.js"; import { customerProducts } from "../cusProductTable.js"; -import { entitlements } from "../../../db/schema.js"; +import type { EntityBalance } from "./cusEntModels.js"; export const customerEntitlements = pgTable( "customer_entitlements", diff --git a/shared/models/cusProductModels/cusEntModels/cusEntWithProduct.ts b/shared/models/cusProductModels/cusEntModels/cusEntWithProduct.ts index 6d4c548a8..c6fde4d72 100644 --- a/shared/models/cusProductModels/cusEntModels/cusEntWithProduct.ts +++ b/shared/models/cusProductModels/cusEntModels/cusEntWithProduct.ts @@ -1,6 +1,6 @@ +import type { z } from "zod/v4"; import { CusProductSchema, FullCusProductSchema } from "../cusProductModels.js"; import { FullCustomerEntitlementSchema } from "./cusEntModels.js"; -import { z } from "zod"; export const FullCusEntWithProductSchema = FullCustomerEntitlementSchema.extend( { diff --git a/shared/models/cusProductModels/cusEntModels/replaceableSchema.ts b/shared/models/cusProductModels/cusEntModels/replaceableSchema.ts index 3f6a9c7be..119ba106b 100644 --- a/shared/models/cusProductModels/cusEntModels/replaceableSchema.ts +++ b/shared/models/cusProductModels/cusEntModels/replaceableSchema.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { EntitlementSchema } from "../../productModels/entModels/entModels.js"; export const ReplaceableSchema = z.object({ diff --git a/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverModels.ts b/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverModels.ts index b4428dbf6..4ab05c8f9 100644 --- a/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverModels.ts +++ b/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverModels.ts @@ -1,4 +1,4 @@ -// import { z } from "zod"; +// import { z } from "zod/v4"; // import { EntityBalance, EntityBalanceSchema } from "../../../index.js"; // import { jsonb } from "drizzle-orm/pg-core"; diff --git a/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverRelations.ts b/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverRelations.ts index 861c1b949..0db4c4590 100644 --- a/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverRelations.ts +++ b/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverRelations.ts @@ -1,6 +1,6 @@ import { relations } from "drizzle-orm"; -import { rollovers } from "./rolloverTable.js"; import { customerEntitlements } from "../cusEntTable.js"; +import { rollovers } from "./rolloverTable.js"; export const rolloverRelations = relations(rollovers, ({ one }) => ({ customer_entitlement: one(customerEntitlements, { diff --git a/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverTable.ts b/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverTable.ts index 2893fa9b1..436cfdfb0 100644 --- a/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverTable.ts +++ b/shared/models/cusProductModels/cusEntModels/rolloverModels/rolloverTable.ts @@ -1,13 +1,13 @@ -import { z } from "zod"; -import { customerEntitlements } from "../cusEntTable.js"; import { foreignKey, - pgTable, - numeric, - jsonb, - text, index, + jsonb, + numeric, + pgTable, + text, } from "drizzle-orm/pg-core"; +import { z } from "zod/v4"; +import { customerEntitlements } from "../cusEntTable.js"; export const EntityRolloverBalanceSchema = z.object({ id: z.string(), diff --git a/shared/models/cusProductModels/cusPriceModels/cusPriceModels.ts b/shared/models/cusProductModels/cusPriceModels/cusPriceModels.ts index 700b140b5..8a1ba264f 100644 --- a/shared/models/cusProductModels/cusPriceModels/cusPriceModels.ts +++ b/shared/models/cusProductModels/cusPriceModels/cusPriceModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { PriceSchema } from "../../productModels/priceModels/priceModels.js"; export const CustomerPriceSchema = z.object({ diff --git a/shared/models/cusProductModels/cusProductModels.ts b/shared/models/cusProductModels/cusProductModels.ts index d5264f713..afbec3c1c 100644 --- a/shared/models/cusProductModels/cusProductModels.ts +++ b/shared/models/cusProductModels/cusProductModels.ts @@ -1,21 +1,11 @@ -import { z } from "zod"; -import { ProcessorType } from "../genModels/genEnums.js"; -import { ProductSchema } from "../productModels/productModels.js"; -import { PriceSchema } from "../productModels/priceModels/priceModels.js"; -import { - CustomerEntitlementSchema, - FullCustomerEntitlementSchema, -} from "./cusEntModels/cusEntModels.js"; -import { EntitlementSchema } from "../productModels/entModels/entModels.js"; -import { FeatureSchema } from "../featureModels/featureModels.js"; +import { z } from "zod/v4"; import { CustomerSchema } from "../cusModels/cusModels.js"; +import { ProcessorType } from "../genModels/genEnums.js"; import { FreeTrialSchema } from "../productModels/freeTrialModels/freeTrialModels.js"; -import { - CustomerPriceSchema, - FullCustomerPriceSchema, -} from "./cusPriceModels/cusPriceModels.js"; -import { CollectionMethod } from "./cusProductEnums.js"; -import { CusProductStatus } from "./cusProductEnums.js"; +import { ProductSchema } from "../productModels/productModels.js"; +import { FullCustomerEntitlementSchema } from "./cusEntModels/cusEntModels.js"; +import { FullCustomerPriceSchema } from "./cusPriceModels/cusPriceModels.js"; +import { CollectionMethod, CusProductStatus } from "./cusProductEnums.js"; export const FeatureOptionsSchema = z.object({ feature_id: z.string(), diff --git a/shared/models/eventModels/eventModels.ts b/shared/models/eventModels/eventModels.ts index 360f8dd22..3b46df15e 100644 --- a/shared/models/eventModels/eventModels.ts +++ b/shared/models/eventModels/eventModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; // export const EventSchema = z.object({ // // Submitted by the client diff --git a/shared/models/featureModels/featureConfig/creditConfig.ts b/shared/models/featureModels/featureConfig/creditConfig.ts index 5dfc6a195..ab38663c1 100644 --- a/shared/models/featureModels/featureConfig/creditConfig.ts +++ b/shared/models/featureModels/featureConfig/creditConfig.ts @@ -1,5 +1,5 @@ +import { z } from "zod/v4"; import { FeatureUsageType } from "../featureEnums.js"; -import { z } from "zod"; export const CreditSchemaItemSchema = z.object({ metered_feature_id: z.string(), diff --git a/shared/models/featureModels/featureConfig/meteredConfig.ts b/shared/models/featureModels/featureConfig/meteredConfig.ts index 3921f3af9..1e8af5a15 100644 --- a/shared/models/featureModels/featureConfig/meteredConfig.ts +++ b/shared/models/featureModels/featureConfig/meteredConfig.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { FeatureUsageType } from "../featureEnums.js"; export interface Expression { diff --git a/shared/models/featureModels/featureModels.ts b/shared/models/featureModels/featureModels.ts index 8c615090e..50ed86c1f 100644 --- a/shared/models/featureModels/featureModels.ts +++ b/shared/models/featureModels/featureModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { AppEnv } from "../genModels/genEnums.js"; import { FeatureType } from "./featureEnums.js"; diff --git a/shared/models/featureModels/featureResModels.ts b/shared/models/featureModels/featureResModels.ts index 86d6ec9bf..55524d461 100644 --- a/shared/models/featureModels/featureResModels.ts +++ b/shared/models/featureModels/featureResModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; export enum APIFeatureType { Boolean = "boolean", diff --git a/shared/models/migrationModels/migrationModels.ts b/shared/models/migrationModels/migrationModels.ts index 41c349bec..8c3ed209d 100644 --- a/shared/models/migrationModels/migrationModels.ts +++ b/shared/models/migrationModels/migrationModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { AppEnv } from "../genModels/genEnums.js"; export enum MigrationJobStep { diff --git a/shared/models/orgModels/frontendOrg.ts b/shared/models/orgModels/frontendOrg.ts index 327b0d20c..fda39c01d 100644 --- a/shared/models/orgModels/frontendOrg.ts +++ b/shared/models/orgModels/frontendOrg.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; export const FrontendOrgSchema = z.object({ id: z.string(), diff --git a/shared/models/orgModels/orgConfig.ts b/shared/models/orgModels/orgConfig.ts index dace8a7c6..7c5823cc7 100644 --- a/shared/models/orgModels/orgConfig.ts +++ b/shared/models/orgModels/orgConfig.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; export const OrgConfigSchema = z.object({ bill_upgrade_immediately: z.boolean().default(true), diff --git a/shared/models/otherModels/metadataModels.ts b/shared/models/otherModels/metadataModels.ts index c71578eea..f531cf5fe 100644 --- a/shared/models/otherModels/metadataModels.ts +++ b/shared/models/otherModels/metadataModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; export const AutumnMetadataSchema = z.object({ id: z.string(), diff --git a/shared/models/productModels/entModels/entModels.ts b/shared/models/productModels/entModels/entModels.ts index 522ee3494..37ae30fa3 100644 --- a/shared/models/productModels/entModels/entModels.ts +++ b/shared/models/productModels/entModels/entModels.ts @@ -1,7 +1,7 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { FeatureSchema } from "../../featureModels/featureModels.js"; -import { EntInterval } from "./entEnums.js"; import { RolloverConfigSchema } from "../../productV2Models/productItemModels/productItemModels.js"; +import { EntInterval } from "./entEnums.js"; export enum AllowanceType { Fixed = "fixed", diff --git a/shared/models/productModels/freeTrialModels/freeTrialModels.ts b/shared/models/productModels/freeTrialModels/freeTrialModels.ts index 8d4b1d593..f07f8a985 100644 --- a/shared/models/productModels/freeTrialModels/freeTrialModels.ts +++ b/shared/models/productModels/freeTrialModels/freeTrialModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { FreeTrialDuration } from "./freeTrialEnums.js"; export const FreeTrialSchema = z.object({ diff --git a/shared/models/productModels/priceModels/priceConfig/fixedPriceConfig.ts b/shared/models/productModels/priceModels/priceConfig/fixedPriceConfig.ts index 6494fbc82..df6a04bfa 100644 --- a/shared/models/productModels/priceModels/priceConfig/fixedPriceConfig.ts +++ b/shared/models/productModels/priceModels/priceConfig/fixedPriceConfig.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { BillingInterval } from "../priceEnums.js"; export const FixedPriceConfigSchema = z.object({ diff --git a/shared/models/productModels/priceModels/priceConfig/usagePriceConfig.ts b/shared/models/productModels/priceModels/priceConfig/usagePriceConfig.ts index 1bdeb3a8c..102b44724 100644 --- a/shared/models/productModels/priceModels/priceConfig/usagePriceConfig.ts +++ b/shared/models/productModels/priceModels/priceConfig/usagePriceConfig.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { Infinite } from "../../productEnums.js"; import { BillingInterval } from "../priceEnums.js"; diff --git a/shared/models/productModels/priceModels/priceModels.ts b/shared/models/productModels/priceModels/priceModels.ts index d0e905aa6..2a01d54ff 100644 --- a/shared/models/productModels/priceModels/priceModels.ts +++ b/shared/models/productModels/priceModels/priceModels.ts @@ -1,9 +1,11 @@ -import { z } from "zod"; -import { UsagePriceConfigSchema } from "./priceConfig/usagePriceConfig.js"; +import { z } from "zod/v4"; +import { + OnDecrease, + OnIncrease, +} from "../../productV2Models/productItemModels/productItemEnums.js"; import { FixedPriceConfigSchema } from "./priceConfig/fixedPriceConfig.js"; +import { UsagePriceConfigSchema } from "./priceConfig/usagePriceConfig.js"; import { BillingType } from "./priceEnums.js"; -import { OnDecrease } from "../../productV2Models/productItemModels/productItemEnums.js"; -import { OnIncrease } from "../../productV2Models/productItemModels/productItemEnums.js"; const ProrationConfigSchema = z.object({ on_increase: z.nativeEnum(OnIncrease).default(OnIncrease.ProrateImmediately), diff --git a/shared/models/productModels/productModels.ts b/shared/models/productModels/productModels.ts index 2715a24c0..a3e163b58 100644 --- a/shared/models/productModels/productModels.ts +++ b/shared/models/productModels/productModels.ts @@ -1,9 +1,9 @@ -import { z } from "zod"; -import { PriceSchema } from "./priceModels/priceModels.js"; -import { EntitlementSchema } from "./entModels/entModels.js"; +import { z } from "zod/v4"; import { FeatureSchema } from "../featureModels/featureModels.js"; -import { FreeTrialSchema } from "./freeTrialModels/freeTrialModels.js"; import { AppEnv } from "../genModels/genEnums.js"; +import { EntitlementSchema } from "./entModels/entModels.js"; +import { FreeTrialSchema } from "./freeTrialModels/freeTrialModels.js"; +import { PriceSchema } from "./priceModels/priceModels.js"; export const ProductSchema = z.object({ id: z.string(), diff --git a/shared/models/productV2Models/productItemModels/checkProdItemModels.ts b/shared/models/productV2Models/productItemModels/checkProdItemModels.ts index 4dcbac377..7e967d4ff 100644 --- a/shared/models/productV2Models/productItemModels/checkProdItemModels.ts +++ b/shared/models/productV2Models/productItemModels/checkProdItemModels.ts @@ -1,4 +1,4 @@ -// import { z } from "zod"; +// import { z } from "zod/v4"; // import { UsageModel } from "../productItemModels.js"; // export const CheckProdItemSchema = z.object({ diff --git a/shared/models/productV2Models/productItemModels/featureItem.ts b/shared/models/productV2Models/productItemModels/featureItem.ts index 9575bcf31..153e86d96 100644 --- a/shared/models/productV2Models/productItemModels/featureItem.ts +++ b/shared/models/productV2Models/productItemModels/featureItem.ts @@ -1,6 +1,6 @@ -import { ProductItemSchema } from "./productItemModels.js"; +import { z } from "zod/v4"; import { Infinite } from "../../productModels/productEnums.js"; -import { z } from "zod"; +import { ProductItemSchema } from "./productItemModels.js"; export const FeatureItemSchema = ProductItemSchema.pick({ feature_id: true, diff --git a/shared/models/productV2Models/productItemModels/featurePriceItem.ts b/shared/models/productV2Models/productItemModels/featurePriceItem.ts index 4ed0d617c..4b203dca9 100644 --- a/shared/models/productV2Models/productItemModels/featurePriceItem.ts +++ b/shared/models/productV2Models/productItemModels/featurePriceItem.ts @@ -1,5 +1,5 @@ +import { z } from "zod/v4"; import { ProductItemSchema } from "./productItemModels.js"; -import { z } from "zod"; export const FeaturePriceItemSchema = ProductItemSchema.pick({ feature_id: true, diff --git a/shared/models/productV2Models/productItemModels/priceItem.ts b/shared/models/productV2Models/productItemModels/priceItem.ts index 4ba1214b9..da26f162a 100644 --- a/shared/models/productV2Models/productItemModels/priceItem.ts +++ b/shared/models/productV2Models/productItemModels/priceItem.ts @@ -1,5 +1,5 @@ +import { z } from "zod/v4"; import { ProductItemSchema } from "./productItemModels.js"; -import { z } from "zod"; export const PriceItemSchema = ProductItemSchema.pick({ price: true, diff --git a/shared/models/productV2Models/productItemModels/prodItemResponseModels.ts b/shared/models/productV2Models/productItemModels/prodItemResponseModels.ts index 8d44f1197..9dc0365d3 100644 --- a/shared/models/productV2Models/productItemModels/prodItemResponseModels.ts +++ b/shared/models/productV2Models/productItemModels/prodItemResponseModels.ts @@ -1,4 +1,6 @@ -import { z } from "zod"; +import { z } from "zod/v4"; +import { APIFeatureSchema } from "../../featureModels/featureResModels.js"; +import { Infinite } from "../../productModels/productEnums.js"; import { PriceTierSchema, ProductItemFeatureType, @@ -6,8 +8,6 @@ import { ProductItemType, UsageModel, } from "./productItemModels.js"; -import { Infinite } from "../../productModels/productEnums.js"; -import { APIFeatureSchema } from "../../featureModels/featureResModels.js"; export const ProductItemResponseSchema = z.object({ // Feature stuff diff --git a/shared/models/productV2Models/productItemModels/productItemModels.ts b/shared/models/productV2Models/productItemModels/productItemModels.ts index 0746f6610..20affbc71 100644 --- a/shared/models/productV2Models/productItemModels/productItemModels.ts +++ b/shared/models/productV2Models/productItemModels/productItemModels.ts @@ -1,7 +1,6 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { Infinite } from "../../productModels/productEnums.js"; -import { OnIncrease } from "./productItemEnums.js"; -import { OnDecrease } from "./productItemEnums.js"; +import { OnDecrease, OnIncrease } from "./productItemEnums.js"; export const TierInfinite = "inf"; diff --git a/shared/models/productV2Models/productResponseModels.ts b/shared/models/productV2Models/productResponseModels.ts index 1db100e4d..db286c361 100644 --- a/shared/models/productV2Models/productResponseModels.ts +++ b/shared/models/productV2Models/productResponseModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { AttachScenario } from "../checkModels/checkPreviewModels.js"; import { AppEnv } from "../genModels/genEnums.js"; import { FreeTrialResponseSchema } from "../productModels/freeTrialModels/freeTrialModels.js"; diff --git a/shared/models/productV2Models/productV2Models.ts b/shared/models/productV2Models/productV2Models.ts index 4aeee0585..d2f6ae29c 100644 --- a/shared/models/productV2Models/productV2Models.ts +++ b/shared/models/productV2Models/productV2Models.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { FreeTrialSchema } from "../productModels/freeTrialModels/freeTrialModels.js"; import { ProductItemSchema } from "./productItemModels/productItemModels.js"; diff --git a/shared/models/rewardModels/referralModels/referralModels.ts b/shared/models/rewardModels/referralModels/referralModels.ts index bcf143639..d3bb7b655 100644 --- a/shared/models/rewardModels/referralModels/referralModels.ts +++ b/shared/models/rewardModels/referralModels/referralModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; const ReferralCodeSchema = z.object({ // Code, org id, env should be unique diff --git a/shared/models/rewardModels/rewardModels/rewardModels.ts b/shared/models/rewardModels/rewardModels/rewardModels.ts index 116afdf5b..2c1c84127 100644 --- a/shared/models/rewardModels/rewardModels/rewardModels.ts +++ b/shared/models/rewardModels/rewardModels/rewardModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { CouponDurationType, RewardType } from "./rewardEnums.js"; const PromoCodeSchema = z.object({ diff --git a/shared/models/rewardModels/rewardModels/rewardResponseModels.ts b/shared/models/rewardModels/rewardModels/rewardResponseModels.ts index 36c3d3849..e09cdea6d 100644 --- a/shared/models/rewardModels/rewardModels/rewardResponseModels.ts +++ b/shared/models/rewardModels/rewardModels/rewardResponseModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { CouponDurationType, RewardType } from "./rewardEnums.js"; export const DiscountResponseSchema = z.object({ diff --git a/shared/models/rewardModels/rewardProgramModels/rewardProgramModels.ts b/shared/models/rewardModels/rewardProgramModels/rewardProgramModels.ts index b8f80a193..efd3fe5ba 100644 --- a/shared/models/rewardModels/rewardProgramModels/rewardProgramModels.ts +++ b/shared/models/rewardModels/rewardProgramModels/rewardProgramModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import type { Reward } from "../rewardModels/rewardModels.js"; import { RewardReceivedBy, RewardTriggerEvent } from "./rewardProgramEnums.js"; diff --git a/shared/models/subModels/subModels.ts b/shared/models/subModels/subModels.ts index fe75d98cd..0e543dbbd 100644 --- a/shared/models/subModels/subModels.ts +++ b/shared/models/subModels/subModels.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from "zod/v4"; import { AppEnv } from "../genModels/genEnums.js"; export const SubscriptionSchema = z.object({ diff --git a/shared/openapi.yaml b/shared/openapi.yaml new file mode 100644 index 000000000..cfbd3413d --- /dev/null +++ b/shared/openapi.yaml @@ -0,0 +1,1445 @@ +openapi: 3.1.0 +info: + title: My API + version: 1.0.0 +security: + - secretKey: [] +paths: + /customers/{customerId}: + get: + parameters: + - in: path + name: customerId + schema: + $ref: "#/components/schemas/customerId" + required: true + description: Your internal ID for the customer + responses: + "200": + description: 200 OK + content: + application/json: + schema: + $ref: "#/components/schemas/Customer" + /customers/{customerId}/features/{featureId}: + patch: + tags: + - customers.features + x-speakeasy-name-override: update + parameters: + - in: path + name: customerId + schema: + $ref: "#/components/schemas/customerId" + required: true + description: Your internal ID for the customer + - in: path + name: featureId + schema: + $ref: "#/components/schemas/featureId" + required: true + description: Feature ID as defined in the dashboard (eg. 'messages') + requestBody: + content: + application/json: + schema: + type: object + properties: + usage: + type: number + required: + - usage + responses: + "200": + description: 200 OK + content: + application/json: + schema: + type: object + properties: + usage: + type: number + required: + - usage + additionalProperties: false + /core/attach: + post: + requestBody: + content: + application/json: + schema: + type: object + properties: + customer_id: + description: ID of the customer to attach the product to + type: string + customer_data: + description: Customer data if using attach to auto create customer + anyOf: + - {} + - type: "null" + entity_id: + anyOf: + - type: string + - type: "null" + entity_data: + anyOf: + - {} + - type: "null" + product_id: + anyOf: + - type: string + - type: "null" + product_ids: + anyOf: + - minItems: 1 + type: array + items: + type: string + - type: "null" + options: + anyOf: + - type: array + items: + type: object + properties: + feature_id: + type: string + quantity: + type: number + upcoming_quantity: + anyOf: + - type: number + - type: "null" + adjustable_quantity: + anyOf: + - type: boolean + - type: "null" + internal_feature_id: + anyOf: + - type: string + - type: "null" + required: + - feature_id + - quantity + - type: "null" + products: + anyOf: + - type: array + items: + type: object + properties: + product_id: + type: string + quantity: + anyOf: + - type: number + - type: "null" + entity_id: + anyOf: + - type: string + - type: "null" + options: + anyOf: + - type: array + items: + type: object + properties: + feature_id: + type: string + quantity: + type: number + upcoming_quantity: + anyOf: + - type: number + - type: "null" + adjustable_quantity: + anyOf: + - type: boolean + - type: "null" + internal_feature_id: + anyOf: + - type: string + - type: "null" + required: + - feature_id + - quantity + - type: "null" + required: + - product_id + - type: "null" + is_custom: + type: boolean + items: + type: array + items: + type: object + properties: + feature_id: + anyOf: + - type: string + - type: "null" + feature_type: + anyOf: + - type: string + enum: + - single_use + - continuous_use + - boolean + - static + - type: "null" + included_usage: + anyOf: + - anyOf: + - type: number + - type: string + const: inf + - type: "null" + interval: + anyOf: + - type: string + enum: + - minute + - hour + - day + - week + - month + - quarter + - semi_annual + - year + - type: "null" + interval_count: + anyOf: + - type: number + - type: "null" + entity_feature_id: + anyOf: + - type: string + - type: "null" + usage_model: + anyOf: + - type: string + enum: + - prepaid + - pay_per_use + - type: "null" + price: + anyOf: + - type: number + - type: "null" + tiers: + anyOf: + - type: array + items: + type: object + properties: + to: + anyOf: + - type: number + - type: string + const: inf + amount: + type: number + required: + - to + - amount + - type: "null" + billing_units: + anyOf: + - type: number + - type: "null" + usage_limit: + anyOf: + - type: number + - type: "null" + reset_usage_when_enabled: + anyOf: + - type: boolean + - type: "null" + config: + anyOf: + - type: object + properties: + on_increase: + anyOf: + - type: string + enum: + - bill_immediately + - prorate_immediately + - prorate_next_cycle + - bill_next_cycle + - type: "null" + on_decrease: + anyOf: + - type: string + enum: + - prorate + - prorate_immediately + - prorate_next_cycle + - none + - no_prorations + - type: "null" + rollover: + anyOf: + - type: object + properties: + max: + anyOf: + - type: number + - type: "null" + duration: + default: month + type: string + enum: + - month + - forever + length: + type: number + required: + - max + - length + - type: "null" + - type: "null" + created_at: + anyOf: + - type: number + - type: "null" + entitlement_id: + anyOf: + - type: string + - type: "null" + price_id: + anyOf: + - type: string + - type: "null" + price_config: + anyOf: + - {} + - type: "null" + free_trial: + anyOf: + - type: object + properties: + length: + anyOf: + - type: string + - type: number + unique_fingerprint: + default: false + type: boolean + duration: + default: day + type: string + enum: + - day + - month + - year + card_required: + default: true + type: boolean + required: + - length + - type: boolean + version: + type: number + success_url: + type: string + force_checkout: + type: boolean + invoice_only: + type: boolean + metadata: {} + billing_cycle_anchor: + type: number + checkout_session_params: {} + reward: + anyOf: + - type: string + - type: array + items: + type: string + invoice: + type: boolean + enable_product_immediately: + type: boolean + finalize_invoice: + type: boolean + skip_checkout: + type: boolean + setup_payment: + type: boolean + required: + - customer_id + responses: + "200": + description: 200 OK + content: + application/json: + schema: + $ref: "#/components/schemas/AttachResult" +components: + schemas: + customerId: + description: Your internal ID for the customer + example: cus_123 + type: string + featureId: + description: Feature ID as defined in the dashboard (eg. 'messages') + example: messages + type: string + Customer: + type: object + properties: + autumn_id: + anyOf: + - type: string + - type: "null" + id: + description: Your internal ID for the customer + example: cus_123 + anyOf: + - type: string + - type: "null" + created_at: + description: The date and time the customer was created in milliseconds since + epoch + example: 1717000000 + type: number + name: + anyOf: + - type: string + - type: "null" + email: + anyOf: + - type: string + - type: "null" + fingerprint: + anyOf: + - type: string + - type: "null" + stripe_id: + default: null + anyOf: + - type: string + - type: "null" + env: + type: string + enum: + - sandbox + - live + products: + type: array + items: + type: object + properties: + id: + type: string + name: + anyOf: + - type: string + - type: "null" + group: + anyOf: + - type: string + - type: "null" + status: + type: string + enum: + - scheduled + - active + - past_due + - expired + - unknown + - trialing + canceled: + anyOf: + - type: boolean + - type: "null" + trialing: + anyOf: + - type: boolean + - type: "null" + canceled_at: + anyOf: + - type: number + - type: "null" + started_at: + type: number + is_default: + type: boolean + is_add_on: + type: boolean + version: + anyOf: + - type: number + - type: "null" + stripe_subscription_ids: + anyOf: + - type: array + items: + type: string + - type: "null" + current_period_start: + anyOf: + - type: number + - type: "null" + current_period_end: + anyOf: + - type: number + - type: "null" + entity_id: + anyOf: + - type: string + - type: "null" + items: + anyOf: + - type: array + items: + type: object + properties: + type: + anyOf: + - type: string + enum: + - feature + - priced_feature + - price + - type: "null" + feature_id: + anyOf: + - type: string + - type: "null" + feature_type: + anyOf: + - type: string + enum: + - single_use + - continuous_use + - boolean + - static + - type: "null" + feature: + anyOf: + - type: object + properties: + id: + type: string + name: + anyOf: + - type: string + - type: "null" + type: + type: string + enum: + - boolean + - single_use + - continuous_use + - credit_system + display: + anyOf: + - type: object + properties: + singular: + type: string + plural: + type: string + required: + - singular + - plural + additionalProperties: false + - type: "null" + credit_schema: + anyOf: + - type: array + items: + type: object + properties: + metered_feature_id: + type: string + credit_cost: + type: number + required: + - metered_feature_id + - credit_cost + additionalProperties: false + - type: "null" + archived: + anyOf: + - type: boolean + - type: "null" + required: + - id + - type + additionalProperties: false + - type: "null" + included_usage: + anyOf: + - anyOf: + - type: number + - type: string + const: inf + - type: "null" + interval: + anyOf: + - type: string + enum: + - minute + - hour + - day + - week + - month + - quarter + - semi_annual + - year + - type: "null" + interval_count: + anyOf: + - type: number + - type: "null" + price: + anyOf: + - type: number + - type: "null" + tiers: + anyOf: + - type: array + items: + type: object + properties: + to: + anyOf: + - type: number + - type: string + const: inf + amount: + type: number + required: + - to + - amount + additionalProperties: false + - type: "null" + usage_model: + anyOf: + - type: string + enum: + - prepaid + - pay_per_use + - type: "null" + billing_units: + anyOf: + - type: number + - type: "null" + reset_usage_when_enabled: + anyOf: + - type: boolean + - type: "null" + quantity: + anyOf: + - type: number + - type: "null" + next_cycle_quantity: + anyOf: + - type: number + - type: "null" + entity_feature_id: + anyOf: + - type: string + - type: "null" + display: + anyOf: + - type: object + properties: + primary_text: + type: string + secondary_text: + anyOf: + - type: string + - type: "null" + required: + - primary_text + additionalProperties: false + - type: "null" + additionalProperties: false + - type: "null" + quantity: + type: number + prepaid_quantities: + anyOf: + - type: array + items: + type: object + properties: + quantity: + type: number + feature_id: + type: string + required: + - quantity + - feature_id + additionalProperties: false + - type: "null" + required: + - id + - name + - group + - status + - started_at + - is_default + - is_add_on + additionalProperties: false + features: {} + invoices: + type: array + items: + type: object + properties: + product_ids: + type: array + items: + type: string + stripe_id: + type: string + status: + type: string + total: + type: number + currency: + type: string + created_at: + type: number + hosted_invoice_url: + anyOf: + - type: string + - type: "null" + required: + - product_ids + - stripe_id + - status + - total + - currency + - created_at + additionalProperties: false + trials_used: + type: array + items: + type: object + properties: + product_id: + type: string + customer_id: + type: string + fingerprint: + anyOf: + - type: string + - type: "null" + required: + - product_id + - customer_id + additionalProperties: false + rewards: + anyOf: + - type: object + properties: + discounts: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + type: + type: string + enum: + - percentage_discount + - fixed_discount + - free_product + - invoice_credits + discount_value: + type: number + duration_type: + type: string + enum: + - one_off + - months + - forever + duration_value: + anyOf: + - type: number + - type: "null" + currency: + anyOf: + - type: string + - type: "null" + start: + anyOf: + - type: number + - type: "null" + end: + anyOf: + - type: number + - type: "null" + subscription_id: + anyOf: + - type: string + - type: "null" + total_discount_amount: + anyOf: + - type: number + - type: "null" + required: + - id + - name + - type + - discount_value + - duration_type + additionalProperties: false + required: + - discounts + additionalProperties: false + - type: "null" + metadata: + default: {} + type: object + propertyNames: {} + additionalProperties: {} + entities: + type: array + items: + type: object + properties: + id: + anyOf: + - type: string + - type: "null" + name: + anyOf: + - type: string + - type: "null" + customer_id: + type: string + feature_id: + anyOf: + - type: string + - type: "null" + created_at: + type: number + env: + type: string + enum: + - sandbox + - live + products: + type: array + items: + type: object + properties: + id: + type: string + name: + anyOf: + - type: string + - type: "null" + group: + anyOf: + - type: string + - type: "null" + status: + type: string + enum: + - scheduled + - active + - past_due + - expired + - unknown + - trialing + canceled: + anyOf: + - type: boolean + - type: "null" + trialing: + anyOf: + - type: boolean + - type: "null" + canceled_at: + anyOf: + - type: number + - type: "null" + started_at: + type: number + is_default: + type: boolean + is_add_on: + type: boolean + version: + anyOf: + - type: number + - type: "null" + stripe_subscription_ids: + anyOf: + - type: array + items: + type: string + - type: "null" + current_period_start: + anyOf: + - type: number + - type: "null" + current_period_end: + anyOf: + - type: number + - type: "null" + entity_id: + anyOf: + - type: string + - type: "null" + items: + anyOf: + - type: array + items: + type: object + properties: + type: + anyOf: + - type: string + enum: + - feature + - priced_feature + - price + - type: "null" + feature_id: + anyOf: + - type: string + - type: "null" + feature_type: + anyOf: + - type: string + enum: + - single_use + - continuous_use + - boolean + - static + - type: "null" + feature: + anyOf: + - type: object + properties: + id: + type: string + name: + anyOf: + - type: string + - type: "null" + type: + type: string + enum: + - boolean + - single_use + - continuous_use + - credit_system + display: + anyOf: + - type: object + properties: + singular: + type: string + plural: + type: string + required: + - singular + - plural + additionalProperties: false + - type: "null" + credit_schema: + anyOf: + - type: array + items: + type: object + properties: + metered_feature_id: + type: string + credit_cost: + type: number + required: + - metered_feature_id + - credit_cost + additionalProperties: false + - type: "null" + archived: + anyOf: + - type: boolean + - type: "null" + required: + - id + - type + additionalProperties: false + - type: "null" + included_usage: + anyOf: + - anyOf: + - type: number + - type: string + const: inf + - type: "null" + interval: + anyOf: + - type: string + enum: + - minute + - hour + - day + - week + - month + - quarter + - semi_annual + - year + - type: "null" + interval_count: + anyOf: + - type: number + - type: "null" + price: + anyOf: + - type: number + - type: "null" + tiers: + anyOf: + - type: array + items: + type: object + properties: + to: + anyOf: + - type: number + - type: string + const: inf + amount: + type: number + required: + - to + - amount + additionalProperties: false + - type: "null" + usage_model: + anyOf: + - type: string + enum: + - prepaid + - pay_per_use + - type: "null" + billing_units: + anyOf: + - type: number + - type: "null" + reset_usage_when_enabled: + anyOf: + - type: boolean + - type: "null" + quantity: + anyOf: + - type: number + - type: "null" + next_cycle_quantity: + anyOf: + - type: number + - type: "null" + entity_feature_id: + anyOf: + - type: string + - type: "null" + display: + anyOf: + - type: object + properties: + primary_text: + type: string + secondary_text: + anyOf: + - type: string + - type: "null" + required: + - primary_text + additionalProperties: false + - type: "null" + additionalProperties: false + - type: "null" + quantity: + type: number + prepaid_quantities: + anyOf: + - type: array + items: + type: object + properties: + quantity: + type: number + feature_id: + type: string + required: + - quantity + - feature_id + additionalProperties: false + - type: "null" + required: + - id + - name + - group + - status + - started_at + - is_default + - is_add_on + additionalProperties: false + features: + type: object + propertyNames: + type: string + additionalProperties: + type: object + properties: + id: + type: string + type: + type: string + enum: + - single_use + - continuous_use + - boolean + - static + name: + anyOf: + - type: string + - type: "null" + interval: + anyOf: + - anyOf: + - type: string + enum: + - lifetime + - minute + - hour + - day + - week + - month + - quarter + - semi_annual + - year + - type: string + const: multiple + - type: "null" + interval_count: + anyOf: + - type: number + - type: "null" + unlimited: + anyOf: + - type: boolean + - type: "null" + balance: + anyOf: + - type: number + - type: "null" + usage: + anyOf: + - type: number + - type: "null" + included_usage: + anyOf: + - type: number + - type: "null" + next_reset_at: + anyOf: + - type: number + - type: "null" + overage_allowed: + anyOf: + - type: boolean + - type: "null" + breakdown: + anyOf: + - type: array + items: + type: object + properties: + interval: + type: string + enum: + - lifetime + - minute + - hour + - day + - week + - month + - quarter + - semi_annual + - year + interval_count: + anyOf: + - type: number + - type: "null" + balance: + anyOf: + - type: number + - type: "null" + usage: + anyOf: + - type: number + - type: "null" + included_usage: + anyOf: + - type: number + - type: "null" + next_reset_at: + anyOf: + - type: number + - type: "null" + required: + - interval + additionalProperties: false + - type: "null" + credit_schema: + anyOf: + - type: array + items: + type: object + properties: + feature_id: + type: string + credit_amount: + type: number + required: + - feature_id + - credit_amount + additionalProperties: false + - type: "null" + usage_limit: + anyOf: + - type: number + - type: "null" + rollovers: + anyOf: + - type: array + items: + type: object + properties: + balance: + type: number + expires_at: + type: number + required: + - balance + - expires_at + additionalProperties: false + - type: "null" + required: + - id + - type + additionalProperties: false + invoices: + type: array + items: + type: object + properties: + product_ids: + type: array + items: + type: string + stripe_id: + type: string + status: + type: string + total: + type: number + currency: + type: string + created_at: + type: number + hosted_invoice_url: + anyOf: + - type: string + - type: "null" + required: + - product_ids + - stripe_id + - status + - total + - currency + - created_at + additionalProperties: false + required: + - id + - name + - customer_id + - created_at + - env + additionalProperties: false + referrals: + type: array + items: + type: object + properties: + program_id: + type: string + customer: + type: object + properties: + id: + type: string + name: + anyOf: + - type: string + - type: "null" + email: + anyOf: + - type: string + - type: "null" + required: + - id + additionalProperties: false + reward_applied: + type: boolean + created_at: + type: number + required: + - program_id + - customer + - reward_applied + - created_at + additionalProperties: false + payment_method: + anyOf: + - {} + - type: "null" + upcoming_invoice: + anyOf: + - type: object + properties: + lines: + type: array + items: + type: object + properties: + product_id: + anyOf: + - type: string + - type: "null" + description: + type: string + amount: + type: number + required: + - description + - amount + additionalProperties: false + discounts: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + type: + type: string + enum: + - percentage_discount + - fixed_discount + - free_product + - invoice_credits + discount_value: + type: number + duration_type: + type: string + enum: + - one_off + - months + - forever + duration_value: + anyOf: + - type: number + - type: "null" + currency: + anyOf: + - type: string + - type: "null" + start: + anyOf: + - type: number + - type: "null" + end: + anyOf: + - type: number + - type: "null" + subscription_id: + anyOf: + - type: string + - type: "null" + total_discount_amount: + anyOf: + - type: number + - type: "null" + required: + - id + - name + - type + - discount_value + - duration_type + additionalProperties: false + subtotal: + type: number + total: + type: number + currency: + type: string + required: + - lines + - discounts + - subtotal + - total + - currency + additionalProperties: false + - type: "null" + required: + - id + - created_at + - name + - email + - fingerprint + - stripe_id + - env + - products + - features + - metadata + additionalProperties: false + AttachResult: + type: object + properties: + message: + $ref: "#/components/schemas/message" + product_ids: + $ref: "#/components/schemas/productIds" + customer_id: + $ref: "#/components/schemas/customerId" + required: + - message + - product_ids + - customer_id + additionalProperties: false + message: + description: A short description on the result of the operation + example: Successfully downgraded from Product A to Product B + type: string + productIds: + description: The IDs of the products that were attached + example: + - pro + - one_off + type: array + items: + type: string + securitySchemes: + secretKey: + type: http + scheme: bearer + bearerFormat: JWT diff --git a/shared/package.json b/shared/package.json index 6d3cc8b45..30d788825 100644 --- a/shared/package.json +++ b/shared/package.json @@ -13,7 +13,7 @@ "author": "Recase Inc.", "license": "Apache-2.0", "scripts": { - "build:tsc": "tsc", + "build:tsc": "tsc && bun api/customer.ts", "build": "bun build ./index.ts --outdir dist --format esm --target bun --external zod", "dev": "bunx nodemon --ext ts --ignore dist --exec \"bun run build && bun run dev:dts\"", "dev:dts": "tsc --emitDeclarationOnly --outDir dist --project tsconfig.json", @@ -29,7 +29,8 @@ "dotenv": "^16.5.0", "drizzle-kit": "^0.31.1", "drizzle-orm": "^0.43.1", - "drizzle-zod": "^0.8.2" + "drizzle-zod": "^0.8.2", + "zod-openapi": "^5.4.1" }, "peerDependencies": { "zod": "^3.25.23" diff --git a/shared/utils/productV2Utils/productItemUtils/mapToItem.ts b/shared/utils/productV2Utils/productItemUtils/mapToItem.ts index 650017e98..c08c29206 100644 --- a/shared/utils/productV2Utils/productItemUtils/mapToItem.ts +++ b/shared/utils/productV2Utils/productItemUtils/mapToItem.ts @@ -1,17 +1,17 @@ import { FeatureType } from "../../../models/featureModels/featureEnums.js"; import { AllowanceType, - EntitlementWithFeature, + type EntitlementWithFeature, } from "../../../models/productModels/entModels/entModels.js"; -import { FixedPriceConfig } from "../../../models/productModels/priceModels/priceConfig/fixedPriceConfig.js"; +import type { FixedPriceConfig } from "../../../models/productModels/priceModels/priceConfig/fixedPriceConfig.js"; import { BillWhen, - UsagePriceConfig, + type UsagePriceConfig, } from "../../../models/productModels/priceModels/priceConfig/usagePriceConfig.js"; -import { Price } from "../../../models/productModels/priceModels/priceModels.js"; +import type { Price } from "../../../models/productModels/priceModels/priceModels.js"; import { Infinite } from "../../../models/productModels/productEnums.js"; import { - ProductItem, + type ProductItem, ProductItemFeatureType, TierInfinite, UsageModel, @@ -74,8 +74,8 @@ export const toFeaturePriceItem = ({ ent: EntitlementWithFeature; price: Price; }) => { - let config = price.config as UsagePriceConfig; - let tiers = config.usage_tiers.map((tier) => { + const config = price.config as UsagePriceConfig; + const tiers = config.usage_tiers.map((tier) => { return { amount: tier.amount, to: tier.to == -1 ? TierInfinite : tier.to, @@ -91,7 +91,7 @@ export const toFeaturePriceItem = ({ itemConfig.rollover = ent.rollover; } - let item: ProductItem = { + const item: ProductItem = { feature_id: ent.feature.id, feature_type: ent.feature.config?.usage_type || ProductItemFeatureType.SingleUse, @@ -127,7 +127,7 @@ export const toFeaturePriceItem = ({ }; export const toPriceItem = ({ price }: { price: Price }) => { - let config = price.config as FixedPriceConfig; + const config = price.config as FixedPriceConfig; return { feature_id: null,