@checkstack/frontend-api 0.3.6 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/package.json +6 -3
- package/src/runtime-config.tsx +64 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @checkstack/frontend-api
|
|
2
2
|
|
|
3
|
+
## 0.3.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 67158e2: Standardize package metadata, unify AJV versions to 8.18.0, and enforce monorepo architecture rules via updated ESLint configuration. This ensures consistent package discovery and runtime dependency safety across the platform.
|
|
8
|
+
- Updated dependencies [67158e2]
|
|
9
|
+
- @checkstack/common@0.6.4
|
|
10
|
+
|
|
11
|
+
## 0.3.7
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 0603d39: Fix onboarding flow not appearing on fresh Docker deployments (issue #79)
|
|
16
|
+
|
|
17
|
+
The `.env.example` had `BASE_URL` defaulting to `http://localhost:5173`
|
|
18
|
+
(the Vite dev server port). Users copying this file verbatim for a Docker
|
|
19
|
+
deployment would get a frontend that silently made all API calls to the
|
|
20
|
+
wrong origin, causing empty state and extreme sluggishness.
|
|
21
|
+
|
|
22
|
+
**Changes:**
|
|
23
|
+
|
|
24
|
+
- `.env.example`: Adds clear comments explaining the value must match the
|
|
25
|
+
container's exposed port.
|
|
26
|
+
- `frontend-api` (`RuntimeConfigProvider`): Removes the silent fallback when
|
|
27
|
+
`/api/config` returns an unreachable baseUrl — instead propagates the error
|
|
28
|
+
so it can be surfaced.
|
|
29
|
+
- `frontend` (`App.tsx`): Renders an actionable error screen when the backend
|
|
30
|
+
config cannot be loaded, showing the exact `BASE_URL` fix and the
|
|
31
|
+
`docker compose` command to recover.
|
|
32
|
+
- `docs/getting-started/docker.md`: Adds a dedicated troubleshooting section
|
|
33
|
+
for this exact misconfiguration.
|
|
34
|
+
|
|
3
35
|
## 0.3.6
|
|
4
36
|
|
|
5
37
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/frontend-api",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"react": "^18.0.0"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@checkstack/common": "0.6.
|
|
16
|
-
"@orpc/client": "^1.13.
|
|
15
|
+
"@checkstack/common": "0.6.3",
|
|
16
|
+
"@orpc/client": "^1.13.14",
|
|
17
17
|
"@orpc/react-query": "1.13.4",
|
|
18
18
|
"@orpc/tanstack-query": "^1.13.2",
|
|
19
19
|
"@tanstack/react-query": "^5.64.0"
|
|
@@ -24,5 +24,8 @@
|
|
|
24
24
|
"typescript": "^5.0.0",
|
|
25
25
|
"@checkstack/tsconfig": "0.0.3",
|
|
26
26
|
"@checkstack/scripts": "0.1.1"
|
|
27
|
+
},
|
|
28
|
+
"checkstack": {
|
|
29
|
+
"type": "tooling"
|
|
27
30
|
}
|
|
28
31
|
}
|
package/src/runtime-config.tsx
CHANGED
|
@@ -42,8 +42,34 @@ interface RuntimeConfigProviderProps {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* Safely reads the current page origin without requiring the DOM lib
|
|
46
|
+
* to be in scope in every consuming package's tsconfig.
|
|
47
|
+
*
|
|
48
|
+
* Accesses `location` via `globalThis` cast to avoid the untyped-global
|
|
49
|
+
* error that appears when non-browser packages (e.g. catalog-common) run
|
|
50
|
+
* TypeScript against this file and their tsconfig doesn't include "DOM".
|
|
51
|
+
*/
|
|
52
|
+
function getCurrentOrigin(): string | undefined {
|
|
53
|
+
const g = globalThis as Record<string, unknown>;
|
|
54
|
+
const loc = g["location"] as { origin?: string } | undefined;
|
|
55
|
+
const origin = loc?.origin;
|
|
56
|
+
return typeof origin === "string" && origin.length > 0 ? origin : undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Fetches runtime config from the backend on mount, then validates the returned
|
|
61
|
+
* `baseUrl` is actually reachable.
|
|
62
|
+
*
|
|
63
|
+
* Why the probe step matters: `/api/config` is always fetched from the current
|
|
64
|
+
* origin and always succeeds — but the `baseUrl` it returns could point to the
|
|
65
|
+
* wrong port (e.g. the Vite dev server) if `BASE_URL` is misconfigured.
|
|
66
|
+
* Without the probe, all subsequent API calls silently fail with CORS/network
|
|
67
|
+
* errors and the user sees an empty, unresponsive dashboard (issue #79).
|
|
68
|
+
*
|
|
69
|
+
* Probe logic:
|
|
70
|
+
* - If `baseUrl` matches the current page origin → trivially reachable, skip probe.
|
|
71
|
+
* - Otherwise → HEAD-request `${baseUrl}/api/config` with a 5 s timeout.
|
|
72
|
+
* A connection error here means the baseUrl is wrong.
|
|
47
73
|
*/
|
|
48
74
|
export const RuntimeConfigProvider: React.FC<RuntimeConfigProviderProps> = ({
|
|
49
75
|
children,
|
|
@@ -55,28 +81,50 @@ export const RuntimeConfigProvider: React.FC<RuntimeConfigProviderProps> = ({
|
|
|
55
81
|
useEffect(() => {
|
|
56
82
|
const fetchConfig = async () => {
|
|
57
83
|
try {
|
|
58
|
-
//
|
|
59
|
-
// In production, this is the same origin
|
|
84
|
+
// Step 1: Fetch config from same-origin backend (always succeeds).
|
|
60
85
|
const response = await fetch("/api/config");
|
|
61
86
|
if (!response.ok) {
|
|
62
|
-
throw new Error(`Failed to fetch config: ${response.status}`);
|
|
87
|
+
throw new Error(`Failed to fetch runtime config: ${response.status}`);
|
|
63
88
|
}
|
|
64
89
|
const data = (await response.json()) as RuntimeConfig;
|
|
65
|
-
|
|
90
|
+
|
|
91
|
+
// Step 2: Validate the returned baseUrl is actually reachable.
|
|
92
|
+
// We only need to probe when baseUrl differs from the current page
|
|
93
|
+
// origin — same-origin is trivially reachable.
|
|
94
|
+
const currentOrigin = getCurrentOrigin();
|
|
95
|
+
if (currentOrigin && data.baseUrl !== currentOrigin) {
|
|
96
|
+
try {
|
|
97
|
+
await fetch(`${data.baseUrl}/api/config`, {
|
|
98
|
+
method: "HEAD",
|
|
99
|
+
signal: AbortSignal.timeout(5000),
|
|
100
|
+
});
|
|
101
|
+
} catch {
|
|
102
|
+
// baseUrl is not reachable — misconfigured BASE_URL env var.
|
|
103
|
+
setError(
|
|
104
|
+
new Error(
|
|
105
|
+
`BASE_URL is set to "${data.baseUrl}" but it cannot be reached. ` +
|
|
106
|
+
`Update BASE_URL in your .env to match the port your container exposes (e.g. ${currentOrigin}).`
|
|
107
|
+
)
|
|
108
|
+
);
|
|
109
|
+
// Don't set config so the error screen renders.
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
cachedConfig = data;
|
|
66
115
|
setConfig(data);
|
|
67
116
|
} catch (error_) {
|
|
68
117
|
console.error("RuntimeConfigProvider: Failed to load config", error_);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
setError(error_ instanceof Error ? error_ : new Error(String(error_)));
|
|
118
|
+
setError(
|
|
119
|
+
error_ instanceof Error ? error_ : new Error(String(error_))
|
|
120
|
+
);
|
|
121
|
+
// Do NOT set a fallback — surface the error visibly.
|
|
74
122
|
} finally {
|
|
75
123
|
setIsLoading(false);
|
|
76
124
|
}
|
|
77
125
|
};
|
|
78
126
|
|
|
79
|
-
fetchConfig();
|
|
127
|
+
void fetchConfig();
|
|
80
128
|
}, []);
|
|
81
129
|
|
|
82
130
|
return (
|
|
@@ -91,15 +139,15 @@ export const RuntimeConfigProvider: React.FC<RuntimeConfigProviderProps> = ({
|
|
|
91
139
|
// =============================================================================
|
|
92
140
|
|
|
93
141
|
/**
|
|
94
|
-
* Access the runtime config
|
|
95
|
-
* Returns { config, isLoading, error }.
|
|
142
|
+
* Access the runtime config. Consumers should check isLoading first.
|
|
96
143
|
*/
|
|
97
144
|
export function useRuntimeConfig(): RuntimeConfig {
|
|
98
145
|
const { config, isLoading } = useContext(RuntimeConfigContext);
|
|
99
146
|
|
|
100
147
|
if (isLoading || !config) {
|
|
101
|
-
// Return fallback
|
|
102
|
-
|
|
148
|
+
// Return a safe fallback while loading — consumers must check isLoading
|
|
149
|
+
// if they need to block on the config being available.
|
|
150
|
+
return { baseUrl: getCurrentOrigin() ?? "http://localhost:3000" };
|
|
103
151
|
}
|
|
104
152
|
|
|
105
153
|
return config;
|