@octanejs/app-core 0.0.43 → 0.0.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@octanejs/app-core",
3
- "version": "0.0.43",
3
+ "version": "0.0.45",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "engines": {
@@ -79,10 +79,10 @@
79
79
  "esbuild": "^0.28.1"
80
80
  },
81
81
  "peerDependencies": {
82
- "octane": "0.1.47"
82
+ "octane": "0.1.49"
83
83
  },
84
84
  "devDependencies": {
85
85
  "@types/node": "^24.13.3",
86
- "octane": "0.1.47"
86
+ "octane": "0.1.49"
87
87
  }
88
88
  }
@@ -177,6 +177,9 @@ export function resolveOctaneConfig(raw, options = {}) {
177
177
  if (raw.compiler?.strong !== undefined && typeof raw.compiler.strong !== 'boolean') {
178
178
  throw new Error('[octane] compiler.strong must be a boolean when provided.');
179
179
  }
180
+ if (raw.compiler?.nativeReads !== undefined && typeof raw.compiler.nativeReads !== 'boolean') {
181
+ throw new Error('[octane] compiler.nativeReads must be a boolean when provided.');
182
+ }
180
183
 
181
184
  if (raw.router?.routes !== undefined && !Array.isArray(raw.router.routes)) {
182
185
  throw new Error('[octane] router.routes must be an array.');
@@ -236,6 +239,7 @@ export function resolveOctaneConfig(raw, options = {}) {
236
239
  adapter: raw.adapter,
237
240
  compiler: {
238
241
  strong: raw.compiler?.strong ?? false,
242
+ nativeReads: raw.compiler?.nativeReads ?? false,
239
243
  renderers: normalizeRendererConfig(raw.compiler?.renderers),
240
244
  },
241
245
  router: {
@@ -14,20 +14,20 @@
14
14
  /**
15
15
  * @typedef {Object} CompiledRoute
16
16
  * @property {Route} route
17
- * @property {RegExp} pattern
17
+ * @property {string | RegExp} pattern
18
18
  * @property {string[]} paramNames
19
19
  * @property {number} specificity - Higher = more specific (static > param > catch-all)
20
20
  */
21
21
 
22
22
  /**
23
- * Convert a route path pattern to a RegExp
23
+ * Compile a route path into an exact string or capturing RegExp
24
24
  * Supports:
25
25
  * - Static segments: /about, /api/hello
26
26
  * - Named params: /posts/:id, /users/:userId/posts/:postId
27
27
  * - Catch-all: /docs/*slug
28
28
  *
29
29
  * @param {string} path
30
- * @returns {{ pattern: RegExp, paramNames: string[], specificity: number }}
30
+ * @returns {{ pattern: string | RegExp, paramNames: string[], specificity: number }}
31
31
  */
32
32
  function compilePath(path) {
33
33
  /** @type {string[]} */
@@ -62,7 +62,9 @@ function compilePath(path) {
62
62
  })
63
63
  .join('/');
64
64
 
65
- const pattern = new RegExp(`^${regexString || '/'}$`);
65
+ // Static paths are already exact matchers. Keep RegExp capture work for the
66
+ // parameter and catch-all routes that need it.
67
+ const pattern = paramNames.length === 0 ? path || '/' : new RegExp(`^${regexString || '/'}$`);
66
68
  return { pattern, paramNames, specificity };
67
69
  }
68
70
 
@@ -98,24 +100,30 @@ export function createRouter(routes) {
98
100
  * @returns {RouteMatch | null}
99
101
  */
100
102
  match(method, pathname) {
103
+ let normalizedMethod;
101
104
  for (const { route, pattern, paramNames } of compiledRoutes) {
102
105
  // Check method for ServerRoute
103
106
  if (route.type === 'server') {
104
107
  const methods = /** @type {ServerRoute} */ (route).methods;
105
- if (!methods.includes(method.toUpperCase())) {
108
+ normalizedMethod ??= method.toUpperCase();
109
+ if (!methods.includes(normalizedMethod)) {
106
110
  continue;
107
111
  }
108
112
  }
109
113
 
114
+ if (typeof pattern === 'string') {
115
+ if (pathname === pattern) return { route, params: {} };
116
+ continue;
117
+ }
118
+
110
119
  const match = pathname.match(pattern);
111
- if (match) {
112
- /** @type {Record<string, string>} */
113
- const params = {};
114
- for (let i = 0; i < paramNames.length; i++) {
115
- params[paramNames[i]] = decodeURIComponent(match[i + 1]);
116
- }
117
- return { route, params };
120
+ if (!match) continue;
121
+ /** @type {Record<string, string>} */
122
+ const params = {};
123
+ for (let i = 0; i < paramNames.length; i++) {
124
+ params[paramNames[i]] = decodeURIComponent(match[i + 1]);
118
125
  }
126
+ return { route, params };
119
127
  }
120
128
  return null;
121
129
  },
package/types/index.d.ts CHANGED
@@ -393,8 +393,10 @@ export interface OctaneConfigOptions {
393
393
  adapter?: OctaneAdapter;
394
394
  /** @experimental Compiler-owned configuration shared by all bundler integrations. */
395
395
  compiler?: {
396
- /** Reject unsafe state updates and ref writes in application-owned modules. @default false */
396
+ /** Assert pure immutable-snapshot renders and reject detectable violations. @default false */
397
397
  strong?: boolean;
398
+ /** Experimental native signal reads in DOM client/server render scopes. */
399
+ nativeReads?: boolean;
398
400
  renderers?: ExperimentalRendererConfigOptions;
399
401
  };
400
402
  router?: {
@@ -456,6 +458,7 @@ export interface ResolvedOctaneConfig {
456
458
  compiler: {
457
459
  /** @default false */
458
460
  strong: boolean;
461
+ nativeReads: boolean;
459
462
  renderers: ExperimentalResolvedRendererConfig;
460
463
  };
461
464
  router: {