veryfront 0.1.738 → 0.1.742

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 (78) hide show
  1. package/esm/cli/templates/manifest.js +3 -3
  2. package/esm/deno.js +1 -1
  3. package/esm/src/agent/ag-ui/sse-parser.d.ts.map +1 -1
  4. package/esm/src/agent/ag-ui/sse-parser.js +20 -12
  5. package/esm/src/agent/hosted/child-tool-input.js +1 -1
  6. package/esm/src/agent/react/use-chat/streaming/handler.d.ts.map +1 -1
  7. package/esm/src/agent/react/use-chat/streaming/handler.js +53 -39
  8. package/esm/src/fs/index.d.ts +1 -1
  9. package/esm/src/fs/index.d.ts.map +1 -1
  10. package/esm/src/fs/index.js +1 -1
  11. package/esm/src/mcp/http-transport.js +1 -1
  12. package/esm/src/mcp/server.d.ts.map +1 -1
  13. package/esm/src/mcp/server.js +1 -4
  14. package/esm/src/mcp/session.d.ts +23 -0
  15. package/esm/src/mcp/session.d.ts.map +1 -1
  16. package/esm/src/mcp/session.js +46 -3
  17. package/esm/src/modules/manifest/route-module-manifest.d.ts.map +1 -1
  18. package/esm/src/modules/manifest/route-module-manifest.js +12 -4
  19. package/esm/src/modules/react-loader/ssr-module-loader/cross-project-import-loader.d.ts.map +1 -1
  20. package/esm/src/modules/react-loader/ssr-module-loader/cross-project-import-loader.js +2 -1
  21. package/esm/src/modules/server/cross-project-source-limit.d.ts +7 -0
  22. package/esm/src/modules/server/cross-project-source-limit.d.ts.map +1 -0
  23. package/esm/src/modules/server/cross-project-source-limit.js +46 -0
  24. package/esm/src/modules/server/module-batch-handler.d.ts.map +1 -1
  25. package/esm/src/modules/server/module-batch-handler.js +3 -4
  26. package/esm/src/modules/server/module-server.d.ts.map +1 -1
  27. package/esm/src/modules/server/module-server.js +11 -1
  28. package/esm/src/oauth/handlers/init-handler.js +6 -6
  29. package/esm/src/oauth/providers/base.d.ts +3 -0
  30. package/esm/src/oauth/providers/base.d.ts.map +1 -1
  31. package/esm/src/oauth/providers/base.js +24 -2
  32. package/esm/src/platform/compat/fs.d.ts +6 -0
  33. package/esm/src/platform/compat/fs.d.ts.map +1 -1
  34. package/esm/src/platform/compat/fs.js +12 -0
  35. package/esm/src/provider/runtime-loader/tool-input-status.d.ts.map +1 -1
  36. package/esm/src/provider/runtime-loader/tool-input-status.js +16 -8
  37. package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.d.ts +2 -0
  38. package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.d.ts.map +1 -1
  39. package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.js +23 -10
  40. package/esm/src/rendering/renderer-concurrency.d.ts.map +1 -1
  41. package/esm/src/rendering/renderer-concurrency.js +9 -2
  42. package/esm/src/security/sandbox/worker-permissions.d.ts +10 -7
  43. package/esm/src/security/sandbox/worker-permissions.d.ts.map +1 -1
  44. package/esm/src/security/sandbox/worker-permissions.js +32 -12
  45. package/esm/src/security/utils/constant-time.d.ts.map +1 -1
  46. package/esm/src/security/utils/constant-time.js +4 -1
  47. package/esm/src/server/services/rendering/ssr.service.d.ts.map +1 -1
  48. package/esm/src/server/services/rendering/ssr.service.js +6 -3
  49. package/esm/src/transforms/mdx/esm-module-loader/loader-helpers.d.ts +4 -0
  50. package/esm/src/transforms/mdx/esm-module-loader/loader-helpers.d.ts.map +1 -1
  51. package/esm/src/transforms/mdx/esm-module-loader/loader-helpers.js +22 -18
  52. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fetcher.d.ts.map +1 -1
  53. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fetcher.js +27 -8
  54. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.d.ts.map +1 -1
  55. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.js +24 -14
  56. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts +1 -1
  57. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts.map +1 -1
  58. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.js +1 -1
  59. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/nested-imports.d.ts +4 -0
  60. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/nested-imports.d.ts.map +1 -1
  61. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/nested-imports.js +45 -37
  62. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/path-cache-lookup.d.ts.map +1 -1
  63. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/path-cache-lookup.js +6 -1
  64. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/render-sessions.d.ts +5 -0
  65. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/render-sessions.d.ts.map +1 -1
  66. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/render-sessions.js +27 -2
  67. package/esm/src/transforms/mdx/esm-module-loader/types.d.ts +2 -0
  68. package/esm/src/transforms/mdx/esm-module-loader/types.d.ts.map +1 -1
  69. package/esm/src/transforms/mdx/esm-module-loader/utils/source-spans.d.ts +23 -0
  70. package/esm/src/transforms/mdx/esm-module-loader/utils/source-spans.d.ts.map +1 -0
  71. package/esm/src/transforms/mdx/esm-module-loader/utils/source-spans.js +188 -0
  72. package/esm/src/utils/version-constant.d.ts +1 -1
  73. package/esm/src/utils/version-constant.js +1 -1
  74. package/esm/src/workflow/executor/dag/index.d.ts.map +1 -1
  75. package/esm/src/workflow/executor/dag/index.js +9 -8
  76. package/esm/src/workflow/worker/workflow-worker.d.ts.map +1 -1
  77. package/esm/src/workflow/worker/workflow-worker.js +9 -1
  78. package/package.json +1 -1
@@ -39,9 +39,9 @@ export default {
39
39
  "app/page.tsx": "'use client'\n\nimport { Chat, useChat } from 'veryfront/chat'\n\nexport default function CodeAgent(): JSX.Element {\n const chat = useChat({ api: '/api/ag-ui' })\n\n return (\n <Chat\n {...chat}\n className=\"flex-1 min-h-0\"\n placeholder=\"Describe what you want to build or fix...\"\n />\n )\n}\n",
40
40
  "globals.css": "@import \"tailwindcss\";\n",
41
41
  "README.md": "# Coding Agent\n\nAn AI assistant that can read, understand, and modify project files.\n\n## What's included\n\n- Coder agent with file system tools\n- Read, list, and edit files through conversation\n- Safe search/replace editing pattern\n\n## Structure\n\n```\nagents/coder.ts Agent with coding instructions\ntools/\n read-file.ts Read file contents\n list-files.ts List directory contents\n edit-file.ts Search and replace in files\napp/\n api/ag-ui/route.ts AG-UI endpoint\n page.tsx Chat interface\n```\n\nThis starter is not production-ready.\n",
42
- "tools/edit-file.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { readTextFile, writeTextFile, resolve, cwd } from \"veryfront/fs\";\n\nexport default tool({\n id: \"edit-file\",\n description: \"Edit a file by replacing a specific string with new content\",\n inputSchema: defineSchema((v) => v.object({\n path: v.string().describe(\"File path relative to the project root\"),\n search: v.string().describe(\"Exact string to find in the file\"),\n replace: v.string().describe(\"String to replace it with\"),\n }))(),\n execute: async ({ path, search, replace }) => {\n const absolute = resolve(cwd(), path);\n\n let content: string;\n try {\n content = await readTextFile(absolute);\n } catch {\n return { error: `File not found: ${path}` };\n }\n\n if (!content.includes(search)) {\n return { error: \"Search string not found in file\" };\n }\n\n const updated = content.replace(search, replace);\n await writeTextFile(absolute, updated);\n return { path, success: true };\n },\n});\n",
43
- "tools/list-files.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { readDir, resolve, cwd } from \"veryfront/fs\";\n\nexport default tool({\n id: \"list-files\",\n description: \"List files in a project directory\",\n inputSchema: defineSchema((v) => v.object({\n directory: v\n .string()\n .default(\".\")\n .describe(\"Directory path relative to project root\"),\n extensions: v\n .array(v.string())\n .optional()\n .describe(\"Filter by file extensions (e.g. ['.ts', '.tsx'])\"),\n }))(),\n execute: async ({ directory, extensions }) => {\n const absolute = resolve(cwd(), directory);\n const entries = await readDir(absolute);\n\n let files = entries\n .filter((e) => e.isFile)\n .map((e) => e.name);\n\n if (extensions?.length) {\n files = files.filter((f) =>\n extensions.some((ext) => f.endsWith(ext))\n );\n }\n\n return { directory, files, count: files.length };\n },\n});\n",
44
- "tools/read-file.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { readTextFile, resolve, cwd } from \"veryfront/fs\";\n\nexport default tool({\n id: \"read-file\",\n description: \"Read the contents of a file in the project\",\n inputSchema: defineSchema((v) => v.object({\n path: v.string().describe(\"File path relative to the project root\"),\n }))(),\n execute: async ({ path }) => {\n try {\n const absolute = resolve(cwd(), path);\n const content = await readTextFile(absolute);\n return { path, content };\n } catch {\n return { error: `File not found: ${path}` };\n }\n },\n});\n",
42
+ "tools/edit-file.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { cwd, readTextFile, realPath, resolve, writeTextFile } from \"veryfront/fs\";\n\n/** True when `target` is the same as, or nested under, `root` (both canonical). */\nfunction isWithin(root: string, target: string): boolean {\n const r = root.replace(/\\\\/g, \"/\");\n const t = target.replace(/\\\\/g, \"/\");\n return t === r || t.startsWith(`${r}/`);\n}\n\nexport default tool({\n id: \"edit-file\",\n description: \"Edit a file by replacing a specific string with new content\",\n inputSchema: defineSchema((v) => v.object({\n path: v.string().describe(\"File path relative to the project root\"),\n search: v.string().describe(\"Exact string to find in the file\"),\n replace: v.string().describe(\"String to replace it with\"),\n }))(),\n execute: async ({ path, search, replace }) => {\n let projectDir: string;\n let absolute: string;\n try {\n // Canonicalize both sides so a symlink that points outside the project\n // is resolved to its real target before the containment check.\n projectDir = await realPath(cwd());\n absolute = await realPath(resolve(projectDir, path));\n } catch {\n return { error: `File not found: ${path}` };\n }\n if (!isWithin(projectDir, absolute)) {\n return { error: `Path escapes project directory: ${path}` };\n }\n\n const content = await readTextFile(absolute);\n if (!content.includes(search)) {\n return { error: \"Search string not found in file\" };\n }\n\n const updated = content.replace(search, replace);\n await writeTextFile(absolute, updated);\n return { path, success: true };\n },\n});\n",
43
+ "tools/list-files.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { cwd, readDir, realPath, resolve } from \"veryfront/fs\";\n\n/** True when `target` is the same as, or nested under, `root` (both canonical). */\nfunction isWithin(root: string, target: string): boolean {\n const r = root.replace(/\\\\/g, \"/\");\n const t = target.replace(/\\\\/g, \"/\");\n return t === r || t.startsWith(`${r}/`);\n}\n\nexport default tool({\n id: \"list-files\",\n description: \"List files in a project directory\",\n inputSchema: defineSchema((v) => v.object({\n directory: v\n .string()\n .default(\".\")\n .describe(\"Directory path relative to project root\"),\n extensions: v\n .array(v.string())\n .optional()\n .describe(\"Filter by file extensions (e.g. ['.ts', '.tsx'])\"),\n }))(),\n execute: async ({ directory, extensions }) => {\n let projectDir: string;\n let absolute: string;\n try {\n // Canonicalize both sides so a symlink that points outside the project\n // is resolved to its real target before the containment check.\n projectDir = await realPath(cwd());\n absolute = await realPath(resolve(projectDir, directory));\n } catch {\n return { error: `Directory not found: ${directory}` };\n }\n if (!isWithin(projectDir, absolute)) {\n return { error: `Path escapes project directory: ${directory}` };\n }\n\n const entries = await readDir(absolute);\n\n let files = entries\n .filter((e) => e.isFile)\n .map((e) => e.name);\n\n if (extensions?.length) {\n files = files.filter((f) =>\n extensions.some((ext) => f.endsWith(ext))\n );\n }\n\n return { directory, files, count: files.length };\n },\n});\n",
44
+ "tools/read-file.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { cwd, readTextFile, realPath, resolve } from \"veryfront/fs\";\n\n/** True when `target` is the same as, or nested under, `root` (both canonical). */\nfunction isWithin(root: string, target: string): boolean {\n const r = root.replace(/\\\\/g, \"/\");\n const t = target.replace(/\\\\/g, \"/\");\n return t === r || t.startsWith(`${r}/`);\n}\n\nexport default tool({\n id: \"read-file\",\n description: \"Read the contents of a file in the project\",\n inputSchema: defineSchema((v) => v.object({\n path: v.string().describe(\"File path relative to the project root\"),\n }))(),\n execute: async ({ path }) => {\n let projectDir: string;\n let absolute: string;\n try {\n // Canonicalize both sides so a symlink that points outside the project\n // is resolved to its real target before the containment check.\n projectDir = await realPath(cwd());\n absolute = await realPath(resolve(projectDir, path));\n } catch {\n return { error: `File not found: ${path}` };\n }\n if (!isWithin(projectDir, absolute)) {\n return { error: `Path escapes project directory: ${path}` };\n }\n const content = await readTextFile(absolute);\n return { path, content };\n },\n});\n",
45
45
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"jsx\": \"react-jsx\",\n \"skipLibCheck\": true,\n \"esModuleInterop\": true,\n \"paths\": {\n \"@/*\": [\"./*\"]\n }\n },\n \"include\": [\"**/*.ts\", \"**/*.tsx\"],\n \"exclude\": [\"node_modules\"]\n}\n"
46
46
  }
47
47
  },
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.738",
3
+ "version": "0.1.742",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": "P2D",
@@ -1 +1 @@
1
- {"version":3,"file":"sse-parser.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/ag-ui/sse-parser.ts"],"names":[],"mappings":"AAGA,kFAAkF;AAClF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;CAmBpB,CAAC;AAEX,iDAAiD;AACjD,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;AAE1F,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC1C,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACzD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE5D;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGjG;AAED,+DAA+D;AAC/D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACtC,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAEhC;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAEvE;AAoLD,yGAAyG;AACzG,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,gBAAgB,CAAC,CA6C3B"}
1
+ {"version":3,"file":"sse-parser.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/ag-ui/sse-parser.ts"],"names":[],"mappings":"AAGA,kFAAkF;AAClF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;CAmBpB,CAAC;AAEX,iDAAiD;AACjD,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;AAE1F,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC1C,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACzD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE5D;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGjG;AAED,+DAA+D;AAC/D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACtC,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAEhC;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAEvE;AAoLD,yGAAyG;AACzG,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,gBAAgB,CAAC,CAoD3B"}
@@ -197,20 +197,28 @@ export async function parseAgUiSseResponse(response, options = {}) {
197
197
  else {
198
198
  const reader = response.body.getReader();
199
199
  let buffer = "";
200
- while (true) {
201
- const result = await reader.read();
202
- if (result.done) {
203
- const tail = decoder.decode();
204
- if (tail.length > 0) {
205
- rawChunks.push(tail);
206
- buffer += tail;
200
+ // try/finally so an error/abort mid-read still releases the reader lock;
201
+ // otherwise the underlying ReadableStream stays locked and the response
202
+ // body leaks.
203
+ try {
204
+ while (true) {
205
+ const result = await reader.read();
206
+ if (result.done) {
207
+ const tail = decoder.decode();
208
+ if (tail.length > 0) {
209
+ rawChunks.push(tail);
210
+ buffer += tail;
211
+ }
212
+ break;
207
213
  }
208
- break;
214
+ const decoded = decoder.decode(result.value, { stream: true });
215
+ rawChunks.push(decoded);
216
+ buffer += decoded;
217
+ buffer = consumeSseBuffer(run, buffer, options, state);
209
218
  }
210
- const decoded = decoder.decode(result.value, { stream: true });
211
- rawChunks.push(decoded);
212
- buffer += decoded;
213
- buffer = consumeSseBuffer(run, buffer, options, state);
219
+ }
220
+ finally {
221
+ reader.releaseLock();
214
222
  }
215
223
  }
216
224
  if (options.onProgress) {
@@ -5,7 +5,7 @@ export const DEFAULT_HOSTED_CHILD_AGENT_ID = "invoke-agent-child";
5
5
  export const getHostedChildForkToolInputSchema = defineSchema((v) => v.object({
6
6
  description: v.string().describe("3-5 word task summary"),
7
7
  prompt: v.string().describe("Detailed instructions for the task"),
8
- context: v.record(v.string(), getJsonValueSchema()).describe("Required structured data payload for the child task. Use this for critical facts, records, ids, decisions, and values the child must act on. Use {} only when the delegation has no record or evidence payload."),
8
+ context: v.record(v.string(), getJsonValueSchema()).default({}).describe("Structured data payload for the child task. Use this for critical facts, records, ids, decisions, and values the child must act on. Defaults to {} when the delegation has no record or evidence payload."),
9
9
  project_id: v.string().optional().describe("Override project context. Use after studio_open_project."),
10
10
  tools: v.array(v.string()).optional().describe("Tool subset for this fork. Omit = inherit all parent tools."),
11
11
  model: v.string().optional().describe('Model override (e.g. "sonnet" for cheaper work).'),
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../../../src/src/agent/react/use-chat/streaming/handler.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAKV,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AA8BpB,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,cAAc,EACpB,SAAS,EAAE,kBAAkB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAmDf;AAED,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,cAAc,EACpB,SAAS,EAAE,kBAAkB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAsCf"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../../../src/src/agent/react/use-chat/streaming/handler.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAKV,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AA8BpB,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,cAAc,EACpB,SAAS,EAAE,kBAAkB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAyDf;AAED,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,cAAc,EACpB,SAAS,EAAE,kBAAkB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA4Cf"}
@@ -21,41 +21,48 @@ export async function handleStreamingResponse(body, callbacks) {
21
21
  const state = createStreamingState();
22
22
  const getBuildParts = () => buildCurrentParts(state.textBlocks, state.reasoningBlocks, state.toolCalls, state.steps, state.dataParts);
23
23
  let buffer = "";
24
- while (true) {
25
- const { done, value } = await reader.read();
26
- if (done)
27
- break;
28
- buffer += decoder.decode(value, { stream: true });
29
- const lines = buffer.split("\n");
30
- buffer = lines.pop() ?? ""; // last element may be incomplete
31
- for (const line of lines) {
32
- if (!line.startsWith("data: ") || !line.trim())
33
- continue;
34
- const data = line.slice(6);
35
- try {
36
- const raw = JSON.parse(data);
37
- if (!raw || typeof raw !== "object")
24
+ // try/finally so a read error or a throwing event handler still releases
25
+ // the reader lock, otherwise the stream stays locked and leaks.
26
+ try {
27
+ while (true) {
28
+ const { done, value } = await reader.read();
29
+ if (done)
30
+ break;
31
+ buffer += decoder.decode(value, { stream: true });
32
+ const lines = buffer.split("\n");
33
+ buffer = lines.pop() ?? ""; // last element may be incomplete
34
+ for (const line of lines) {
35
+ if (!line.startsWith("data: ") || !line.trim())
38
36
  continue;
39
- const parsed = raw;
40
- processStreamEvent(parsed, state, callbacks, getBuildParts);
41
- }
42
- catch (_) {
43
- /* expected: skip malformed JSON in SSE stream */
37
+ const data = line.slice(6);
38
+ try {
39
+ const raw = JSON.parse(data);
40
+ if (!raw || typeof raw !== "object")
41
+ continue;
42
+ const parsed = raw;
43
+ processStreamEvent(parsed, state, callbacks, getBuildParts);
44
+ }
45
+ catch (_) {
46
+ /* expected: skip malformed JSON in SSE stream */
47
+ }
44
48
  }
45
49
  }
46
- }
47
- // Process any remaining buffered data
48
- if (buffer.startsWith("data: ") && buffer.trim()) {
49
- try {
50
- const raw = JSON.parse(buffer.slice(6));
51
- if (raw && typeof raw === "object") {
52
- const parsed = raw;
53
- processStreamEvent(parsed, state, callbacks, getBuildParts);
50
+ // Process any remaining buffered data
51
+ if (buffer.startsWith("data: ") && buffer.trim()) {
52
+ try {
53
+ const raw = JSON.parse(buffer.slice(6));
54
+ if (raw && typeof raw === "object") {
55
+ const parsed = raw;
56
+ processStreamEvent(parsed, state, callbacks, getBuildParts);
57
+ }
58
+ }
59
+ catch {
60
+ // Skip invalid JSON
54
61
  }
55
62
  }
56
- catch {
57
- // Skip invalid JSON
58
- }
63
+ }
64
+ finally {
65
+ reader.releaseLock();
59
66
  }
60
67
  }
61
68
  export async function handleAgUiStreamingResponse(body, callbacks) {
@@ -69,18 +76,25 @@ export async function handleAgUiStreamingResponse(body, callbacks) {
69
76
  processChatStreamEvent(event, state, callbacks, getBuildParts);
70
77
  }
71
78
  };
72
- while (true) {
73
- const { done, value } = await reader.read();
74
- if (done)
75
- break;
76
- const decoded = decodeAgUiSseChunk(decoderState, decoder.decode(value, { stream: true }));
77
- for (const event of decoded.events) {
79
+ // try/finally so a read error or a throwing event handler still releases
80
+ // the reader lock, otherwise the stream stays locked and leaks.
81
+ try {
82
+ while (true) {
83
+ const { done, value } = await reader.read();
84
+ if (done)
85
+ break;
86
+ const decoded = decodeAgUiSseChunk(decoderState, decoder.decode(value, { stream: true }));
87
+ for (const event of decoded.events) {
88
+ processDecodedEvents(event.chatEvents);
89
+ }
90
+ }
91
+ const flushed = flushAgUiSseChunk(decoderState);
92
+ for (const event of flushed.events) {
78
93
  processDecodedEvents(event.chatEvents);
79
94
  }
80
95
  }
81
- const flushed = flushAgUiSseChunk(decoderState);
82
- for (const event of flushed.events) {
83
- processDecodedEvents(event.chatEvents);
96
+ finally {
97
+ reader.releaseLock();
84
98
  }
85
99
  }
86
100
  function processStreamEvent(parsed, state, callbacks, getBuildParts) {
@@ -28,7 +28,7 @@
28
28
  * ```
29
29
  */
30
30
  import "../../_dnt.polyfills.js";
31
- export { createFileSystem, exists, type FileSystem, mkdir, readDir, readTextFile, remove, writeTextFile, } from "../platform/compat/fs.js";
31
+ export { createFileSystem, exists, type FileSystem, mkdir, readDir, readTextFile, realPath, remove, writeTextFile, } from "../platform/compat/fs.js";
32
32
  export { basename, dirname, extname, join, resolve, } from "../platform/compat/path/index.js";
33
33
  export { cwd } from "../platform/compat/process.js";
34
34
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/fs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,EACL,gBAAgB,EAChB,MAAM,EACN,KAAK,UAAU,EACf,KAAK,EACL,OAAO,EACP,YAAY,EACZ,MAAM,EACN,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,QAAQ,EACR,OAAO,EACP,OAAO,EACP,IAAI,EACJ,OAAO,GACR,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/fs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,EACL,gBAAgB,EAChB,MAAM,EACN,KAAK,UAAU,EACf,KAAK,EACL,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,QAAQ,EACR,OAAO,EACP,OAAO,EACP,IAAI,EACJ,OAAO,GACR,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAC"}
@@ -28,6 +28,6 @@
28
28
  * ```
29
29
  */
30
30
  import "../../_dnt.polyfills.js";
31
- export { createFileSystem, exists, mkdir, readDir, readTextFile, remove, writeTextFile, } from "../platform/compat/fs.js";
31
+ export { createFileSystem, exists, mkdir, readDir, readTextFile, realPath, remove, writeTextFile, } from "../platform/compat/fs.js";
32
32
  export { basename, dirname, extname, join, resolve, } from "../platform/compat/path/index.js";
33
33
  export { cwd } from "../platform/compat/process.js";
@@ -76,7 +76,7 @@ export function createMCPHTTPHandler(dependencies) {
76
76
  return createJSONResponse(rpcResponse, { headers: responseHeaders });
77
77
  }
78
78
  let sessionId;
79
- if (sessionManager.size > 0) {
79
+ if (sessionManager.requiresSessionHeader()) {
80
80
  sessionId = request.headers.get("MCP-Session-Id") ?? undefined;
81
81
  if (!sessionId) {
82
82
  return createJSONRPCErrorResponse(400, -32600, "Missing MCP-Session-Id header");
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -493,10 +493,7 @@ export class MCPServer {
493
493
  const p = toParamsRecord(params);
494
494
  const level = p.level;
495
495
  if (!MCPServer.LOG_LEVELS.includes(level)) {
496
- return Promise.reject({
497
- code: -32602,
498
- message: `Invalid log level: ${level}. Valid levels: ${MCPServer.LOG_LEVELS.join(", ")}`,
499
- });
496
+ return Promise.reject(new JsonRpcError(-32602, `Invalid log level: ${level}. Valid levels: ${MCPServer.LOG_LEVELS.join(", ")}`));
500
497
  }
501
498
  this.logLevel = level;
502
499
  return Promise.resolve({});
@@ -1,9 +1,32 @@
1
+ /**
2
+ * Manages MCP sessions for the Streamable HTTP transport.
3
+ * Sessions are created during initialization and validated on subsequent requests.
4
+ *
5
+ * Sessions expire after a period of inactivity so that clients which disconnect
6
+ * uncleanly (closed tab, crash, dropped network) don't leak entries forever.
7
+ * Expiry is lazy: stale entries are pruned on access, so no background timer is
8
+ * required.
9
+ */
10
+ export interface SessionManagerOptions {
11
+ /** Inactivity TTL in ms (default 30 minutes). */
12
+ ttlMs?: number;
13
+ /** Clock, injectable for tests. Defaults to Date.now. */
14
+ now?: () => number;
15
+ }
1
16
  export declare class SessionManager {
17
+ /** id -> last-seen timestamp (ms). */
2
18
  private sessions;
19
+ private readonly ttlMs;
20
+ private readonly now;
21
+ private sessionHeaderRequired;
22
+ constructor(options?: SessionManagerOptions);
3
23
  create(): string;
4
24
  isValid(id: string): boolean;
5
25
  terminate(id: string): void;
6
26
  get size(): number;
7
27
  clear(): void;
28
+ requiresSessionHeader(): boolean;
29
+ private isExpired;
30
+ private pruneExpired;
8
31
  }
9
32
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/session.ts"],"names":[],"mappings":"AAMA,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAqB;IAErC,MAAM,IAAI,MAAM;IAMhB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI5B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI3B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,KAAK,IAAI,IAAI;CAGd"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,WAAW,qBAAqB;IACpC,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,cAAc;IACzB,sCAAsC;IACtC,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,qBAAqB,CAAS;gBAE1B,OAAO,GAAE,qBAA0B;IAK/C,MAAM,IAAI,MAAM;IAQhB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAY5B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK3B,IAAI,IAAI,IAAI,MAAM,CAGjB;IAED,KAAK,IAAI,IAAI;IAKb,qBAAqB,IAAI,OAAO;IAIhC,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,YAAY;CAMrB"}
@@ -1,25 +1,68 @@
1
1
  /**
2
2
  * Manages MCP sessions for the Streamable HTTP transport.
3
3
  * Sessions are created during initialization and validated on subsequent requests.
4
+ *
5
+ * Sessions expire after a period of inactivity so that clients which disconnect
6
+ * uncleanly (closed tab, crash, dropped network) don't leak entries forever.
7
+ * Expiry is lazy: stale entries are pruned on access, so no background timer is
8
+ * required.
4
9
  */
10
+ /** Default inactivity window before a session is considered expired (30 min). */
5
11
  import * as dntShim from "../../_dnt.shims.js";
12
+ const DEFAULT_SESSION_TTL_MS = 30 * 60_000;
6
13
  export class SessionManager {
7
- sessions = new Set();
14
+ /** id -> last-seen timestamp (ms). */
15
+ sessions = new Map();
16
+ ttlMs;
17
+ now;
18
+ sessionHeaderRequired = false;
19
+ constructor(options = {}) {
20
+ this.ttlMs = options.ttlMs ?? DEFAULT_SESSION_TTL_MS;
21
+ this.now = options.now ?? Date.now;
22
+ }
8
23
  create() {
24
+ this.pruneExpired();
9
25
  const id = dntShim.crypto.randomUUID();
10
- this.sessions.add(id);
26
+ this.sessions.set(id, this.now());
27
+ this.sessionHeaderRequired = true;
11
28
  return id;
12
29
  }
13
30
  isValid(id) {
14
- return this.sessions.has(id);
31
+ const lastSeen = this.sessions.get(id);
32
+ if (lastSeen === undefined)
33
+ return false;
34
+ if (this.isExpired(lastSeen)) {
35
+ this.sessions.delete(id);
36
+ return false;
37
+ }
38
+ // Touch: activity refreshes the inactivity window.
39
+ this.sessions.set(id, this.now());
40
+ return true;
15
41
  }
16
42
  terminate(id) {
17
43
  this.sessions.delete(id);
44
+ if (this.sessions.size === 0)
45
+ this.sessionHeaderRequired = false;
18
46
  }
19
47
  get size() {
48
+ this.pruneExpired();
20
49
  return this.sessions.size;
21
50
  }
22
51
  clear() {
23
52
  this.sessions.clear();
53
+ this.sessionHeaderRequired = false;
54
+ }
55
+ requiresSessionHeader() {
56
+ return this.sessionHeaderRequired;
57
+ }
58
+ isExpired(lastSeen) {
59
+ return this.now() - lastSeen > this.ttlMs;
60
+ }
61
+ pruneExpired() {
62
+ const cutoff = this.now() - this.ttlMs;
63
+ for (const [id, lastSeen] of this.sessions) {
64
+ if (lastSeen < cutoff)
65
+ this.sessions.delete(id);
66
+ }
24
67
  }
25
68
  }
@@ -1 +1 @@
1
- {"version":3,"file":"route-module-manifest.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/manifest/route-module-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAuBD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,UAAQ,GAChB,IAAI,CAEN;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,eAAe,GAAE,MAAM,EAAO,GAC7B,IAAI,CAwCN;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,aAAa,GAAG,IAAI,CAYtB;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAOV;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAQV;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,GAChB,IAAI,CA2BN;AAED,wBAAgB,sCAAsC,CACpD,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,SAAK,GACZ,MAAM,EAAE,CAQV;AAED,wBAAgB,gBAAgB,IAAI;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5E,CAcA;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAS/D;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC"}
1
+ {"version":3,"file":"route-module-manifest.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/manifest/route-module-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAyBD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,UAAQ,GAChB,IAAI,CAEN;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,eAAe,GAAE,MAAM,EAAO,GAC7B,IAAI,CAwCN;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,aAAa,GAAG,IAAI,CAYtB;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAOV;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAQV;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,GAChB,IAAI,CA2BN;AAED,wBAAgB,sCAAsC,CACpD,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,SAAK,GACZ,MAAM,EAAE,CAQV;AAED,wBAAgB,gBAAgB,IAAI;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5E,CAcA;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAU/D;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC"}
@@ -10,9 +10,16 @@
10
10
  * @module module-system/manifest/route-module-manifest
11
11
  */
12
12
  import { serverLogger } from "../../utils/index.js";
13
+ import { LRUCache } from "../../utils/lru-wrapper.js";
13
14
  const logger = serverLogger.component("route-module-manifest");
14
- const manifestStore = new Map();
15
- const pendingCollections = new Map();
15
+ /** Bound on tracked routes; manifests are a regenerable preload optimization. */
16
+ const MAX_TRACKED_ROUTES = 2_000;
17
+ /** Bound on in-flight collections; abandoned ones (render errors) get evicted. */
18
+ const MAX_PENDING_COLLECTIONS = 2_000;
19
+ const manifestStore = new LRUCache({ maxEntries: MAX_TRACKED_ROUTES });
20
+ const pendingCollections = new LRUCache({
21
+ maxEntries: MAX_PENDING_COLLECTIONS,
22
+ });
16
23
  function buildKey(projectSlug, route) {
17
24
  return `${projectSlug ?? "default"}:${route || "index"}`;
18
25
  }
@@ -132,7 +139,7 @@ export function generateModulePreloadHintsFromManifest(projectSlug, route, maxHi
132
139
  export function getManifestStats() {
133
140
  const routes = [];
134
141
  let totalModules = 0;
135
- for (const [key, manifest] of manifestStore) {
142
+ for (const [key, manifest] of manifestStore.entries()) {
136
143
  routes.push({
137
144
  route: key,
138
145
  moduleCount: manifest.moduleCount,
@@ -144,7 +151,8 @@ export function getManifestStats() {
144
151
  }
145
152
  export function clearProjectManifests(projectSlug) {
146
153
  const prefix = `${projectSlug}:`;
147
- for (const key of manifestStore.keys()) {
154
+ // Snapshot keys before deleting to avoid mutating during iteration.
155
+ for (const key of [...manifestStore.keys()]) {
148
156
  if (!key.startsWith(prefix))
149
157
  continue;
150
158
  manifestStore.delete(key);
@@ -1 +1 @@
1
- {"version":3,"file":"cross-project-import-loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/cross-project-import-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAInF,OAAO,EAAE,cAAc,IAAI,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,UAAU,uBAAuB;IAC/B,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE,KAAK,IAAI,UAAU,CAAC;CACrB;AAED,UAAU,sCAAsC;IAC9C,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,OAAO,EAAE,IAAI,CACX,sBAAsB,EACtB,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,CAC/E,CAAC;IACF,KAAK,EAAE,uBAAuB,CAAC;IAC/B,qBAAqB,EAAE,CAAC,CAAC,EACvB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KACxB,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,cAAc,CAAC;IAC3C,iBAAiB,CAAC,EAAE,OAAO,aAAa,CAAC;IACzC,UAAU,CAAC,EAAE,IAAI,CAAC,OAAO,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAOD,wBAAsB,+BAA+B,CACnD,WAAW,EAAE,sCAAsC,GAClD,OAAO,CAAC,MAAM,CAAC,CA0GjB"}
1
+ {"version":3,"file":"cross-project-import-loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/cross-project-import-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAInF,OAAO,EAAE,cAAc,IAAI,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGzD,UAAU,uBAAuB;IAC/B,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE,KAAK,IAAI,UAAU,CAAC;CACrB;AAED,UAAU,sCAAsC;IAC9C,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,OAAO,EAAE,IAAI,CACX,sBAAsB,EACtB,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,CAC/E,CAAC;IACF,KAAK,EAAE,uBAAuB,CAAC;IAC/B,qBAAqB,EAAE,CAAC,CAAC,EACvB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KACxB,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,cAAc,CAAC;IAC3C,iBAAiB,CAAC,EAAE,OAAO,aAAa,CAAC;IACzC,UAAU,CAAC,EAAE,IAAI,CAAC,OAAO,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAOD,wBAAsB,+BAA+B,CACnD,WAAW,EAAE,sCAAsC,GAClD,OAAO,CAAC,MAAM,CAAC,CA0GjB"}
@@ -7,6 +7,7 @@ import { HTTP_FETCH_TIMEOUT_MS } from "../../../utils/constants/http.js";
7
7
  import { writeCacheFile } from "../../../utils/cache-file-ops.js";
8
8
  import { rendererLogger as logger } from "../../../utils/index.js";
9
9
  import { globalCrossProjectCache } from "./cache/index.js";
10
+ import { readLimitedCrossProjectSource } from "../../server/cross-project-source-limit.js";
10
11
  function getRegistryBaseUrl(apiBaseUrl) {
11
12
  const resolvedApiBaseUrl = apiBaseUrl || getApiBaseUrlEnv();
12
13
  return resolvedApiBaseUrl.replace(/\/api\/?$/, "");
@@ -40,7 +41,7 @@ export async function transformCrossProjectImportFlow(flowOptions) {
40
41
  detail: `Failed to fetch ${registryUrl}: ${response.status} ${response.statusText}`,
41
42
  });
42
43
  }
43
- const sourceCode = await response.text();
44
+ const sourceCode = await readLimitedCrossProjectSource(response, registryUrl);
44
45
  const contentHash = await cache.hashContentAsync(sourceCode);
45
46
  const ext = path.match(/\.(tsx?|jsx?|mdx)$/)?.[0] ?? ".tsx";
46
47
  const syntheticFilePath = `cross-project/${projectRef}/@/${path}`;
@@ -0,0 +1,7 @@
1
+ /** Max size of a fetched cross-project module source, to bound memory use. */
2
+ export declare const MAX_CROSS_PROJECT_SOURCE_BYTES: number;
3
+ export declare class CrossProjectSourceTooLargeError extends Error {
4
+ constructor(registryUrl: string, maxBytes?: number);
5
+ }
6
+ export declare function readLimitedCrossProjectSource(response: Response, registryUrl: string, maxBytes?: number): Promise<string>;
7
+ //# sourceMappingURL=cross-project-source-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-project-source-limit.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/cross-project-source-limit.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,eAAO,MAAM,8BAA8B,QAAkB,CAAC;AAE9D,qBAAa,+BAAgC,SAAQ,KAAK;gBAC5C,WAAW,EAAE,MAAM,EAAE,QAAQ,SAAiC;CAI3E;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,SAAiC,GACxC,OAAO,CAAC,MAAM,CAAC,CAwCjB"}
@@ -0,0 +1,46 @@
1
+ /** Max size of a fetched cross-project module source, to bound memory use. */
2
+ export const MAX_CROSS_PROJECT_SOURCE_BYTES = 5 * 1024 * 1024; // 5MB
3
+ export class CrossProjectSourceTooLargeError extends Error {
4
+ constructor(registryUrl, maxBytes = MAX_CROSS_PROJECT_SOURCE_BYTES) {
5
+ super(`Cross-project source exceeds size limit: ${registryUrl} (${maxBytes} bytes)`);
6
+ this.name = "CrossProjectSourceTooLargeError";
7
+ }
8
+ }
9
+ export async function readLimitedCrossProjectSource(response, registryUrl, maxBytes = MAX_CROSS_PROJECT_SOURCE_BYTES) {
10
+ const declaredLength = Number(response.headers.get("content-length") ?? "");
11
+ if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
12
+ await response.body?.cancel();
13
+ throw new CrossProjectSourceTooLargeError(registryUrl, maxBytes);
14
+ }
15
+ if (!response.body) {
16
+ const text = await response.text();
17
+ if (new TextEncoder().encode(text).byteLength > maxBytes) {
18
+ throw new CrossProjectSourceTooLargeError(registryUrl, maxBytes);
19
+ }
20
+ return text;
21
+ }
22
+ const reader = response.body.getReader();
23
+ const decoder = new TextDecoder();
24
+ const chunks = [];
25
+ let totalBytes = 0;
26
+ try {
27
+ while (true) {
28
+ const { done, value } = await reader.read();
29
+ if (done)
30
+ break;
31
+ totalBytes += value.byteLength;
32
+ if (totalBytes > maxBytes) {
33
+ await reader.cancel();
34
+ throw new CrossProjectSourceTooLargeError(registryUrl, maxBytes);
35
+ }
36
+ chunks.push(decoder.decode(value, { stream: true }));
37
+ }
38
+ const tail = decoder.decode();
39
+ if (tail.length > 0)
40
+ chunks.push(tail);
41
+ return chunks.join("");
42
+ }
43
+ finally {
44
+ reader.releaseLock();
45
+ }
46
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"module-batch-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-batch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAqDtE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2K/F;AA4JD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAY1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKrE"}
1
+ {"version":3,"file":"module-batch-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-batch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAqDtE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2K/F;AA2JD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAY1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKrE"}
@@ -298,10 +298,9 @@ function generateBatchBundle(successes, failures) {
298
298
  * Converts ES module syntax to work within the bundle wrapper
299
299
  */
300
300
  function transformExportsForBundle(code) {
301
- return code
302
- .split("\n")
303
- .map((line) => ` ${line}`)
304
- .join("\n");
301
+ // Indent every line by two spaces. A single regex avoids allocating an
302
+ // intermediate array of lines per module on the batch hot path.
303
+ return code.replace(/^/gm, " ");
305
304
  }
306
305
  /**
307
306
  * Clear the transform cache (on deployment or memory pressure)
@@ -1 +1 @@
1
- {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAsBtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAsDrD,CAAC;AASF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0TzF;AA+PD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGrD"}
1
+ {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAuBtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAsDrD,CAAC;AAQF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0TzF;AA+PD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGrD"}
@@ -15,6 +15,7 @@ import { applySSRImportRewrites } from "./ssr-import-rewriter.js";
15
15
  import { addHMRTimestamps } from "../../transforms/esm/import-rewriter.js";
16
16
  import { FRAMEWORK_ROOT, resolveFrameworkSourcePath, } from "../../platform/compat/framework-source-resolver.js";
17
17
  import { getReactUrls, REACT_DEFAULT_VERSION } from "../../utils/constants/cdn.js";
18
+ import { readLimitedCrossProjectSource } from "./cross-project-source-limit.js";
18
19
  const logger = serverLogger.component("module-server");
19
20
  /**
20
21
  * Embedded polyfills for compiled Deno binaries.
@@ -600,5 +601,14 @@ async function fetchCrossProjectSource(projectRef, filePath) {
600
601
  });
601
602
  return null;
602
603
  }
603
- return response.text();
604
+ try {
605
+ return await readLimitedCrossProjectSource(response, registryUrl);
606
+ }
607
+ catch (error) {
608
+ logger.warn("Cross-project source too large", {
609
+ registryUrl,
610
+ error: error instanceof Error ? error.message : String(error),
611
+ });
612
+ return null;
613
+ }
604
614
  }