forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathruntime-config.client.ts
More file actions
65 lines (60 loc) · 2.66 KB
/
Copy pathruntime-config.client.ts
File metadata and controls
65 lines (60 loc) · 2.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// Client-side runtime config reader. Reads from
// window.__SHOWCASE_CONFIG__ which the root layout injects via an
// inline <script> tag BEFORE React hydrates (see app/layout.tsx). This
// is the ONLY public API for these URLs in client code — never read
// process.env.NEXT_PUBLIC_* directly (an ESLint rule enforces this).
//
// shell-dojo's `RuntimeConfig` is intentionally empty today (no URL
// consumers); the module exists to keep the pattern symmetric across
// shells. When a URL is added on the server side, this reader picks it
// up via the shared interface.
import type { RuntimeConfig } from "./runtime-config";
export type { RuntimeConfig };
declare global {
interface Window {
__SHOWCASE_CONFIG__?: RuntimeConfig;
}
}
/**
* Sentinel returned during SSR when `window` is unavailable. "use client"
* components in the Next.js App Router are server-side rendered on the
* initial request (that's how the HTML is streamed before hydration),
* which means their function bodies execute on the server too. We can't
* throw here without breaking SSR — instead we return a placeholder, and
* post-hydration the next render reads the real values out of
* window.__SHOWCASE_CONFIG__. Server components that need the live env
* values MUST import getRuntimeConfig from runtime-config.ts (the server
* variant), not this file.
*
* shell-dojo's RuntimeConfig is currently `{}` — the placeholder is the
* empty object that matches the interface.
*/
const SSR_PLACEHOLDER: RuntimeConfig = {};
/**
* Returns the runtime config injected by the root server layout.
*
* During SSR (no window) returns a sentinel placeholder; client code
* re-reads after hydration and gets the real values. If the inline
* <script> never runs (a route bypassed the layout, or injection ran
* with empty inputs), the post-hydration read throws — surfacing the
* wiring bug loudly rather than silently rendering empty URLs.
*/
export function getRuntimeConfig(): RuntimeConfig {
if (typeof window === "undefined") {
// SSR phase — "use client" component bodies execute here too.
// Return placeholder; hydration will re-render with real values.
return SSR_PLACEHOLDER;
}
const cfg = window.__SHOWCASE_CONFIG__;
if (!cfg) {
// The root layout always emits the <script> tag, so a missing
// value here is a wiring bug (e.g. a route bypassed the layout,
// or the injection script ran with empty inputs). Surface it
// loudly rather than silently returning empty strings.
throw new Error(
"[runtime-config.client] window.__SHOWCASE_CONFIG__ is missing. " +
"The root layout must inject runtime config before client mount.",
);
}
return cfg;
}