devframe 0.6.0-beta.2 → 0.6.0

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.
Files changed (60) hide show
  1. package/dist/adapters/build.d.mts +1 -1
  2. package/dist/adapters/build.mjs +2 -2
  3. package/dist/adapters/cli.d.mts +1 -1
  4. package/dist/adapters/cli.mjs +9 -6
  5. package/dist/adapters/dev.d.mts +9 -2
  6. package/dist/adapters/dev.mjs +1 -1
  7. package/dist/adapters/embedded.d.mts +1 -1
  8. package/dist/adapters/mcp.d.mts +1 -1
  9. package/dist/adapters/mcp.mjs +1 -337
  10. package/dist/build-server-0jWgMrz-.mjs +338 -0
  11. package/dist/client/index.d.mts +2 -2
  12. package/dist/client/index.mjs +56 -22
  13. package/dist/constants.d.mts +31 -1
  14. package/dist/constants.mjs +33 -1
  15. package/dist/{context-3x_bgBgZ.mjs → context-CKJheEtf.mjs} +2 -2
  16. package/dist/{context-BEVByy_Z.d.mts → context-UX9qUDK7.d.mts} +1 -1
  17. package/dist/{dev-BaX8fLH2.mjs → dev-zC5542OV.mjs} +49 -6
  18. package/dist/{devframe-D-gr9sBx.d.mts → devframe-BtVHhmwM.d.mts} +76 -4
  19. package/dist/{dump-DoXkj4ku.mjs → dump-D09PZb7T.mjs} +14 -4
  20. package/dist/{hash-DFc5WwhO.mjs → hash-PAfnyu2k.mjs} +1 -1
  21. package/dist/helpers/vite.d.mts +1 -1
  22. package/dist/helpers/vite.mjs +2 -2
  23. package/dist/{host-h3-C5SZlk03.mjs → host-h3-Dsf-Tgwx.mjs} +37 -11
  24. package/dist/http-COX960WK.mjs +114 -0
  25. package/dist/index-ByaMT1Xp.d.mts +107 -0
  26. package/dist/{index-CxaPKDXX.d.mts → index-Dy6GFDRf.d.mts} +1 -0
  27. package/dist/index.d.mts +2 -2
  28. package/dist/{launch-editor-DPfltGA4.mjs → launch-editor-DIzaS5EG.mjs} +58 -43
  29. package/dist/node/auth.d.mts +2 -64
  30. package/dist/node/auth.mjs +2 -100
  31. package/dist/node/hub-internals.d.mts +2 -2
  32. package/dist/node/hub-internals.mjs +1 -1
  33. package/dist/node/index.d.mts +3 -3
  34. package/dist/node/index.mjs +3 -3
  35. package/dist/recipes/interactive-auth.d.mts +53 -0
  36. package/dist/recipes/interactive-auth.mjs +132 -0
  37. package/dist/recipes/open-helpers.mjs +2 -2
  38. package/dist/{revoke-ENfxWkFK.mjs → revoke-BtQDKTp7.mjs} +1 -1
  39. package/dist/rpc/dump.mjs +1 -1
  40. package/dist/rpc/index.d.mts +2 -2
  41. package/dist/rpc/index.mjs +4 -1
  42. package/dist/rpc/transports/ws-client.mjs +21 -8
  43. package/dist/{server-Dl6TU5LE.mjs → server-CAsvfJNK.mjs} +51 -15
  44. package/dist/{server-rX781kz-.d.mts → server-Cfr1NrGQ.d.mts} +52 -10
  45. package/dist/{shared-state-D4PPieA0.mjs → shared-state-QtMas0NG.mjs} +34 -4
  46. package/dist/state-WX3HT5a3.mjs +101 -0
  47. package/dist/{storage-l2ezeend.mjs → storage-yrUZaiib.mjs} +55 -6
  48. package/dist/types/index.d.mts +2 -2
  49. package/dist/utils/crypto-token.mjs +1 -1
  50. package/dist/utils/events.d.mts +1 -1
  51. package/dist/utils/hash.mjs +1 -1
  52. package/dist/utils/launch-editor.mjs +1 -1
  53. package/dist/utils/open.mjs +1 -1
  54. package/dist/utils/serve-static.mjs +2 -1
  55. package/dist/utils/shared-state.d.mts +1 -1
  56. package/dist/utils/shared-state.mjs +1 -1
  57. package/dist/utils/streaming-channel.d.mts +1 -1
  58. package/dist/utils/when.d.mts +1 -1
  59. package/package.json +10 -9
  60. package/dist/{open-Dusa2Zzd.mjs → open-Deb5xmIT.mjs} +1 -1
@@ -1,3 +1,3 @@
1
1
  import { C as RpcFunctionType, E as Thenable, S as RpcFunctionSetupResult, T as RpcReturnSchema, _ as RpcFunctionDefinition, a as RpcDefinitionsFilter, b as RpcFunctionDefinitionBase, c as RpcDump, d as RpcDumpDefinition, f as RpcDumpGetter, g as RpcFunctionAgentOptions, h as RpcDumpStore, i as RpcArgsSchema, l as RpcDumpClientOptions, m as RpcDumpRecordError, n as BirpcReturn, o as RpcDefinitionsToFunctions, p as RpcDumpRecord, r as EntriesToObject, s as RpcDefinitionsToFunctionsWithNamespace, t as BirpcFn, u as RpcDumpCollectionOptions, v as RpcFunctionDefinitionAny, w as RpcFunctionsCollector, x as RpcFunctionDefinitionToFunction, y as RpcFunctionDefinitionAnyWithContext } from "../types-DZEx4ffs.mjs";
2
- import { C as RpcCacheManager, S as RpcFunctionsCollectorBase, _ as strictJsonStringify, a as StaticRpcDumpManifestStaticEntry, b as createDefineWrapperWithContext, c as collectStaticRpcDump, d as getDefinitionsWithDumps, f as reviveDumpError, g as STRUCTURED_CLONE_PREFIX, h as validateDefinitions, i as StaticRpcDumpManifestQueryEntry, l as createClientFromDump, m as validateDefinition, n as StaticRpcDumpFile, o as StaticRpcDumpManifestValue, p as serializeDumpError, r as StaticRpcDumpManifest, s as StaticRpcDumpSerialization, t as StaticRpcDumpCollection, u as dumpFunctions, v as getRpcHandler, w as RpcCacheOptions, x as defineRpcFunction, y as getRpcResolvedSetupResult } from "../index-CxaPKDXX.mjs";
3
- export { BirpcFn, BirpcReturn, EntriesToObject, RpcArgsSchema, RpcCacheManager, RpcCacheOptions, RpcDefinitionsFilter, RpcDefinitionsToFunctions, RpcDefinitionsToFunctionsWithNamespace, RpcDump, RpcDumpClientOptions, RpcDumpCollectionOptions, RpcDumpDefinition, RpcDumpGetter, RpcDumpRecord, RpcDumpRecordError, RpcDumpStore, RpcFunctionAgentOptions, RpcFunctionDefinition, RpcFunctionDefinitionAny, RpcFunctionDefinitionAnyWithContext, RpcFunctionDefinitionBase, RpcFunctionDefinitionToFunction, RpcFunctionSetupResult, RpcFunctionType, RpcFunctionsCollector, RpcFunctionsCollectorBase, RpcReturnSchema, STRUCTURED_CLONE_PREFIX, StaticRpcDumpCollection, StaticRpcDumpFile, StaticRpcDumpManifest, StaticRpcDumpManifestQueryEntry, StaticRpcDumpManifestStaticEntry, StaticRpcDumpManifestValue, StaticRpcDumpSerialization, Thenable, collectStaticRpcDump, createClientFromDump, createDefineWrapperWithContext, defineRpcFunction, dumpFunctions, getDefinitionsWithDumps, getRpcHandler, getRpcResolvedSetupResult, reviveDumpError, serializeDumpError, strictJsonStringify, validateDefinition, validateDefinitions };
2
+ import { C as RpcCacheManager, S as RpcFunctionsCollectorBase, _ as strictJsonStringify, a as StaticRpcDumpManifestStaticEntry, b as createDefineWrapperWithContext, c as collectStaticRpcDump, d as getDefinitionsWithDumps, f as reviveDumpError, g as STRUCTURED_CLONE_PREFIX, h as validateDefinitions, i as StaticRpcDumpManifestQueryEntry, l as createClientFromDump, m as validateDefinition, n as StaticRpcDumpFile, o as StaticRpcDumpManifestValue, p as serializeDumpError, r as StaticRpcDumpManifest, s as StaticRpcDumpSerialization, t as StaticRpcDumpCollection, u as dumpFunctions, v as getRpcHandler, w as RpcCacheOptions, x as defineRpcFunction, y as getRpcResolvedSetupResult } from "../index-Dy6GFDRf.mjs";
3
+ export { type BirpcFn, type BirpcReturn, EntriesToObject, RpcArgsSchema, RpcCacheManager, RpcCacheOptions, RpcDefinitionsFilter, RpcDefinitionsToFunctions, RpcDefinitionsToFunctionsWithNamespace, RpcDump, RpcDumpClientOptions, RpcDumpCollectionOptions, RpcDumpDefinition, RpcDumpGetter, RpcDumpRecord, RpcDumpRecordError, RpcDumpStore, RpcFunctionAgentOptions, RpcFunctionDefinition, RpcFunctionDefinitionAny, RpcFunctionDefinitionAnyWithContext, RpcFunctionDefinitionBase, RpcFunctionDefinitionToFunction, RpcFunctionSetupResult, RpcFunctionType, RpcFunctionsCollector, RpcFunctionsCollectorBase, RpcReturnSchema, STRUCTURED_CLONE_PREFIX, StaticRpcDumpCollection, StaticRpcDumpFile, StaticRpcDumpManifest, StaticRpcDumpManifestQueryEntry, StaticRpcDumpManifestStaticEntry, StaticRpcDumpManifestValue, StaticRpcDumpSerialization, Thenable, collectStaticRpcDump, createClientFromDump, createDefineWrapperWithContext, defineRpcFunction, dumpFunctions, getDefinitionsWithDumps, getRpcHandler, getRpcResolvedSetupResult, reviveDumpError, serializeDumpError, strictJsonStringify, validateDefinition, validateDefinitions };
@@ -1,4 +1,4 @@
1
- import { a as dumpFunctions$1, c as serializeDumpError$1, d as hash, i as createClientFromDump$1, l as validateDefinition, n as getRpcHandler, o as getDefinitionsWithDumps$1, r as getRpcResolvedSetupResult, s as reviveDumpError$1, t as collectStaticRpcDump$1, u as validateDefinitions } from "../dump-DoXkj4ku.mjs";
1
+ import { a as dumpFunctions$1, c as serializeDumpError$1, d as hash, i as createClientFromDump$1, l as validateDefinition, n as getRpcHandler, o as getDefinitionsWithDumps$1, r as getRpcResolvedSetupResult, s as reviveDumpError$1, t as collectStaticRpcDump$1, u as validateDefinitions } from "../dump-D09PZb7T.mjs";
2
2
  import { t as diagnostics } from "../diagnostics-BXwBQmoN.mjs";
3
3
  import { n as defineRpcFunction, t as createDefineWrapperWithContext } from "../define-BLWPsH6y.mjs";
4
4
  import { n as strictJsonStringify, t as STRUCTURED_CLONE_PREFIX } from "../serialization-DpLXCy13.mjs";
@@ -24,6 +24,9 @@ var RpcCacheManager = class {
24
24
  const methodCache = this.cacheMap.get(m);
25
25
  if (methodCache) return methodCache.get(this.keySerializer(a));
26
26
  }
27
+ has(m, a) {
28
+ return this.cacheMap.get(m)?.has(this.keySerializer(a)) ?? false;
29
+ }
27
30
  apply(req, res) {
28
31
  const methodCache = this.cacheMap.get(req.m) || /* @__PURE__ */ new Map();
29
32
  methodCache.set(this.keySerializer(req.a), res);
@@ -1,3 +1,4 @@
1
+ import { DEVFRAME_AUTH_TOKEN_QUERY_PARAM } from "../../constants.mjs";
1
2
  import { n as strictJsonStringify } from "../../serialization-DpLXCy13.mjs";
2
3
  import { n as structuredCloneStringify, t as structuredCloneParse } from "../../structured-clone-XpHLZ8nr.mjs";
3
4
  //#region src/rpc/transports/ws-client.ts
@@ -9,14 +10,15 @@ const EMPTY_DEFS = /* @__PURE__ */ new Map();
9
10
  */
10
11
  function createWsRpcChannel(options) {
11
12
  let url = options.url;
12
- if (options.authToken) url = `${url}?devframe_auth_token=${encodeURIComponent(options.authToken)}`;
13
+ if (options.authToken) url = `${url}?${DEVFRAME_AUTH_TOKEN_QUERY_PARAM}=${encodeURIComponent(options.authToken)}`;
13
14
  const ws = new WebSocket(url);
14
15
  const { onConnected = NOOP, onError = NOOP, onDisconnected = NOOP, definitions = EMPTY_DEFS } = options;
15
16
  ws.addEventListener("open", (e) => {
16
17
  onConnected(e);
17
18
  });
18
19
  ws.addEventListener("error", (e) => {
19
- onError(e instanceof Error ? e : new Error(e.type));
20
+ const _e = e instanceof Error ? e : new Error(e.type);
21
+ onError(_e);
20
22
  });
21
23
  ws.addEventListener("close", (e) => {
22
24
  onDisconnected(e);
@@ -29,14 +31,25 @@ function createWsRpcChannel(options) {
29
31
  });
30
32
  },
31
33
  post: (data) => {
32
- if (ws.readyState === WebSocket.OPEN) ws.send(data);
33
- else {
34
- function handler() {
35
- ws.send(data);
36
- ws.removeEventListener("open", handler);
34
+ if (ws.readyState === WebSocket.OPEN) {
35
+ ws.send(data);
36
+ return;
37
+ }
38
+ if (ws.readyState === WebSocket.CONNECTING) {
39
+ const onOpen = () => {
40
+ cleanup();
41
+ if (ws.readyState === WebSocket.OPEN) ws.send(data);
42
+ };
43
+ const onClose = () => cleanup();
44
+ function cleanup() {
45
+ ws.removeEventListener("open", onOpen);
46
+ ws.removeEventListener("close", onClose);
37
47
  }
38
- ws.addEventListener("open", handler);
48
+ ws.addEventListener("open", onOpen);
49
+ ws.addEventListener("close", onClose);
50
+ return;
39
51
  }
52
+ onError(/* @__PURE__ */ new Error("Devframe WebSocket is not open; message dropped"));
40
53
  },
41
54
  serialize: (msg) => {
42
55
  let method;
@@ -1,6 +1,7 @@
1
1
  import { createRpcServer } from "./rpc/server.mjs";
2
2
  import { attachWsRpcTransport } from "./rpc/transports/ws-server.mjs";
3
- import { t as getInternalContext } from "./context-3x_bgBgZ.mjs";
3
+ import { a as diagnostics } from "./storage-yrUZaiib.mjs";
4
+ import { t as getInternalContext } from "./context-CKJheEtf.mjs";
4
5
  import { createServer } from "node:http";
5
6
  import { AsyncLocalStorage } from "node:async_hooks";
6
7
  import { H3, toNodeHandler } from "h3";
@@ -18,18 +19,32 @@ async function startHttpAndWs(options) {
18
19
  const httpServer = options.server ?? createServer(toNodeHandler(app));
19
20
  const rpcHost = context.rpc;
20
21
  const asyncStorage = new AsyncLocalStorage();
21
- const rpcGroup = createRpcServer(rpcHost.functions, { rpcOptions: { resolver(name, fn) {
22
- const rpc = this;
23
- if (!fn) return void 0;
24
- return async function(...args) {
25
- return await asyncStorage.run({
26
- rpc,
27
- meta: rpc.$meta
28
- }, async () => {
29
- return (await fn).apply(this, args);
30
- });
31
- };
32
- } } });
22
+ const authHandler = typeof options.auth === "object" ? options.auth : void 0;
23
+ const effectiveAuthorize = options.authorize ?? authHandler?.authorize;
24
+ if (authHandler) {
25
+ for (const fn of authHandler.rpcFunctions) if (!rpcHost.definitions.has(fn.name)) rpcHost.register(fn);
26
+ }
27
+ const rpcGroup = createRpcServer(rpcHost.functions, { rpcOptions: {
28
+ onFunctionError: options.rpcOptions?.onFunctionError,
29
+ onGeneralError: options.rpcOptions?.onGeneralError,
30
+ resolver(name, fn) {
31
+ const rpc = this;
32
+ if (!fn) return void 0;
33
+ return async function(...args) {
34
+ const meta = rpc.$meta;
35
+ if (effectiveAuthorize && !effectiveAuthorize(name, {
36
+ meta,
37
+ rpc
38
+ })) throw diagnostics.DF0036({ name });
39
+ return await asyncStorage.run({
40
+ rpc,
41
+ meta
42
+ }, async () => {
43
+ return (await fn).apply(this, args);
44
+ });
45
+ };
46
+ }
47
+ } });
33
48
  const separateWsPort = ownsHttpServer && options.wsPort != null && options.wsPort !== port ? options.wsPort : void 0;
34
49
  const { ws, close: closeWs } = attachWsRpcTransport(rpcGroup, {
35
50
  ...separateWsPort != null ? {
@@ -39,6 +54,14 @@ async function startHttpAndWs(options) {
39
54
  path: options.path,
40
55
  destroyUnmatched: ownsHttpServer,
41
56
  allowedOrigins: options.allowedOrigins,
57
+ onConnected: authHandler || options.onPeerConnect ? (peer, meta) => {
58
+ const session = {
59
+ meta,
60
+ rpc: rpcGroup.clients.find((client) => client.$meta === meta)
61
+ };
62
+ authHandler?.onConnect(peer, session);
63
+ options.onPeerConnect?.(peer, session);
64
+ } : void 0,
42
65
  onDisconnected: (_peer, meta) => {
43
66
  rpcHost._emitSessionDisconnected(meta);
44
67
  }
@@ -46,8 +69,8 @@ async function startHttpAndWs(options) {
46
69
  rpcHost._rpcGroup = rpcGroup;
47
70
  rpcHost._asyncStorage = asyncStorage;
48
71
  rpcHost._authDisabled = options.auth === false;
49
- if (options.auth === false && !rpcHost.definitions.has("devframe:anonymous:auth")) rpcHost.register({
50
- name: "devframe:anonymous:auth",
72
+ if (options.auth === false && !rpcHost.definitions.has("anonymous:devframe:auth")) rpcHost.register({
73
+ name: "anonymous:devframe:auth",
51
74
  type: "action",
52
75
  handler: () => {
53
76
  const session = rpcHost.getCurrentRpcSession();
@@ -69,12 +92,25 @@ async function startHttpAndWs(options) {
69
92
  port: resolvedPort,
70
93
  app
71
94
  });
95
+ function connectionMeta() {
96
+ const jsonSerializableMethods = [];
97
+ for (const def of rpcHost.definitions.values()) if (def.jsonSerializable === true) jsonSerializableMethods.push(def.name);
98
+ return {
99
+ backend: "websocket",
100
+ websocket: separateWsPort != null ? {
101
+ port: separateWsPort,
102
+ path: options.path
103
+ } : { path: options.path },
104
+ jsonSerializableMethods
105
+ };
106
+ }
72
107
  return {
73
108
  origin,
74
109
  port: resolvedPort,
75
110
  app,
76
111
  ws,
77
112
  rpcGroup,
113
+ connectionMeta,
78
114
  async close() {
79
115
  await closeWs();
80
116
  if (ownsHttpServer) await new Promise((r) => httpServer.close(() => r()));
@@ -1,5 +1,7 @@
1
- import { it as DevframeRpcServerFunctions, m as DevframeNodeContext, rt as DevframeRpcClientFunctions } from "./devframe-D-gr9sBx.mjs";
2
- import { BirpcGroup } from "birpc";
1
+ import { at as DevframeRpcServerFunctions, f as ConnectionMeta, g as DevframeNodeRpcSession, h as DevframeNodeContext, it as DevframeRpcClientFunctions } from "./devframe-BtVHhmwM.mjs";
2
+ import { c as DevframeAuthHandler } from "./index-ByaMT1Xp.mjs";
3
+ import { BirpcGroup, EventOptions } from "birpc";
4
+ import { Peer } from "crossws";
3
5
  import { NodeAdapter } from "crossws/adapters/node";
4
6
  import { Server } from "node:http";
5
7
  import { H3 } from "h3";
@@ -41,16 +43,48 @@ interface StartHttpAndWsOptions {
41
43
  */
42
44
  server?: Server;
43
45
  /**
44
- * When `false`, the RPC server is started without a trust handshake.
45
- * Intended for single-user localhost tools where an auth round-trip
46
- * would only get in the way. The Vite-flavoured auth layer in
47
- * `@vitejs/devtools` already honors the equivalent
48
- * `devtools.clientAuth` setting; devframe records the intent here so
49
- * future auth plumbing can consult it without another API change.
46
+ * Authentication for the server:
50
47
  *
51
- * Default: `true`.
48
+ * - `true` (default) — no gate; every registered method is callable
49
+ * regardless of trust (today's behavior, unchanged).
50
+ * - `false` — the RPC server is started without a trust handshake.
51
+ * Intended for single-user localhost tools where an auth round-trip
52
+ * would only get in the way. A noop `anonymous:devframe:auth` handler
53
+ * is registered so the browser client's unconditional handshake call
54
+ * succeeds and auto-trusts.
55
+ * - A {@link DevframeAuthHandler} (e.g. from
56
+ * `devframe/recipes/interactive-auth`'s `createInteractiveAuth`) —
57
+ * registers its `rpcFunctions`, wires its `authorize` as the resolver
58
+ * gate, and wires its `onConnect` on every new peer. This is the
59
+ * fully-authenticated server: an untrusted caller can only reach
60
+ * `anonymous:`-prefixed methods (see `isAnonymousRpcMethod`).
52
61
  */
53
- auth?: boolean;
62
+ auth?: boolean | DevframeAuthHandler;
63
+ /**
64
+ * Lower-level escape hatch: gate individual RPC calls by method name and
65
+ * session without a full {@link DevframeAuthHandler}. Ignored when `auth`
66
+ * is a handler object (its own `authorize` is used); combine with `auth:
67
+ * true` to layer a custom policy on top of an otherwise ungated server.
68
+ */
69
+ authorize?: (methodName: string, session: DevframeNodeRpcSession) => boolean;
70
+ /**
71
+ * Called once per new WS connection, right after its session is created
72
+ * (before any RPC call is dispatched). Runs after the auth handler's own
73
+ * `onConnect` (when `auth` is a {@link DevframeAuthHandler}), so it can
74
+ * observe — but not override — the connect-time trust decision.
75
+ */
76
+ onPeerConnect?: (peer: Peer, session: DevframeNodeRpcSession) => void;
77
+ /**
78
+ * Forwarded verbatim to the internal `createRpcServer`'s birpc
79
+ * `rpcOptions`, alongside the resolver `startHttpAndWs` installs for
80
+ * auth/session wiring. Use this so a host that owns its own structured
81
+ * diagnostics (e.g. a coded error reporter) keeps seeing RPC failures
82
+ * instead of them being silently absorbed by delegating to
83
+ * `startHttpAndWs`. Returning `true` from either callback suppresses
84
+ * birpc's own error response to the caller — see birpc's
85
+ * `EventOptions` for the full contract.
86
+ */
87
+ rpcOptions?: Pick<EventOptions<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>, 'onFunctionError' | 'onGeneralError'>;
54
88
  /**
55
89
  * Extra origins to accept on the WS upgrade beyond the loopback default
56
90
  * (`localhost`/`127.0.0.1`/`::1` and any `Origin`-less request from a
@@ -78,6 +112,14 @@ interface StartedServer {
78
112
  /** The crossws node adapter driving the RPC socket (connected peers, pub/sub). */
79
113
  ws: NodeAdapter;
80
114
  rpcGroup: BirpcGroup<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>;
115
+ /**
116
+ * The {@link ConnectionMeta} descriptor for this server — the same shape
117
+ * a `__connection.json` route should serve so a devframe client's
118
+ * `resolveWsUrl` can dial back in. Reflects the `path` / `wsPort` this
119
+ * server was started with and the `jsonSerializable` methods currently
120
+ * registered on `context.rpc`.
121
+ */
122
+ connectionMeta: () => ConnectionMeta;
81
123
  close: () => Promise<void>;
82
124
  }
83
125
  /**
@@ -1,6 +1,6 @@
1
1
  import { createEventEmitter } from "./utils/events.mjs";
2
2
  import { nanoid } from "./utils/nanoid.mjs";
3
- //#region ../../node_modules/.pnpm/immer@11.1.8/node_modules/immer/dist/immer.mjs
3
+ //#region ../../node_modules/.pnpm/immer@11.1.11/node_modules/immer/dist/immer.mjs
4
4
  var NOTHING = Symbol.for("immer-nothing");
5
5
  var DRAFTABLE = Symbol.for("immer-draftable");
6
6
  var DRAFT_STATE = Symbol.for("immer-state");
@@ -350,6 +350,21 @@ function createProxyProxy(base, parent) {
350
350
  var objectTraps = {
351
351
  get(state, prop) {
352
352
  if (prop === DRAFT_STATE) return state;
353
+ if (prop === "constructor" || prop === "__proto__") {
354
+ const value2 = latest(state)[prop];
355
+ return new Proxy(value2 || {}, {
356
+ get: (target, key) => {
357
+ if (key === "__proto__" || key === "prototype") return Object.freeze(/* @__PURE__ */ Object.create(null));
358
+ return Reflect.get(target, key);
359
+ },
360
+ set: () => {
361
+ return true;
362
+ },
363
+ apply: (target, thisArg, args) => {
364
+ return Reflect.apply(target, thisArg, args);
365
+ }
366
+ });
367
+ }
353
368
  let arrayPlugin = state.scope_.arrayMethodsPlugin_;
354
369
  const isArrayWithStringProp = state.type_ === 1 && typeof prop === "string";
355
370
  if (isArrayWithStringProp) {
@@ -369,12 +384,14 @@ var objectTraps = {
369
384
  return value;
370
385
  },
371
386
  has(state, prop) {
387
+ if (prop === "constructor" || prop === "__proto__" || prop === "prototype") return false;
372
388
  return prop in latest(state);
373
389
  },
374
390
  ownKeys(state) {
375
391
  return Reflect.ownKeys(latest(state));
376
392
  },
377
393
  set(state, prop, value) {
394
+ if (prop === "constructor" || prop === "__proto__" || prop === "prototype") return true;
378
395
  const desc = getDescriptorFromProto(latest(state), prop);
379
396
  if (desc?.set) {
380
397
  desc.set.call(state.draft_, value);
@@ -392,7 +409,7 @@ var objectTraps = {
392
409
  prepareCopy(state);
393
410
  markChanged(state);
394
411
  }
395
- if (state.copy_[prop] === value && (value !== void 0 || prop in state.copy_) || Number.isNaN(value) && Number.isNaN(state.copy_[prop])) return true;
412
+ if (state.copy_[prop] === value && (value !== void 0 || has(state.copy_, prop, state.type_)) || Number.isNaN(value) && Number.isNaN(state.copy_[prop])) return true;
396
413
  state.copy_[prop] = value;
397
414
  state.assigned_.set(prop, true);
398
415
  handleCrossReference(state, prop, value);
@@ -894,6 +911,19 @@ var produceWithPatches = /* @__PURE__ */ immer.produceWithPatches.bind(immer);
894
911
  var applyPatches = /* @__PURE__ */ immer.applyPatches.bind(immer);
895
912
  //#endregion
896
913
  //#region src/utils/shared-state.ts
914
+ /**
915
+ * Upper bound on retained syncIds. Loop echoes arrive near-immediately, so a
916
+ * generous window preserves de-dup while capping memory on long-lived,
917
+ * frequently-mutated states (e.g. a 1s terminal poll).
918
+ */
919
+ const MAX_SYNC_IDS = 1e3;
920
+ function rememberSyncId(syncIds, syncId) {
921
+ syncIds.add(syncId);
922
+ if (syncIds.size > MAX_SYNC_IDS) {
923
+ const oldest = syncIds.values().next().value;
924
+ if (oldest !== void 0) syncIds.delete(oldest);
925
+ }
926
+ }
897
927
  function createSharedState(options) {
898
928
  const { enablePatches: enablePatches$1 = false } = options;
899
929
  const events = createEventEmitter();
@@ -906,12 +936,12 @@ function createSharedState(options) {
906
936
  if (syncIds.has(syncId)) return;
907
937
  enablePatches();
908
938
  state = applyPatches(state, patches);
909
- syncIds.add(syncId);
939
+ rememberSyncId(syncIds, syncId);
910
940
  events.emit("updated", state, void 0, syncId);
911
941
  },
912
942
  mutate: (fn, syncId = nanoid()) => {
913
943
  if (syncIds.has(syncId)) return;
914
- syncIds.add(syncId);
944
+ rememberSyncId(syncIds, syncId);
915
945
  if (enablePatches$1) {
916
946
  const [newState, patches] = produceWithPatches(state, fn);
917
947
  state = newState;
@@ -0,0 +1,101 @@
1
+ import { DEVFRAME_OTP_URL_PARAM } from "./constants.mjs";
2
+ import { a as timingSafeEqual, i as randomToken, r as randomDigits } from "./revoke-BtQDKTp7.mjs";
3
+ //#region src/node/auth/state.ts
4
+ /** Number of decimal digits in a human-typed one-time authentication code. */
5
+ const TEMP_AUTH_CODE_LENGTH = 6;
6
+ /**
7
+ * How long an authentication code stays valid after it is (re)generated. A
8
+ * 6-digit code only has ~20 bits of entropy, so a short lifetime plus the
9
+ * attempt cap below are what keep it brute-force resistant.
10
+ */
11
+ const TEMP_AUTH_CODE_TTL = 5 * 6e4;
12
+ /** Failed attempts allowed against a single code before it is rotated. */
13
+ const TEMP_AUTH_MAX_ATTEMPTS = 5;
14
+ let tempAuthCode = generateTempCode();
15
+ let tempAuthCodeExpiresAt = Date.now() + TEMP_AUTH_CODE_TTL;
16
+ let tempAuthFailedAttempts = 0;
17
+ function generateTempCode() {
18
+ return randomDigits(TEMP_AUTH_CODE_LENGTH);
19
+ }
20
+ /**
21
+ * The current one-time authentication code. Display this to the user (e.g. in
22
+ * the dev-server terminal) so they can type it into the browser to authenticate.
23
+ */
24
+ function getTempAuthCode() {
25
+ return tempAuthCode;
26
+ }
27
+ /**
28
+ * Rotate the authentication code, resetting its expiry window and failed-attempt
29
+ * counter. Call this when a new authentication flow begins (e.g. when an
30
+ * untrusted client starts authenticating) so the displayed code is freshly
31
+ * valid for its full TTL.
32
+ */
33
+ function refreshTempAuthCode() {
34
+ tempAuthCode = generateTempCode();
35
+ tempAuthCodeExpiresAt = Date.now() + TEMP_AUTH_CODE_TTL;
36
+ tempAuthFailedAttempts = 0;
37
+ return tempAuthCode;
38
+ }
39
+ /**
40
+ * Build a "magic link" authentication URL that embeds a one-time code (OTP) as
41
+ * a query parameter. Opening it authenticates the client without typing — print
42
+ * it on startup (devframe stays headless, so the host prints its own banner).
43
+ * Defaults to the current code; the link is subject to the same TTL.
44
+ */
45
+ function buildOtpAuthUrl(baseUrl, code = tempAuthCode) {
46
+ const url = new URL(baseUrl);
47
+ url.searchParams.set(DEVFRAME_OTP_URL_PARAM, code);
48
+ return url.href;
49
+ }
50
+ /**
51
+ * Re-authenticate a connection that presents a previously-issued bearer token.
52
+ * Returns `true` and marks the session trusted when the token is known.
53
+ *
54
+ * Used by the `anonymous:devframe:auth` handler so a client that already
55
+ * authenticated (token persisted in the browser) is trusted on reconnect
56
+ * without entering the code again.
57
+ */
58
+ function verifyAuthToken(token, session, storage) {
59
+ if (!token || !storage.value().trusted[token]) return false;
60
+ session.meta.clientAuthToken = token;
61
+ session.meta.isTrusted = true;
62
+ return true;
63
+ }
64
+ /**
65
+ * Exchange a one-time authentication code for a fresh, node-issued bearer token.
66
+ *
67
+ * On success this mints a high-entropy token, records it in the trusted store,
68
+ * marks the calling session trusted, rotates the code, and returns the token
69
+ * for the client to persist. Returns `null` on any failure.
70
+ *
71
+ * Because the code is short and human-typed, verification is hardened against
72
+ * brute force: it enforces a time-to-live, compares in constant time, and
73
+ * rotates the code after {@link TEMP_AUTH_MAX_ATTEMPTS} failed attempts so an
74
+ * attacker cannot keep guessing against the same code.
75
+ */
76
+ function exchangeTempAuthCode(code, session, info, storage) {
77
+ if (Date.now() > tempAuthCodeExpiresAt) {
78
+ refreshTempAuthCode();
79
+ return null;
80
+ }
81
+ if (!timingSafeEqual(code, tempAuthCode)) {
82
+ tempAuthFailedAttempts += 1;
83
+ if (tempAuthFailedAttempts >= TEMP_AUTH_MAX_ATTEMPTS) refreshTempAuthCode();
84
+ return null;
85
+ }
86
+ const authToken = randomToken();
87
+ storage.mutate((state) => {
88
+ state.trusted[authToken] = {
89
+ authToken,
90
+ ua: info.ua,
91
+ origin: info.origin,
92
+ timestamp: Date.now()
93
+ };
94
+ });
95
+ session.meta.clientAuthToken = authToken;
96
+ session.meta.isTrusted = true;
97
+ refreshTempAuthCode();
98
+ return authToken;
99
+ }
100
+ //#endregion
101
+ export { verifyAuthToken as a, refreshTempAuthCode as i, exchangeTempAuthCode as n, getTempAuthCode as r, buildOtpAuthUrl as t };
@@ -2,6 +2,7 @@ import { t as devframeReporter } from "./diagnostics-reporter-CsIG85Q5.mjs";
2
2
  import { defineDiagnostics } from "nostics";
3
3
  import fs from "node:fs";
4
4
  import { dirname } from "pathe";
5
+ import process$1 from "node:process";
5
6
  import { destr } from "destr";
6
7
  //#region src/node/diagnostics.ts
7
8
  const diagnostics = defineDiagnostics({
@@ -46,6 +47,14 @@ const diagnostics = defineDiagnostics({
46
47
  DF0034: {
47
48
  why: (p) => `Scoped RPC registration for namespace "${p.namespace}" received an already-namespaced function name "${p.name}".`,
48
49
  fix: "A scoped context auto-namespaces ids. Pass a bare name without a \":\" separator (e.g. `register({ name: \"get-cwd\" })`), or use the unscoped `ctx.base.rpc.register` for a fully-qualified name."
50
+ },
51
+ DF0035: {
52
+ why: (p) => `Failed to persist storage file: ${p.filepath}`,
53
+ fix: "Check that the storage directory is writable and has free space."
54
+ },
55
+ DF0036: {
56
+ why: (p) => `RPC call to "${p.name}" was rejected: the caller is not authorized.`,
57
+ fix: "Complete the auth handshake (or connect with a static/pre-shared token) before calling a trusted method. Untrusted callers may only call `anonymous:`-prefixed methods — see `isAnonymousRpcMethod`."
49
58
  }
50
59
  }
51
60
  });
@@ -89,7 +98,7 @@ function createEventEmitter() {
89
98
  };
90
99
  }
91
100
  //#endregion
92
- //#region ../../node_modules/.pnpm/immer@11.1.8/node_modules/immer/dist/immer.mjs
101
+ //#region ../../node_modules/.pnpm/immer@11.1.11/node_modules/immer/dist/immer.mjs
93
102
  var NOTHING = Symbol.for("immer-nothing");
94
103
  var DRAFTABLE = Symbol.for("immer-draftable");
95
104
  var DRAFT_STATE = Symbol.for("immer-state");
@@ -439,6 +448,21 @@ function createProxyProxy(base, parent) {
439
448
  var objectTraps = {
440
449
  get(state, prop) {
441
450
  if (prop === DRAFT_STATE) return state;
451
+ if (prop === "constructor" || prop === "__proto__") {
452
+ const value2 = latest(state)[prop];
453
+ return new Proxy(value2 || {}, {
454
+ get: (target, key) => {
455
+ if (key === "__proto__" || key === "prototype") return Object.freeze(/* @__PURE__ */ Object.create(null));
456
+ return Reflect.get(target, key);
457
+ },
458
+ set: () => {
459
+ return true;
460
+ },
461
+ apply: (target, thisArg, args) => {
462
+ return Reflect.apply(target, thisArg, args);
463
+ }
464
+ });
465
+ }
442
466
  let arrayPlugin = state.scope_.arrayMethodsPlugin_;
443
467
  const isArrayWithStringProp = state.type_ === 1 && typeof prop === "string";
444
468
  if (isArrayWithStringProp) {
@@ -458,12 +482,14 @@ var objectTraps = {
458
482
  return value;
459
483
  },
460
484
  has(state, prop) {
485
+ if (prop === "constructor" || prop === "__proto__" || prop === "prototype") return false;
461
486
  return prop in latest(state);
462
487
  },
463
488
  ownKeys(state) {
464
489
  return Reflect.ownKeys(latest(state));
465
490
  },
466
491
  set(state, prop, value) {
492
+ if (prop === "constructor" || prop === "__proto__" || prop === "prototype") return true;
467
493
  const desc = getDescriptorFromProto(latest(state), prop);
468
494
  if (desc?.set) {
469
495
  desc.set.call(state.draft_, value);
@@ -481,7 +507,7 @@ var objectTraps = {
481
507
  prepareCopy(state);
482
508
  markChanged(state);
483
509
  }
484
- if (state.copy_[prop] === value && (value !== void 0 || prop in state.copy_) || Number.isNaN(value) && Number.isNaN(state.copy_[prop])) return true;
510
+ if (state.copy_[prop] === value && (value !== void 0 || has(state.copy_, prop, state.type_)) || Number.isNaN(value) && Number.isNaN(state.copy_[prop])) return true;
485
511
  state.copy_[prop] = value;
486
512
  state.assigned_.set(prop, true);
487
513
  handleCrossReference(state, prop, value);
@@ -992,6 +1018,19 @@ function nanoid(size = 21) {
992
1018
  }
993
1019
  //#endregion
994
1020
  //#region src/utils/shared-state.ts
1021
+ /**
1022
+ * Upper bound on retained syncIds. Loop echoes arrive near-immediately, so a
1023
+ * generous window preserves de-dup while capping memory on long-lived,
1024
+ * frequently-mutated states (e.g. a 1s terminal poll).
1025
+ */
1026
+ const MAX_SYNC_IDS = 1e3;
1027
+ function rememberSyncId(syncIds, syncId) {
1028
+ syncIds.add(syncId);
1029
+ if (syncIds.size > MAX_SYNC_IDS) {
1030
+ const oldest = syncIds.values().next().value;
1031
+ if (oldest !== void 0) syncIds.delete(oldest);
1032
+ }
1033
+ }
995
1034
  function createSharedState(options) {
996
1035
  const { enablePatches: enablePatches$1 = false } = options;
997
1036
  const events = createEventEmitter();
@@ -1004,12 +1043,12 @@ function createSharedState(options) {
1004
1043
  if (syncIds.has(syncId)) return;
1005
1044
  enablePatches();
1006
1045
  state = applyPatches(state, patches);
1007
- syncIds.add(syncId);
1046
+ rememberSyncId(syncIds, syncId);
1008
1047
  events.emit("updated", state, void 0, syncId);
1009
1048
  },
1010
1049
  mutate: (fn, syncId = nanoid()) => {
1011
1050
  if (syncIds.has(syncId)) return;
1012
- syncIds.add(syncId);
1051
+ rememberSyncId(syncIds, syncId);
1013
1052
  if (enablePatches$1) {
1014
1053
  const [newState, patches] = produceWithPatches(state, fn);
1015
1054
  state = newState;
@@ -1132,8 +1171,18 @@ function createStorage(options) {
1132
1171
  enablePatches: false
1133
1172
  });
1134
1173
  state.on("updated", debounce((newState) => {
1135
- fs.mkdirSync(dirname(options.filepath), { recursive: true });
1136
- fs.writeFileSync(options.filepath, `${JSON.stringify(newState, null, 2)}\n`);
1174
+ try {
1175
+ const dir = dirname(options.filepath);
1176
+ fs.mkdirSync(dir, { recursive: true });
1177
+ const tmp = `${options.filepath}.${process$1.pid}.tmp`;
1178
+ fs.writeFileSync(tmp, `${JSON.stringify(newState, null, 2)}\n`);
1179
+ fs.renameSync(tmp, options.filepath);
1180
+ } catch (error) {
1181
+ diagnostics.DF0035({
1182
+ filepath: options.filepath,
1183
+ cause: error
1184
+ }, { method: "error" });
1185
+ }
1137
1186
  }, debounceTime));
1138
1187
  return state;
1139
1188
  }
@@ -1,4 +1,4 @@
1
- import { $ as ScopedServerFunctions, G as DevframeScopedNodeContext, H as EntriesToObject, J as DevframeSettings, K as DevframeScopedNodeRpc, Q as ScopedClientFunctions, S as RpcStreamingHost, St as EventsMap, U as PartialWithoutId, W as Thenable, X as DevframeSettingsStore, Y as DevframeSettingsRegistry, Z as ScopedBroadcastOptions, _ as RpcFunctionsHost, _t as AgentToolInput, a as DevframeDuplicationStrategy, at as DevframeRpcSharedStates, b as RpcStreamingChannel, bt as EventEmitter, c as DevframeSpaOptions, ct as DevframeDiagnosticsDefinition, d as ConnectionMeta, dt as AgentHandle, et as ScopedSharedStates, f as ConnectionMetaWebsocket, ft as AgentManifest, g as RpcBroadcastOptions, gt as AgentTool, h as DevframeNodeRpcSession, ht as AgentResourceInput, i as DevframeDeploymentKind, it as DevframeRpcServerFunctions, l as DevframeWsOptions, lt as DevframeDiagnosticsHost, m as DevframeNodeContext, mt as AgentResourceContent, n as DevframeCliOptions, nt as DevframeViewHost, o as DevframeRuntime, ot as DevframeHost, p as DevframeCapabilities, pt as AgentResource, q as DevframeScopedStreamingHost, r as DevframeDefinition, rt as DevframeRpcClientFunctions, s as DevframeSetupInfo, st as DevframeDefineDiagnosticsOptions, t as DevframeBrowserContext, tt as SettingsForNamespace, u as defineDevframe, ut as DevframeDiagnosticsLogger, v as RpcSharedStateGetOptions, vt as DevframeAgentHost, x as RpcStreamingChannelOptions, xt as EventUnsubscribe, y as RpcSharedStateHost, yt as DevframeAgentHostEvents } from "../devframe-D-gr9sBx.mjs";
1
+ import { $ as ScopedClientFunctions, C as RpcStreamingHost, Ct as EventsMap, G as Thenable, J as DevframeScopedStreamingHost, K as DevframeScopedNodeContext, Q as ScopedBroadcastOptions, S as RpcStreamingChannelOptions, St as EventUnsubscribe, U as EntriesToObject, W as PartialWithoutId, X as DevframeSettingsRegistry, Y as DevframeSettings, Z as DevframeSettingsStore, _ as RpcBroadcastOptions, _t as AgentTool, a as DevframeDuplicationStrategy, at as DevframeRpcServerFunctions, b as RpcSharedStateHost, bt as DevframeAgentHostEvents, c as DevframeSpaOptions, ct as DevframeDefineDiagnosticsOptions, d as defineDevframe, dt as DevframeDiagnosticsLogger, et as ScopedServerFunctions, f as ConnectionMeta, ft as AgentHandle, g as DevframeNodeRpcSession, gt as AgentResourceInput, h as DevframeNodeContext, ht as AgentResourceContent, i as DevframeDeploymentKind, it as DevframeRpcClientFunctions, l as DevframeWsOptions, lt as DevframeDiagnosticsDefinition, m as DevframeCapabilities, mt as AgentResource, n as DevframeCliOptions, nt as SettingsForNamespace, o as DevframeRuntime, ot as DevframeRpcSharedStates, p as ConnectionMetaWebsocket, pt as AgentManifest, q as DevframeScopedNodeRpc, r as DevframeDefinition, rt as DevframeViewHost, s as DevframeSetupInfo, st as DevframeHost, t as DevframeBrowserContext, tt as ScopedSharedStates, u as McpRouteOptions, ut as DevframeDiagnosticsHost, v as RpcFunctionsHost, vt as AgentToolInput, x as RpcStreamingChannel, xt as EventEmitter, y as RpcSharedStateGetOptions, yt as DevframeAgentHost } from "../devframe-BtVHhmwM.mjs";
2
2
  import { g as RpcFunctionAgentOptions } from "../types-DZEx4ffs.mjs";
3
3
  import { t as DevframeNodeRpcSessionMeta } from "../ws-server-Bc2wBHl-.mjs";
4
- export { AgentHandle, AgentManifest, AgentResource, AgentResourceContent, AgentResourceInput, AgentTool, AgentToolInput, ConnectionMeta, ConnectionMetaWebsocket, DevframeAgentHost, DevframeAgentHostEvents, DevframeBrowserContext, DevframeCapabilities, DevframeCliOptions, DevframeDefineDiagnosticsOptions, DevframeDefinition, DevframeDeploymentKind, DevframeDiagnosticsDefinition, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeDuplicationStrategy, DevframeHost, DevframeNodeContext, DevframeNodeRpcSession, DevframeNodeRpcSessionMeta, DevframeRpcClientFunctions, DevframeRpcServerFunctions, DevframeRpcSharedStates, DevframeRuntime, DevframeScopedNodeContext, DevframeScopedNodeRpc, DevframeScopedStreamingHost, DevframeSettings, DevframeSettingsRegistry, DevframeSettingsStore, DevframeSetupInfo, DevframeSpaOptions, DevframeViewHost, DevframeWsOptions, EntriesToObject, EventEmitter, EventUnsubscribe, EventsMap, PartialWithoutId, RpcBroadcastOptions, RpcFunctionAgentOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, ScopedBroadcastOptions, ScopedClientFunctions, ScopedServerFunctions, ScopedSharedStates, SettingsForNamespace, Thenable, defineDevframe };
4
+ export { AgentHandle, AgentManifest, AgentResource, AgentResourceContent, AgentResourceInput, AgentTool, AgentToolInput, ConnectionMeta, ConnectionMetaWebsocket, DevframeAgentHost, DevframeAgentHostEvents, DevframeBrowserContext, DevframeCapabilities, DevframeCliOptions, DevframeDefineDiagnosticsOptions, DevframeDefinition, DevframeDeploymentKind, DevframeDiagnosticsDefinition, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeDuplicationStrategy, DevframeHost, DevframeNodeContext, DevframeNodeRpcSession, type DevframeNodeRpcSessionMeta, DevframeRpcClientFunctions, DevframeRpcServerFunctions, DevframeRpcSharedStates, DevframeRuntime, DevframeScopedNodeContext, DevframeScopedNodeRpc, DevframeScopedStreamingHost, DevframeSettings, DevframeSettingsRegistry, DevframeSettingsStore, DevframeSetupInfo, DevframeSpaOptions, DevframeViewHost, DevframeWsOptions, EntriesToObject, EventEmitter, EventUnsubscribe, EventsMap, McpRouteOptions, PartialWithoutId, RpcBroadcastOptions, type RpcFunctionAgentOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, ScopedBroadcastOptions, ScopedClientFunctions, ScopedServerFunctions, ScopedSharedStates, SettingsForNamespace, Thenable, defineDevframe };
@@ -19,7 +19,7 @@ function randomToken(byteLength = 16) {
19
19
  */
20
20
  function randomDigits(length) {
21
21
  const limit = 250;
22
- const buf = new Uint8Array(1);
22
+ const buf = /* @__PURE__ */ new Uint8Array(1);
23
23
  let out = "";
24
24
  while (out.length < length) {
25
25
  globalThis.crypto.getRandomValues(buf);
@@ -1,4 +1,4 @@
1
- import { St as EventsMap, bt as EventEmitter } from "../devframe-D-gr9sBx.mjs";
1
+ import { Ct as EventsMap, xt as EventEmitter } from "../devframe-BtVHhmwM.mjs";
2
2
 
3
3
  //#region src/utils/events.d.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { t as hash } from "../hash-DFc5WwhO.mjs";
1
+ import { t as hash } from "../hash-PAfnyu2k.mjs";
2
2
  export { hash };
@@ -1,2 +1,2 @@
1
- import { t as launchEditor } from "../launch-editor-DPfltGA4.mjs";
1
+ import { t as launchEditor } from "../launch-editor-DIzaS5EG.mjs";
2
2
  export { launchEditor };
@@ -1,2 +1,2 @@
1
- import { t as open } from "../open-Dusa2Zzd.mjs";
1
+ import { t as open } from "../open-Deb5xmIT.mjs";
2
2
  export { open };
@@ -143,7 +143,8 @@ function serveStaticNodeMiddleware(dir, options) {
143
143
  res.end();
144
144
  return;
145
145
  }
146
- const file = await resolveTarget(absDir, req.url ?? "/", opts.indexNames, opts.single);
146
+ const url = req.url ?? "/";
147
+ const file = await resolveTarget(absDir, url, opts.indexNames, opts.single);
147
148
  if (!file) {
148
149
  if (next) {
149
150
  next();