From 0bfd033f9fc67854606bcf3732cef3d57529fa7b Mon Sep 17 00:00:00 2001 From: Adir Amsalem Date: Sun, 22 Feb 2026 16:09:34 +0200 Subject: [PATCH] feat(tokens): support optional metadata on client token creation Add CreateTokenOptions type with optional metadata field to tokens.create(). Always sends application/json, includes metadata key only when provided. Exported new type from package index. Includes 2 new unit tests verifying metadata forwarding and empty-body behavior. --- packages/sdk/src/index.ts | 2 +- packages/sdk/src/tokens/client.ts | 20 ++++++++++++++--- packages/sdk/tests/unit.test.ts | 37 +++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index 1693fc9..ddbbbca 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -60,7 +60,7 @@ export { type VideoModels, } from "./shared/model"; export type { ModelState } from "./shared/types"; -export type { CreateTokenResponse, TokensClient } from "./tokens/client"; +export type { CreateTokenOptions, CreateTokenResponse, TokensClient } from "./tokens/client"; export { type DecartSDKError, ERROR_CODES } from "./utils/errors"; export { createConsoleLogger, type Logger, type LogLevel, noopLogger } from "./utils/logger"; diff --git a/packages/sdk/src/tokens/client.ts b/packages/sdk/src/tokens/client.ts index 92dbbf7..4831b04 100644 --- a/packages/sdk/src/tokens/client.ts +++ b/packages/sdk/src/tokens/client.ts @@ -7,6 +7,11 @@ export type TokensClientOptions = { integration?: string; }; +export type CreateTokenOptions = { + /** Custom key-value pairs to attach to the client token. */ + metadata?: Record; +}; + export type CreateTokenResponse = { apiKey: string; expiresAt: string; @@ -15,26 +20,35 @@ export type CreateTokenResponse = { export type TokensClient = { /** * Create a client token. + * @param options - Optional configuration for the token. + * @param options.metadata - Custom key-value pairs to attach to the token. * @returns A short-lived API key safe for client-side use. * @example * ```ts * const client = createDecartClient({ apiKey: process.env.DECART_API_KEY }); * const token = await client.tokens.create(); * // Returns: { apiKey: "ek_...", expiresAt: "2024-12-15T12:10:00Z" } + * + * // With metadata: + * const token = await client.tokens.create({ metadata: { role: "viewer" } }); * ``` */ - create: () => Promise; + create: (options?: CreateTokenOptions) => Promise; }; export const createTokensClient = (opts: TokensClientOptions): TokensClient => { const { baseUrl, apiKey, integration } = opts; - const create = async (): Promise => { - const headers = buildAuthHeaders({ apiKey, integration }); + const create = async (options?: CreateTokenOptions): Promise => { + const headers: HeadersInit = { + ...buildAuthHeaders({ apiKey, integration }), + "content-type": "application/json", + }; const response = await fetch(`${baseUrl}/v1/client/tokens`, { method: "POST", headers, + body: JSON.stringify(options?.metadata ? { metadata: options.metadata } : {}), }); if (!response.ok) { diff --git a/packages/sdk/tests/unit.test.ts b/packages/sdk/tests/unit.test.ts index c1cbde6..4a14ca6 100644 --- a/packages/sdk/tests/unit.test.ts +++ b/packages/sdk/tests/unit.test.ts @@ -909,6 +909,43 @@ describe("Tokens API", () => { await expect(decart.tokens.create()).rejects.toThrow("Failed to create token"); }); + + it("sends metadata when provided", async () => { + server.use( + http.post("http://localhost/v1/client/tokens", async ({ request }) => { + lastRequest = request; + return HttpResponse.json({ + apiKey: "ek_test123", + expiresAt: "2024-12-15T12:10:00Z", + }); + }), + ); + + const result = await decart.tokens.create({ metadata: { role: "viewer" } }); + + expect(result.apiKey).toBe("ek_test123"); + const body = await lastRequest?.json(); + expect(body).toEqual({ metadata: { role: "viewer" } }); + expect(lastRequest?.headers.get("content-type")).toBe("application/json"); + }); + + it("sends JSON body without metadata when none provided", async () => { + server.use( + http.post("http://localhost/v1/client/tokens", async ({ request }) => { + lastRequest = request; + return HttpResponse.json({ + apiKey: "ek_test123", + expiresAt: "2024-12-15T12:10:00Z", + }); + }), + ); + + await decart.tokens.create(); + + expect(lastRequest?.headers.get("content-type")).toBe("application/json"); + const body = await lastRequest?.text(); + expect(JSON.parse(body!)).toEqual({}); + }); }); });