From 20c9691d4fe4174a539bf151b5c839505f72511d Mon Sep 17 00:00:00 2001 From: Bilal Godil Date: Fri, 17 Oct 2025 14:51:57 -0700 Subject: [PATCH] client, clientReadOnly, server --- apps/backend/src/lib/payments.tsx | 8 +++- .../v1/payments/create-purchase-url.test.ts | 48 +++++++++++++++---- .../api/v1/payments/products.test.ts | 36 ++++++++++++-- .../api/v1/payments/purchase-session.test.ts | 6 +-- packages/stack-shared/src/schema-fields.ts | 16 +++++-- 5 files changed, 91 insertions(+), 23 deletions(-) diff --git a/apps/backend/src/lib/payments.tsx b/apps/backend/src/lib/payments.tsx index c110df0c0..1865db6ba 100644 --- a/apps/backend/src/lib/payments.tsx +++ b/apps/backend/src/lib/payments.tsx @@ -62,7 +62,9 @@ export async function ensureProductIdOrInlineProduct( freeTrial: value.free_trial, serverOnly: true, }])), - metadata: inlineProduct.metadata, + clientMetadata: inlineProduct.client_metadata ?? undefined, + clientReadOnlyMetadata: inlineProduct.client_read_only_metadata ?? undefined, + serverMetadata: inlineProduct.server_metadata ?? undefined, includedItems: typedFromEntries(Object.entries(inlineProduct.included_items).map(([key, value]) => [key, { repeat: value.repeat ?? "never", quantity: value.quantity ?? 0, @@ -429,7 +431,9 @@ export function productToInlineProduct(product: ProductWithMetadata): yup.InferT stackable: product.stackable === true, server_only: product.serverOnly === true, included_items: product.includedItems, - metadata: product.metadata, + client_metadata: product.clientMetadata ?? null, + client_read_only_metadata: product.clientReadOnlyMetadata ?? null, + server_metadata: product.serverMetadata ?? null, prices: product.prices === "include-by-default" ? {} : typedFromEntries(typedEntries(product.prices).map(([key, value]) => [key, filterUndefined({ ...typedFromEntries(SUPPORTED_CURRENCIES.map(c => [c.code, getOrUndefined(value, c.code)])), interval: value.interval, diff --git a/apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts b/apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts index 7198f4024..328130201 100644 --- a/apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts +++ b/apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts @@ -300,7 +300,7 @@ it("should return inline product metadata when validating purchase code", async }, }, included_items: {}, - metadata: { + server_metadata: { reference_id: "ref-123", features: ["priority-support", "analytics"], }, @@ -320,15 +320,43 @@ it("should return inline product metadata when validating purchase code", async full_code: fullCode, }, }); - expect(validateResponse.status).toBe(200); - const validateBody = validateResponse.body; - expect(validateBody.product.metadata).toMatchInlineSnapshot(` - { - "features": [ - "priority-support", - "analytics", - ], - "reference_id": "ref-123", + expect(validateResponse).toMatchInlineSnapshot(` + NiceResponse { + "status": 200, + "body": { + "already_bought_non_stackable": false, + "charges_enabled": false, + "conflicting_products": [], + "product": { + "client_metadata": null, + "client_read_only_metadata": null, + "customer_type": "user", + "display_name": "Metadata Inline Product", + "included_items": {}, + "prices": { + "monthly-metadata": { + "USD": "1500", + "interval": [ + 1, + "month", + ], + }, + }, + "server_metadata": { + "features": [ + "priority-support", + "analytics", + ], + "reference_id": "ref-123", + }, + "server_only": true, + "stackable": false, + }, + "project_id": "", + "stripe_account_id": , + "test_mode": true, + }, + "headers": Headers {