@ilha/router 0.11.0 → 0.11.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.
@@ -1,4 +1,4 @@
1
- import { C as runWithIslandRequest, a as authorizeFrameRequest, b as setFrameAuth, c as frameScopedUrl, f as isSafeFramePath, h as parseFrameProps, n as FrameError, s as frameEnvelope, u as getFrameGuard, x as setFrameGuard, y as renderServerIslandResult } from "./ssr-WA3bSsCo.js";
1
+ import { C as runWithIslandRequest, a as authorizeFrameRequest, b as setFrameAuth, c as frameScopedUrl, f as isSafeFramePath, h as parseFrameProps, n as FrameError, s as frameEnvelope, u as getFrameGuard, x as setFrameGuard, y as renderServerIslandResult } from "./ssr-CV_vNpS3.js";
2
2
  import { existsSync, readFileSync, statSync, watch } from "node:fs";
3
3
  import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
4
4
  import * as Result from "effect/Result";
@@ -8,6 +8,22 @@ import { createHash } from "node:crypto";
8
8
 
9
9
  //#region src/server-islands.ts
10
10
  /**
11
+ * Build-time support for server-defined islands. The plugin scans
12
+ * `*.server.ts(x)` modules for island exports (`export const X = ilha…`),
13
+ * generates a client virtual module per file that re-creates those exports as
14
+ * proxies wired to tacho stubs, and rewrites client-graph import sites so
15
+ * island bindings resolve to the proxy while everything else keeps flowing
16
+ * through oxidejs's tacho stub replacement.
17
+ */
18
+ /** Oxide RPC client key — basename without `.server.*` (oxide indexes by module name). */
19
+ function serverModuleRpcKey(spec) {
20
+ return basename(spec).replace(/\.server\.(?:[jt]sx?)$/i, "");
21
+ }
22
+ /** Client repaint group key — full normalized path so same-basename files stay distinct. */
23
+ function serverModuleRepaintKey(spec) {
24
+ return spec.replace(/\\/g, "/").replace(/\.server\.(?:[jt]sx?)$/i, "");
25
+ }
26
+ /**
11
27
  * Replace identity `action(` wrappers of exported server actions with the
12
28
  * capture-aware shim on ALREADY-COMPILED module code. Must run inside the
13
29
  * SSR transform so upstream JSX/TS output is preserved.
@@ -165,11 +181,12 @@ function serverIslandPublicId(spec, name) {
165
181
  return createHash("sha256").update(`${spec}#${name}`).digest("base64url");
166
182
  }
167
183
  function generateServerIslandModule(spec, scan) {
168
- const moduleKey = basename(spec).replace(/\.server\.(?:[jt]sx?)$/i, "");
184
+ const rpcKey = serverModuleRpcKey(spec);
185
+ const repaintKey = serverModuleRepaintKey(spec);
169
186
  const lines = [
170
187
  `import { client as $$rpc } from "virtual:oxide/client";`,
171
188
  `import { __ilhaApplyHead, __ilhaServerIsland } from "@ilha/router/server-island";`,
172
- `const $$call = (method, args) => { const opts = args.at(-1); return opts && typeof opts === "object" && opts.signal instanceof AbortSignal && Object.keys(opts).length === 1 ? $$rpc[${JSON.stringify(moduleKey)}][method](args.slice(0, -1), opts) : $$rpc[${JSON.stringify(moduleKey)}][method](args); };`,
189
+ `const $$call = (method, args) => { const opts = args.at(-1); return opts && typeof opts === "object" && opts.signal instanceof AbortSignal && Object.keys(opts).length === 1 ? $$rpc[${JSON.stringify(rpcKey)}][method](...args.slice(0, -1), opts) : $$rpc[${JSON.stringify(rpcKey)}][method](...args); };`,
173
190
  ...scan.clientRefs.map((ref, index) => ref.imported === "default" ? `import $$child${index} from ${JSON.stringify(ref.spec)};` : `import { ${ref.imported} as $$child${index} } from ${JSON.stringify(ref.spec)};`)
174
191
  ];
175
192
  for (const name of scan.exports) if (!scan.islands.some((island) => island.name === name)) lines.push(`export const ${name} = (...args) => $$call(${JSON.stringify(name)}, args);`);
@@ -186,7 +203,7 @@ function generateServerIslandModule(spec, scan) {
186
203
  if (scan.clientRefs.length) wiring.push(`children: { ${scan.clientRefs.map((ref, index) => `${JSON.stringify(ref.id)}: $$child${index}`).join(", ")} }`);
187
204
  const id = serverIslandPublicId(spec, island.name);
188
205
  wiring.push(`frame: (props) => fetch("/__ilha/frame", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ id: ${JSON.stringify(id)}, path: location.pathname + location.search, props }) }).then((r) => { if (!r.ok) throw new Error("frame failed"); return r.json(); }).then((j) => { if (j.redirect) { try { const u = new URL(j.redirect, location.href); if (u.origin === location.origin) location.assign(u.pathname + u.search + u.hash); } catch {} throw new Error("frame redirected"); } __ilhaApplyHead(j.head); return j.html; })`);
189
- const call = `__ilhaServerIsland(${JSON.stringify(id)}, ${JSON.stringify(island.as)}, { ${wiring.join(", ")} })`;
206
+ const call = `__ilhaServerIsland(${JSON.stringify(id)}, ${JSON.stringify(island.as)}, { ${wiring.join(", ")} }, ${JSON.stringify(repaintKey)})`;
190
207
  if (island.name === "default") lines.push(`export default ${call};`);
191
208
  else lines.push(`export const ${island.name} = ${call};`);
192
209
  }
package/dist/rsbuild.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as ilhaPages } from "./plugin-C3AAI3e_.js";
1
+ import { t as ilhaPages } from "./plugin-Bfnn44nu.js";
2
2
 
3
3
  //#region src/rsbuild.ts
4
4
  /** Rsbuild plugin — use via `@ilha/router/rsbuild`. */
@@ -15,6 +15,8 @@
15
15
  * `data-ilha-actions` manifest emitted by `hydratable()`.
16
16
  */
17
17
  declare const ISLAND_CALL: unique symbol;
18
+ /** @internal Repaint every mounted island from the same `*.server` module. */
19
+ export declare function __ilhaRepaintServerModule(moduleKey: string): void;
18
20
  export type ServerStreamFn = (signal: AbortSignal) => AsyncGenerator<unknown> | Generator<unknown>;
19
21
  export interface ServerIslandWiring {
20
22
  /** Stream key → client transport. The plugin wires these to tacho stubs. */
@@ -52,5 +54,5 @@ export type ServerIslandCallable = Record<symbol, unknown> & ((props?: Record<st
52
54
  toString: () => string;
53
55
  key: (slotKey: string) => (props?: Record<string, unknown>) => IslandCallShape;
54
56
  };
55
- export declare function __ilhaServerIsland(id: string, as: string, wiring?: ServerIslandWiring): ServerIslandCallable;
57
+ export declare function __ilhaServerIsland(id: string, as: string, wiring?: ServerIslandWiring, moduleKey?: string): ServerIslandCallable;
56
58
  export {};
@@ -27,6 +27,23 @@ const EVENT_SENTINEL_ATTR = "data-ilha-on";
27
27
  const ACTIONS_ATTR = "data-ilha-actions";
28
28
  const PROPS_ATTR = "data-ilha-props";
29
29
  const CLIENT_REF_ATTR = "data-ilha-client-ref";
30
+ const moduleRepaints = /* @__PURE__ */ new Map();
31
+ /** @internal Repaint every mounted island from the same `*.server` module. */
32
+ function __ilhaRepaintServerModule(moduleKey) {
33
+ for (const repaint of moduleRepaints.get(moduleKey) ?? []) repaint();
34
+ }
35
+ function linkServerModuleRepaints(moduleKey, repaint) {
36
+ let set = moduleRepaints.get(moduleKey);
37
+ if (!set) {
38
+ set = /* @__PURE__ */ new Set();
39
+ moduleRepaints.set(moduleKey, set);
40
+ }
41
+ set.add(repaint);
42
+ return () => {
43
+ set.delete(repaint);
44
+ if (set.size === 0) moduleRepaints.delete(moduleKey);
45
+ };
46
+ }
30
47
  /** @internal Apply head entries returned with a server-page frame. */
31
48
  function __ilhaApplyHead(entries) {
32
49
  if (Array.isArray(entries)) applyHeadEntriesToDocument(entries);
@@ -85,7 +102,7 @@ async function startServerStream(fn, signal) {
85
102
  }
86
103
  throw last;
87
104
  }
88
- function hydrateServerIsland(host, id, wiring, props) {
105
+ function hydrateServerIsland(host, id, wiring, props, moduleKey) {
89
106
  const controller = new AbortController();
90
107
  const cleanups = [];
91
108
  cleanups.push(() => controller.abort());
@@ -115,6 +132,11 @@ function hydrateServerIsland(host, id, wiring, props) {
115
132
  if (!controller.signal.aborted) console.error(`[ilha-router] frame render failed for "${id}":`, err);
116
133
  });
117
134
  };
135
+ const repaintModule = () => {
136
+ if (moduleKey) __ilhaRepaintServerModule(moduleKey);
137
+ else scheduleRepaint();
138
+ };
139
+ if (moduleKey) cleanups.push(linkServerModuleRepaints(moduleKey, scheduleRepaint));
118
140
  const attached = [];
119
141
  const readManifest = () => {
120
142
  const raw = host.querySelector(`:scope > template[${ACTIONS_ATTR}], template[${ACTIONS_ATTR}]`)?.getAttribute(ACTIONS_ATTR) ?? host.getAttribute(ACTIONS_ATTR) ?? null;
@@ -145,7 +167,7 @@ function hydrateServerIsland(host, id, wiring, props) {
145
167
  const action = actionKey == null ? void 0 : wiring.actions?.[actionKey];
146
168
  if (!action) continue;
147
169
  const listener = () => {
148
- Promise.resolve(action(...callArgs)).then(() => scheduleRepaint()).catch((err) => {
170
+ Promise.resolve(action(...callArgs)).then(() => repaintModule()).catch((err) => {
149
171
  console.error(`[ilha-router] action "${String(actionKey)}" failed:`, err);
150
172
  });
151
173
  };
@@ -170,7 +192,7 @@ function hydrateServerIsland(host, id, wiring, props) {
170
192
  if (!action) continue;
171
193
  const args = Array.isArray(marker.a) ? marker.a : [];
172
194
  props[key] = (..._runtimeArgs) => Promise.resolve(action(...args)).then((result) => {
173
- scheduleRepaint();
195
+ repaintModule();
174
196
  return result;
175
197
  });
176
198
  }
@@ -204,7 +226,7 @@ function hydrateServerIsland(host, id, wiring, props) {
204
226
  const { done, value } = step;
205
227
  if (controller.signal.aborted || done) break;
206
228
  state[key] = value;
207
- scheduleRepaint();
229
+ repaintModule();
208
230
  step = await gen.next();
209
231
  }
210
232
  } catch (err) {
@@ -232,7 +254,7 @@ function hydrateServerIsland(host, id, wiring, props) {
232
254
  }
233
255
  };
234
256
  }
235
- function __ilhaServerIsland(id, as, wiring = {}) {
257
+ function __ilhaServerIsland(id, as, wiring = {}, moduleKey) {
236
258
  const slotTag = assertValidTag(as);
237
259
  const island = ((props) => {
238
260
  return "";
@@ -250,10 +272,10 @@ function __ilhaServerIsland(id, as, wiring = {}) {
250
272
  key: slotKey
251
273
  });
252
274
  };
253
- island[ISLAND_MOUNT_INTERNAL] = (host, mountProps) => hydrateServerIsland(host, id, wiring, mountProps);
254
- island.mount = (host, mountProps) => hydrateServerIsland(host, id, wiring, mountProps).unmount;
275
+ island[ISLAND_MOUNT_INTERNAL] = (host, mountProps) => hydrateServerIsland(host, id, wiring, mountProps, moduleKey);
276
+ island.mount = (host, mountProps) => hydrateServerIsland(host, id, wiring, mountProps, moduleKey).unmount;
255
277
  return island;
256
278
  }
257
279
 
258
280
  //#endregion
259
- export { __ilhaApplyHead, __ilhaServerIsland };
281
+ export { __ilhaApplyHead, __ilhaRepaintServerModule, __ilhaServerIsland };
@@ -6,6 +6,10 @@
6
6
  * island bindings resolve to the proxy while everything else keeps flowing
7
7
  * through oxidejs's tacho stub replacement.
8
8
  */
9
+ /** Oxide RPC client key — basename without `.server.*` (oxide indexes by module name). */
10
+ export declare function serverModuleRpcKey(spec: string): string;
11
+ /** Client repaint group key — full normalized path so same-basename files stay distinct. */
12
+ export declare function serverModuleRepaintKey(spec: string): string;
9
13
  export interface ScannedServerIsland {
10
14
  /** Export binding name, or `"default"` for `export default ilha…`. */
11
15
  name: string;
@@ -5,6 +5,7 @@ import * as Result from "effect/Result";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  import * as Data from "effect/Data";
7
7
  import * as Effect from "effect/Effect";
8
+ import { action, brandServerAction } from "oxidejs";
8
9
 
9
10
  //#region src/request-scope.ts
10
11
  /**
@@ -184,19 +185,10 @@ function frameEnvelope(status, body) {
184
185
  body: JSON.stringify(body)
185
186
  };
186
187
  }
187
- const ACTION_CALL = Symbol.for("ilha.actionCall");
188
188
  /** @internal Brand an exported server action with its generated RPC transport key. */
189
189
  function __ilhaServerAction(key, fn) {
190
- const wrapped = ((...args) => fn(...args));
191
- wrapped.with = (...args) => {
192
- const handler = ((..._ev) => wrapped(...args));
193
- handler[ACTION_CALL] = {
194
- k: key,
195
- a: args
196
- };
197
- return handler;
198
- };
199
- return wrapped;
190
+ const handle = typeof fn === "function" && fn.$$atom === 1 ? fn : action(fn);
191
+ return brandServerAction(key, handle);
200
192
  }
201
193
  function registerServerIsland(id, render) {
202
194
  registry().set(id, { render });
package/dist/ssr.d.ts CHANGED
@@ -110,9 +110,7 @@ export interface FrameEnvelope {
110
110
  }
111
111
  export declare function frameEnvelope(status: number, body: Record<string, unknown>): FrameEnvelope;
112
112
  /** @internal Brand an exported server action with its generated RPC transport key. */
113
- export declare function __ilhaServerAction<A extends unknown[], R>(key: string, fn: (...args: A) => R): ((...args: A) => R) & {
114
- with: (...args: A) => (...ev: unknown[]) => R;
115
- };
113
+ export declare function __ilhaServerAction<A extends unknown[], R>(key: string, fn: (...args: A) => R | Promise<R>): import("oxidejs").ServerActionHandle<A, Awaited<Awaited<R>>>;
116
114
  export declare function registerServerIsland(id: string, render: () => unknown): void;
117
115
  export declare function getServerIslandEntry(id: string): ServerIslandEntry | undefined;
118
116
  declare const FrameError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
package/dist/ssr.js CHANGED
@@ -1,3 +1,3 @@
1
- import { S as ssr, _ as registerServerIsland, a as authorizeFrameRequest, b as setFrameAuth, c as frameScopedUrl, d as getServerIslandEntry, f as isSafeFramePath, g as readBodyBounded, h as parseFrameProps, i as __ilhaServerAction, l as getFrameAuth, m as json, n as FrameError, o as forwardIdentityHeaders, p as isTrustedOrigin, r as MAX_BODY, s as frameEnvelope, t as FRAME_ENDPOINT, u as getFrameGuard, v as renderServerIsland, x as setFrameGuard, y as renderServerIslandResult } from "./ssr-WA3bSsCo.js";
1
+ import { S as ssr, _ as registerServerIsland, a as authorizeFrameRequest, b as setFrameAuth, c as frameScopedUrl, d as getServerIslandEntry, f as isSafeFramePath, g as readBodyBounded, h as parseFrameProps, i as __ilhaServerAction, l as getFrameAuth, m as json, n as FrameError, o as forwardIdentityHeaders, p as isTrustedOrigin, r as MAX_BODY, s as frameEnvelope, t as FRAME_ENDPOINT, u as getFrameGuard, v as renderServerIsland, x as setFrameGuard, y as renderServerIslandResult } from "./ssr-CV_vNpS3.js";
2
2
 
3
3
  export { FRAME_ENDPOINT, FrameError, MAX_BODY, __ilhaServerAction, authorizeFrameRequest, ssr as default, forwardIdentityHeaders, frameEnvelope, frameScopedUrl, getFrameAuth, getFrameGuard, getServerIslandEntry, isSafeFramePath, isTrustedOrigin, json, parseFrameProps, readBodyBounded, registerServerIsland, renderServerIsland, renderServerIslandResult, setFrameAuth, setFrameGuard };
package/dist/vite.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as ilhaPages } from "./plugin-C3AAI3e_.js";
1
+ import { t as ilhaPages } from "./plugin-Bfnn44nu.js";
2
2
 
3
3
  //#region src/vite.ts
4
4
  /** Vite plugin — use via `@ilha/router/vite`. */
package/oxlint.cjs CHANGED
@@ -1,6 +1,5 @@
1
- const PRIMITIVES = new Set(["atom", "when", "watch", "wait"]);
2
- // when/watch/wait return Instructions — they are only consumable by a generator frame.
3
- const INSTRUCTIONS = new Set(["when", "watch", "wait"]);
1
+ const PRIMITIVES = new Set(["atom", "watch", "when"]);
2
+ const INSTRUCTIONS = new Set(["when"]);
4
3
  const CONDITIONAL = new Set([
5
4
  "IfStatement",
6
5
  "ForStatement",
@@ -38,8 +37,48 @@ function ancestorsOf(context, node) {
38
37
  return [];
39
38
  }
40
39
 
41
- function calleeName(node) {
42
- return node.type === "Identifier" ? node.name : null;
40
+ function blockBody(node) {
41
+ if (node.type === "BlockStatement") return node.body;
42
+ if (
43
+ node.type === "FunctionDeclaration" ||
44
+ node.type === "FunctionExpression" ||
45
+ node.type === "ArrowFunctionExpression"
46
+ ) {
47
+ const body = node.body;
48
+ if (body?.type === "BlockStatement") return body.body;
49
+ }
50
+ return null;
51
+ }
52
+
53
+ function bindingInitType(name, ancestors) {
54
+ for (let i = ancestors.length - 1; i >= 0; i--) {
55
+ const a = ancestors[i];
56
+ if (a.type === "VariableDeclarator" && a.id?.type === "Identifier" && a.id.name === name) {
57
+ return a.init?.type ?? "none";
58
+ }
59
+ if (a.type === "FunctionDeclaration" && a.id?.name === name) {
60
+ return "FunctionDeclaration";
61
+ }
62
+ const stmts = blockBody(a);
63
+ if (stmts) {
64
+ for (const stmt of stmts) {
65
+ if (stmt.type !== "VariableDeclaration") continue;
66
+ for (const decl of stmt.declarations) {
67
+ if (decl.id?.type === "Identifier" && decl.id.name === name) {
68
+ return decl.init?.type ?? "none";
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+
77
+ function isFunctionBinding(name, ancestors, moduleFns) {
78
+ const local = bindingInitType(name, ancestors);
79
+ if (local === "FunctionDeclaration") return true;
80
+ if (local !== null) return FN_TYPES.has(local);
81
+ return moduleFns.has(name);
43
82
  }
44
83
 
45
84
  function enclosingFunctions(ancestors) {
@@ -49,7 +88,7 @@ function enclosingFunctions(ancestors) {
49
88
  const noConditionalPrimitive = {
50
89
  meta: {
51
90
  type: "problem",
52
- docs: { description: "Disallow atom/when/watch/wait inside conditionals or loops" },
91
+ docs: { description: "Disallow atom/watch/when inside conditionals or loops" },
53
92
  messages: {
54
93
  conditional:
55
94
  "Do not call {{name}}() inside a condition or loop. Primitive registration order must be stable — put the branch inside the primitive or the view.",
@@ -83,7 +122,7 @@ const noPrimitiveOutsideComponent = {
83
122
  meta: {
84
123
  type: "problem",
85
124
  docs: {
86
- description: "Call atom/when/watch/wait inside a component, never at module top level",
125
+ description: "Call atom/watch/when inside a component, never at module top level",
87
126
  },
88
127
  messages: {
89
128
  outside:
@@ -112,7 +151,7 @@ const noPrimitiveOutsideComponent = {
112
151
  const noInstructionOutsideGenerator = {
113
152
  meta: {
114
153
  type: "problem",
115
- docs: { description: "Use when/watch/wait only inside a generator, with yield*" },
154
+ docs: { description: "Use when only inside a generator, with yield*" },
116
155
  messages: {
117
156
  notGenerator:
118
157
  "{{name}}() returns an instruction that only a generator frame can run. Make the enclosing component a generator and yield* it.",
@@ -186,18 +225,20 @@ const preferLowercaseEvents = {
186
225
  const functionInAtom = {
187
226
  meta: {
188
227
  type: "problem",
189
- docs: { description: "atom(fn) is a computed initializer — wrap function values" },
228
+ docs: {
229
+ description:
230
+ "atom(fn) and atom(() => …) are invalid — use atom.lazy, Atom.map, or Atom.transform",
231
+ },
190
232
  messages: {
191
- init: "atom({{name}}) treats the function as a computed initializer. Wrap it: atom(() => {{name}}).",
192
- set: "{{setter}}({{name}}) is fine as a value, but computed atoms reject set(). Store a function with a plain wrapper if you really mean it.",
233
+ init: "atom({{name}}) is not valid. Use atom.lazy(() => {{name}}) to store a function value.",
234
+ derived:
235
+ "atom(() => …) is not supported. Use atom(Atom.map(...)) or atom(Atom.transform(...)) for derived values, or atom.lazy() for one-time init.",
193
236
  },
194
237
  schema: [],
195
238
  },
196
239
  create(context) {
197
240
  const b = bindings();
198
241
  const fns = new Set();
199
- const atoms = new Set();
200
- const computed = new Set();
201
242
  return {
202
243
  ImportDeclaration(node) {
203
244
  takeImport(b, node);
@@ -215,23 +256,26 @@ const functionInAtom = {
215
256
  fns.add(node.id.name);
216
257
  }
217
258
  if (!init || primitiveName(init, b) !== "atom") return;
218
- atoms.add(node.id.name);
219
- // atom(() => …) or atom(function…) — computed; flag set() on it.
220
- if (init.arguments[0] && FN_TYPES.has(init.arguments[0].type)) computed.add(node.id.name);
259
+ const arg = init.arguments[0];
260
+ if (arg && FN_TYPES.has(arg.type)) {
261
+ context.report({ node: arg, messageId: "derived" });
262
+ }
263
+ if (
264
+ arg?.type === "Identifier" &&
265
+ isFunctionBinding(arg.name, ancestorsOf(context, arg), fns)
266
+ ) {
267
+ context.report({ node: arg, messageId: "init", data: { name: arg.name } });
268
+ }
221
269
  },
222
270
  CallExpression(node) {
223
271
  if (node.arguments.length === 0) return;
224
272
  const arg = node.arguments[0];
225
- if (arg.type !== "Identifier" || !fns.has(arg.name)) return;
226
- if (primitiveName(node, b) === "atom") {
273
+ if (arg.type !== "Identifier") return;
274
+ if (
275
+ primitiveName(node, b) === "atom" &&
276
+ isFunctionBinding(arg.name, ancestorsOf(context, arg), fns)
277
+ ) {
227
278
  context.report({ node: arg, messageId: "init", data: { name: arg.name } });
228
- return;
229
- }
230
- const setter = calleeName(node.callee);
231
- // set(fn) on a computed atom never makes sense; on a writable atom it
232
- // is the classic "I meant to store this function" mistake.
233
- if (setter && atoms.has(setter) && computed.has(setter)) {
234
- context.report({ node: arg, messageId: "set", data: { setter, name: arg.name } });
235
279
  }
236
280
  },
237
281
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ilha/router",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "A tiny SPA router for Ilha",
5
5
  "keywords": [
6
6
  "frontend",
@@ -69,14 +69,21 @@
69
69
  "test": "bun test"
70
70
  },
71
71
  "dependencies": {
72
- "effect": "^4.0.0-rc.112",
72
+ "effect": "4.0.0-rc.112",
73
73
  "unplugin": "3.3.0"
74
74
  },
75
75
  "devDependencies": {
76
- "ilha": "0.14.0",
76
+ "ilha": "^0.14.2",
77
+ "oxidejs": "^0.3.0",
77
78
  "vite": "^8.2.2"
78
79
  },
79
80
  "peerDependencies": {
80
- "ilha": ">=0.14.0"
81
+ "ilha": ">=0.14.2",
82
+ "oxidejs": ">=0.3.0"
83
+ },
84
+ "peerDependenciesMeta": {
85
+ "oxidejs": {
86
+ "optional": true
87
+ }
81
88
  }
82
89
  }