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 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.4.0] - unreleased
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-12
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-19
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-19
219
+ ## [0.0.3-canary.17] - 2025-11-21
158
220
 
159
- - ✨ Added complete notification system (local & push)
160
- - 🔔 New useNotification() React hook
161
- - 📱 Firebase Cloud Messaging conditional build support
162
- - 🤖 Android notification handling in MainActivity
163
- - 🔧 5 new notification commands + 5 callbacks in NativeBridge
164
- - 📦 Auto-processing of notification icons & sounds
165
- - ⚙️ Conditional dependencies based on notification config
166
- - 🧹 Updated .gitignore & .npmignore
167
- - 📋 Enhanced build process with automatic permission injection
168
- - 🔗 Deep link integration with notifications
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-19
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-09-29
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-09-28
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-09-26
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-11
263
+ ## [0.0.3-canary.10] - 2025-09-17
202
264
 
203
- - **Sentry import bug fix**
204
- - **Open telemetry SDK**
265
+ - Sentry import bug fix.
266
+ - Open telemetry SDK.
205
267
 
206
268
  ## [0.0.3-canary.9] - 2025-09-11
207
269
 
208
- - **App name configuration**
209
- - **Device Info API**
210
- - **Access control configuration**
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.7] - 2025-01-06
274
+ ## [0.0.3-canary.8] - 2025-08-08
219
275
 
220
- ### 🚀 Features
276
+ - App icon configuration.
277
+ - Splash screen integration.
278
+ - Url Whitelisting.
221
279
 
222
- - **Native API Integration**: Enhanced native module integration for better performance
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
- ### 🔧 Improvements
234
-
235
- - **Performance**: Optimized native module loading and execution
236
- - **Developer Experience**: Enhanced CLI with better error messages and debugging info
237
- - **Configuration**: Dynamic config updates without requiring restarts
238
- - **Build Process**: Faster and more reliable build pipeline
239
-
240
- ### 🧪 Testing & Validation
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
@@ -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
  ]),
@@ -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", "WEBPACK_DEV_SERVER_HOSTNAME", "WEBPACK_DEV_SERVER_PORT", "BUILD_OUTPUT_PATH", "PUBLIC_STATIC_ASSET_PATH", "PUBLIC_STATIC_ASSET_URL", "CLIENT_ENV_VARIABLES", "ANALYZE_BUNDLE"];
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), WEBPACK_DEV_SERVER_HOSTNAME (string), WEBPACK_DEV_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), ANALYZE_BUNDLE (boolean). 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, WEBPACK_DEV_SERVER_HOSTNAME: 'localhost', WEBPACK_DEV_SERVER_PORT: 3001, BUILD_OUTPUT_PATH: 'build', PUBLIC_STATIC_ASSET_PATH: '/assets/', PUBLIC_STATIC_ASSET_URL: 'https://cdn.example.com', CLIENT_ENV_VARIABLES: ['API_URL'], ANALYZE_BUNDLE: false }",
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/scripts/validator.js",
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 THREE 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.",
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/scripts/validator.js",
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\nTHREE 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).",
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 the two generations. If no version can be detected, ask which version the project targets.",
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.jsx"]
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 the 0.4.0 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 Outlet, Link, useParams, useNavigate, useLocation, Navigate and every other router name from 'react-router' directly. The one exception is RouterProvider: client/index.js imports it from 'react-router/dom', the DOM build that wires ReactDOM.flushSync into the router (the 'react-router' export renders the same tree but silently skips flushSync, so view transitions and flushSync navigations degrade). 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.",
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.4.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.jsx",
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
@@ -436,6 +436,7 @@ const TOOLS = [
436
436
  "seo_metadata",
437
437
  "transport_architecture",
438
438
  "webview_config",
439
+ "version_migration",
439
440
  ],
440
441
  description:
441
442
  "Optional: only pass when you are certain of the section. Omit if unsure — wrong section returns zero results.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "catalyst-core",
3
- "version": "0.3.0-canary.1",
3
+ "version": "0.3.0-canary.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.jsx",
6
6
  "description": "Web framework that provides great performance out of the box",
@@ -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; unset here they'd make render.js:18
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 (prod branch)", () => {
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 = {