catalyst-core 0.3.0-canary.1 → 0.3.0-canary.2
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 +113 -79
- package/dist/scripts/serve.js +0 -2
- package/dist/scripts/start.js +0 -2
- package/dist/server/renderer/render.js +1 -9
- package/dist/server/utils/validator.js +1 -1
- package/mcp_v2/knowledge-base.json +69 -15
- package/mcp_v2/mcp.js +1 -0
- package/package.json +1 -1
- package/test/scripts/preflight.test.ts +0 -3
- package/test/server/handler.assets.test.ts +0 -1
- package/test/server/handler.test.ts +1 -3
- package/test/server/render.test.ts +2 -21
- package/test/server/validator.test.ts +0 -3
package/changelog.md
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
# 1.0.0-beta.1
|
|
2
|
-
|
|
3
|
-
- Replaced the Webpack build and SSR pipeline with Vite and ESM.
|
|
4
|
-
- Added React 19 Suspense-aware routing, split components, and manifest-based asset loading.
|
|
5
|
-
- Added opt-in request, compression, flush, and bot-aware OpenTelemetry spans.
|
|
6
|
-
- Preserved native application builds, internal plugins, Sentry exports, and safe-area SSR hydration.
|
|
7
|
-
- Removed the legacy `devBuild` and `devServe` commands.
|
|
8
|
-
|
|
9
1
|
# Changelog
|
|
10
2
|
|
|
11
|
-
## [0.
|
|
3
|
+
## [1.0.0] - unreleased
|
|
12
4
|
|
|
13
5
|
This release freezes the public API. The root entry of `catalyst-core` now exports exactly eight names and nothing else: `RouterDataProvider`, `useCurrentRouteData`, `useRouterData`, `MetaTag`, `split`, `hydrationReady`, `Head`, and `Body`. Anything previously reachable through the root entry but not in that list is no longer public. Applications that import a removed name will fail at build time rather than silently resolving to `undefined`.
|
|
14
6
|
|
|
@@ -68,7 +60,7 @@ Where a hook had two names for one value, the shorter one is canonical and the o
|
|
|
68
60
|
|
|
69
61
|
Hooks fall into three categories, and the category decides whether a hook has `execute`. A hook that wraps a single native operation exposes it as `execute` plus a domain-specific alias — `takePhoto`, `pickFile`, `openFile`, `signIn`, `trigger`, `request`. A hook that wraps several distinct operations has no single action to name, so its named functions are the API and it has no `execute` at all: `useVideoStream`, `useDataProtection`, and `useNativeTransition` work this way. A read-only hook reports ambient device state and has no action functions at all: `useNetworkStatus`, `useDeviceInfo`, and `useSafeArea` return state plus the runtime-context keys. `useNotification` is the one exception. It carries `execute` and `schedule` as aliases of `scheduleLocal` for backward compatibility. Both are frozen, both are discouraged, and neither should be read as the pattern for multi-action hooks. `execute` never takes an operation name as a string argument; it takes the arguments of the operation itself.
|
|
70
62
|
|
|
71
|
-
Hook errors are `CatalystError` values from the framework-wide error registry introduced in this release, carrying a `RUNTIME-NATIVE-*` code, a message, a category, a suggested action, a documentation link, and the originating platform error as `cause`. `useVideoStream` in particular used to report seventeen failures as bare `{ message }` objects with no code at all; those now carry real codes, and a camera denial reports the same code whether it comes from the permission hook or the stream.
|
|
63
|
+
Hook errors are `CatalystError` values from the framework-wide error registry introduced in this release, carrying a `RUNTIME-NATIVE-*` code, a message, a category, a suggested action, a documentation link, and the originating platform error as `cause`. `useVideoStream` in particular used to report seventeen failures as bare `{ message }` objects with no code at all; those now carry real codes, and a camera denial reports the same code whether it comes from the permission hook or the stream. The error object's fields changed with it: `action` is now `suggestedAction`, `nativeError` is now `cause`, `recoverable` and `timestamp` are gone, and `code` values are registry codes such as `RUNTIME-NATIVE-001` instead of names such as `PERMISSION_DENIED`, so compare against `ERROR_CODES` from `catalyst-core/errors` rather than string literals.
|
|
72
64
|
|
|
73
65
|
One consequence for error logging: `CatalystError` extends `Error`, so `message` now lives on the prototype rather than as an own property. Reading `error.message` is unaffected, but `JSON.stringify(error)` no longer includes it. Log `error.message` explicitly, or use the `code` and `docUrl` fields.
|
|
74
66
|
|
|
@@ -87,12 +79,82 @@ The app contract validators in `server/utils/validator.js` used to log a bare me
|
|
|
87
79
|
The route and store checks moved out of the per-request path. `validateGetRoutes` and `validateConfigureStore` now run once when the renderer module loads — at server startup in production, and on the first SSR request in development, where the handler is loaded lazily — rather than once per request inside the handler's `try`/`catch`. The shape of `addMiddlewares` from `server/server.js` is checked during server setup.
|
|
88
80
|
|
|
89
81
|
Module aliases and `config/config.json` keys are not checked at load time; a missing alias or key still surfaces where it is used. An application that satisfies the contract sees no change. The full contract — the files Catalyst imports by fixed path and the required module aliases — is documented under File Conventions.
|
|
82
|
+
The webpack-era keys `WEBPACK_DEV_SERVER_HOSTNAME`, `WEBPACK_DEV_SERVER_PORT` and `ANALYZE_BUNDLE` are no longer required or read; remove them from `config/config.json`.
|
|
83
|
+
|
|
84
|
+
## [0.3.0-beta.5] - 2026-08-18
|
|
85
|
+
|
|
86
|
+
- Upgrade react-router-dom v6 to v7.18.2 (CVE fixes) (#399).
|
|
87
|
+
- Docs: clarify setMetaData must return array of JSX elements (#327).
|
|
88
|
+
|
|
89
|
+
## [0.3.0-beta.4] - 2026-08-10
|
|
90
|
+
|
|
91
|
+
- Detect CommonJS by parsing, not by matching source text (#397).
|
|
92
|
+
- Sub-path base + HMR config for reverse-proxy dev setups (#379).
|
|
93
|
+
|
|
94
|
+
## [0.3.0-beta.3] - 2026-08-04
|
|
95
|
+
|
|
96
|
+
- Resolve semgrep and dependency findings from security scan (#375).
|
|
97
|
+
|
|
98
|
+
## [0.3.0-beta.2] - 2026-08-03
|
|
99
|
+
|
|
100
|
+
- @catalyst/cloud-ai — multi-provider AI integration with useAI hook (#288).
|
|
101
|
+
- Eliminate SSR streaming race between onShellReady and onAllReady (#323).
|
|
102
|
+
- Update iOS release docs and MCP guidance (#324).
|
|
103
|
+
- Patch @tailwindcss/postcss base so Vite scans the whole app (#326).
|
|
104
|
+
|
|
105
|
+
## [0.3.0-beta.1] - 2026-07-15
|
|
106
|
+
|
|
107
|
+
- Replaced the Webpack build and SSR pipeline with Vite and ESM.
|
|
108
|
+
- Added React 19 Suspense-aware routing, split components, and manifest-based asset loading.
|
|
109
|
+
- Added opt-in request, compression, flush, and bot-aware OpenTelemetry spans.
|
|
110
|
+
- Preserved native application builds, internal plugins, Sentry exports, and safe-area SSR hydration.
|
|
111
|
+
- Removed the legacy `devBuild` and `devServe` commands.
|
|
112
|
+
|
|
113
|
+
## [0.2.0-beta.3] - 2026-07-14
|
|
114
|
+
|
|
115
|
+
- Catalyst Profiler Runtime (#274).
|
|
116
|
+
|
|
117
|
+
## [0.2.0-beta.2] - 2026-07-09
|
|
118
|
+
|
|
119
|
+
- Route Caching (#287).
|
|
120
|
+
- Android build fixes (#303).
|
|
121
|
+
|
|
122
|
+
## [0.2.0-beta.1] - 2026-07-08
|
|
123
|
+
|
|
124
|
+
- Catalyst react + rendering update (#293).
|
|
125
|
+
- Add GitHub feedback integration to Catalyst MCP v2 (#272).
|
|
126
|
+
- Sync MCP v2: extract seeding, delegate docs sync, add FTS + initial sync (#295).
|
|
127
|
+
|
|
128
|
+
## [0.1.0-beta.7] - 2026-06-29
|
|
129
|
+
|
|
130
|
+
- Syncing dweb branch with main (#283).
|
|
131
|
+
|
|
132
|
+
## [0.1.0-beta.6] - 2026-06-11
|
|
133
|
+
|
|
134
|
+
- Add examples folder with local testing app for catalyst-core (#246).
|
|
135
|
+
|
|
136
|
+
## [0.1.0-beta.5] - 2026-06-09
|
|
137
|
+
|
|
138
|
+
- Semgrep Plugin Fixes (#266).
|
|
139
|
+
|
|
140
|
+
## [0.1.0-beta.4] - 2026-06-03
|
|
141
|
+
|
|
142
|
+
- Merge video hook, web fallback, and plugin system into monorepo (#258).
|
|
143
|
+
|
|
144
|
+
## [0.1.0-beta.3] - 2026-06-02
|
|
145
|
+
|
|
146
|
+
- Security Fixes (semgrep) (#259).
|
|
147
|
+
- Catalyst Docs Mismatches Fix (#244).
|
|
90
148
|
|
|
91
149
|
## [0.1.0-beta.2] - 2026-05-06
|
|
92
150
|
|
|
93
151
|
- Moved Catalyst into a monorepo structure with `catalyst-core`, `create-catalyst-app`, the Catalyst docs app, and the Catalyst core test app managed from one repository.
|
|
94
152
|
- Replaced the internal-package pre-release flow with a local release sandbox that scaffolds a real app using current-branch CCA and a locally packed current-branch `catalyst-core`.
|
|
95
153
|
|
|
154
|
+
## [0.1.0-canary.9] - 2026-05-06
|
|
155
|
+
|
|
156
|
+
- Changelog-only update; same code as 0.1.0-beta.2.
|
|
157
|
+
|
|
96
158
|
## [0.1.0-canary.8] - 2026-04-15
|
|
97
159
|
|
|
98
160
|
- Introduced Catalyst’s internal plugin architecture, adding the `PluginBridge` web API, native plugin runtimes for Android and iOS, and manifest-driven build composition for modular native capabilities.
|
|
@@ -120,7 +182,7 @@ Module aliases and `config/config.json` keys are not checked at load time; a mis
|
|
|
120
182
|
- Improved universal app runtime behavior with safe-area inset support, edge-to-edge rendering, and notification permission override fixes.
|
|
121
183
|
- Expanded platform support with offline fallback handling, notification/access-control refinements, localhost HTTP allowances for local development, and file-picker/HTTPS server improvements.
|
|
122
184
|
|
|
123
|
-
## [0.1.0-canary.4] - 2026-02-
|
|
185
|
+
## [0.1.0-canary.4] - 2026-02-16
|
|
124
186
|
|
|
125
187
|
- Added Google Sign-In support for both Android and iOS in Catalyst, enabling a unified native authentication experience for apps built on the framework.
|
|
126
188
|
- Improved release/build reliability with related bridge and CI updates, making integration smoother and more consistent across platforms.
|
|
@@ -148,26 +210,26 @@ Module aliases and `config/config.json` keys are not checked at load time; a mis
|
|
|
148
210
|
- Notification refactor: streamlined config toggle for local vs push, centralized permission/asset handling, and simpler routing into the web app
|
|
149
211
|
- Access control: combined access control config for ios
|
|
150
212
|
|
|
151
|
-
## [0.0.3-canary.18] - 2025-11-
|
|
213
|
+
## [0.0.3-canary.18] - 2025-11-25
|
|
152
214
|
|
|
153
215
|
- Configuration Files
|
|
154
216
|
- Android Native WebView - MainActivity.kt
|
|
155
217
|
- Android Native WebView - CustomWebview.kt
|
|
156
218
|
|
|
157
|
-
## [0.0.3-canary.17] - 2025-11-
|
|
219
|
+
## [0.0.3-canary.17] - 2025-11-21
|
|
158
220
|
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
-
|
|
165
|
-
-
|
|
166
|
-
-
|
|
167
|
-
-
|
|
168
|
-
-
|
|
221
|
+
- Added complete notification system (local & push)
|
|
222
|
+
- New useNotification() React hook
|
|
223
|
+
- Firebase Cloud Messaging conditional build support
|
|
224
|
+
- Android notification handling in MainActivity
|
|
225
|
+
- 5 new notification commands + 5 callbacks in NativeBridge
|
|
226
|
+
- Auto-processing of notification icons & sounds
|
|
227
|
+
- Conditional dependencies based on notification config
|
|
228
|
+
- Updated .gitignore & .npmignore
|
|
229
|
+
- Enhanced build process with automatic permission injection
|
|
230
|
+
- Deep link integration with notifications
|
|
169
231
|
|
|
170
|
-
## [0.0.3-canary.16] - 2025-11-
|
|
232
|
+
## [0.0.3-canary.16] - 2025-11-20
|
|
171
233
|
|
|
172
234
|
- FeaturesGallery Support for File Picker: Enhanced file picker to open native gallery for selecting images and videos
|
|
173
235
|
- HTTPS Framework Server: Enabled HTTPS support for the framework server with self-signed SSL certificate
|
|
@@ -177,17 +239,17 @@ Module aliases and `config/config.json` keys are not checked at load time; a mis
|
|
|
177
239
|
|
|
178
240
|
- Adding Android release support and appInfo key
|
|
179
241
|
|
|
180
|
-
## [0.0.3-canary.14] - 2025-
|
|
242
|
+
## [0.0.3-canary.14] - 2025-10-29
|
|
181
243
|
|
|
182
244
|
- Android custom splashscreen
|
|
183
245
|
|
|
184
|
-
## [0.0.3-canary.13] - 2025-
|
|
246
|
+
## [0.0.3-canary.13] - 2025-10-28
|
|
185
247
|
|
|
186
248
|
- Multi file support in useFilePicker hook
|
|
187
249
|
- Android multiple app icon support
|
|
188
250
|
- Android whitelisting toggle support
|
|
189
251
|
|
|
190
|
-
## [0.0.3-canary.12] - 2025-
|
|
252
|
+
## [0.0.3-canary.12] - 2025-10-13
|
|
191
253
|
|
|
192
254
|
- Universal App Context: Added comprehensive context support for building universal mobile applications
|
|
193
255
|
- OpenTelemetry SDK Integration: Built-in support for observability and performance monitoring with Otel SDK
|
|
@@ -198,70 +260,42 @@ Module aliases and `config/config.json` keys are not checked at load time; a mis
|
|
|
198
260
|
- Enhanced Android native support: Add support for native keyboard and webview resizing in Android
|
|
199
261
|
- Device info API web support: Web support in device info API
|
|
200
262
|
|
|
201
|
-
## [0.0.3-canary.10] - 2025-09-
|
|
263
|
+
## [0.0.3-canary.10] - 2025-09-17
|
|
202
264
|
|
|
203
|
-
-
|
|
204
|
-
-
|
|
265
|
+
- Sentry import bug fix.
|
|
266
|
+
- Open telemetry SDK.
|
|
205
267
|
|
|
206
268
|
## [0.0.3-canary.9] - 2025-09-11
|
|
207
269
|
|
|
208
|
-
-
|
|
209
|
-
-
|
|
210
|
-
-
|
|
211
|
-
|
|
212
|
-
## [0.0.3-canary.8] - 2025-01-06
|
|
213
|
-
|
|
214
|
-
- **App icon configuration**
|
|
215
|
-
- **Splash screen integration**
|
|
216
|
-
- **Url Whitelisting**
|
|
270
|
+
- App name configuration.
|
|
271
|
+
- Device Info API.
|
|
272
|
+
- Access control configuration.
|
|
217
273
|
|
|
218
|
-
## [0.0.3-canary.
|
|
274
|
+
## [0.0.3-canary.8] - 2025-08-08
|
|
219
275
|
|
|
220
|
-
|
|
276
|
+
- App icon configuration.
|
|
277
|
+
- Splash screen integration.
|
|
278
|
+
- Url Whitelisting.
|
|
221
279
|
|
|
222
|
-
-
|
|
223
|
-
- **Automated IP Resolution**: Intelligent network detection eliminates manual IP configuration
|
|
224
|
-
- **Universal Build System**: Streamlined one-command builds for both Android and iOS platforms
|
|
225
|
-
- **Enhanced CLI Interface**: Improved command-line tools for better developer experience
|
|
226
|
-
|
|
227
|
-
### 🐛 Bug Fixes
|
|
280
|
+
## [0.0.3-canary.7] - 2025-08-06
|
|
228
281
|
|
|
282
|
+
- Native API Integration: Enhanced native module integration for better performance
|
|
283
|
+
- Automated IP Resolution: Intelligent network detection eliminates manual IP configuration
|
|
284
|
+
- Universal Build System: Streamlined one-command builds for both Android and iOS platforms
|
|
285
|
+
- Enhanced CLI Interface: Improved command-line tools for better developer experience
|
|
229
286
|
- Fixed IP address detection issues on development environments
|
|
230
287
|
- Resolved build configuration conflicts between platforms
|
|
231
288
|
- Improved error handling and recovery mechanisms
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
-
|
|
236
|
-
-
|
|
237
|
-
-
|
|
238
|
-
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
- ✅ **Android Build**: Verified APK generation, installation, and runtime behavior
|
|
243
|
-
- ✅ **iOS Build**: Tested build process and device compatibility
|
|
244
|
-
- ✅ **IP Detection**: Validated automatic network resolution across platforms
|
|
245
|
-
- ✅ **Native Modules**: Confirmed API integration and performance benchmarks
|
|
246
|
-
- ✅ **CLI Operations**: Tested enhanced command-line workflows and error handling
|
|
247
|
-
|
|
248
|
-
### 🔄 Breaking Changes
|
|
249
|
-
|
|
250
|
-
**None** - All changes maintain backward compatibility while enhancing existing functionality
|
|
251
|
-
|
|
252
|
-
### 📝 Technical Details
|
|
253
|
-
|
|
289
|
+
- Performance: Optimized native module loading and execution
|
|
290
|
+
- Developer Experience: Enhanced CLI with better error messages and debugging info
|
|
291
|
+
- Configuration: Dynamic config updates without requiring restarts
|
|
292
|
+
- Build Process: Faster and more reliable build pipeline
|
|
293
|
+
- Android Build: Verified APK generation, installation, and runtime behavior
|
|
294
|
+
- iOS Build: Tested build process and device compatibility
|
|
295
|
+
- IP Detection: Validated automatic network resolution across platforms
|
|
296
|
+
- Native Modules: Confirmed API integration and performance benchmarks
|
|
297
|
+
- CLI Operations: Tested enhanced command-line workflows and error handling
|
|
254
298
|
- Improved native API bridge for better cross-platform communication
|
|
255
299
|
- Enhanced error reporting with detailed stack traces and suggestions
|
|
256
300
|
- Optimized build configuration for faster development cycles
|
|
257
301
|
- Added comprehensive logging for debugging and monitoring
|
|
258
|
-
|
|
259
|
-
### 🔗 Migration Notes
|
|
260
|
-
|
|
261
|
-
- No migration steps required
|
|
262
|
-
- Existing projects will automatically benefit from improvements
|
|
263
|
-
- Optional: Update CLI usage to leverage new enhanced features
|
|
264
|
-
|
|
265
|
-
## Version
|
|
266
|
-
|
|
267
|
-
- Target version: 0.0.3-canary.7
|
package/dist/scripts/serve.js
CHANGED
|
@@ -40,14 +40,12 @@ function startProd() {
|
|
|
40
40
|
...process.env,
|
|
41
41
|
src_path: process.env.PWD,
|
|
42
42
|
NODE_ENV: "production",
|
|
43
|
-
IS_DEV_COMMAND: false,
|
|
44
43
|
APPLICATION: name || "catalyst_app",
|
|
45
44
|
CATALYST_OUTPUT_MODE: outputMode,
|
|
46
45
|
...argumentsObject,
|
|
47
46
|
filterKeys: JSON.stringify([
|
|
48
47
|
"src_path",
|
|
49
48
|
"NODE_ENV",
|
|
50
|
-
"IS_DEV_COMMAND",
|
|
51
49
|
"APPLICATION",
|
|
52
50
|
...Object.keys(argumentsObject),
|
|
53
51
|
]),
|
package/dist/scripts/start.js
CHANGED
|
@@ -35,14 +35,12 @@ function start() {
|
|
|
35
35
|
...process.env,
|
|
36
36
|
src_path: process.env.PWD,
|
|
37
37
|
NODE_ENV: "development",
|
|
38
|
-
IS_DEV_COMMAND: false,
|
|
39
38
|
APPLICATION: name || "catalyst_app",
|
|
40
39
|
CATALYST_OUTPUT_MODE: outputMode,
|
|
41
40
|
...argumentsObject,
|
|
42
41
|
filterKeys: JSON.stringify([
|
|
43
42
|
"src_path",
|
|
44
43
|
"NODE_ENV",
|
|
45
|
-
"IS_DEV_COMMAND",
|
|
46
44
|
"APPLICATION",
|
|
47
45
|
...Object.keys(argumentsObject),
|
|
48
46
|
]),
|
|
@@ -11,15 +11,7 @@ export const renderStart = ({
|
|
|
11
11
|
isBot,
|
|
12
12
|
fetcherData
|
|
13
13
|
}) => {
|
|
14
|
-
const {
|
|
15
|
-
IS_DEV_COMMAND,
|
|
16
|
-
WEBPACK_DEV_SERVER_HOSTNAME,
|
|
17
|
-
WEBPACK_DEV_SERVER_PORT
|
|
18
|
-
} = process.env;
|
|
19
|
-
let publicAssetPath = `${process.env.PUBLIC_STATIC_ASSET_URL}${process.env.PUBLIC_STATIC_ASSET_PATH}`;
|
|
20
|
-
if (JSON.parse(IS_DEV_COMMAND)) {
|
|
21
|
-
publicAssetPath = `http://${WEBPACK_DEV_SERVER_HOSTNAME}:${WEBPACK_DEV_SERVER_PORT}/assets/`;
|
|
22
|
-
}
|
|
14
|
+
const publicAssetPath = `${process.env.PUBLIC_STATIC_ASSET_URL}${process.env.PUBLIC_STATIC_ASSET_PATH}`;
|
|
23
15
|
return {
|
|
24
16
|
inlineCss,
|
|
25
17
|
deferredRouteInlineCss,
|
|
@@ -43,7 +43,7 @@ const validateReducerFunction = fn => {
|
|
|
43
43
|
const validateConfigFile = obj => {
|
|
44
44
|
if (!obj) return createError(ERROR_CODES.PREFLIGHT_CONFIG_MISSING);
|
|
45
45
|
if (typeof obj !== "object") return createError(ERROR_CODES.PREFLIGHT_CONFIG_NOT_OBJECT);
|
|
46
|
-
const requiredConfigKeys = ["NODE_SERVER_HOSTNAME", "NODE_SERVER_PORT", "
|
|
46
|
+
const requiredConfigKeys = ["NODE_SERVER_HOSTNAME", "NODE_SERVER_PORT", "BUILD_OUTPUT_PATH", "PUBLIC_STATIC_ASSET_PATH", "PUBLIC_STATIC_ASSET_URL", "CLIENT_ENV_VARIABLES"];
|
|
47
47
|
for (const key of requiredConfigKeys) {
|
|
48
48
|
if (!(key in obj)) return createError(ERROR_CODES.PREFLIGHT_CONFIG_KEY_MISSING, {
|
|
49
49
|
details: `${key} key not found inside config.json`
|
|
@@ -474,9 +474,9 @@
|
|
|
474
474
|
{
|
|
475
475
|
"section": "config_structure",
|
|
476
476
|
"title": "Full config/config.json Schema",
|
|
477
|
-
"content": "config/config.json contains all runtime config. Required keys (enforced by validator.js at startup \u2014 missing any = server crash): NODE_SERVER_HOSTNAME (string), NODE_SERVER_PORT (number),
|
|
477
|
+
"content": "config/config.json contains all runtime config. Required keys (enforced by validator.js at startup \u2014 missing any = server crash): NODE_SERVER_HOSTNAME (string), NODE_SERVER_PORT (number), BUILD_OUTPUT_PATH (string, e.g. 'build'), PUBLIC_STATIC_ASSET_PATH (string, e.g. '/assets/'), PUBLIC_STATIC_ASSET_URL (string, CDN base URL), CLIENT_ENV_VARIABLES (array of env var names to expose to client bundle). WEBPACK_DEV_SERVER_HOSTNAME, WEBPACK_DEV_SERVER_PORT, and ANALYZE_BUNDLE are no longer required or read \u2014 they are ignored if present. Optional top-level keys: API_URL (string, app convention not enforced), WEBVIEW_CONFIG (object, required for native builds \u2014 contains splashScreen, appInfo, android, ios, etc.). Common mistake: CLIENT_ENV_KEYS is WRONG \u2014 the actual key is CLIENT_ENV_VARIABLES. Common mistake: splashScreen is NOT a top-level key \u2014 it lives inside WEBVIEW_CONFIG. Example: { NODE_SERVER_HOSTNAME: 'localhost', NODE_SERVER_PORT: 3000, BUILD_OUTPUT_PATH: 'build', PUBLIC_STATIC_ASSET_PATH: '/assets/', PUBLIC_STATIC_ASSET_URL: 'https://cdn.example.com', CLIENT_ENV_VARIABLES: ['API_URL'] }",
|
|
478
478
|
"layer": "Config",
|
|
479
|
-
"source": "extracted:src/
|
|
479
|
+
"source": "extracted:src/server/utils/validator.ts",
|
|
480
480
|
"tags": ["config", "schema", "required-fields"]
|
|
481
481
|
},
|
|
482
482
|
{
|
|
@@ -570,10 +570,10 @@
|
|
|
570
570
|
{
|
|
571
571
|
"section": "server_structure",
|
|
572
572
|
"title": "Required Server Files",
|
|
573
|
-
"content": "Catalyst requires 3 specific files in server/: server/index.js (lifecycle hooks), server/server.js (Express middleware), server/document.js (HTML template). These are NOT optional. Missing any one = server startup fails. Any repo using custom Express, Next.js, CRA, or Vite must rebuild all 3 from scratch.",
|
|
573
|
+
"content": "Catalyst requires 3 specific files in server/: server/index.js (lifecycle hooks), server/server.js (Express middleware), server/document.js (HTML template). These are NOT optional. Missing any one = server startup fails. Any repo using custom Express, Next.js, CRA, or Vite must rebuild all 3 from scratch. From 1.0.0, a file that exists but lacks a required export is reported once at startup, naming the file and the export; the server still boots (log-and-continue) and the affected feature fails instead.",
|
|
574
574
|
"layer": "Build",
|
|
575
575
|
"source": "static",
|
|
576
|
-
"tags": ["server", "required-files", "structure"]
|
|
576
|
+
"tags": ["server", "required-files", "structure", "1.0.0"]
|
|
577
577
|
},
|
|
578
578
|
{
|
|
579
579
|
"section": "server_structure",
|
|
@@ -610,7 +610,7 @@
|
|
|
610
610
|
{
|
|
611
611
|
"section": "native_hooks",
|
|
612
612
|
"title": "Native Hooks \u2014 Overview & Common Interface",
|
|
613
|
-
"content": "catalyst-core hooks fall into
|
|
613
|
+
"content": "catalyst-core hooks fall into TWO CATEGORIES.\n\nSINGLE-ACTION HOOKS wrap exactly one native operation and share a standardized base interface: { data, loading, progress, error, isWeb, isNative, execute, clear, clearError }. execute takes the operation's own arguments — it NEVER takes an operation-name string. Each also exposes a domain alias for execute: useCamera->takePhoto, useFilePicker->pickFile, useIntent->openFile, useGoogleSignIn->signIn, useHapticFeedback->trigger/triggerHaptic, useCameraPermission->request.\n\nMULTI-ACTION HOOKS wrap several distinct operations, so their NAMED FUNCTIONS ARE THE API and they have NO execute: useNotification (scheduleLocal, cancelLocal, registerForPush, updateBadge, subscribeToTopic, unsubscribeFromTopic, getSubscribedTopics, requestPermission), useVideoStream (start, stop, sendCommand, flip), useDataProtection (setScreenSecure, clearWebData), useNativeTransition (navigate, cancelTransition). EXCEPTION: useNotification carries execute as a frozen-but-discouraged alias of scheduleLocal — do NOT copy that pattern for other multi-action hooks.\n\nREAD-ONLY HOOKS report ambient state with no action functions: useNetworkStatus, useDeviceInfo, useSafeArea.\n\nisNative is true when running inside the native shell (Android/iOS WebView). isWeb is true on browser. All return SSR-safe stubs when window is undefined. Import from catalyst-core/hooks.\n\nWEB FALLBACK SYSTEM: Hooks that implement browser fallbacks additionally expose: { webFallbackActive: boolean, webFallbackDisabled: boolean, setWebFallback: (enabled: boolean) => void }. webFallbackActive=true means the hook is currently running its browser fallback (not native bridge). setWebFallback(false) disables the built-in fallback at runtime \u2014 React re-runs effects and cleans up side effects automatically (e.g. stops MediaStream, removes event listeners). webFallbackDisabled=true means the hook returned an inert no-op shape (all actions are no-ops, data/error/loading are null/false) \u2014 consumer must render its own UI.\n\nDYNAMIC PROP SYNC: The webFallback prop syncs dynamically after mount in all hooks (both useBaseHook consumers and thin-state hooks) via useEffect. Passing a new webFallback prop value re-evaluates webFallbackActive without remounting the component.\n\nRULES OF HOOKS: All hooks (useState, useRef, useCallback, useEffect) are always called unconditionally at top level, regardless of webFallbackActive/webFallbackDisabled. Branching only happens in return statements.\n\nHooks with web fallbacks: useCamera, useFilePicker, useHapticFeedback, useVideoStream, useDataProtection, useCameraPermission, useNetworkStatus, useSafeArea, useDeviceInfo.",
|
|
614
614
|
"layer": "Runtime",
|
|
615
615
|
"source": "static",
|
|
616
616
|
"tags": [
|
|
@@ -729,7 +729,7 @@
|
|
|
729
729
|
"title": "moduleAliases \u2014 Required Path Aliases in package.json",
|
|
730
730
|
"content": "package.json must have a _moduleAliases key (used by module-alias package) with these 6 required entries (enforced by validator.js \u2014 missing any = server crash): @api -> api/ (WARNING: common bug \u2014 @api accidentally set to src/static/css in legacy repos, causes all API imports to break silently), @containers -> src/js/containers, @server -> server, @config -> config, @css -> src/static/css, @routes -> src/js/routes/. Additional aliases (@store, @utils, @components, etc.) are optional but recommended. Dollar-prefix aliases (, , , , ) are server-side only \u2014 do not import in client code. Restriction: alias names containing catalyst are reserved. Migration check: always verify @api points to the actual API module, not a static asset path.",
|
|
731
731
|
"layer": "Config",
|
|
732
|
-
"source": "extracted:src/
|
|
732
|
+
"source": "extracted:src/server/utils/validator.ts",
|
|
733
733
|
"tags": ["module-aliases", "package-json", "required", "config"]
|
|
734
734
|
},
|
|
735
735
|
{
|
|
@@ -1072,7 +1072,7 @@
|
|
|
1072
1072
|
{
|
|
1073
1073
|
"section": "native_hooks",
|
|
1074
1074
|
"title": "Native Hooks \u2014 Full List and Standard Interface",
|
|
1075
|
-
"content": "All hooks live in src/native/bridge/hooks/ (one file per domain). hooks.js is a 2-line re-export shim for backwards compat.\n\
|
|
1075
|
+
"content": "All hooks live in src/native/bridge/hooks/ (one file per domain). hooks.js is a 2-line re-export shim for backwards compat.\n\nTWO CATEGORIES:\n- SINGLE-ACTION hooks wrap one operation and expose it as execute (plus a domain alias). execute takes the operation's arguments, never an operation-name string. These are: useCamera (takePhoto), useFilePicker (pickFile), useIntent (openFile), useGoogleSignIn (signIn), useHapticFeedback (trigger/triggerHaptic), useCameraPermission (request).\n- MULTI-ACTION hooks wrap several operations, so the named functions ARE the API and there is NO execute: useNotification, useVideoStream, useDataProtection, useNativeTransition. useNotification is the sole exception carrying execute as a frozen-but-discouraged alias of scheduleLocal — never copy that pattern.\n- READ-ONLY hooks have no action functions: useNetworkStatus, useDeviceInfo, useSafeArea.\n\nSTANDARD BASE INTERFACE (single-action useBaseHook consumers):\n{ data, loading, progress, error, isWeb, isNative, execute, clear, clearError,\n webFallbackActive, webFallbackDisabled, setWebFallback }\n\nMulti-action hooks share the same state keys (data, loading, error, isWeb, isNative, clear, clearError) but replace execute with their named functions.\n\nERROR SHAPE: error is a standard error object everywhere EXCEPT useDeviceInfo and useNetworkStatus, where it remains a plain string until 2.0. useNativeTransition and useSafeArea are error-exempt — they have no error key at all (transition failures self-heal into a plain navigate; safe-area insets always resolve to numeric defaults). useAI's shape is owned by the catalyst-ai package and is outside this contract.\n\nprogress shape: { state, percentage, message, phase, transport, bytesLoaded, bytesTotal }\n\nENVIRONMENT DETECTION (useBaseHook):\nisNative = window.WebBridge && (window.NativeBridge || window.webkit?.messageHandlers?.NativeBridge)\nisWeb = !isNative\n\nWEB FALLBACK SYSTEM:\n- Hooks that support a browser fallback declare hasWebFallback: true in useBaseHook options.\n- webFallbackActive defaults to true on web when a fallback exists (unless webFallback prop === false).\n- webFallback prop syncs dynamically after mount \u2014 all hooks (useBaseHook consumers and thin-state hooks) update webFallbackActive via a useEffect that watches the prop.\n- setWebFallback(false) disables fallback at runtime \u2014 React re-runs effects + cleanups (e.g. stops MediaStream, removes event listeners).\n- When disabled: webFallbackDisabled=true, all action methods are no-ops, data/error/loading are null/false.\n- Thin-state hooks (useNetworkStatus, useSafeArea, useDeviceInfo, useCameraPermission) manage webFallback locally and expose isNative, isWeb, webFallbackActive, webFallbackDisabled, setWebFallback \u2014 same surface as useBaseHook consumers.\n- Rules of Hooks: all hooks are always called unconditionally at top level \u2014 early returns and conditional branches only in return statements, never around hook calls.\n\nFULL HOOK LIST:\nWith web fallback:\n- useCamera \u2014 capture photo. Web: <input type=file capture=environment>.\n- useFilePicker \u2014 pick file. Web: <input type=file>.\n- useHapticFeedback \u2014 haptic/vibration. Web: navigator.vibrate.\n- useVideoStream \u2014 live camera stream + sendCommand (zoom/torch/fps). Web: getUserMedia (requires secure context) with track.applyConstraints. Stream auto-stopped on mode change or unmount.\n- useDataProtection \u2014 setScreenSecure + clearWebData. Web: overlay div on visibilitychange + localStorage/sessionStorage/cookie/IndexedDB clear.\n- useCameraPermission \u2014 camera permission state + request(). Web: navigator.permissions API (query) + getUserMedia side-effect for request().\n- useNetworkStatus \u2014 online/type. Web: navigator.onLine (defaults true if not boolean) + online/offline events (live updates).\n- useSafeArea \u2014 inset pixels. Web: CSS env() vars.\n- useDeviceInfo \u2014 device metadata. Web: navigator/screen APIs.\n\nNo web fallback (native-only or scoped out):\n- useNotification \u2014 push notifications. Web: scoped out (Service Worker required, unreliable in WebView).\n- useNotificationPermission \u2014 notification permission.\n- useGoogleSignIn \u2014 Google sign-in via native.\n- useIntent \u2014 open file with external app.\n- useNativeTransition \u2014 navigate with native slide/fade transitions. Web: CSS overlay on document.body driven by the same state machine (not a webFallback-prop hook).",
|
|
1076
1076
|
"layer": "Bridge",
|
|
1077
1077
|
"source": "static",
|
|
1078
1078
|
"tags": [
|
|
@@ -1126,7 +1126,7 @@
|
|
|
1126
1126
|
{
|
|
1127
1127
|
"section": "native_hooks",
|
|
1128
1128
|
"title": "useDeviceInfo \u2014 return shape",
|
|
1129
|
-
"content": "useDeviceInfo() is a READ-ONLY hook (no action functions, no execute). Returns: { data: { model, manufacturer, platform, screenWidth, screenHeight, screenDensity, appInfo }, deviceInfo (=data, deprecated alias removed at 2.0), loading, error, isWeb, isNative, webFallbackActive, webFallbackDisabled, setWebFallback }. NOTE: error is a plain STRING here, not a standard error object — this stays a string until 2.0.\n\nThis is a NEW React hook (did not exist before \u2014 only WebBridge.getDeviceInfo() imperative method existed). Use useDeviceInfo() in React components instead of calling WebBridge.getDeviceInfo() imperatively.\n\nOn native: wraps WebBridge.getDeviceInfo() promise, resolves on ON_DEVICE_INFO_SUCCESS callback.\n\nWEB FALLBACK: Populates device info from browser APIs:\n- platform: navigator.platform or 'web'\n- model/manufacturer: derived from navigator.userAgent (best-effort)\n- screenWidth/Height: screen.width/height\n- screenDensity: window.devicePixelRatio\n- appInfo: null on web (no native app context)\n\nManages webFallback state locally (thin-state hook, not via useBaseHook).",
|
|
1129
|
+
"content": "useDeviceInfo() is a READ-ONLY hook (no action functions, no execute). Returns: { data: { model, manufacturer, platform, screenWidth, screenHeight, screenDensity, appInfo }, deviceInfo (=data, deprecated alias removed at 2.0), loading, error, isWeb, isNative, webFallbackActive, webFallbackDisabled, setWebFallback }. NOTE: error is a plain STRING here, not a standard error object — this stays a string until 2.0.\n\nThis is a NEW React hook (did not exist before \u2014 only WebBridge.getDeviceInfo() imperative method existed). Use useDeviceInfo() in React components instead of calling WebBridge.getDeviceInfo() imperatively.\n\nOn native: wraps WebBridge.getDeviceInfo() promise, resolves on ON_DEVICE_INFO_SUCCESS callback.\n\nWEB FALLBACK: Populates device info from browser APIs:\n- platform: navigator.platform or 'web'\n- model/manufacturer: derived from navigator.userAgent (best-effort)\n- screenWidth/Height: screen.width/height\n- screenDensity: window.devicePixelRatio\n- appVersion/appInfo: null on web (no native app context)\n\nManages webFallback state locally (thin-state hook, not via useBaseHook).",
|
|
1130
1130
|
"layer": "Runtime",
|
|
1131
1131
|
"source": "static",
|
|
1132
1132
|
"tags": [
|
|
@@ -1177,7 +1177,7 @@
|
|
|
1177
1177
|
{
|
|
1178
1178
|
"section": "native_hooks",
|
|
1179
1179
|
"title": "Native hooks \u2014 aliases and deprecations (removed at 2.0)",
|
|
1180
|
-
"content": "Alias keys kept from earlier releases. Both names work and return the same value. ALL ALIASES ARE REMOVED AT 2.0 \u2014 write new code against the canonical key.\n\nALIAS -> CANONICAL:\n- isLoading -> loading (useCamera, useFilePicker, useIntent, useCameraPermission, useNotificationPermission)\n- transitioning -> loading (useNativeTransition)\n- deviceInfo -> data (useDeviceInfo)\n- permission -> data (useCameraPermission, useNotificationPermission)\n- request -> execute (useCameraPermission)\n\nuseNotification.execute and useNotification.schedule both alias scheduleLocal. They are frozen for backward compatibility but DISCOURAGED, and they are explicitly NOT the pattern to copy for multi-action hooks \u2014 every other multi-action hook (useVideoStream, useDataProtection, useNativeTransition) has no execute key at all.\n\nERROR SHAPE EXCEPTIONS: error is a standard error object everywhere EXCEPT useDeviceInfo and useNetworkStatus, where it stays a plain string until 2.0. useNativeTransition and useSafeArea are error-exempt \u2014 no error key at all. useAI's shape is owned by the catalyst-ai package and sits outside this contract.\n\nDUAL SURFACES: requestHapticFeedback and requestCameraPermission exist BOTH as catalyst-core/hooks exports and as WebBridge methods, with different defaults and return types. requestHapticFeedback: hooks export defaults to 'light' and resolves the raw status string; WebBridge.requestHapticFeedback defaults to 'VIRTUAL_KEY' and resolves the parsed result object. requestCameraPermission: hooks export takes no arguments and REJECTS on denial; WebBridge.requestCameraPermission takes a config object ({ includeDetails }) and RESOLVES with the denied status. The hooks exports are SSR-safe (return Promise<null> when window is undefined). The two surfaces are unified at 2.0.",
|
|
1180
|
+
"content": "Alias keys kept from earlier releases. Both names work and return the same value. ALL ALIASES ARE REMOVED AT 2.0 \u2014 write new code against the canonical key.\n\nALIAS -> CANONICAL:\n- isLoading -> loading (useCamera, useFilePicker, useIntent, useCameraPermission, useNotificationPermission)\n- transitioning -> loading (useNativeTransition)\n- deviceInfo -> data (useDeviceInfo)\n- permission -> data (useCameraPermission, useNotificationPermission)\n- request -> execute (useCameraPermission)\n- photo -> data (useCamera)\n- clearPhoto -> clear (useCamera)\n- clearFile -> clear (useFilePicker)\n- reset -> clear (useIntent)\n\nuseNotification.execute and useNotification.schedule both alias scheduleLocal. They are frozen for backward compatibility but DISCOURAGED, and they are explicitly NOT the pattern to copy for multi-action hooks \u2014 every other multi-action hook (useVideoStream, useDataProtection, useNativeTransition) has no execute key at all. With useNotification.execute and schedule, the list above is the complete set of 16 aliases as of 1.0.0; every one carries an @deprecated marker in the shipped type declarations.\n\nERROR SHAPE EXCEPTIONS: error is a standard error object everywhere EXCEPT useDeviceInfo and useNetworkStatus, where it stays a plain string until 2.0. useNativeTransition and useSafeArea are error-exempt \u2014 no error key at all. useAI's shape is owned by the catalyst-ai package and sits outside this contract.\n\nDUAL SURFACES: requestHapticFeedback and requestCameraPermission exist BOTH as catalyst-core/hooks exports and as WebBridge methods, with different defaults and return types. requestHapticFeedback: hooks export defaults to 'light' and resolves the raw status string; WebBridge.requestHapticFeedback defaults to 'VIRTUAL_KEY' and resolves the parsed result object. requestCameraPermission: hooks export takes no arguments and REJECTS on denial; WebBridge.requestCameraPermission takes a config object ({ includeDetails }) and RESOLVES with the denied status. The hooks exports are SSR-safe (return Promise<null> when window is undefined). The two surfaces are unified at 2.0.",
|
|
1181
1181
|
"layer": "Runtime",
|
|
1182
1182
|
"source": "static",
|
|
1183
1183
|
"tags": [
|
|
@@ -1257,11 +1257,11 @@
|
|
|
1257
1257
|
{
|
|
1258
1258
|
"section": "framework_identity",
|
|
1259
1259
|
"title": "Catalyst Runtime Generations",
|
|
1260
|
-
"content": "Always determine the installed catalyst-core version before giving web runtime guidance. Catalyst 0.2.x is the legacy webpack generation and uses @tata1mg/router plus @loadable/component. Catalyst 0.3.x, beginning with 0.3.0-beta.1, is the Vite/ESM generation: router APIs are exported by catalyst-core and split()/hydrationReady() replace loadable APIs. Do not combine instructions from
|
|
1260
|
+
"content": "Always determine the installed catalyst-core version before giving web runtime guidance. Catalyst 0.2.x is the legacy webpack generation and uses @tata1mg/router plus @loadable/component. Catalyst 0.3.x, beginning with 0.3.0-beta.1, is the Vite/ESM generation: router APIs are exported by catalyst-core and split()/hydrationReady() replace loadable APIs. Catalyst 1.0.0 is the API freeze (there is no 0.4.0 release); see 'Upgrading catalyst-core 0.3.x to 1.0.0'. Do not combine instructions from different generations. If no version can be detected, ask which version the project targets.",
|
|
1261
1261
|
"layer": "Framework",
|
|
1262
1262
|
"source": "static",
|
|
1263
|
-
"tags": ["versions", "0.2.x", "0.3.x", "migration", "webpack", "vite"],
|
|
1264
|
-
"github_files": ["packages/catalyst-core/package.json", "packages/catalyst-core/src/index.
|
|
1263
|
+
"tags": ["versions", "0.2.x", "0.3.x", "1.0.0", "migration", "webpack", "vite"],
|
|
1264
|
+
"github_files": ["packages/catalyst-core/package.json", "packages/catalyst-core/src/index.tsx"]
|
|
1265
1265
|
},
|
|
1266
1266
|
{
|
|
1267
1267
|
"section": "build_system",
|
|
@@ -1303,12 +1303,12 @@
|
|
|
1303
1303
|
{
|
|
1304
1304
|
"section": "routing",
|
|
1305
1305
|
"title": "Catalyst 0.3.x Integrated Router",
|
|
1306
|
-
"content": "Catalyst 0.3.x removes the @tata1mg/router package dependency. As of
|
|
1306
|
+
"content": "Catalyst 0.3.x removes the @tata1mg/router package dependency. As of 1.0.0 (the API freeze), catalyst-core does NOT re-export React Router. Its root entry exports exactly eight names: RouterDataProvider, useCurrentRouteData, useRouterData, MetaTag, split, hydrationReady, Head, Body. There is no default export (split was previously also the default). React Router is a peerDependency (^7.18.2): install react-router in the application and import RouterProvider, Outlet, Link, useParams, useNavigate, useLocation, Navigate and every other router name from 'react-router' directly. Metadata utilities (getMetaData, mergeHeadElements, deleteHeadTagsByDataAttribute), RouterContext, serverDataFetcher and useNavigateWithTransition are no longer public. Existing route arrays and preparedRoutes structure remain unchanged. Keeping both router packages can create duplicate runtime contracts and invalid React element errors.",
|
|
1307
1307
|
"layer": "Runtime",
|
|
1308
1308
|
"source": "static",
|
|
1309
1309
|
"tags": [
|
|
1310
1310
|
"0.3.x",
|
|
1311
|
-
"0.
|
|
1311
|
+
"1.0.0",
|
|
1312
1312
|
"router",
|
|
1313
1313
|
"react-router",
|
|
1314
1314
|
"peer-dependency",
|
|
@@ -1317,7 +1317,7 @@
|
|
|
1317
1317
|
"api-freeze"
|
|
1318
1318
|
],
|
|
1319
1319
|
"github_files": [
|
|
1320
|
-
"packages/catalyst-core/src/index.
|
|
1320
|
+
"packages/catalyst-core/src/index.tsx",
|
|
1321
1321
|
"packages/catalyst-core/src/web-router/components/RouterDataProvider.jsx"
|
|
1322
1322
|
]
|
|
1323
1323
|
},
|
|
@@ -1373,5 +1373,59 @@
|
|
|
1373
1373
|
"layer": "Runtime",
|
|
1374
1374
|
"source": "static",
|
|
1375
1375
|
"tags": ["known-error", "0.3.x", "offline", "start", "build", "serve"]
|
|
1376
|
+
},
|
|
1377
|
+
{
|
|
1378
|
+
"section": "version_migration",
|
|
1379
|
+
"title": "Upgrading catalyst-core 0.3.x to 1.0.0",
|
|
1380
|
+
"content": "Upgrade path for an application on catalyst-core 0.3.0-beta.5. Older applications first move to 0.3.x (see 'Legacy 0.2.x Migration Phase 0' and 'Catalyst 0.3.x React Runtime Contract'). 1.0.0 is the API freeze; there is no 0.4.0 release. Do the steps in order.\n\n1. DEPENDENCIES: set catalyst-core to 1.0.0. Add react-router ^7.18.2 as an application dependency: it is now a peer dependency and the server throws at startup if it is missing or outside that range. Keep react and react-dom pinned to 19.0.0. TypeScript applications also need @types/react ^19.0.0.\n\n2. NODE: run node -v. catalyst-core 1.0.0 requires >=22.12; on Node 20, importing catalyst-core/hooks or catalyst-core/WebBridge fails with ERR_REQUIRE_ESM. If the runtime is older, stop and tell the user; do not change the project's Node pin yourself.\n\n3. IMPORTS: the root entry exports exactly RouterDataProvider, useCurrentRouteData, useRouterData, MetaTag, split, hydrationReady, Head, Body. Move every React Router name (Link, Outlet, RouterProvider, useParams, useNavigate, useLocation, Navigate, ...) from 'catalyst-core' to 'react-router'. Replace `import split from 'catalyst-core'` with `import { split } from 'catalyst-core'`; there is no default export. Replace imports from 'catalyst-core/document' with Head and Body from 'catalyst-core'. 'catalyst-core/caching' is removed with no replacement. RouterContext, serverDataFetcher, mergeHeadElements, deleteHeadTagsByDataAttribute, getMetaData, useNavigateWithTransition and sanitizeFilePickerOptions (catalyst-core/hooks) are internal with no replacement: if the application uses one, stop and tell the user instead of inventing a substitute.\n\n4. BUILD AND START: run the build, then start the server once. The build catches removed imports (they fail instead of resolving to undefined); startup catches the react-router range and the Node version.\n\n5. HOOK ERROR FIELDS (not caught by the build): hook errors are now CatalystError instances. Rename reads of error.action to error.suggestedAction and error.nativeError to error.cause; error.recoverable and error.timestamp no longer exist. error.code values are registry codes (RUNTIME-NATIVE-xxx) instead of names like PERMISSION_DENIED, so replace string-literal comparisons with ERROR_CODES from catalyst-core/errors (for example ERROR_CODES.RUNTIME_NATIVE_PERMISSION_DENIED). See 'CatalystError shape (1.0.0)'.\n\n6. OPTIONAL, NON-BREAKING: rename deprecated hook alias keys to the canonical ones (see 'Native hooks \u2014 aliases and deprecations'); aliases keep working until 2.0.\n\nUnchanged: route arrays, preparedRoutes, server hooks, config/config.json keys and module aliases. Full guide: docs/content/12-Migration/02-Version-Upgrades.md.",
|
|
1381
|
+
"layer": "Framework",
|
|
1382
|
+
"source": "static",
|
|
1383
|
+
"tags": [
|
|
1384
|
+
"migration",
|
|
1385
|
+
"migrate",
|
|
1386
|
+
"upgrade",
|
|
1387
|
+
"update",
|
|
1388
|
+
"bump",
|
|
1389
|
+
"1.0.0",
|
|
1390
|
+
"0.3.x",
|
|
1391
|
+
"breaking-changes",
|
|
1392
|
+
"api-freeze",
|
|
1393
|
+
"react-router",
|
|
1394
|
+
"peer-dependency",
|
|
1395
|
+
"peerDependency",
|
|
1396
|
+
"node"
|
|
1397
|
+
],
|
|
1398
|
+
"github_files": ["docs/content/12-Migration/02-Version-Upgrades.md"]
|
|
1399
|
+
},
|
|
1400
|
+
{
|
|
1401
|
+
"section": "known_errors",
|
|
1402
|
+
"title": "ERR_REQUIRE_ESM importing catalyst-core/hooks on Node 20",
|
|
1403
|
+
"content": "Symptom: importing catalyst-core/hooks or catalyst-core/WebBridge throws ERR_REQUIRE_ESM on Node 20. Cause: the CommonJS native bridge require()s the ESM error registry, which older Node runtimes refuse without a flag; the package's engines field sets the supported minimum. Fix: run Node 22.12 or newer (catalyst-core 1.0.0 declares engines node >=22.12). Do not change the project's Node pin without telling the user.",
|
|
1404
|
+
"layer": "Runtime",
|
|
1405
|
+
"source": "static",
|
|
1406
|
+
"tags": ["1.0.0", "node", "22.12", "ERR_REQUIRE_ESM", "error", "hooks", "WebBridge"]
|
|
1407
|
+
},
|
|
1408
|
+
{
|
|
1409
|
+
"section": "native_hooks",
|
|
1410
|
+
"title": "CatalystError shape (1.0.0)",
|
|
1411
|
+
"content": "From 1.0.0, hook failures are CatalystError instances (class exported from catalyst-core/errors) with fields code, message, category, suggestedAction, docUrl, details and cause (the originating platform error). code is a registry code such as RUNTIME-NATIVE-001; compare against ERROR_CODES from catalyst-core/errors (ERROR_CODES.RUNTIME_NATIVE_PERMISSION_DENIED and so on), never against string literals.\n\nCHANGED FROM 0.3.x: the error used to be a plain object { code, category, message, details, recoverable, action, nativeError, timestamp } with code values like PERMISSION_DENIED. action is now suggestedAction, nativeError is now cause, recoverable and timestamp are gone, and code values changed. These renames are not caught by a build.\n\nCatalystError extends Error, so message is non-enumerable: JSON.stringify(error) omits it. Log error.message explicitly or use code and docUrl. Render error.message in JSX, never the error object. Exceptions to the object shape (string errors, error-exempt hooks) are listed under 'Native hooks \u2014 aliases and deprecations'.",
|
|
1412
|
+
"layer": "Runtime",
|
|
1413
|
+
"source": "static",
|
|
1414
|
+
"tags": [
|
|
1415
|
+
"1.0.0",
|
|
1416
|
+
"CatalystError",
|
|
1417
|
+
"error",
|
|
1418
|
+
"error-shape",
|
|
1419
|
+
"suggestedAction",
|
|
1420
|
+
"cause",
|
|
1421
|
+
"ERROR_CODES",
|
|
1422
|
+
"RUNTIME-NATIVE",
|
|
1423
|
+
"JSON.stringify",
|
|
1424
|
+
"native-hooks"
|
|
1425
|
+
],
|
|
1426
|
+
"github_files": [
|
|
1427
|
+
"packages/catalyst-core/src/errors/index.js",
|
|
1428
|
+
"packages/catalyst-core/src/native/bridge/errors.ts"
|
|
1429
|
+
]
|
|
1376
1430
|
}
|
|
1377
1431
|
]
|
package/mcp_v2/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -13,13 +13,10 @@ import { ERROR_CODES } from "../../src/errors/registry.js"
|
|
|
13
13
|
const VALID_CONFIG = {
|
|
14
14
|
NODE_SERVER_HOSTNAME: "localhost",
|
|
15
15
|
NODE_SERVER_PORT: 3000,
|
|
16
|
-
WEBPACK_DEV_SERVER_HOSTNAME: "localhost",
|
|
17
|
-
WEBPACK_DEV_SERVER_PORT: 3001,
|
|
18
16
|
BUILD_OUTPUT_PATH: "build",
|
|
19
17
|
PUBLIC_STATIC_ASSET_PATH: "/assets/",
|
|
20
18
|
PUBLIC_STATIC_ASSET_URL: "http://localhost:3000",
|
|
21
19
|
CLIENT_ENV_VARIABLES: [],
|
|
22
|
-
ANALYZE_BUNDLE: false,
|
|
23
20
|
}
|
|
24
21
|
const VALID_PKG = {
|
|
25
22
|
name: "fixture-app",
|
|
@@ -113,7 +113,6 @@ beforeEach(() => {
|
|
|
113
113
|
process.env.src_path = path.dirname(buildDir)
|
|
114
114
|
process.env.BUILD_OUTPUT_PATH = path.basename(buildDir)
|
|
115
115
|
process.env.APPLICATION = "test"
|
|
116
|
-
process.env.IS_DEV_COMMAND = "false"
|
|
117
116
|
process.env.PUBLIC_STATIC_ASSET_URL = "http://localhost"
|
|
118
117
|
process.env.PUBLIC_STATIC_ASSET_PATH = "/assets/"
|
|
119
118
|
vi.spyOn(console, "error").mockImplementation(() => {})
|
|
@@ -82,13 +82,11 @@ function makeReqRes(url = "/") {
|
|
|
82
82
|
|
|
83
83
|
// Set the env handler.jsx + its render helpers read at module load /
|
|
84
84
|
// render time before the first import. In production these are always set
|
|
85
|
-
// by serve.js / start.js
|
|
86
|
-
// (`JSON.parse(IS_DEV_COMMAND)`) throw and the render promise hang.
|
|
85
|
+
// by serve.js / start.js.
|
|
87
86
|
beforeEach(() => {
|
|
88
87
|
process.env.src_path = process.cwd()
|
|
89
88
|
process.env.BUILD_OUTPUT_PATH = "build"
|
|
90
89
|
process.env.APPLICATION = "test"
|
|
91
|
-
process.env.IS_DEV_COMMAND = "false"
|
|
92
90
|
process.env.PUBLIC_STATIC_ASSET_URL = "http://localhost"
|
|
93
91
|
process.env.PUBLIC_STATIC_ASSET_PATH = "/assets/"
|
|
94
92
|
vi.spyOn(console, "error").mockImplementation(() => {})
|
|
@@ -4,13 +4,7 @@ import { renderEnd, renderStart } from "../../src/server/renderer/render.js"
|
|
|
4
4
|
|
|
5
5
|
// Pure prop-shaping helpers pulled in by handler.jsx (#348 coverage).
|
|
6
6
|
|
|
7
|
-
const ENV_KEYS = [
|
|
8
|
-
"IS_DEV_COMMAND",
|
|
9
|
-
"WEBPACK_DEV_SERVER_HOSTNAME",
|
|
10
|
-
"WEBPACK_DEV_SERVER_PORT",
|
|
11
|
-
"PUBLIC_STATIC_ASSET_URL",
|
|
12
|
-
"PUBLIC_STATIC_ASSET_PATH",
|
|
13
|
-
]
|
|
7
|
+
const ENV_KEYS = ["PUBLIC_STATIC_ASSET_URL", "PUBLIC_STATIC_ASSET_PATH"]
|
|
14
8
|
let saved: Record<string, string | undefined>
|
|
15
9
|
|
|
16
10
|
beforeEach(() => {
|
|
@@ -39,8 +33,7 @@ describe("renderStart", () => {
|
|
|
39
33
|
fetcherData: { "/": { data: 1 } },
|
|
40
34
|
}
|
|
41
35
|
|
|
42
|
-
it("passes props through and builds publicAssetPath from the PUBLIC_STATIC_ASSET_* env
|
|
43
|
-
process.env.IS_DEV_COMMAND = "false"
|
|
36
|
+
it("passes props through and builds publicAssetPath from the PUBLIC_STATIC_ASSET_* env", () => {
|
|
44
37
|
process.env.PUBLIC_STATIC_ASSET_URL = "https://cdn.example.com"
|
|
45
38
|
process.env.PUBLIC_STATIC_ASSET_PATH = "/static/"
|
|
46
39
|
|
|
@@ -54,18 +47,6 @@ describe("renderStart", () => {
|
|
|
54
47
|
expect(out.isBot).toBe(false)
|
|
55
48
|
expect(out.fetcherData).toEqual({ "/": { data: 1 } })
|
|
56
49
|
})
|
|
57
|
-
|
|
58
|
-
it("uses the webpack dev-server host/port for publicAssetPath when IS_DEV_COMMAND is true", () => {
|
|
59
|
-
process.env.IS_DEV_COMMAND = "true"
|
|
60
|
-
process.env.WEBPACK_DEV_SERVER_HOSTNAME = "localhost"
|
|
61
|
-
process.env.WEBPACK_DEV_SERVER_PORT = "8081"
|
|
62
|
-
process.env.PUBLIC_STATIC_ASSET_URL = "https://cdn.example.com"
|
|
63
|
-
process.env.PUBLIC_STATIC_ASSET_PATH = "/static/"
|
|
64
|
-
|
|
65
|
-
const out = renderStart(baseArgs)
|
|
66
|
-
|
|
67
|
-
expect(out.publicAssetPath).toBe("http://localhost:8081/assets/")
|
|
68
|
-
})
|
|
69
50
|
})
|
|
70
51
|
|
|
71
52
|
describe("renderEnd", () => {
|
|
@@ -23,13 +23,10 @@ import { createError } from "../../src/errors/index.js"
|
|
|
23
23
|
const VALID_CONFIG = {
|
|
24
24
|
NODE_SERVER_HOSTNAME: "localhost",
|
|
25
25
|
NODE_SERVER_PORT: 3000,
|
|
26
|
-
WEBPACK_DEV_SERVER_HOSTNAME: "localhost",
|
|
27
|
-
WEBPACK_DEV_SERVER_PORT: 3001,
|
|
28
26
|
BUILD_OUTPUT_PATH: "build",
|
|
29
27
|
PUBLIC_STATIC_ASSET_PATH: "/assets/",
|
|
30
28
|
PUBLIC_STATIC_ASSET_URL: "http://localhost:3000",
|
|
31
29
|
CLIENT_ENV_VARIABLES: [],
|
|
32
|
-
ANALYZE_BUNDLE: false,
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
const VALID_ALIASES = {
|