From 129eb2fa0221d4e5476c80b2ed243d99fb7d3fe1 Mon Sep 17 00:00:00 2001 From: John Yeo Date: Sat, 12 Jul 2025 11:35:54 +0100 Subject: [PATCH] feat: added feature res models --- .npmrc | 3 ++- docker/dev.dockerfile | 6 +++++- .../internal/api/features/featureApiRouter.ts | 4 ++-- .../internal/features/convertFeatureUtils.ts | 20 +++++++++++++++++++ shared/models/featureModels/featureModels.ts | 2 +- .../models/featureModels/featureResModels.ts | 15 ++++++++++++++ .../prodItemResponseModels.ts | 4 ++++ 7 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 server/src/internal/features/convertFeatureUtils.ts create mode 100644 shared/models/featureModels/featureResModels.ts diff --git a/.npmrc b/.npmrc index 0612bf9c7..c2fb42ea4 100644 --- a/.npmrc +++ b/.npmrc @@ -1,4 +1,5 @@ optionalDependencies=false install-optional=false -PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ No newline at end of file +PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true +PUPPETEER_SKIP_DOWNLOAD=true \ No newline at end of file diff --git a/docker/dev.dockerfile b/docker/dev.dockerfile index d788b44aa..7ca2c9f00 100644 --- a/docker/dev.dockerfile +++ b/docker/dev.dockerfile @@ -5,6 +5,10 @@ WORKDIR /app RUN npm install -g pnpm +# Skip Puppeteer Chromium download to speed up install +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true +ENV PUPPETEER_SKIP_DOWNLOAD=true + COPY package*.json ./ COPY pnpm-workspace.yaml ./ COPY pnpm-lock.yaml ./ @@ -12,7 +16,7 @@ COPY shared/package*.json ./shared/ COPY server/package*.json ./server/ COPY vite/package*.json ./vite/ -RUN pnpm install +RUN pnpm install --frozen-lockfile RUN npm install -g nodemon tsx # Stage 1: /localtunnel diff --git a/server/src/internal/api/features/featureApiRouter.ts b/server/src/internal/api/features/featureApiRouter.ts index 5b7a67013..c747153ac 100644 --- a/server/src/internal/api/features/featureApiRouter.ts +++ b/server/src/internal/api/features/featureApiRouter.ts @@ -4,7 +4,7 @@ import RecaseError, { handleRequestError, } from "@/utils/errorUtils.js"; import { handleUpdateFeature } from "./handlers/handleUpdateFeature.js"; -import { Feature, FeatureResponseSchema, FeatureType } from "@autumn/shared"; +import { Feature, MinFeatureSchema, FeatureType } from "@autumn/shared"; import { CreateFeatureSchema } from "@autumn/shared"; import express, { Router } from "express"; import { generateId } from "@/utils/genUtils.js"; @@ -68,7 +68,7 @@ featureApiRouter.get("", async (req: any, res) => { let features = await FeatureService.getFromReq(req); res .status(200) - .json(features.map((feature) => FeatureResponseSchema.parse(feature))); + .json(features.map((feature) => MinFeatureSchema.parse(feature))); }); featureApiRouter.post("", async (req: any, res) => { diff --git a/server/src/internal/features/convertFeatureUtils.ts b/server/src/internal/features/convertFeatureUtils.ts new file mode 100644 index 000000000..e689ae666 --- /dev/null +++ b/server/src/internal/features/convertFeatureUtils.ts @@ -0,0 +1,20 @@ +import { Feature, FeatureType } from "@autumn/shared"; +import { + FeatureResponseSchema, + FeatureResType, +} from "@shared/models/featureModels/featureResModels.js"; + +export const featureToResponse = (feature: Feature) => { + // return FeatureResponseSchema.parse(feature); + // 1. Get feature type + let featureType = feature.type; + if (feature.type == FeatureType.Metered) { + featureType = feature.config.usage_type; + } + + return FeatureResponseSchema.parse({ + id: feature.id, + name: feature.name, + type: featureType, + }); +}; diff --git a/shared/models/featureModels/featureModels.ts b/shared/models/featureModels/featureModels.ts index 212ec7360..cde6400f4 100644 --- a/shared/models/featureModels/featureModels.ts +++ b/shared/models/featureModels/featureModels.ts @@ -28,7 +28,7 @@ export const CreateFeatureSchema = FeatureSchema.pick({ display: true, }); -export const FeatureResponseSchema = z.object({ +export const MinFeatureSchema = z.object({ internal_id: z.string(), id: z.string(), name: z.string(), diff --git a/shared/models/featureModels/featureResModels.ts b/shared/models/featureModels/featureResModels.ts new file mode 100644 index 000000000..5aba49923 --- /dev/null +++ b/shared/models/featureModels/featureResModels.ts @@ -0,0 +1,15 @@ +import { z } from "zod"; + +export enum FeatureResType { + Boolean = "boolean", + SingleUsage = "single_use", + ContinuousUse = "continuous_use", + CreditSystem = "credit_system", +} +export const FeatureResponseSchema = z.object({ + id: z.string(), + name: z.string(), + type: z.nativeEnum(FeatureResType), +}); + +export type FeatureResponse = z.infer; diff --git a/shared/models/productV2Models/productItemModels/prodItemResponseModels.ts b/shared/models/productV2Models/productItemModels/prodItemResponseModels.ts index f0c7c62d0..4345131d4 100644 --- a/shared/models/productV2Models/productItemModels/prodItemResponseModels.ts +++ b/shared/models/productV2Models/productItemModels/prodItemResponseModels.ts @@ -7,6 +7,7 @@ import { UsageModel, } from "./productItemModels.js"; import { Infinite } from "../../productModels/productEnums.js"; +import { FeatureResponseSchema } from "../../featureModels/featureResModels.js"; export const ProductItemResponseSchema = z.object({ // Feature stuff @@ -14,6 +15,9 @@ export const ProductItemResponseSchema = z.object({ feature_id: z.string().nullish(), feature_type: z.nativeEnum(ProductItemFeatureType).nullish(), + // Feature response + feature: FeatureResponseSchema.nullish(), + included_usage: z.number().or(z.literal(Infinite)).nullish(), interval: z.nativeEnum(ProductItemInterval).nullish(),