History

feat(cloud): manage cloudflared installation and relay defaults

Julius Marminge committed 5 months ago

Commit 91e8bff1 parent b9c613a38 files · +1557 −74Browse files

Showing the changes to scripts (3 of 38 files). Show all

Unified · Split

3 files
  1. scripts/dev-runner.ts +4 −0
  2. scripts/lib/public-config.test.ts +74 −0
  3. scripts/lib/public-config.ts +78 −0
scripts/dev-runner.ts+4−0
@@ -17,6 +17,10 @@ import * as Schema from "effect/Schema"; · 16 unmodified lines
1717 import { Argument, Command, Flag } from "effect/unstable/cli";
1818 import { ChildProcess } from "effect/unstable/process";
1919
20+import { loadRepoEnv } from "./lib/public-config.ts";
21+
22+Object.assign(process.env, loadRepoEnv());
23+
2024 const BASE_SERVER_PORT = 13773;
2125 const BASE_WEB_PORT = 5733;
2226 const MAX_HASH_OFFSET = 3000;
scripts/lib/public-config.test.ts+74−0
@@ -0,0 +1,74 @@
1+// @effect-diagnostics nodeBuiltinImport:off - Tests exercise root env file precedence directly.
2+import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3+import { tmpdir } from "node:os";
4+import { join } from "node:path";
5+import { afterEach, describe, expect, it } from "vitest";
6+
7+import { DEFAULT_PUBLIC_CONFIG, loadRepoEnv, resolvePublicConfig } from "./public-config.ts";
8+
9+const temporaryDirectories: string[] = [];
10+
11+afterEach(() => {
12+ for (const directory of temporaryDirectories.splice(0)) {
13+ rmSync(directory, { recursive: true, force: true });
14+ }
15+});
16+
17+describe("loadRepoEnv", () => {
18+ it("projects checked-in public defaults into Vite and Expo aliases", () => {
19+ const env = loadRepoEnv({ baseEnv: {}, repoRoot: makeTemporaryDirectory() });
20+
21+ expect(env.T3CODE_CLERK_PUBLISHABLE_KEY).toBe(DEFAULT_PUBLIC_CONFIG.clerkPublishableKey);
22+ expect(env.VITE_CLERK_PUBLISHABLE_KEY).toBe(DEFAULT_PUBLIC_CONFIG.clerkPublishableKey);
23+ expect(env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY).toBe(DEFAULT_PUBLIC_CONFIG.clerkPublishableKey);
24+ expect(env.T3_RELAY_URL).toBe(DEFAULT_PUBLIC_CONFIG.relayUrl);
25+ expect(env.VITE_T3_RELAY_URL).toBe(DEFAULT_PUBLIC_CONFIG.relayUrl);
26+ });
27+
28+ it("applies process, root local, root, and checked-in precedence in that order", () => {
29+ const repoRoot = makeTemporaryDirectory();
30+ writeFileSync(
31+ join(repoRoot, ".env"),
32+ "T3CODE_CLERK_PUBLISHABLE_KEY=pk_root\nT3_RELAY_URL=https://root.example.test\n",
33+ );
34+ writeFileSync(
35+ join(repoRoot, ".env.local"),
36+ "T3CODE_CLERK_PUBLISHABLE_KEY=pk_local\nT3_RELAY_URL=https://local.example.test\n",
37+ );
38+
39+ expect(loadRepoEnv({ baseEnv: {}, repoRoot }).T3_RELAY_URL).toBe("https://local.example.test");
40+ expect(
41+ loadRepoEnv({
42+ baseEnv: {
43+ T3CODE_CLERK_PUBLISHABLE_KEY: "pk_ci",
44+ T3_RELAY_URL: "https://ci.example.test",
45+ },
46+ repoRoot,
47+ }),
48+ ).toMatchObject({
49+ T3CODE_CLERK_PUBLISHABLE_KEY: "pk_ci",
50+ VITE_CLERK_PUBLISHABLE_KEY: "pk_ci",
51+ EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY: "pk_ci",
52+ T3_RELAY_URL: "https://ci.example.test",
53+ VITE_T3_RELAY_URL: "https://ci.example.test",
54+ });
55+ });
56+
57+ it("accepts legacy framework aliases as root overrides", () => {
58+ expect(
59+ resolvePublicConfig({
60+ VITE_CLERK_PUBLISHABLE_KEY: "pk_legacy",
61+ VITE_T3_RELAY_URL: "https://legacy.example.test",
62+ }),
63+ ).toEqual({
64+ clerkPublishableKey: "pk_legacy",
65+ relayUrl: "https://legacy.example.test",
66+ });
67+ });
68+});
69+
70+function makeTemporaryDirectory() {
71+ const directory = mkdtempSync(join(tmpdir(), "t3code-public-config-"));
72+ temporaryDirectories.push(directory);
73+ return directory;
74+}
scripts/lib/public-config.ts+78−0
@@ -0,0 +1,78 @@
1+// @effect-diagnostics nodeBuiltinImport:off - Build bootstrap reads optional root env files before an Effect runtime exists.
2+import * as NodeFS from "node:fs";
3+import * as NodePath from "node:path";
4+import * as NodeURL from "node:url";
5+import * as NodeUtil from "node:util";
6+
7+import { DEFAULT_T3_CLERK_PUBLISHABLE_KEY, DEFAULT_T3_RELAY_URL } from "@t3tools/shared/relayAuth";
8+
9+export interface T3CodePublicConfig {
10+ readonly clerkPublishableKey: string;
11+ readonly relayUrl: string;
12+}
13+
14+type Environment = Readonly<Record<string, string | undefined>>;
15+
16+const REPO_ROOT = NodePath.dirname(
17+ NodePath.dirname(NodePath.dirname(NodeURL.fileURLToPath(import.meta.url))),
18+);
19+
20+// These values are intentionally public. Client builds embed them so a fresh clone can use
21+// T3 Cloud without local setup. Use root .env files or CI environment variables to override them.
22+export const DEFAULT_PUBLIC_CONFIG: T3CodePublicConfig = {
23+ clerkPublishableKey: DEFAULT_T3_CLERK_PUBLISHABLE_KEY,
24+ relayUrl: DEFAULT_T3_RELAY_URL,
25+};
26+
27+export function loadRepoEnv({
28+ baseEnv = process.env,
29+ repoRoot = REPO_ROOT,
30+}: {
31+ readonly baseEnv?: Environment;
32+ readonly repoRoot?: string;
33+} = {}): Record<string, string | undefined> {
34+ const rootEnv = readEnvFile(NodePath.join(repoRoot, ".env"));
35+ const localEnv = readEnvFile(NodePath.join(repoRoot, ".env.local"));
36+ const config = resolvePublicConfig(baseEnv, localEnv, rootEnv);
37+
38+ return {
39+ ...rootEnv,
40+ ...localEnv,
41+ ...baseEnv,
42+ T3CODE_CLERK_PUBLISHABLE_KEY: config.clerkPublishableKey,
43+ T3_RELAY_URL: config.relayUrl,
44+ VITE_CLERK_PUBLISHABLE_KEY: config.clerkPublishableKey,
45+ VITE_T3_RELAY_URL: config.relayUrl,
46+ EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY: config.clerkPublishableKey,
47+ };
48+}
49+
50+export function resolvePublicConfig(...sources: readonly Environment[]): T3CodePublicConfig {
51+ return {
52+ clerkPublishableKey:
53+ firstNonEmpty(
54+ sources,
55+ "T3CODE_CLERK_PUBLISHABLE_KEY",
56+ "VITE_CLERK_PUBLISHABLE_KEY",
57+ "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY",
58+ ) ?? DEFAULT_PUBLIC_CONFIG.clerkPublishableKey,
59+ relayUrl:
60+ firstNonEmpty(sources, "T3_RELAY_URL", "VITE_T3_RELAY_URL") ?? DEFAULT_PUBLIC_CONFIG.relayUrl,
61+ };
62+}
63+
64+function firstNonEmpty(sources: readonly Environment[], ...names: readonly string[]) {
65+ for (const source of sources) {
66+ for (const name of names) {
67+ const value = source[name]?.trim();
68+ if (value) {
69+ return value;
70+ }
71+ }
72+ }
73+ return undefined;
74+}
75+
76+function readEnvFile(path: string): Record<string, string | undefined> {
77+ return NodeFS.existsSync(path) ? NodeUtil.parseEnv(NodeFS.readFileSync(path, "utf8")) : {};
78+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t