diff --git a/apps/mobile/src/features/cloud/publicConfig.test.ts b/apps/mobile/src/features/cloud/publicConfig.test.ts index 0307fcdab30..05bf1a8fbcc 100644 --- a/apps/mobile/src/features/cloud/publicConfig.test.ts +++ b/apps/mobile/src/features/cloud/publicConfig.test.ts @@ -1,6 +1,11 @@ import { describe, expect, it, vi } from "vite-plus/test"; -import { hasTracingPublicConfig, resolveCloudPublicConfig } from "./publicConfig"; +import { + CloudPublicConfigMissingError, + hasTracingPublicConfig, + resolveCloudPublicConfig, + resolveRelayClerkTokenOptions, +} from "./publicConfig"; vi.mock("expo-constants", () => ({ default: { @@ -11,6 +16,12 @@ vi.mock("expo-constants", () => ({ })); describe("resolveCloudPublicConfig", () => { + it("reports the missing Clerk JWT template as structured configuration", () => { + expect(() => resolveRelayClerkTokenOptions()).toThrowError( + new CloudPublicConfigMissingError({ key: "T3CODE_CLERK_JWT_TEMPLATE" }), + ); + }); + it("returns no cloud configuration for an unconfigured build", () => { expect(resolveCloudPublicConfig({})).toEqual({ clerk: { diff --git a/apps/mobile/src/features/cloud/publicConfig.ts b/apps/mobile/src/features/cloud/publicConfig.ts index 2d304da7c02..93a78fa4f44 100644 --- a/apps/mobile/src/features/cloud/publicConfig.ts +++ b/apps/mobile/src/features/cloud/publicConfig.ts @@ -1,6 +1,18 @@ import Constants from "expo-constants"; import { relayClerkTokenOptions } from "@t3tools/shared/relayAuth"; import { normalizeSecureRelayUrl } from "@t3tools/shared/relayUrl"; +import * as Schema from "effect/Schema"; + +export class CloudPublicConfigMissingError extends Schema.TaggedErrorClass()( + "CloudPublicConfigMissingError", + { + key: Schema.Literal("T3CODE_CLERK_JWT_TEMPLATE"), + }, +) { + override get message(): string { + return `${this.key} is not configured.`; + } +} export interface CloudPublicConfig { readonly clerk: { @@ -87,7 +99,7 @@ export function hasTracingPublicConfig( export function resolveRelayClerkTokenOptions() { const { jwtTemplate } = resolveCloudPublicConfig().clerk; if (!jwtTemplate) { - throw new Error("T3CODE_CLERK_JWT_TEMPLATE is not configured."); + throw new CloudPublicConfigMissingError({ key: "T3CODE_CLERK_JWT_TEMPLATE" }); } return relayClerkTokenOptions(jwtTemplate); } diff --git a/apps/web/src/cloud/publicConfig.test.ts b/apps/web/src/cloud/publicConfig.test.ts index bb188d0b110..d42aa34baa2 100644 --- a/apps/web/src/cloud/publicConfig.test.ts +++ b/apps/web/src/cloud/publicConfig.test.ts @@ -1,6 +1,10 @@ import { afterEach, describe, expect, it, vi } from "vite-plus/test"; -import { hasCloudPublicConfig } from "./publicConfig.ts"; +import { + CloudPublicConfigMissingError, + hasCloudPublicConfig, + resolveRelayClerkTokenOptions, +} from "./publicConfig.ts"; afterEach(() => { vi.unstubAllEnvs(); @@ -30,4 +34,12 @@ describe("hasCloudPublicConfig", () => { expect(hasCloudPublicConfig()).toBe(false); }); + + it("reports the missing Clerk JWT template as structured configuration", () => { + vi.stubEnv("VITE_CLERK_JWT_TEMPLATE", ""); + + expect(() => resolveRelayClerkTokenOptions()).toThrowError( + new CloudPublicConfigMissingError({ key: "T3CODE_CLERK_JWT_TEMPLATE" }), + ); + }); }); diff --git a/apps/web/src/cloud/publicConfig.ts b/apps/web/src/cloud/publicConfig.ts index f7b3ca6bc31..d9d0e5f44cb 100644 --- a/apps/web/src/cloud/publicConfig.ts +++ b/apps/web/src/cloud/publicConfig.ts @@ -1,5 +1,17 @@ import { relayClerkTokenOptions } from "@t3tools/shared/relayAuth"; import { normalizeSecureRelayUrl } from "@t3tools/shared/relayUrl"; +import * as Schema from "effect/Schema"; + +export class CloudPublicConfigMissingError extends Schema.TaggedErrorClass()( + "CloudPublicConfigMissingError", + { + key: Schema.Literal("T3CODE_CLERK_JWT_TEMPLATE"), + }, +) { + override get message(): string { + return `${this.key} is not configured.`; + } +} export interface CloudPublicConfig { readonly clerkPublishableKey: string | null; @@ -65,7 +77,7 @@ export function hasCloudPublicConfig(): boolean { export function resolveRelayClerkTokenOptions() { const { clerkJwtTemplate } = resolveCloudPublicConfig(); if (!clerkJwtTemplate) { - throw new Error("T3CODE_CLERK_JWT_TEMPLATE is not configured."); + throw new CloudPublicConfigMissingError({ key: "T3CODE_CLERK_JWT_TEMPLATE" }); } return relayClerkTokenOptions(clerkJwtTemplate); }