theokit 0.73.0 → 0.74.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/{actions-virtual-module-OHENNMQG.js → actions-virtual-module-J2HYO7QZ.js} +4 -4
- package/dist/{actions-virtual-module-QCDKQ6QD.js → actions-virtual-module-JV7URROJ.js} +5 -5
- package/dist/adapters/agent-mount.js +3 -3
- package/dist/adapters/security-headers.js +9 -4
- package/dist/adapters/security-headers.js.map +1 -1
- package/dist/{agent-OWJ5A7W5.js → agent-5J7CQAYR.js} +3 -3
- package/dist/{app-typed-client-ILLQYTXP.js → app-typed-client-EOA3A2AR.js} +5 -5
- package/dist/{app-typed-client-ILLQYTXP.js.map → app-typed-client-EOA3A2AR.js.map} +1 -1
- package/dist/{app-typed-client-2PTK2SJH.js → app-typed-client-XD4DZBV7.js} +6 -6
- package/dist/app-typed-client-XD4DZBV7.js.map +1 -0
- package/dist/{aws-lambda-OP2L5RKZ.js → aws-lambda-ZYSPTD3O.js} +61 -27
- package/dist/aws-lambda-ZYSPTD3O.js.map +1 -0
- package/dist/{build-CVP2XU5M.js → build-7YZSJGP2.js} +79 -72
- package/dist/build-7YZSJGP2.js.map +1 -0
- package/dist/{bun-CZXHPK2W.js → bun-I7YM3RDB.js} +81 -20
- package/dist/bun-I7YM3RDB.js.map +1 -0
- package/dist/{chunk-WBB3MEEN.js → chunk-2NG5T77O.js} +47 -12
- package/dist/{chunk-WBB3MEEN.js.map → chunk-2NG5T77O.js.map} +1 -1
- package/dist/{chunk-NO6HA4FG.js → chunk-4WP7A7RX.js} +41 -35
- package/dist/chunk-4WP7A7RX.js.map +1 -0
- package/dist/chunk-4X43VTST.js +31 -0
- package/dist/chunk-4X43VTST.js.map +1 -0
- package/dist/{chunk-FHQP23Z5.js → chunk-6R5F5YF2.js} +17 -14
- package/dist/chunk-6R5F5YF2.js.map +1 -0
- package/dist/chunk-72RSCKMW.js +53 -0
- package/dist/chunk-72RSCKMW.js.map +1 -0
- package/dist/{chunk-SEGD3JUC.js → chunk-EQJF2EH5.js} +8 -7
- package/dist/chunk-EQJF2EH5.js.map +1 -0
- package/dist/{chunk-6U67SO5U.js → chunk-HK57MPSZ.js} +2 -2
- package/dist/{chunk-R7G2B2WH.js → chunk-HKF6YNY4.js} +17 -14
- package/dist/{chunk-R7G2B2WH.js.map → chunk-HKF6YNY4.js.map} +1 -1
- package/dist/chunk-IJQQNHL7.js +34 -0
- package/dist/chunk-IJQQNHL7.js.map +1 -0
- package/dist/chunk-NPQ5A3RU.js +53 -0
- package/dist/chunk-NPQ5A3RU.js.map +1 -0
- package/dist/{chunk-D3M7LPHY.js → chunk-NQZIQJFH.js} +57 -17
- package/dist/{chunk-D3M7LPHY.js.map → chunk-NQZIQJFH.js.map} +1 -1
- package/dist/{chunk-M3DT6EMK.js → chunk-QAS5SKZP.js} +2 -2
- package/dist/{chunk-WRHT5NAJ.js → chunk-QX5Q3FBJ.js} +57 -17
- package/dist/chunk-QX5Q3FBJ.js.map +1 -0
- package/dist/{chunk-HDAILYVM.js → chunk-SG62LZOJ.js} +3 -3
- package/dist/{chunk-EDBQM6RB.js → chunk-SHIXTMQE.js} +47 -12
- package/dist/{chunk-EDBQM6RB.js.map → chunk-SHIXTMQE.js.map} +1 -1
- package/dist/{chunk-G7U7FQVC.js → chunk-UFBBFP75.js} +13 -3
- package/dist/chunk-UFBBFP75.js.map +1 -0
- package/dist/{chunk-4CIHLTSI.js → chunk-V7ISZGNS.js} +45 -39
- package/dist/chunk-V7ISZGNS.js.map +1 -0
- package/dist/{chunk-RCFD5W5V.js → chunk-WR5B2XNT.js} +6 -6
- package/dist/chunk-WR5B2XNT.js.map +1 -0
- package/dist/{chunk-R36YNWBU.js → chunk-XLFDYTWO.js} +2 -2
- package/dist/cli/index.js +8 -8
- package/dist/{cloudflare-2SVRRVV5.js → cloudflare-Q5SUXRXY.js} +184 -82
- package/dist/cloudflare-Q5SUXRXY.js.map +1 -0
- package/dist/{config-support-SB5NDQZB.js → config-support-MOZYHRWG.js} +13 -2
- package/dist/{config-support-SB5NDQZB.js.map → config-support-MOZYHRWG.js.map} +1 -1
- package/dist/{deno-deploy-OK4QFJIZ.js → deno-deploy-XW3Q6OMD.js} +109 -11
- package/dist/deno-deploy-XW3Q6OMD.js.map +1 -0
- package/dist/{dev-B2IZEVAD.js → dev-FZ4OTCPT.js} +7 -7
- package/dist/{dev-emit-7KZFUA7M.js → dev-emit-T3X6RR7M.js} +5 -5
- package/dist/{dev-emit-7KZFUA7M.js.map → dev-emit-T3X6RR7M.js.map} +1 -1
- package/dist/{dev-emit-JPJJFBXL.js → dev-emit-ZK5GCHXN.js} +6 -6
- package/dist/dev-emit-ZK5GCHXN.js.map +1 -0
- package/dist/index.js +5 -5
- package/dist/{internal-api-5Y3MLZH4.js → internal-api-GKPJYL3G.js} +5 -5
- package/dist/{internal-api-6XNLCNI5.js → internal-api-ZUBUYGCQ.js} +4 -4
- package/dist/{mcp-GJQIREYC.js → mcp-VUHRRX36.js} +3 -3
- package/dist/{netlify-IAC53FVZ.js → netlify-ALPCTQFO.js} +158 -48
- package/dist/netlify-ALPCTQFO.js.map +1 -0
- package/dist/{node-QUGTW6XV.js → node-4HQO6KKZ.js} +2 -2
- package/dist/{openapi-Q53YOBIU.js → openapi-C4UX2SFV.js} +5 -5
- package/dist/openapi-C4UX2SFV.js.map +1 -0
- package/dist/{preview-XBP622HM.js → preview-II33QNAC.js} +3 -3
- package/dist/registry-WVUO2WNR.js +34 -0
- package/dist/registry-WVUO2WNR.js.map +1 -0
- package/dist/{routes-FDF4SLOB.js → routes-3PTNISSO.js} +2 -2
- package/dist/server/index.js +2 -2
- package/dist/server/scan/index.d.ts +38 -2
- package/dist/server/scan/index.js +2 -2
- package/dist/{server-boundary-IFIYNGTA.js → server-boundary-QCJNECJP.js} +5 -5
- package/dist/{server-boundary-E5GFVPLB.js → server-boundary-RTRPHX5I.js} +4 -4
- package/dist/{start-JGNBTTG2.js → start-EREUCSN6.js} +6 -6
- package/dist/{static-NQPLPAB6.js → static-7LP7LPGN.js} +2 -2
- package/dist/theo-cloud-GIA67L4Q.js +40 -0
- package/dist/theo-cloud-GIA67L4Q.js.map +1 -0
- package/dist/{vercel-EHAOKPF7.js → vercel-VLR52RXT.js} +173 -73
- package/dist/vercel-VLR52RXT.js.map +1 -0
- package/dist/vite-plugin/index.d.ts +10 -1
- package/dist/vite-plugin/index.js +7 -5
- package/dist/{vite-plugin-54XIRMKT.js → vite-plugin-3LTZJTUM.js} +9 -7
- package/package.json +5 -5
- package/dist/app-typed-client-2PTK2SJH.js.map +0 -1
- package/dist/aws-lambda-OP2L5RKZ.js.map +0 -1
- package/dist/build-CVP2XU5M.js.map +0 -1
- package/dist/bun-CZXHPK2W.js.map +0 -1
- package/dist/chunk-4CIHLTSI.js.map +0 -1
- package/dist/chunk-FHQP23Z5.js.map +0 -1
- package/dist/chunk-G7U7FQVC.js.map +0 -1
- package/dist/chunk-NO6HA4FG.js.map +0 -1
- package/dist/chunk-RCFD5W5V.js.map +0 -1
- package/dist/chunk-SEGD3JUC.js.map +0 -1
- package/dist/chunk-WRHT5NAJ.js.map +0 -1
- package/dist/cloudflare-2SVRRVV5.js.map +0 -1
- package/dist/deno-deploy-OK4QFJIZ.js.map +0 -1
- package/dist/dev-emit-JPJJFBXL.js.map +0 -1
- package/dist/netlify-IAC53FVZ.js.map +0 -1
- package/dist/openapi-Q53YOBIU.js.map +0 -1
- package/dist/registry-L6JG75LY.js +0 -23
- package/dist/registry-L6JG75LY.js.map +0 -1
- package/dist/theo-cloud-HMFNZ3FS.js +0 -33
- package/dist/theo-cloud-HMFNZ3FS.js.map +0 -1
- package/dist/vercel-EHAOKPF7.js.map +0 -1
- /package/dist/{actions-virtual-module-OHENNMQG.js.map → actions-virtual-module-J2HYO7QZ.js.map} +0 -0
- /package/dist/{actions-virtual-module-QCDKQ6QD.js.map → actions-virtual-module-JV7URROJ.js.map} +0 -0
- /package/dist/{agent-OWJ5A7W5.js.map → agent-5J7CQAYR.js.map} +0 -0
- /package/dist/{chunk-6U67SO5U.js.map → chunk-HK57MPSZ.js.map} +0 -0
- /package/dist/{chunk-M3DT6EMK.js.map → chunk-QAS5SKZP.js.map} +0 -0
- /package/dist/{chunk-HDAILYVM.js.map → chunk-SG62LZOJ.js.map} +0 -0
- /package/dist/{chunk-R36YNWBU.js.map → chunk-XLFDYTWO.js.map} +0 -0
- /package/dist/{dev-B2IZEVAD.js.map → dev-FZ4OTCPT.js.map} +0 -0
- /package/dist/{internal-api-5Y3MLZH4.js.map → internal-api-GKPJYL3G.js.map} +0 -0
- /package/dist/{internal-api-6XNLCNI5.js.map → internal-api-ZUBUYGCQ.js.map} +0 -0
- /package/dist/{mcp-GJQIREYC.js.map → mcp-VUHRRX36.js.map} +0 -0
- /package/dist/{node-QUGTW6XV.js.map → node-4HQO6KKZ.js.map} +0 -0
- /package/dist/{preview-XBP622HM.js.map → preview-II33QNAC.js.map} +0 -0
- /package/dist/{routes-FDF4SLOB.js.map → routes-3PTNISSO.js.map} +0 -0
- /package/dist/{server-boundary-IFIYNGTA.js.map → server-boundary-QCJNECJP.js.map} +0 -0
- /package/dist/{server-boundary-E5GFVPLB.js.map → server-boundary-RTRPHX5I.js.map} +0 -0
- /package/dist/{start-JGNBTTG2.js.map → start-EREUCSN6.js.map} +0 -0
- /package/dist/{static-NQPLPAB6.js.map → static-7LP7LPGN.js.map} +0 -0
- /package/dist/{vite-plugin-54XIRMKT.js.map → vite-plugin-3LTZJTUM.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/scan/agent-scan.ts","../src/server/scan/detect-agent-policy.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: walks `<projectRoot>/agents/` derived from cwd.\n * No HTTP input ever reaches these fs calls.\n */\nimport { existsSync, readFileSync, statSync } from 'node:fs'\nimport { extname, join, relative } from 'node:path'\n\nimport { walkSourceFiles } from '../_internal/scan-walker.js'\n\nimport { declaresAgentPolicy } from './detect-agent-policy.js'\nimport { MissingAgentPolicyError } from './errors.js'\nimport { createFileStampCache } from './file-stamp-cache.js'\n\nconst AGENT_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\n// Convention § 5: a co-located test file is not an agent.\nconst TEST_FILE = /\\.(test|spec)$/\n\n/**\n * Folder-semantic discovery (Eve-style \"file = identity\"): an agent may be a self-contained folder that\n * co-locates its composition — `agents/<name>/{index.ts, tools/, skills/, prompts/, lib/}`. Files INSIDE\n * these conventional sub-folders are that concern (a tool, a skill, a prompt, a helper), NOT a routed\n * agent, so the scanner skips any file whose path passes through one of them. Only `<name>.ts` or\n * `<name>/index.ts` is served at `/api/agents/<name>`. A flat file literally named `tools.ts` is still a\n * valid agent (the reserved names only apply to intermediate DIRECTORIES, never the agent file itself).\n */\nconst AGENT_SUBFOLDERS = new Set([\n 'tools',\n 'skills',\n 'prompts',\n 'lib',\n 'hooks',\n 'channels',\n 'connections',\n 'subagents',\n 'schedules',\n 'sandbox',\n 'workflows',\n 'evals',\n 'memory',\n])\n\n/**\n * A discovered agent file. `name` is the client-facing key; `agentPath` is the mounted\n * SSE route (M0/M1 `UIMessageStream`).\n */\nexport interface AgentNode {\n filePath: string\n agentPath: string\n name: string\n}\n\n/**\n * M2 — scan the TOP-LEVEL `agents/` convention (sibling of `server/`, per the LOCKED naming\n * decision). Mirrors `scanWebSocketRoutes`: one file → one endpoint, `index` stripped.\n */\n/**\n * Resolved paths already reported, so a per-request scan says it once — B-249, NFR-001.\n *\n * Keyed by the RESOLVED path rather than by the process: a test harness legitimately scans two\n * roots, and each distinct mistake deserves its own line. Same shape as `warnedAboutLegacySalt` in\n * `packages/http/src/action-encryption.ts`, and for the same reason: `scanAgents` runs per request\n * on a scanned deploy target, so an unbounded warning is a log flood on the exact path an anonymous\n * caller can drive.\n */\nconst reportedMissingDirs = new Set<string>()\n\nexport function scanAgents(projectRoot: string, configured?: string): AgentNode[] {\n const agentsDirName = configured ?? 'agents'\n // `agentsDirName` (config `agentsDir`, default \"agents\") — the dir holding `<name>.ts` agent\n // definitions, relative to the project root. May be nested (e.g. \"core/agents\"). (#95 follow-up)\n const agentsDir = join(projectRoot, agentsDirName)\n if (!existsSync(agentsDir) || !statSync(agentsDir).isDirectory()) {\n // B-249 — the same `[]` as before, and no longer the same silence.\n //\n // A configured value that resolves to nothing produced a result byte-identical to \"this app\n // declares no agents\", so a deployed `/api/agents/<name>` answered 404 with an empty log and an\n // operator had no reason to suspect configuration. The loudest way in is an ABSOLUTE path —\n // this parameter is a NAME joined onto the root, so `join()` silently yields\n // `<root><abs>` — but a typo, a missing nesting level and a directory a build did not copy all\n // land in exactly the same place, and one rule covers all four.\n //\n // Silent when NOTHING was configured: a project with no agents is the ordinary case, and a gate\n // that fires on ordinary work is a gate somebody disables. The parameter is OPTIONAL rather\n // than defaulted for exactly that reason — a default erases the difference between \"nobody\n // configured this\" and \"somebody configured 'agents'\", and only the first should stay quiet.\n //\n // The return value does not move (FR-003) and the contract stays relative (FR-004): reporting a\n // path that does not exist tells the operator what went wrong without widening a documented\n // public contract, which is a decision for a plan rather than a repair.\n if (configured !== undefined && !reportedMissingDirs.has(agentsDir)) {\n reportedMissingDirs.add(agentsDir)\n console.warn(\n `[theokit] agentsDir ${JSON.stringify(agentsDirName)} resolves to ${JSON.stringify(agentsDir)}, ` +\n `which is not a directory, so NO agents were found and every /api/agents/* route will 404. ` +\n `The value is a path relative to the project root ${JSON.stringify(projectRoot)} — an ` +\n `absolute path is joined onto it and cannot resolve.`,\n )\n }\n return []\n }\n\n const results: AgentNode[] = []\n walkSourceFiles(agentsDir, { extensions: AGENT_EXTENSIONS }, (absPath) => {\n let rel = relative(agentsDir, absPath)\n rel = rel.replace(/\\\\/g, '/')\n rel = rel.slice(0, -extname(rel).length)\n if (TEST_FILE.test(rel)) return\n // Eve-style: a file living under a composition sub-folder (tools/, skills/, prompts/, …) is that\n // concern, not a routed agent. Check the intermediate DIRECTORIES only — the agent file itself may\n // be named anything.\n const dirs = rel.split('/').slice(0, -1)\n if (dirs.some((segment) => AGENT_SUBFOLDERS.has(segment))) return\n // Unlike routes/ws, an agent needs an explicit name — a bare `agents/index.ts`\n // (name `''` → `/api/agents/`) is nonsensical for a typed `useAgent(name)` binding.\n // `agents/foo/index.ts` still collapses to `foo` (a named nested agent).\n if (rel.endsWith('/index')) rel = rel.slice(0, -6)\n if (rel === 'index' || rel === '') return\n const agentPath = `/api/agents/${rel}`\n assertAgentDeclaresPolicy(absPath, agentPath)\n results.push({\n filePath: absPath,\n agentPath,\n name: rel,\n })\n })\n return results\n}\n\n/**\n * Cache of the policy-declaration answer, keyed by path + mtime + size.\n *\n * `theokit dev` re-scans the agents directory on EVERY request, so parsing each agent file with the\n * TypeScript AST per request would turn a build-time check into per-request latency. Keying on the\n * file's own mtime and size means an edit invalidates the entry without anyone remembering to, and\n * a `theokit build` (one process, one scan) never notices the cache exists.\n */\nconst policyDeclarationCache = createFileStampCache<boolean>()\n\n/** Test seam — the module-level cache would otherwise outlive a fixture directory. */\nexport function _resetAgentPolicyCacheForTests(): void {\n policyDeclarationCache.clear()\n}\n\n/**\n * Refuse an agent file that declares no access policy (usetheokit/theokit#365).\n *\n * The refusal lives in the scanner, next to the reserved-name and empty-name refusals, because this\n * is the one place every entry point passes through: `theokit build`, `theokit start`, `theokit dev`\n * and the manifest generator all reach agents by calling `scanAgents`.\n *\n * The blast radius stops at the file system, exactly as it does for routes. A module handed to\n * `mountAgent` in memory — a test, an embedder, an `@Expose`d controller method — never passed a\n * scanner, and `admitAgentRequest` still treats an undeclared policy as \"not declared\" rather than\n * as denial. Absence is refused where an application DECLARES its agents, not where a caller passes\n * one.\n */\nfunction assertAgentDeclaresPolicy(filePath: string, agentPath: string): void {\n // The stamping and the `has`-vs-truthy subtlety moved into `createFileStampCache` (#417), where\n // the route scanner shares them rather than growing a second copy keyed \"the same way\".\n const declared = policyDeclarationCache.get(filePath, () =>\n declaresAgentPolicy(filePath, readFileSync(filePath, 'utf8')),\n )\n if (!declared) throw new MissingAgentPolicyError({ file: filePath, agentPath })\n}\n","/**\n * Does this agent file declare an access policy? (usetheokit/theokit#365)\n *\n * The sibling of `detect-route-policy.ts`, and deliberately the same instrument: the TypeScript\n * AST rather than a regex, because `// policy: ...` in a comment and the word `policy` in a doc\n * block are both things an agent file legitimately contains, and neither declares anything.\n *\n * ## What it looks for, and why it is simpler than the route detector\n *\n * A route file declares one policy PER exported HTTP method, so the route detector has to return a\n * set and reason about which method carried which config. An agent file is one agent, so the\n * question is a single yes or no: is there a top-level export named `policy`?\n *\n * ```ts\n * export const policy = 'public'\n * export const policy = ({ subject, params }) => requireOwner(subject, ownerOf(params.sessionId))\n * const policy = ...; export { policy }\n * export { agentPolicy as policy } from './shared' // ← also counts; see below\n * ```\n *\n * ## Where this is deliberately laxer than the route detector\n *\n * The route detector refuses `export { GET } from './shared'`, on the reasoning that it cannot see\n * whether the re-exported value declares a policy. Here there is nothing to look inside: the export\n * IS the policy, so a re-export names one as surely as a local const does. The value's SHAPE is\n * checked at runtime by `readAgentPolicy`, which throws on anything that is neither `'public'` nor\n * a function — so a wrong type fails loudly rather than being served open.\n */\nimport { createRequire } from 'node:module'\n\nimport type * as TS from 'typescript'\n\nconst require_ = createRequire(import.meta.url)\n\nconst ts = require_('typescript') as typeof TS\n\nconst POLICY_EXPORT = 'policy'\n\nfunction hasExportModifier(modifiers: readonly TS.Modifier[] | undefined): boolean {\n if (!modifiers) return false\n for (const m of modifiers) {\n if (m.kind === ts.SyntaxKind.ExportKeyword) return true\n }\n return false\n}\n\n/** `export const policy = ...` (also `let`/`var`, which are legal if unusual). */\nfunction variableStatementDeclaresPolicy(stmt: TS.VariableStatement): boolean {\n if (!hasExportModifier(ts.getModifiers(stmt))) return false\n return stmt.declarationList.declarations.some(\n (decl) => ts.isIdentifier(decl.name) && decl.name.text === POLICY_EXPORT,\n )\n}\n\n/** `export { policy }`, `export { p as policy }`, `export { p as policy } from './shared'`. */\nfunction exportDeclarationDeclaresPolicy(stmt: TS.ExportDeclaration): boolean {\n if (!stmt.exportClause || !ts.isNamedExports(stmt.exportClause)) return false\n return stmt.exportClause.elements.some((spec) => spec.name.text === POLICY_EXPORT)\n}\n\n/** `export function policy() {}` — a function declaration is a policy as much as a const is. */\nfunction functionDeclarationDeclaresPolicy(stmt: TS.FunctionDeclaration): boolean {\n return hasExportModifier(ts.getModifiers(stmt)) && stmt.name?.text === POLICY_EXPORT\n}\n\n/**\n * True when the file has a top-level export named `policy`.\n *\n * `content` is passed in rather than read here so the caller reads each file once — the same\n * contract `detectRoutePolicyKinds` follows.\n */\nexport function declaresAgentPolicy(filePath: string, content: string): boolean {\n const sourceFile = ts.createSourceFile(\n filePath,\n content,\n ts.ScriptTarget.Latest,\n /* setParentNodes */ false,\n ts.ScriptKind.TS,\n )\n for (const stmt of sourceFile.statements) {\n if (ts.isVariableStatement(stmt) && variableStatementDeclaresPolicy(stmt)) return true\n if (ts.isExportDeclaration(stmt) && exportDeclarationDeclaresPolicy(stmt)) return true\n if (ts.isFunctionDeclaration(stmt) && functionDeclarationDeclaresPolicy(stmt)) return true\n }\n return false\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/server/scan/agent-scan.ts","../src/server/scan/detect-agent-policy.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: walks `<projectRoot>/agents/` derived from cwd.\n * No HTTP input ever reaches these fs calls.\n */\nimport { existsSync, readFileSync, statSync } from 'node:fs'\nimport { extname, join, relative } from 'node:path'\n\nimport { walkSourceFiles } from '../_internal/scan-walker.js'\n\nimport { declaresAgentPolicy } from './detect-agent-policy.js'\nimport { MissingAgentPolicyError } from './errors.js'\nimport { createFileStampCache } from './file-stamp-cache.js'\n\nconst AGENT_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\n// Convention § 5: a co-located test file is not an agent.\nconst TEST_FILE = /\\.(test|spec)$/\n\n/**\n * Folder-semantic discovery (Eve-style \"file = identity\"): an agent may be a self-contained folder that\n * co-locates its composition — `agents/<name>/{index.ts, tools/, skills/, prompts/, lib/}`. Files INSIDE\n * these conventional sub-folders are that concern (a tool, a skill, a prompt, a helper), NOT a routed\n * agent, so the scanner skips any file whose path passes through one of them. Only `<name>.ts` or\n * `<name>/index.ts` is served at `/api/agents/<name>`. A flat file literally named `tools.ts` is still a\n * valid agent (the reserved names only apply to intermediate DIRECTORIES, never the agent file itself).\n */\nconst AGENT_SUBFOLDERS = new Set([\n 'tools',\n 'skills',\n 'prompts',\n 'lib',\n 'hooks',\n 'channels',\n 'connections',\n 'subagents',\n 'schedules',\n 'sandbox',\n 'workflows',\n 'evals',\n 'memory',\n])\n\n/**\n * A discovered agent file. `name` is the client-facing key; `agentPath` is the mounted\n * SSE route (M0/M1 `UIMessageStream`).\n */\nexport interface AgentNode {\n filePath: string\n agentPath: string\n name: string\n}\n\n/**\n * M2 — scan the TOP-LEVEL `agents/` convention (sibling of `server/`, per the LOCKED naming\n * decision). Mirrors `scanWebSocketRoutes`: one file → one endpoint, `index` stripped.\n */\n/**\n * Resolved paths already reported, so a per-request scan says it once — B-249, NFR-001.\n *\n * Keyed by the RESOLVED path rather than by the process: a test harness legitimately scans two\n * roots, and each distinct mistake deserves its own line. Same shape as `warnedAboutLegacySalt` in\n * `packages/http/src/action-encryption.ts`, and for the same reason: `scanAgents` runs per request\n * on a scanned deploy target, so an unbounded warning is a log flood on the exact path an anonymous\n * caller can drive.\n */\nconst reportedMissingDirs = new Set<string>()\n\nexport function scanAgents(projectRoot: string, configured?: string): AgentNode[] {\n const agentsDirName = configured ?? 'agents'\n // `agentsDirName` (config `agentsDir`, default \"agents\") — the dir holding `<name>.ts` agent\n // definitions, relative to the project root. May be nested (e.g. \"core/agents\"). (#95 follow-up)\n const agentsDir = join(projectRoot, agentsDirName)\n if (!existsSync(agentsDir) || !statSync(agentsDir).isDirectory()) {\n // B-249 — the same `[]` as before, and no longer the same silence.\n //\n // A configured value that resolves to nothing produced a result byte-identical to \"this app\n // declares no agents\", so a deployed `/api/agents/<name>` answered 404 with an empty log and an\n // operator had no reason to suspect configuration. The loudest way in is an ABSOLUTE path —\n // this parameter is a NAME joined onto the root, so `join()` silently yields\n // `<root><abs>` — but a typo, a missing nesting level and a directory a build did not copy all\n // land in exactly the same place, and one rule covers all four.\n //\n // Silent when NOTHING was configured: a project with no agents is the ordinary case, and a gate\n // that fires on ordinary work is a gate somebody disables. The parameter is OPTIONAL rather\n // than defaulted for exactly that reason — a default erases the difference between \"nobody\n // configured this\" and \"somebody configured 'agents'\", and only the first should stay quiet.\n //\n // The return value does not move (FR-003) and the contract stays relative (FR-004): reporting a\n // path that does not exist tells the operator what went wrong without widening a documented\n // public contract, which is a decision for a plan rather than a repair.\n if (configured !== undefined && !reportedMissingDirs.has(agentsDir)) {\n reportedMissingDirs.add(agentsDir)\n console.warn(\n `[theokit] agentsDir ${JSON.stringify(agentsDirName)} resolves to ${JSON.stringify(agentsDir)}, ` +\n `which is not a directory, so NO agents were found and every /api/agents/* route will 404. ` +\n `The value is a path relative to the project root ${JSON.stringify(projectRoot)} — an ` +\n `absolute path is joined onto it and cannot resolve.`,\n )\n }\n return []\n }\n\n const results: AgentNode[] = []\n walkSourceFiles(agentsDir, { extensions: AGENT_EXTENSIONS }, (absPath) => {\n let rel = relative(agentsDir, absPath)\n rel = rel.replace(/\\\\/g, '/')\n rel = rel.slice(0, -extname(rel).length)\n if (TEST_FILE.test(rel)) return\n // Eve-style: a file living under a composition sub-folder (tools/, skills/, prompts/, …) is that\n // concern, not a routed agent. Check the intermediate DIRECTORIES only — the agent file itself may\n // be named anything.\n const dirs = rel.split('/').slice(0, -1)\n if (dirs.some((segment) => AGENT_SUBFOLDERS.has(segment))) return\n // Unlike routes/ws, an agent needs an explicit name — a bare `agents/index.ts`\n // (name `''` → `/api/agents/`) is nonsensical for a typed `useAgent(name)` binding.\n // `agents/foo/index.ts` still collapses to `foo` (a named nested agent).\n if (rel.endsWith('/index')) rel = rel.slice(0, -6)\n if (rel === 'index' || rel === '') return\n const agentPath = `/api/agents/${rel}`\n assertAgentDeclaresPolicy(absPath, agentPath)\n results.push({\n filePath: absPath,\n agentPath,\n name: rel,\n })\n })\n return results\n}\n\n/**\n * Cache of the policy-declaration answer, keyed by path + mtime + size.\n *\n * `theokit dev` re-scans the agents directory on EVERY request, so parsing each agent file with the\n * TypeScript AST per request would turn a build-time check into per-request latency. Keying on the\n * file's own mtime and size means an edit invalidates the entry without anyone remembering to, and\n * a `theokit build` (one process, one scan) never notices the cache exists.\n */\nconst policyDeclarationCache = createFileStampCache<boolean>()\n\n/** Test seam — the module-level cache would otherwise outlive a fixture directory. */\nexport function _resetAgentPolicyCacheForTests(): void {\n policyDeclarationCache.clear()\n}\n\n/**\n * Refuse an agent file that declares no access policy (usetheokit/theokit#365).\n *\n * The refusal lives in the scanner, next to the reserved-name and empty-name refusals, because this\n * is the one place every entry point passes through: `theokit build`, `theokit start`, `theokit dev`\n * and the manifest generator all reach agents by calling `scanAgents`.\n *\n * The blast radius stops at the file system, exactly as it does for routes. A module handed to\n * `mountAgent` in memory — a test, an embedder, an `@Expose`d controller method — never passed a\n * scanner, and `admitAgentRequest` still treats an undeclared policy as \"not declared\" rather than\n * as denial. Absence is refused where an application DECLARES its agents, not where a caller passes\n * one.\n */\nfunction assertAgentDeclaresPolicy(filePath: string, agentPath: string): void {\n // The stamping and the `has`-vs-truthy subtlety moved into `createFileStampCache` (#417), where\n // the route scanner shares them rather than growing a second copy keyed \"the same way\".\n const declared = policyDeclarationCache.get(filePath, () =>\n declaresAgentPolicy(filePath, readFileSync(filePath, 'utf8')),\n )\n if (!declared) throw new MissingAgentPolicyError({ file: filePath, agentPath })\n}\n","/**\n * Does this agent file declare an access policy? (usetheokit/theokit#365)\n *\n * The sibling of `detect-route-policy.ts`, and deliberately the same instrument: the TypeScript\n * AST rather than a regex, because `// policy: ...` in a comment and the word `policy` in a doc\n * block are both things an agent file legitimately contains, and neither declares anything.\n *\n * ## What it looks for, and why it is simpler than the route detector\n *\n * A route file declares one policy PER exported HTTP method, so the route detector has to return a\n * set and reason about which method carried which config. An agent file is one agent, so the\n * question is a single yes or no: is there a top-level export named `policy`?\n *\n * ```ts\n * export const policy = 'public'\n * export const policy = ({ subject, params }) => requireOwner(subject, ownerOf(params.sessionId))\n * const policy = ...; export { policy }\n * export { agentPolicy as policy } from './shared' // ← also counts; see below\n * ```\n *\n * ## Where this is deliberately laxer than the route detector\n *\n * The route detector refuses `export { GET } from './shared'`, on the reasoning that it cannot see\n * whether the re-exported value declares a policy. Here there is nothing to look inside: the export\n * IS the policy, so a re-export names one as surely as a local const does. The value's SHAPE is\n * checked at runtime by `readAgentPolicy`, which throws on anything that is neither `'public'` nor\n * a function — so a wrong type fails loudly rather than being served open.\n */\nimport { createRequire } from 'node:module'\n\nimport type * as TS from 'typescript'\n\n/**\n * The compiler, loaded on first use and never at import time.\n *\n * This was module scope, and a Cloudflare deploy found what that costs: `theokit/server/scan` is\n * imported by the generated worker (through `agent-scan.ts`), Cloudflare EXECUTES the module during\n * validation, and there `import.meta.url` is undefined — so `createRequire` threw before the worker\n * ever answered a request (B-263, error 10021). `wrangler deploy --dry-run` had returned exit 0 on\n * the same bundle minutes earlier: it bundles and does not execute.\n *\n * The second reason is independent of Workers and would hold anyway: this is a BUILD-TIME AST\n * scanner, and nothing that merely imports the module should pay for the TypeScript compiler.\n *\n * Cached, so scanning many files still loads it once.\n */\nlet compiler: typeof TS | undefined\n\nfunction ts_(): typeof TS {\n compiler ??= createRequire(import.meta.url)('typescript') as typeof TS\n return compiler\n}\n\nconst POLICY_EXPORT = 'policy'\n\nfunction hasExportModifier(modifiers: readonly TS.Modifier[] | undefined): boolean {\n if (!modifiers) return false\n for (const m of modifiers) {\n if (m.kind === ts_().SyntaxKind.ExportKeyword) return true\n }\n return false\n}\n\n/** `export const policy = ...` (also `let`/`var`, which are legal if unusual). */\nfunction variableStatementDeclaresPolicy(stmt: TS.VariableStatement): boolean {\n if (!hasExportModifier(ts_().getModifiers(stmt))) return false\n return stmt.declarationList.declarations.some(\n (decl) => ts_().isIdentifier(decl.name) && decl.name.text === POLICY_EXPORT,\n )\n}\n\n/** `export { policy }`, `export { p as policy }`, `export { p as policy } from './shared'`. */\nfunction exportDeclarationDeclaresPolicy(stmt: TS.ExportDeclaration): boolean {\n if (!stmt.exportClause || !ts_().isNamedExports(stmt.exportClause)) return false\n return stmt.exportClause.elements.some((spec) => spec.name.text === POLICY_EXPORT)\n}\n\n/** `export function policy() {}` — a function declaration is a policy as much as a const is. */\nfunction functionDeclarationDeclaresPolicy(stmt: TS.FunctionDeclaration): boolean {\n return hasExportModifier(ts_().getModifiers(stmt)) && stmt.name?.text === POLICY_EXPORT\n}\n\n/**\n * True when the file has a top-level export named `policy`.\n *\n * `content` is passed in rather than read here so the caller reads each file once — the same\n * contract `detectRoutePolicyKinds` follows.\n */\nexport function declaresAgentPolicy(filePath: string, content: string): boolean {\n const sourceFile = ts_().createSourceFile(\n filePath,\n content,\n ts_().ScriptTarget.Latest,\n /* setParentNodes */ false,\n ts_().ScriptKind.TS,\n )\n for (const stmt of sourceFile.statements) {\n if (ts_().isVariableStatement(stmt) && variableStatementDeclaresPolicy(stmt)) return true\n if (ts_().isExportDeclaration(stmt) && exportDeclarationDeclaresPolicy(stmt)) return true\n if (ts_().isFunctionDeclaration(stmt) && functionDeclarationDeclaresPolicy(stmt)) return true\n }\n return false\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "tsx/esm";
|
|
3
|
+
import {
|
|
4
|
+
findRootDiv
|
|
5
|
+
} from "./chunk-3PWQQWT6.js";
|
|
6
|
+
|
|
7
|
+
// src/adapters/deployed-document-shell.ts
|
|
8
|
+
import { existsSync, readFileSync } from "fs";
|
|
9
|
+
import { resolve } from "path";
|
|
10
|
+
function readDocumentShell(cwd, streaming) {
|
|
11
|
+
if (!streaming) return {};
|
|
12
|
+
const indexPath = resolve(cwd, ".theokit/client/index.html");
|
|
13
|
+
if (!existsSync(indexPath)) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`[adapter-cloudflare] ssrStreaming is on but ${indexPath} does not exist, so the worker would serve a document with no <head> and no client entry. Run the client build first, or set ssrStreaming: false in theo.config.ts.`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
const indexHtml = readFileSync(indexPath, "utf-8");
|
|
19
|
+
const rootDiv = findRootDiv(indexHtml);
|
|
20
|
+
if (rootDiv === void 0) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`[adapter-cloudflare] ${indexPath} has no <div id="root">, so the streamed document has nowhere to put the app. Add one, or set ssrStreaming: false in theo.config.ts.`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
htmlHead: indexHtml.slice(0, rootDiv.insertAt),
|
|
27
|
+
htmlTail: indexHtml.slice(rootDiv.insertAt)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
readDocumentShell
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=chunk-IJQQNHL7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/deployed-document-shell.ts"],"sourcesContent":["/**\n * Where the app goes inside the built client shell, for a target that renders the document itself.\n *\n * Extracted from `cloudflare.ts` on 2026-09-28 (B-317), when the Vercel target gained a document branch\n * and needed the same knowledge. One adapter importing another is the coupling `deployed-baked-routes.ts`\n * was extracted to avoid, and this is the second instance of that shape rather than a new one.\n *\n * It THROWS rather than degrading, in both directions, and the messages say what to do. A target that\n * renders a document with no `<head>` and no client entry produces a page that loads nothing and reports\n * no error — the failure this refuses to ship.\n */\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport { findRootDiv } from '../core/contracts/find-root-div.js'\n\nexport function readDocumentShell(\n cwd: string,\n streaming: boolean,\n): { htmlHead?: string; htmlTail?: string } {\n if (!streaming) return {}\n\n const indexPath = resolve(cwd, '.theokit/client/index.html')\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- a constant suffix under the caller's project root\n if (!existsSync(indexPath)) {\n throw new Error(\n `[adapter-cloudflare] ssrStreaming is on but ${indexPath} does not exist, so the worker ` +\n `would serve a document with no <head> and no client entry. Run the client build first, ` +\n `or set ssrStreaming: false in theo.config.ts.`,\n )\n }\n\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- the same path, proven above\n const indexHtml = readFileSync(indexPath, 'utf-8')\n const rootDiv = findRootDiv(indexHtml)\n if (rootDiv === undefined) {\n throw new Error(\n `[adapter-cloudflare] ${indexPath} has no <div id=\"root\">, so the streamed document has ` +\n `nowhere to put the app. Add one, or set ssrStreaming: false in theo.config.ts.`,\n )\n }\n\n return {\n htmlHead: indexHtml.slice(0, rootDiv.insertAt),\n htmlTail: indexHtml.slice(rootDiv.insertAt),\n }\n}\n"],"mappings":";;;;;;;AAWA,SAAS,YAAY,oBAAoB;AACzC,SAAS,eAAe;AAIjB,SAAS,kBACd,KACA,WAC0C;AAC1C,MAAI,CAAC,UAAW,QAAO,CAAC;AAExB,QAAM,YAAY,QAAQ,KAAK,4BAA4B;AAE3D,MAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,UAAM,IAAI;AAAA,MACR,+CAA+C,SAAS;AAAA,IAG1D;AAAA,EACF;AAGA,QAAM,YAAY,aAAa,WAAW,OAAO;AACjD,QAAM,UAAU,YAAY,SAAS;AACrC,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI;AAAA,MACR,wBAAwB,SAAS;AAAA,IAEnC;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,UAAU,MAAM,GAAG,QAAQ,QAAQ;AAAA,IAC7C,UAAU,UAAU,MAAM,QAAQ,QAAQ;AAAA,EAC5C;AACF;","names":[]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "tsx/esm";
|
|
3
|
+
|
|
4
|
+
// src/adapters/bundle-deployed-function.ts
|
|
5
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
6
|
+
import { dirname, resolve, sep } from "path";
|
|
7
|
+
import { build as viteBuild } from "vite";
|
|
8
|
+
var PathOutsideProjectRootError = class extends Error {
|
|
9
|
+
name = "PathOutsideProjectRootError";
|
|
10
|
+
constructor(field, value, resolved, projectRoot) {
|
|
11
|
+
super(
|
|
12
|
+
`bundleDeployedFunction: \`${field}\` must stay inside \`projectRoot\`. Given ${JSON.stringify(value)}, which resolves to ${JSON.stringify(resolved)}, outside ${JSON.stringify(projectRoot)}.`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
async function bundleDeployedFunction(options) {
|
|
17
|
+
const rootAbs = resolve(options.projectRoot);
|
|
18
|
+
const isInside = (candidate) => candidate === rootAbs || candidate.startsWith(`${rootAbs}${sep}`);
|
|
19
|
+
const stageAbs = resolve(rootAbs, options.stagePath);
|
|
20
|
+
if (!isInside(stageAbs)) {
|
|
21
|
+
throw new PathOutsideProjectRootError("stagePath", options.stagePath, stageAbs, rootAbs);
|
|
22
|
+
}
|
|
23
|
+
mkdirSync(dirname(stageAbs), { recursive: true });
|
|
24
|
+
writeFileSync(stageAbs, options.entrySource, "utf8");
|
|
25
|
+
await viteBuild({
|
|
26
|
+
root: options.projectRoot,
|
|
27
|
+
// The project's own vite config is for its APP. Reading it here would apply its plugins, its
|
|
28
|
+
// aliases and its `build.outDir` to a server entry that wants none of them.
|
|
29
|
+
configFile: false,
|
|
30
|
+
logLevel: "warn",
|
|
31
|
+
// The whole point: without this, vite externalises every bare specifier and the output has the
|
|
32
|
+
// same unresolvable imports the input had.
|
|
33
|
+
ssr: { noExternal: true },
|
|
34
|
+
build: {
|
|
35
|
+
ssr: true,
|
|
36
|
+
outDir: options.outDir,
|
|
37
|
+
emptyOutDir: true,
|
|
38
|
+
// Measured: with `root` at the project, vite otherwise copies `index.html`, `logo.png`,
|
|
39
|
+
// `favicon.svg` and `robots.txt` into the function directory — a lambda carrying the site's
|
|
40
|
+
// static assets, and an `index.html` sitting beside a handler.
|
|
41
|
+
copyPublicDir: false,
|
|
42
|
+
rollupOptions: {
|
|
43
|
+
input: stageAbs,
|
|
44
|
+
output: { entryFileNames: options.entryFileName, format: "esm" }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
bundleDeployedFunction
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=chunk-NPQ5A3RU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/bundle-deployed-function.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve, sep } from 'node:path'\n\nimport { build as viteBuild } from 'vite'\n\n/** What the caller has to say to get a self-contained function out. */\nexport interface BundleDeployedFunctionOptions {\n /** The project being built. Everything else is resolved against it. */\n projectRoot: string\n /** The generated entry source, as the adapter rendered it. */\n entrySource: string\n /**\n * Where the staged entry is written, relative to `projectRoot`.\n *\n * Inside the root is not a preference. Measured while establishing ADR 0020: an entry staged in\n * `/tmp` makes rollup resolve `theokit/server/scan` from `/tmp` and the build fails with an\n * unresolved import, because a specifier resolves relative to the importing FILE.\n */\n stagePath: string\n /**\n * The directory the platform will upload, absolute.\n *\n * It reaches vite with `emptyOutDir: true`, so whatever is there is DELETED. Emptying a build\n * output directory is the point, and it is why this must be a directory the caller owns — it is not\n * required to sit inside `projectRoot` (the test for this function passes a sibling, deliberately),\n * so nothing here can check it for you.\n */\n outDir: string\n /** The file name the platform expects inside `outDir`. */\n entryFileName: string\n}\n\n/**\n * Bundle a generated entry into a directory that loads with no `node_modules` beside it.\n *\n * ## Why this exists at all\n *\n * A platform either resolves the entry's bare specifiers or it does not, and three answers are in\n * play. `wrangler` bundles with esbuild at deploy time; Bun resolves against the project's own\n * `node_modules` at run time; **Vercel's Build Output API v3 uploads a `.func` directory as it is**,\n * and AWS Lambda does the same with a zip. Measured 2026-09-26 on this repository's own scaffold:\n *\n * cp -a .vercel/output/functions/api.func/. /tmp/fn/ && cd /tmp/fn\n * node -e \"import('./index.mjs')\"\n * -> ERR_MODULE_NOT_FOUND: Cannot find package 'theokit'\n *\n * So the adapter bundles when the platform will not. The decision, the rejected alternatives and the\n * measurements are ADR 0020; this is its one implementation, shared rather than copied per target\n * because B-315 is what five copies of one call look like after a while.\n *\n * ## Why vite\n *\n * The parsimony ladder's fourth rung. `esbuild` resolves from neither the repository root nor\n * `packages/theo` — it is an undeclared transitive dependency — while `vite` is declared and\n * `adapters/node.ts` already runs `viteBuild` for the same shape of job. Reuse over addition.\n *\n * ## What it does NOT do\n *\n * It does not verify the bundle answers a request. That needs the platform. What it establishes is\n * the property that was false: the directory loads on its own.\n */\n/**\n * Thrown at BUILD time when a path this function would write to leaves the project.\n *\n * Named like `UnserialisableRateLimitError` next door, because the adapters report a build-time\n * refusal as a typed domain error rather than a string (`rules/error-handling.md`).\n *\n * The invariant was DECLARED and unenforced. `stagePath`'s own docblock says \"inside the root is not a\n * preference\", and nothing checked it — `resolve(root, '../outside/entry.mjs')` wrote the entry outside\n * the project, and `resolve(root, '/etc/theo-entry.mjs')` discarded the root entirely and was stopped\n * only by filesystem permissions (`EACCES`, measured 2026-09-28).\n *\n * It covers `stagePath` and NOT `outDir`, which is a correction rather than an omission. A first\n * version checked both, and the pre-existing test for this function passes an `outDir` that is a\n * SIBLING of `projectRoot` — which the option's contract permits, since it is documented as \"the\n * directory the platform will upload, absolute\" and nothing more. The invariant was invented, the test\n * refused it, and the test was right.\n */\nexport class PathOutsideProjectRootError extends Error {\n override readonly name = 'PathOutsideProjectRootError'\n\n constructor(field: string, value: string, resolved: string, projectRoot: string) {\n super(\n `bundleDeployedFunction: \\`${field}\\` must stay inside \\`projectRoot\\`. ` +\n `Given ${JSON.stringify(value)}, which resolves to ${JSON.stringify(resolved)}, ` +\n `outside ${JSON.stringify(projectRoot)}.`,\n )\n }\n}\n\nexport async function bundleDeployedFunction(\n options: BundleDeployedFunctionOptions,\n): Promise<void> {\n // Validated at the boundary, before anything is written — `rules/error-handling.md`: reject invalid\n // input before processing, and this function's first act is a write.\n const rootAbs = resolve(options.projectRoot)\n const isInside = (candidate: string): boolean =>\n candidate === rootAbs || candidate.startsWith(`${rootAbs}${sep}`)\n\n const stageAbs = resolve(rootAbs, options.stagePath)\n if (!isInside(stageAbs)) {\n throw new PathOutsideProjectRootError('stagePath', options.stagePath, stageAbs, rootAbs)\n }\n // `stageAbs` is proven above to resolve inside `projectRoot`, and it is a build-time path rather\n // than request input. The exemption is per-call rather than per-file on purpose: a file-scope\n // disable would silently cover an fs call somebody adds later, whose path nothing proved.\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- proven inside projectRoot above\n mkdirSync(dirname(stageAbs), { recursive: true })\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- proven inside projectRoot above\n writeFileSync(stageAbs, options.entrySource, 'utf8')\n\n await viteBuild({\n root: options.projectRoot,\n // The project's own vite config is for its APP. Reading it here would apply its plugins, its\n // aliases and its `build.outDir` to a server entry that wants none of them.\n configFile: false,\n logLevel: 'warn',\n // The whole point: without this, vite externalises every bare specifier and the output has the\n // same unresolvable imports the input had.\n ssr: { noExternal: true },\n build: {\n ssr: true,\n outDir: options.outDir,\n emptyOutDir: true,\n // Measured: with `root` at the project, vite otherwise copies `index.html`, `logo.png`,\n // `favicon.svg` and `robots.txt` into the function directory — a lambda carrying the site's\n // static assets, and an `index.html` sitting beside a handler.\n copyPublicDir: false,\n rollupOptions: {\n input: stageAbs,\n output: { entryFileNames: options.entryFileName, format: 'esm' },\n },\n },\n })\n}\n"],"mappings":";;;;AAAA,SAAS,WAAW,qBAAqB;AACzC,SAAS,SAAS,SAAS,WAAW;AAEtC,SAAS,SAAS,iBAAiB;AA2E5B,IAAM,8BAAN,cAA0C,MAAM;AAAA,EACnC,OAAO;AAAA,EAEzB,YAAY,OAAe,OAAe,UAAkB,aAAqB;AAC/E;AAAA,MACE,6BAA6B,KAAK,8CACvB,KAAK,UAAU,KAAK,CAAC,uBAAuB,KAAK,UAAU,QAAQ,CAAC,aAClE,KAAK,UAAU,WAAW,CAAC;AAAA,IAC1C;AAAA,EACF;AACF;AAEA,eAAsB,uBACpB,SACe;AAGf,QAAM,UAAU,QAAQ,QAAQ,WAAW;AAC3C,QAAM,WAAW,CAAC,cAChB,cAAc,WAAW,UAAU,WAAW,GAAG,OAAO,GAAG,GAAG,EAAE;AAElE,QAAM,WAAW,QAAQ,SAAS,QAAQ,SAAS;AACnD,MAAI,CAAC,SAAS,QAAQ,GAAG;AACvB,UAAM,IAAI,4BAA4B,aAAa,QAAQ,WAAW,UAAU,OAAO;AAAA,EACzF;AAKA,YAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAEhD,gBAAc,UAAU,QAAQ,aAAa,MAAM;AAEnD,QAAM,UAAU;AAAA,IACd,MAAM,QAAQ;AAAA;AAAA;AAAA,IAGd,YAAY;AAAA,IACZ,UAAU;AAAA;AAAA;AAAA,IAGV,KAAK,EAAE,YAAY,KAAK;AAAA,IACxB,OAAO;AAAA,MACL,KAAK;AAAA,MACL,QAAQ,QAAQ;AAAA,MAChB,aAAa;AAAA;AAAA;AAAA;AAAA,MAIb,eAAe;AAAA,MACf,eAAe;AAAA,QACb,OAAO;AAAA,QACP,QAAQ,EAAE,gBAAgB,QAAQ,eAAe,QAAQ,MAAM;AAAA,MACjE;AAAA,IACF;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
isAgentCardPath,
|
|
14
14
|
matchAgentAuxRoute,
|
|
15
15
|
serveMatchedAuxRoute
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-HK57MPSZ.js";
|
|
17
17
|
import {
|
|
18
18
|
admitAgentRequest,
|
|
19
19
|
agentAccessDenied,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
securitySchema,
|
|
30
30
|
storageSchema,
|
|
31
31
|
uploadSchema
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-2NG5T77O.js";
|
|
33
33
|
import {
|
|
34
34
|
broadcastToDevtools
|
|
35
35
|
} from "./chunk-OIGJOYX6.js";
|
|
@@ -84,10 +84,10 @@ import {
|
|
|
84
84
|
scanServerActions,
|
|
85
85
|
scanServerRoutes,
|
|
86
86
|
scanWebSocketRoutes
|
|
87
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-V7ISZGNS.js";
|
|
88
88
|
import {
|
|
89
89
|
scanAgents
|
|
90
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-6R5F5YF2.js";
|
|
91
91
|
import {
|
|
92
92
|
resolveProvider
|
|
93
93
|
} from "./chunk-ICXXHV4V.js";
|
|
@@ -1871,24 +1871,42 @@ async function runConfigureServer(server, ctx) {
|
|
|
1871
1871
|
server.watcher.on("unlink", handleRouteChange);
|
|
1872
1872
|
if (ctx.resolvedOpenApi !== void 0) {
|
|
1873
1873
|
const openApiCfg = ctx.resolvedOpenApi;
|
|
1874
|
-
const { reEmitOpenApi } = await import("./dev-emit-
|
|
1874
|
+
const { reEmitOpenApi } = await import("./dev-emit-T3X6RR7M.js");
|
|
1875
1875
|
const openApiServerDir = ctx.serverDir;
|
|
1876
1876
|
const openApiDistDir = resolve7(ctx.projectRoot, ctx.resolvedDistDir);
|
|
1877
1877
|
const isRouteFileForOpenApi = (file) => file.startsWith(openApiServerDir) && /\.(ts|tsx|js|mjs)$/.test(file);
|
|
1878
|
-
void reEmitOpenApi(openApiServerDir, openApiDistDir, openApiCfg);
|
|
1878
|
+
void reEmitOpenApi(openApiServerDir, openApiDistDir, openApiCfg, ctx.projectRoot, ctx.agentsDir);
|
|
1879
1879
|
server.watcher.on("change", (file) => {
|
|
1880
1880
|
if (isRouteFileForOpenApi(file)) {
|
|
1881
|
-
void reEmitOpenApi(
|
|
1881
|
+
void reEmitOpenApi(
|
|
1882
|
+
openApiServerDir,
|
|
1883
|
+
openApiDistDir,
|
|
1884
|
+
openApiCfg,
|
|
1885
|
+
ctx.projectRoot,
|
|
1886
|
+
ctx.agentsDir
|
|
1887
|
+
);
|
|
1882
1888
|
}
|
|
1883
1889
|
});
|
|
1884
1890
|
server.watcher.on("add", (file) => {
|
|
1885
1891
|
if (isRouteFileForOpenApi(file)) {
|
|
1886
|
-
void reEmitOpenApi(
|
|
1892
|
+
void reEmitOpenApi(
|
|
1893
|
+
openApiServerDir,
|
|
1894
|
+
openApiDistDir,
|
|
1895
|
+
openApiCfg,
|
|
1896
|
+
ctx.projectRoot,
|
|
1897
|
+
ctx.agentsDir
|
|
1898
|
+
);
|
|
1887
1899
|
}
|
|
1888
1900
|
});
|
|
1889
1901
|
server.watcher.on("unlink", (file) => {
|
|
1890
1902
|
if (isRouteFileForOpenApi(file)) {
|
|
1891
|
-
void reEmitOpenApi(
|
|
1903
|
+
void reEmitOpenApi(
|
|
1904
|
+
openApiServerDir,
|
|
1905
|
+
openApiDistDir,
|
|
1906
|
+
openApiCfg,
|
|
1907
|
+
ctx.projectRoot,
|
|
1908
|
+
ctx.agentsDir
|
|
1909
|
+
);
|
|
1892
1910
|
}
|
|
1893
1911
|
});
|
|
1894
1912
|
}
|
|
@@ -2618,7 +2636,26 @@ function generateStreamingEntry(options) {
|
|
|
2618
2636
|
const appTree = buildAppTreeJs(options);
|
|
2619
2637
|
return [
|
|
2620
2638
|
`import React, { Suspense } from 'react'`,
|
|
2621
|
-
|
|
2639
|
+
// A NAMESPACE import, deliberately. `react-dom/server` resolves to `server.bun.js` under Bun,
|
|
2640
|
+
// which exports `renderToReadableStream`, `renderToStaticMarkup`, `renderToString`, `resume` and
|
|
2641
|
+
// `version` — and NOT `renderToPipeableStream`, the Node-only API. A NAMED import of a missing
|
|
2642
|
+
// export is a link-time error, so importing both by name made this entire bundle unloadable on
|
|
2643
|
+
// every Web runtime, and the Web renderer it exists to provide could never be reached:
|
|
2644
|
+
//
|
|
2645
|
+
// SyntaxError: Export named 'renderToPipeableStream' not found in module
|
|
2646
|
+
// .../react-dom/server.bun.js
|
|
2647
|
+
//
|
|
2648
|
+
// Measured on Bun 1.3.14 and Node 22 by importing the namespace on both: it loads on both, and the
|
|
2649
|
+
// Node-only binding is a function on Node and `undefined` on Bun. The Node renderers below are
|
|
2650
|
+
// never reached on a Web runtime — `renderBunEntry` calls `renderStreamingWeb` and nothing else —
|
|
2651
|
+
// so the destructure is safe and the call sites keep their original text.
|
|
2652
|
+
//
|
|
2653
|
+
// A lazy `await import('react-dom/server')` was tried first and rejected: it cost a helper, an
|
|
2654
|
+
// await inside a Promise executor that is not async, and it broke
|
|
2655
|
+
// `entry-server-web-execution.test.ts`, which materializes the generated module in a temp
|
|
2656
|
+
// directory where a dynamic specifier does not resolve.
|
|
2657
|
+
`import * as __theoReactDOMServer from 'react-dom/server'`,
|
|
2658
|
+
`const { renderToReadableStream, renderToPipeableStream } = __theoReactDOMServer`,
|
|
2622
2659
|
`import { createStaticHandler, createStaticRouter, StaticRouterProvider, matchRoutes } from 'react-router'`,
|
|
2623
2660
|
`import { routes, __theoPreloadMap, __theoPreloadPathsFor } from '/@theo/route-manifest'`,
|
|
2624
2661
|
`import { NonceProvider } from 'theokit/client'`,
|
|
@@ -3030,19 +3067,21 @@ async function theoPluginAsync(rootOrOptions) {
|
|
|
3030
3067
|
}
|
|
3031
3068
|
const { assetsMapPlugin } = await import("./assets-map-CV2YZ3MY.js");
|
|
3032
3069
|
const assetsMap = assetsMapPlugin({ appDir: resolve9(projectRoot, options.appDir ?? "app") });
|
|
3033
|
-
const { appTypedClientPlugin } = await import("./app-typed-client-
|
|
3070
|
+
const { appTypedClientPlugin } = await import("./app-typed-client-EOA3A2AR.js");
|
|
3034
3071
|
const appClientPlugin = appTypedClientPlugin({
|
|
3035
3072
|
cwd: projectRoot,
|
|
3036
3073
|
serverDir: serverDirAbs,
|
|
3037
|
-
distDir: resolve9(projectRoot, ".theokit")
|
|
3074
|
+
distDir: resolve9(projectRoot, ".theokit"),
|
|
3075
|
+
// B-313 — the same name line 226 already passes. This call passed neither it nor the root.
|
|
3076
|
+
agentsDir: agentsDirName
|
|
3038
3077
|
});
|
|
3039
|
-
const { actionsVirtualModule } = await import("./actions-virtual-module-
|
|
3078
|
+
const { actionsVirtualModule } = await import("./actions-virtual-module-J2HYO7QZ.js");
|
|
3040
3079
|
const actionsPlugin = actionsVirtualModule({
|
|
3041
3080
|
serverDir: serverDirAbs,
|
|
3042
3081
|
distDir: resolve9(projectRoot, ".theokit")
|
|
3043
3082
|
});
|
|
3044
3083
|
const { agentsTypedClientPlugin } = await import("./agents-typed-client-PVUZU65B.js");
|
|
3045
|
-
const { generateManifest } = await import("./internal-api-
|
|
3084
|
+
const { generateManifest } = await import("./internal-api-ZUBUYGCQ.js");
|
|
3046
3085
|
const agentsClientPlugin = agentsTypedClientPlugin({
|
|
3047
3086
|
projectRoot,
|
|
3048
3087
|
agentsDir: agentsDirName,
|
|
@@ -3059,7 +3098,7 @@ async function theoPluginAsync(rootOrOptions) {
|
|
|
3059
3098
|
const controllerTransformPlugin = controllerSwcTransformPlugin({
|
|
3060
3099
|
serverDir: serverDirAbs
|
|
3061
3100
|
});
|
|
3062
|
-
const { serverOnlyImportBoundary } = await import("./server-boundary-
|
|
3101
|
+
const { serverOnlyImportBoundary } = await import("./server-boundary-RTRPHX5I.js");
|
|
3063
3102
|
const serverBoundaryPlugin = serverOnlyImportBoundary({
|
|
3064
3103
|
projectRoot,
|
|
3065
3104
|
serverDir: serverDirAbs
|
|
@@ -3087,7 +3126,7 @@ function buildOptimizeDepsInclude(projectRoot, viteOptimizeDeps) {
|
|
|
3087
3126
|
if (existsSync8(resolve9(projectRoot, "node_modules", "lucide-react"))) {
|
|
3088
3127
|
include.push("lucide-react");
|
|
3089
3128
|
}
|
|
3090
|
-
include.push("devalue");
|
|
3129
|
+
include.push("theokit > devalue");
|
|
3091
3130
|
if (Array.isArray(viteOptimizeDeps)) {
|
|
3092
3131
|
for (const pkg of viteOptimizeDeps) {
|
|
3093
3132
|
if (typeof pkg === "string" && pkg.length > 0 && !include.includes(pkg)) {
|
|
@@ -3241,6 +3280,7 @@ export {
|
|
|
3241
3280
|
IntegrationRouteCollisionError,
|
|
3242
3281
|
createIntegrationRegistry,
|
|
3243
3282
|
theoPluginAsync,
|
|
3283
|
+
buildOptimizeDepsInclude,
|
|
3244
3284
|
theoPlugin
|
|
3245
3285
|
};
|
|
3246
|
-
//# sourceMappingURL=chunk-
|
|
3286
|
+
//# sourceMappingURL=chunk-NQZIQJFH.js.map
|