theokit 0.2.3 → 0.2.4

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 (88) hide show
  1. package/LICENSE +201 -0
  2. package/dist/{actions-virtual-module-E6PU47GV.js → actions-virtual-module-HWNTIEPI.js} +40 -6
  3. package/dist/actions-virtual-module-HWNTIEPI.js.map +1 -0
  4. package/dist/{actions-virtual-module-E7IELVHL.js → actions-virtual-module-SEIPACG5.js} +40 -6
  5. package/dist/actions-virtual-module-SEIPACG5.js.map +1 -0
  6. package/dist/add-2ZFFGGE4.js +0 -0
  7. package/dist/{app-typed-client-FOWJP534.js → app-typed-client-6GC6VWXS.js} +4 -4
  8. package/dist/{app-typed-client-IMILAGER.js → app-typed-client-US2ZXBEC.js} +3 -3
  9. package/dist/aws-lambda-XYCGZH3I.js +0 -0
  10. package/dist/broadcast-QOQGUNNK.js +0 -0
  11. package/dist/{build-KRSHWXMJ.js → build-MREW6MVS.js} +5 -5
  12. package/dist/build-request-body-preview-II2235E6.js +0 -0
  13. package/dist/bun-K73TQEWC.js +0 -0
  14. package/dist/check-PZR67OY5.js +0 -0
  15. package/dist/chunk-5ODOE6EF.js +0 -0
  16. package/dist/{chunk-MOT42NAH.js → chunk-5OFPQK6N.js} +18 -3
  17. package/dist/chunk-5OFPQK6N.js.map +1 -0
  18. package/dist/{chunk-RIBIAL7A.js → chunk-5OKZY2VL.js} +5 -5
  19. package/dist/{chunk-7DHGV77J.js → chunk-7TOMTMHT.js} +18 -3
  20. package/dist/chunk-7TOMTMHT.js.map +1 -0
  21. package/dist/{chunk-SEVYARIU.js → chunk-BE2LKDI7.js} +3 -3
  22. package/dist/chunk-F3TG5FJV.js +0 -0
  23. package/dist/chunk-KT3MWNZG.js +0 -0
  24. package/dist/chunk-O7335ZGH.js +0 -0
  25. package/dist/{chunk-QLGES2HC.js → chunk-SNDZQ64K.js} +2 -2
  26. package/dist/chunk-TPCT3MXV.js +0 -0
  27. package/dist/chunk-WZ7CPVQB.js +0 -0
  28. package/dist/{chunk-F7RLPDXW.js → chunk-X2OLD264.js} +6 -6
  29. package/dist/chunk-X4JAX2U3.js +0 -0
  30. package/dist/chunk-XMS5VRIK.js +0 -0
  31. package/dist/chunk-XP7YXRHO.js +0 -0
  32. package/dist/{chunk-ERAZNHHR.js → chunk-YWWHK7R6.js} +2 -2
  33. package/dist/chunk-ZJW5FFYJ.js +0 -0
  34. package/dist/chunk-ZOXNJV2O.js +0 -0
  35. package/dist/cli/index.js +5 -5
  36. package/dist/cloudflare-LCAOTRYZ.js +0 -0
  37. package/dist/configure-agent-registry-6YGTJYBC.js +0 -0
  38. package/dist/deno-deploy-ZN4RE5HF.js +0 -0
  39. package/dist/{dev-UZJVBUF3.js → dev-6P2DM33Q.js} +4 -4
  40. package/dist/{dev-emit-3CHM73TV.js → dev-emit-MLDFOLUU.js} +3 -3
  41. package/dist/{dev-emit-I3CKOHML.js → dev-emit-PRSRPDHA.js} +4 -4
  42. package/dist/dispatcher-E6QV32BO.js +0 -0
  43. package/dist/dist-E6BL4ZVY.js +0 -0
  44. package/dist/docker-EZDA5FT7.js +0 -0
  45. package/dist/generate-DT4IIAHF.js +0 -0
  46. package/dist/index.js +2 -2
  47. package/dist/info-FJ4NXKTB.js +0 -0
  48. package/dist/lib-NL5JXGEB.js +0 -0
  49. package/dist/netlify-5VQ22Z2P.js +0 -0
  50. package/dist/node-3APTLGWB.js +0 -0
  51. package/dist/{openapi-ILYEJ6OR.js → openapi-SOKZTFE3.js} +4 -4
  52. package/dist/proper-lockfile-4Y3DP3RP.js +0 -0
  53. package/dist/registry-5QFTLOL2.js +0 -0
  54. package/dist/{routes-IGT42JJO.js → routes-XVRAUH6H.js} +3 -3
  55. package/dist/scan-C2BOKLSY.js +0 -0
  56. package/dist/schema-VR6YNVLQ.js +0 -0
  57. package/dist/server/index.d.ts +10 -0
  58. package/dist/server/index.js +2 -2
  59. package/dist/services-typed-client-ZX5JUHH3.js +0 -0
  60. package/dist/sqlite-vec-ARPNUBWT.js +0 -0
  61. package/dist/{start-UX2IPPSH.js → start-R7XSQL5L.js} +4 -4
  62. package/dist/static-TZBVBDTB.js +0 -0
  63. package/dist/storage-manager-D5KBXXKB.js +0 -0
  64. package/dist/theo-cloud-3K4DGB3S.js +0 -0
  65. package/dist/upgrade-readiness-GUJBCJIS.js +0 -0
  66. package/dist/vercel-MWW24ABC.js +0 -0
  67. package/dist/vite-plugin/index.js +2 -2
  68. package/dist/{vite-plugin-FTYXDKKG.js → vite-plugin-6MPHTKIW.js} +4 -4
  69. package/package.json +7 -7
  70. package/dist/actions-virtual-module-E6PU47GV.js.map +0 -1
  71. package/dist/actions-virtual-module-E7IELVHL.js.map +0 -1
  72. package/dist/chunk-7DHGV77J.js.map +0 -1
  73. package/dist/chunk-MOT42NAH.js.map +0 -1
  74. /package/dist/{app-typed-client-FOWJP534.js.map → app-typed-client-6GC6VWXS.js.map} +0 -0
  75. /package/dist/{app-typed-client-IMILAGER.js.map → app-typed-client-US2ZXBEC.js.map} +0 -0
  76. /package/dist/{build-KRSHWXMJ.js.map → build-MREW6MVS.js.map} +0 -0
  77. /package/dist/{chunk-RIBIAL7A.js.map → chunk-5OKZY2VL.js.map} +0 -0
  78. /package/dist/{chunk-SEVYARIU.js.map → chunk-BE2LKDI7.js.map} +0 -0
  79. /package/dist/{chunk-QLGES2HC.js.map → chunk-SNDZQ64K.js.map} +0 -0
  80. /package/dist/{chunk-F7RLPDXW.js.map → chunk-X2OLD264.js.map} +0 -0
  81. /package/dist/{chunk-ERAZNHHR.js.map → chunk-YWWHK7R6.js.map} +0 -0
  82. /package/dist/{dev-UZJVBUF3.js.map → dev-6P2DM33Q.js.map} +0 -0
  83. /package/dist/{dev-emit-3CHM73TV.js.map → dev-emit-MLDFOLUU.js.map} +0 -0
  84. /package/dist/{dev-emit-I3CKOHML.js.map → dev-emit-PRSRPDHA.js.map} +0 -0
  85. /package/dist/{openapi-ILYEJ6OR.js.map → openapi-SOKZTFE3.js.map} +0 -0
  86. /package/dist/{routes-IGT42JJO.js.map → routes-XVRAUH6H.js.map} +0 -0
  87. /package/dist/{start-UX2IPPSH.js.map → start-R7XSQL5L.js.map} +0 -0
  88. /package/dist/{vite-plugin-FTYXDKKG.js.map → vite-plugin-6MPHTKIW.js.map} +0 -0
@@ -34,7 +34,7 @@ import {
34
34
  } from "./chunk-2BQYEBCK.js";
35
35
  import {
36
36
  scanServerActions
37
- } from "./chunk-7DHGV77J.js";
37
+ } from "./chunk-7TOMTMHT.js";
38
38
  import {
39
39
  generateNonce
40
40
  } from "./chunk-PB4GR7EP.js";
@@ -1969,13 +1969,13 @@ async function theoPluginAsync(rootOrOptions) {
1969
1969
  })
1970
1970
  );
1971
1971
  }
1972
- const { appTypedClientPlugin } = await import("./app-typed-client-IMILAGER.js");
1972
+ const { appTypedClientPlugin } = await import("./app-typed-client-US2ZXBEC.js");
1973
1973
  const appClientPlugin = appTypedClientPlugin({
1974
1974
  cwd: projectRoot,
1975
1975
  serverDir: resolve6(projectRoot, "server"),
1976
1976
  distDir: resolve6(projectRoot, ".theo")
1977
1977
  });
1978
- const { actionsVirtualModule } = await import("./actions-virtual-module-E7IELVHL.js");
1978
+ const { actionsVirtualModule } = await import("./actions-virtual-module-SEIPACG5.js");
1979
1979
  const actionsPlugin = actionsVirtualModule({
1980
1980
  serverDir: resolve6(projectRoot, "server"),
1981
1981
  distDir: resolve6(projectRoot, ".theo")
@@ -2238,7 +2238,7 @@ function theoPlugin(rootOrOptions) {
2238
2238
  server.watcher.on("unlink", handleRouteChange);
2239
2239
  if (resolvedOpenApi !== void 0) {
2240
2240
  const openApiCfg = resolvedOpenApi;
2241
- const { reEmitOpenApi } = await import("./dev-emit-3CHM73TV.js");
2241
+ const { reEmitOpenApi } = await import("./dev-emit-MLDFOLUU.js");
2242
2242
  const openApiServerDir = resolve6(projectRoot, "server");
2243
2243
  const openApiDistDir = resolve6(projectRoot, resolvedDistDir);
2244
2244
  const isRouteFileForOpenApi = (file) => file.startsWith(openApiServerDir) && /\.(ts|tsx|js|mjs)$/.test(file);
@@ -2284,4 +2284,4 @@ export {
2284
2284
  theoPluginAsync,
2285
2285
  theoPlugin
2286
2286
  };
2287
- //# sourceMappingURL=chunk-RIBIAL7A.js.map
2287
+ //# sourceMappingURL=chunk-5OKZY2VL.js.map
@@ -45,6 +45,7 @@ function scanServerActionsEnriched(serverDir) {
45
45
  walkSourceFiles(actionsDir, { extensions: ACTION_EXTENSIONS }, (absPath) => {
46
46
  if (TEST_FILE_RE.test(absPath)) return;
47
47
  const rel = relative(actionsDir, absPath).replace(/\\/g, "/");
48
+ if (rel.startsWith("schemas/")) return;
48
49
  const name = rel.slice(0, -extname(rel).length);
49
50
  const basename = name.includes("/") ? name.split("/").pop() ?? name : name;
50
51
  if (RESERVED_NAMES.has(basename)) {
@@ -59,6 +60,7 @@ function scanServerActionsEnriched(serverDir) {
59
60
  const accept = /\baccept\s*:\s*['"]form['"]/.test(stripped) ? "form" : "json";
60
61
  const hasInput = /\binput\s*:\s*z\./.test(stripped) || /\binput\s*:\s*\w+\(/.test(stripped);
61
62
  const exportNames = extractActionExportNames(stripped);
63
+ const schemaFilePath = name.includes("/") ? void 0 : detectSchemaFile(actionsDir, basename);
62
64
  for (const exportName of exportNames) {
63
65
  const proxyKey = exportName === "default" ? name : exportName;
64
66
  if (seenNames.has(proxyKey)) {
@@ -69,13 +71,17 @@ function scanServerActionsEnriched(serverDir) {
69
71
  );
70
72
  }
71
73
  seenNames.add(proxyKey);
72
- entries.push({
74
+ const entry = {
73
75
  name: proxyKey,
74
76
  filePath: absPath,
75
77
  urlPath: `/api/__actions/${name}/${exportName}`,
76
78
  accept,
77
79
  hasInput
78
- });
80
+ };
81
+ if (schemaFilePath !== void 0) {
82
+ entry.schemaFilePath = schemaFilePath;
83
+ }
84
+ entries.push(entry);
79
85
  }
80
86
  });
81
87
  for (const entry of entries) {
@@ -110,6 +116,15 @@ function extractActionExportNames(stripped) {
110
116
  if (names.size === 0) names.add("default");
111
117
  return [...names];
112
118
  }
119
+ function detectSchemaFile(actionsDir, basename) {
120
+ const schemasDir = join(actionsDir, "schemas");
121
+ if (!existsSync(schemasDir)) return void 0;
122
+ for (const ext of [".ts", ".tsx", ".js", ".jsx"]) {
123
+ const candidate = join(schemasDir, `${basename}${ext}`);
124
+ if (existsSync(candidate)) return candidate;
125
+ }
126
+ return void 0;
127
+ }
113
128
  function stripComments(source) {
114
129
  let out = "";
115
130
  let i = 0;
@@ -137,4 +152,4 @@ export {
137
152
  scanServerActions,
138
153
  scanServerActionsEnriched
139
154
  };
140
- //# sourceMappingURL=chunk-7DHGV77J.js.map
155
+ //# sourceMappingURL=chunk-7TOMTMHT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/scan/action-scan.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: walks `serverDir/actions/` 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\nexport interface ActionNode {\n filePath: string\n actionPath: string\n}\n\n/**\n * Enriched manifest entry per plan g3-server-actions-and-useaction v1.2\n * § Phase 1 / T1.4 + ADR D4. Consumed by virtual module `@theo/actions`\n * (T3.1) and G4 devtools \"Actions\" tab (T5.1).\n */\nexport interface ActionManifestEntry {\n name: string\n filePath: string\n urlPath: string\n accept: 'form' | 'json'\n hasInput: boolean\n /**\n * P#4 plugin-forms shared-schema convention (per plan p4-plugin-forms v1.1 T1.1).\n * When present, points to an isomorphic schema file at\n * `<serverDir>/actions/schemas/<basename>.ts` exporting `export const schema = z.object(...)`.\n * Virtual module emits `import {schema} from '<schemaFilePath>'` + attaches as\n * `actions.X.__zodSchema` so client-side <TheoForm> can drive zodResolver.\n * Undefined when convention not followed (graceful degrade — TheoForm still\n * works via explicit `schema={...}` prop escape hatch).\n */\n schemaFilePath?: string\n}\n\n/**\n * EC-2: structured error for scan-time defects (name collision, reserved\n * identifier, etc.). Throw at scan time to fail loud — silent shadowing is\n * a security/correctness footgun.\n */\nexport class ActionScanError extends Error {\n readonly code: 'NAME_COLLISION' | 'RESERVED_NAME'\n readonly conflictingPaths: readonly string[]\n\n constructor(\n code: 'NAME_COLLISION' | 'RESERVED_NAME',\n message: string,\n conflictingPaths: readonly string[],\n ) {\n super(message)\n this.code = code\n this.conflictingPaths = conflictingPaths\n }\n}\n\nconst ACTION_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\nconst TEST_FILE_RE = /\\.(test|spec)\\.(ts|tsx|js|jsx)$/\nconst RESERVED_NAMES = new Set(['index', 'constructor', '__proto__', 'prototype', 'hasOwnProperty'])\n\n/**\n * Backward-compatible: original simple-shape scanner used by existing\n * consumers. Preserved verbatim; new consumers should call\n * `scanServerActionsEnriched`.\n */\nexport function scanServerActions(serverDir: string): ActionNode[] {\n const actionsDir = join(serverDir, 'actions')\n if (!existsSync(actionsDir) || !statSync(actionsDir).isDirectory()) {\n return []\n }\n\n const results: ActionNode[] = []\n walkSourceFiles(actionsDir, { extensions: ACTION_EXTENSIONS }, (absPath) => {\n if (TEST_FILE_RE.test(absPath)) return\n let rel = relative(actionsDir, absPath)\n rel = rel.replace(/\\\\/g, '/')\n rel = rel.slice(0, -extname(rel).length)\n results.push({\n filePath: absPath,\n actionPath: rel,\n })\n })\n return results\n}\n\n/**\n * Enriched scan: light AST detection of `accept: 'form'|'json'` + `input:`\n * presence via regex-after-comment-stripping (EC-9). Throws ActionScanError\n * on file/dir name collision (EC-2) or reserved JS identifier names.\n *\n * Output `ActionManifestEntry[]` is sorted by `name` for deterministic\n * `.theo/actions-manifest.json` emission.\n */\nexport function scanServerActionsEnriched(serverDir: string): ActionManifestEntry[] {\n const actionsDir = join(serverDir, 'actions')\n if (!existsSync(actionsDir) || !statSync(actionsDir).isDirectory()) {\n return []\n }\n\n const seenNames = new Set<string>()\n const entries: ActionManifestEntry[] = []\n\n // Collect first; collision-check after the full walk.\n walkSourceFiles(actionsDir, { extensions: ACTION_EXTENSIONS }, (absPath) => {\n if (TEST_FILE_RE.test(absPath)) return\n const rel = relative(actionsDir, absPath).replace(/\\\\/g, '/')\n // P#4 plugin-forms — `schemas/` subdir holds isomorphic zod schemas\n // for the shared-schema convention (T1.1). NOT executable actions; skip.\n if (rel.startsWith('schemas/')) return\n const name = rel.slice(0, -extname(rel).length)\n\n const basename = name.includes('/') ? (name.split('/').pop() ?? name) : name\n if (RESERVED_NAMES.has(basename)) {\n throw new ActionScanError(\n 'RESERVED_NAME',\n `Reserved JS identifier \"${basename}\" cannot be an action name (${absPath})`,\n [absPath],\n )\n }\n // File-level collision (one file appearing twice) is impossible via the\n // walker; per-export collision check happens inside the export loop below.\n const source = readFileSync(absPath, 'utf8')\n const stripped = stripComments(source)\n const accept = /\\baccept\\s*:\\s*['\"]form['\"]/.test(stripped) ? 'form' : 'json'\n const hasInput = /\\binput\\s*:\\s*z\\./.test(stripped) || /\\binput\\s*:\\s*\\w+\\(/.test(stripped)\n\n // T7.1 wire fix — extract exports so the urlPath includes the second\n // segment required by action-middleware (`/api/__actions/<file>/<export>`).\n // Each named action export becomes its own manifest entry.\n // Proxy key on the EXPORT name (so consumers write `actions.saveMemory(input)`).\n // URL keeps the runtime 2-segment shape `/api/__actions/<file>/<export>`\n // expected by action-middleware. Cross-file export collisions become a\n // scan error to surface the ambiguity early.\n const exportNames = extractActionExportNames(stripped)\n // P#4 plugin-forms shared-schema convention: check for\n // `<actionsDir>/schemas/<basename>.ts` (or .tsx/.js/.jsx).\n // Skip when actions live in subdirs (`schemas/` is flat by convention).\n const schemaFilePath = name.includes('/') ? undefined : detectSchemaFile(actionsDir, basename)\n for (const exportName of exportNames) {\n const proxyKey = exportName === 'default' ? name : exportName\n if (seenNames.has(proxyKey)) {\n throw new ActionScanError(\n 'NAME_COLLISION',\n `Duplicate action proxy key \"${proxyKey}\" (two files export the same name)`,\n [absPath],\n )\n }\n seenNames.add(proxyKey)\n const entry: ActionManifestEntry = {\n name: proxyKey,\n filePath: absPath,\n urlPath: `/api/__actions/${name}/${exportName}`,\n accept,\n hasInput,\n }\n if (schemaFilePath !== undefined) {\n entry.schemaFilePath = schemaFilePath\n }\n entries.push(entry)\n }\n })\n\n // EC-2: detect file vs dir collisions (e.g., foo.ts AND foo/bar.ts).\n // After walk completes, any name that has children prefixed `name/` triggers collision.\n for (const entry of entries) {\n const childPrefix = `${entry.name}/`\n const conflictingChild = entries.find((other) => other.name.startsWith(childPrefix))\n if (conflictingChild) {\n throw new ActionScanError(\n 'NAME_COLLISION',\n `Action \"${entry.name}\" conflicts with directory of same name containing \"${conflictingChild.name}\"`,\n [entry.filePath, conflictingChild.filePath],\n )\n }\n }\n\n entries.sort((a, b) => {\n if (a.name < b.name) return -1\n if (a.name > b.name) return 1\n return 0\n })\n return entries\n}\n\n/**\n * Strip JavaScript line + block comments from source. Simple state machine\n * (does not parse strings — false positives if a comment marker appears\n * inside a string literal, but that's an acceptable trade-off for v1 vs\n * full AST parse).\n */\n/**\n * Extract action export names via regex over comment-stripped source.\n * Matches `export const <name> = defineAction(...)`, `export default\n * defineAction(...)`, and `export function <name>(...)` forms. Returns\n * `['default']` when no named action exports are found (best-effort fallback\n * for default-export shapes the regex misses).\n */\nfunction extractActionExportNames(stripped: string): string[] {\n const names = new Set<string>()\n const namedRe = /\\bexport\\s+(?:const|let|var|function\\*?)\\s+([a-zA-Z_$][\\w$]*)\\s*[=(]/g\n let m: RegExpExecArray | null\n while ((m = namedRe.exec(stripped)) !== null) {\n const name = m[1]\n if (typeof name === 'string' && name.length > 0) names.add(name)\n }\n if (/\\bexport\\s+default\\s+defineAction\\b/.test(stripped)) {\n names.add('default')\n }\n if (names.size === 0) names.add('default')\n return [...names]\n}\n\n/**\n * P#4 plugin-forms shared-schema convention helper (per plan p4-plugin-forms v1.1 T1.1).\n * Returns the resolved path to `<actionsDir>/schemas/<basename>.<ext>` if it exists.\n * Tries `.ts`, `.tsx`, `.js`, `.jsx` in that order. Returns undefined when no match.\n */\nfunction detectSchemaFile(actionsDir: string, basename: string): string | undefined {\n const schemasDir = join(actionsDir, 'schemas')\n if (!existsSync(schemasDir)) return undefined\n for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {\n const candidate = join(schemasDir, `${basename}${ext}`)\n if (existsSync(candidate)) return candidate\n }\n return undefined\n}\n\nfunction stripComments(source: string): string {\n let out = ''\n let i = 0\n while (i < source.length) {\n const ch = source[i]\n const next = source[i + 1]\n if (ch === '/' && next === '/') {\n // Line comment: skip until newline\n while (i < source.length && source[i] !== '\\n') i++\n continue\n }\n if (ch === '/' && next === '*') {\n // Block comment: skip until */\n i += 2\n while (i < source.length - 1 && !(source[i] === '*' && source[i + 1] === '/')) i++\n i += 2\n continue\n }\n out += ch\n i++\n }\n return out\n}\n"],"mappings":"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","names":[]}
@@ -4,10 +4,10 @@ import {
4
4
  compilePattern,
5
5
  scanServerRoutes,
6
6
  scanWebSocketRoutes
7
- } from "./chunk-QLGES2HC.js";
7
+ } from "./chunk-SNDZQ64K.js";
8
8
  import {
9
9
  scanServerActions
10
- } from "./chunk-MOT42NAH.js";
10
+ } from "./chunk-5OFPQK6N.js";
11
11
 
12
12
  // src/server/scan/manifest.ts
13
13
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
@@ -72,4 +72,4 @@ export {
72
72
  writeManifest,
73
73
  loadManifest
74
74
  };
75
- //# sourceMappingURL=chunk-SEVYARIU.js.map
75
+ //# sourceMappingURL=chunk-BE2LKDI7.js.map
File without changes
File without changes
File without changes
@@ -2,7 +2,7 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  walkSourceFiles
5
- } from "./chunk-MOT42NAH.js";
5
+ } from "./chunk-5OFPQK6N.js";
6
6
 
7
7
  // src/core/contracts/http-methods.ts
8
8
  var HTTP_METHODS = [
@@ -186,4 +186,4 @@ export {
186
186
  scanServerRoutes,
187
187
  scanWebSocketRoutes
188
188
  };
189
- //# sourceMappingURL=chunk-QLGES2HC.js.map
189
+ //# sourceMappingURL=chunk-SNDZQ64K.js.map
File without changes
File without changes
@@ -31,10 +31,10 @@ import {
31
31
  matchRoute,
32
32
  scanServerRoutes,
33
33
  scanWebSocketRoutes
34
- } from "./chunk-QLGES2HC.js";
34
+ } from "./chunk-SNDZQ64K.js";
35
35
  import {
36
36
  scanServerActions
37
- } from "./chunk-MOT42NAH.js";
37
+ } from "./chunk-5OFPQK6N.js";
38
38
 
39
39
  // src/vite-plugin/index.ts
40
40
  import { existsSync as existsSync5 } from "fs";
@@ -1886,13 +1886,13 @@ async function theoPluginAsync(rootOrOptions) {
1886
1886
  })
1887
1887
  );
1888
1888
  }
1889
- const { appTypedClientPlugin } = await import("./app-typed-client-FOWJP534.js");
1889
+ const { appTypedClientPlugin } = await import("./app-typed-client-6GC6VWXS.js");
1890
1890
  const appClientPlugin = appTypedClientPlugin({
1891
1891
  cwd: projectRoot,
1892
1892
  serverDir: resolve4(projectRoot, "server"),
1893
1893
  distDir: resolve4(projectRoot, ".theo")
1894
1894
  });
1895
- const { actionsVirtualModule } = await import("./actions-virtual-module-E6PU47GV.js");
1895
+ const { actionsVirtualModule } = await import("./actions-virtual-module-HWNTIEPI.js");
1896
1896
  const actionsPlugin = actionsVirtualModule({
1897
1897
  serverDir: resolve4(projectRoot, "server"),
1898
1898
  distDir: resolve4(projectRoot, ".theo")
@@ -2155,7 +2155,7 @@ function theoPlugin(rootOrOptions) {
2155
2155
  server.watcher.on("unlink", handleRouteChange);
2156
2156
  if (resolvedOpenApi !== void 0) {
2157
2157
  const openApiCfg = resolvedOpenApi;
2158
- const { reEmitOpenApi } = await import("./dev-emit-I3CKOHML.js");
2158
+ const { reEmitOpenApi } = await import("./dev-emit-PRSRPDHA.js");
2159
2159
  const openApiServerDir = resolve4(projectRoot, "server");
2160
2160
  const openApiDistDir = resolve4(projectRoot, resolvedDistDir);
2161
2161
  const isRouteFileForOpenApi = (file) => file.startsWith(openApiServerDir) && /\.(ts|tsx|js|mjs)$/.test(file);
@@ -2193,4 +2193,4 @@ export {
2193
2193
  theoPluginAsync,
2194
2194
  theoPlugin
2195
2195
  };
2196
- //# sourceMappingURL=chunk-F7RLPDXW.js.map
2196
+ //# sourceMappingURL=chunk-X2OLD264.js.map
File without changes
File without changes
File without changes
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-2BQYEBCK.js";
6
6
  import {
7
7
  scanServerActions
8
- } from "./chunk-7DHGV77J.js";
8
+ } from "./chunk-7TOMTMHT.js";
9
9
 
10
10
  // src/server/scan/manifest.ts
11
11
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
@@ -70,4 +70,4 @@ export {
70
70
  writeManifest,
71
71
  loadManifest
72
72
  };
73
- //# sourceMappingURL=chunk-ERAZNHHR.js.map
73
+ //# sourceMappingURL=chunk-YWWHK7R6.js.map
File without changes
File without changes
package/dist/cli/index.js CHANGED
@@ -6,12 +6,12 @@ import "../chunk-KT3MWNZG.js";
6
6
  import cac from "cac";
7
7
  var cli = cac("theokit");
8
8
  cli.command("dev", "Start development server").option("--port <port>", "Port number").action(async (options) => {
9
- const { devCommand } = await import("../dev-UZJVBUF3.js");
9
+ const { devCommand } = await import("../dev-6P2DM33Q.js");
10
10
  await devCommand({ port: options.port ? Number(options.port) : void 0 });
11
11
  });
12
12
  cli.command("build", "Build for production").option("--target <target>", "Deploy target (node, vercel, cloudflare)").action(async (options) => {
13
13
  try {
14
- const { buildCommand } = await import("../build-KRSHWXMJ.js");
14
+ const { buildCommand } = await import("../build-MREW6MVS.js");
15
15
  await buildCommand({ target: options.target });
16
16
  } catch (err) {
17
17
  const msg = err instanceof Error ? err.message : String(err);
@@ -23,7 +23,7 @@ cli.command("build", "Build for production").option("--target <target>", "Deploy
23
23
  });
24
24
  cli.command("start", "Start production server").option("--port <port>", "Port number").action(async (options) => {
25
25
  try {
26
- const { startCommand } = await import("../start-UX2IPPSH.js");
26
+ const { startCommand } = await import("../start-R7XSQL5L.js");
27
27
  await startCommand({ port: options.port ? Number(options.port) : void 0 });
28
28
  } catch (err) {
29
29
  const msg = err instanceof Error ? err.message : String(err);
@@ -47,7 +47,7 @@ cli.command("generate <type> <name>", "Generate a route, action, page, or ws end
47
47
  });
48
48
  cli.command("routes", "List all routes, actions, and WebSocket endpoints").action(async () => {
49
49
  try {
50
- const { routesCommand } = await import("../routes-IGT42JJO.js");
50
+ const { routesCommand } = await import("../routes-XVRAUH6H.js");
51
51
  await routesCommand();
52
52
  } catch (err) {
53
53
  const msg = err instanceof Error ? err.message : String(err);
@@ -96,7 +96,7 @@ cli.command(
96
96
  "Generate <distDir>/openapi.json from route schemas (opt-in via config.openapi)"
97
97
  ).option("--dry-run", "Print the document to stdout without writing to disk (EC-3)").action(async (options) => {
98
98
  try {
99
- const { openapiCommand } = await import("../openapi-ILYEJ6OR.js");
99
+ const { openapiCommand } = await import("../openapi-SOKZTFE3.js");
100
100
  await openapiCommand({ dryRun: Boolean(options.dryRun) });
101
101
  } catch (err) {
102
102
  const msg = err instanceof Error ? err.message : String(err);
File without changes
File without changes
File without changes
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-XMS5VRIK.js";
9
9
  import {
10
10
  theoPluginAsync
11
- } from "./chunk-F7RLPDXW.js";
11
+ } from "./chunk-X2OLD264.js";
12
12
  import "./chunk-TPCT3MXV.js";
13
13
  import {
14
14
  loadConfig,
@@ -20,8 +20,8 @@ import "./chunk-O7335ZGH.js";
20
20
  import {
21
21
  orchestrateDev
22
22
  } from "./chunk-WZ7CPVQB.js";
23
- import "./chunk-QLGES2HC.js";
24
- import "./chunk-MOT42NAH.js";
23
+ import "./chunk-SNDZQ64K.js";
24
+ import "./chunk-5OFPQK6N.js";
25
25
  import "./chunk-KT3MWNZG.js";
26
26
 
27
27
  // src/cli/commands/dev.ts
@@ -89,4 +89,4 @@ export {
89
89
  devCommand,
90
90
  startDevServer
91
91
  };
92
- //# sourceMappingURL=dev-UZJVBUF3.js.map
92
+ //# sourceMappingURL=dev-6P2DM33Q.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generateManifest
3
- } from "./chunk-ERAZNHHR.js";
3
+ } from "./chunk-YWWHK7R6.js";
4
4
  import "./chunk-2BQYEBCK.js";
5
- import "./chunk-7DHGV77J.js";
5
+ import "./chunk-7TOMTMHT.js";
6
6
  import "./chunk-X2VVCJ4V.js";
7
7
  import "./chunk-WSJKACWB.js";
8
8
  import "./chunk-DGUM43GV.js";
@@ -387,4 +387,4 @@ export {
387
387
  _resetInFlightForTests,
388
388
  reEmitOpenApi
389
389
  };
390
- //# sourceMappingURL=dev-emit-3CHM73TV.js.map
390
+ //# sourceMappingURL=dev-emit-MLDFOLUU.js.map
@@ -6,9 +6,9 @@ import {
6
6
  } from "./chunk-ZOXNJV2O.js";
7
7
  import {
8
8
  generateManifest
9
- } from "./chunk-SEVYARIU.js";
10
- import "./chunk-QLGES2HC.js";
11
- import "./chunk-MOT42NAH.js";
9
+ } from "./chunk-BE2LKDI7.js";
10
+ import "./chunk-SNDZQ64K.js";
11
+ import "./chunk-5OFPQK6N.js";
12
12
  import "./chunk-KT3MWNZG.js";
13
13
 
14
14
  // src/vite-plugin/openapi-emit/dev-emit.ts
@@ -41,4 +41,4 @@ export {
41
41
  _resetInFlightForTests,
42
42
  reEmitOpenApi
43
43
  };
44
- //# sourceMappingURL=dev-emit-I3CKOHML.js.map
44
+ //# sourceMappingURL=dev-emit-PRSRPDHA.js.map
File without changes
File without changes
File without changes
File without changes
package/dist/index.js CHANGED
@@ -8,12 +8,12 @@ import {
8
8
  scanRoutes,
9
9
  theoConfigSchema,
10
10
  theoPlugin
11
- } from "./chunk-RIBIAL7A.js";
11
+ } from "./chunk-5OKZY2VL.js";
12
12
  import "./chunk-7BIM27LV.js";
13
13
  import "./chunk-O4BLVPML.js";
14
14
  import "./chunk-CZM6WWWS.js";
15
15
  import "./chunk-2BQYEBCK.js";
16
- import "./chunk-7DHGV77J.js";
16
+ import "./chunk-7TOMTMHT.js";
17
17
  import "./chunk-PB4GR7EP.js";
18
18
  import "./chunk-GY5Q27BJ.js";
19
19
  import "./chunk-X2VVCJ4V.js";
File without changes
File without changes
File without changes
File without changes
@@ -11,9 +11,9 @@ import "./chunk-X4JAX2U3.js";
11
11
  import "./chunk-WZ7CPVQB.js";
12
12
  import {
13
13
  generateManifest
14
- } from "./chunk-SEVYARIU.js";
15
- import "./chunk-QLGES2HC.js";
16
- import "./chunk-MOT42NAH.js";
14
+ } from "./chunk-BE2LKDI7.js";
15
+ import "./chunk-SNDZQ64K.js";
16
+ import "./chunk-5OFPQK6N.js";
17
17
  import "./chunk-KT3MWNZG.js";
18
18
 
19
19
  // src/cli/commands/openapi.ts
@@ -81,4 +81,4 @@ function emitOpenApiInMemory(manifest, config) {
81
81
  export {
82
82
  openapiCommand
83
83
  };
84
- //# sourceMappingURL=openapi-ILYEJ6OR.js.map
84
+ //# sourceMappingURL=openapi-SOKZTFE3.js.map
File without changes
File without changes
@@ -11,10 +11,10 @@ import "./chunk-WZ7CPVQB.js";
11
11
  import {
12
12
  scanServerRoutes,
13
13
  scanWebSocketRoutes
14
- } from "./chunk-QLGES2HC.js";
14
+ } from "./chunk-SNDZQ64K.js";
15
15
  import {
16
16
  scanServerActions
17
- } from "./chunk-MOT42NAH.js";
17
+ } from "./chunk-5OFPQK6N.js";
18
18
  import "./chunk-KT3MWNZG.js";
19
19
 
20
20
  // src/cli/commands/routes.ts
@@ -63,4 +63,4 @@ async function routesCommand() {
63
63
  export {
64
64
  routesCommand
65
65
  };
66
- //# sourceMappingURL=routes-IGT42JJO.js.map
66
+ //# sourceMappingURL=routes-XVRAUH6H.js.map
File without changes
File without changes
@@ -881,6 +881,16 @@ interface ActionManifestEntry$1 {
881
881
  urlPath: string;
882
882
  accept: 'form' | 'json';
883
883
  hasInput: boolean;
884
+ /**
885
+ * P#4 plugin-forms shared-schema convention (per plan p4-plugin-forms v1.1 T1.1).
886
+ * When present, points to an isomorphic schema file at
887
+ * `<serverDir>/actions/schemas/<basename>.ts` exporting `export const schema = z.object(...)`.
888
+ * Virtual module emits `import {schema} from '<schemaFilePath>'` + attaches as
889
+ * `actions.X.__zodSchema` so client-side <TheoForm> can drive zodResolver.
890
+ * Undefined when convention not followed (graceful degrade — TheoForm still
891
+ * works via explicit `schema={...}` prop escape hatch).
892
+ */
893
+ schemaFilePath?: string;
884
894
  }
885
895
  /**
886
896
  * EC-2: structured error for scan-time defects (name collision, reserved
@@ -2,7 +2,7 @@ import {
2
2
  generateManifest,
3
3
  loadManifest,
4
4
  writeManifest
5
- } from "../chunk-ERAZNHHR.js";
5
+ } from "../chunk-YWWHK7R6.js";
6
6
  import {
7
7
  _resetKeyCacheForTests,
8
8
  assertProductionSecret,
@@ -142,7 +142,7 @@ import {
142
142
  ActionScanError,
143
143
  scanServerActions,
144
144
  scanServerActionsEnriched
145
- } from "../chunk-7DHGV77J.js";
145
+ } from "../chunk-7TOMTMHT.js";
146
146
  import {
147
147
  AuthRequiredError,
148
148
  generateNonce,
File without changes
File without changes
@@ -25,15 +25,15 @@ import "./chunk-X4JAX2U3.js";
25
25
  import "./chunk-WZ7CPVQB.js";
26
26
  import {
27
27
  loadManifest
28
- } from "./chunk-SEVYARIU.js";
28
+ } from "./chunk-BE2LKDI7.js";
29
29
  import {
30
30
  matchRoute,
31
31
  scanServerRoutes,
32
32
  scanWebSocketRoutes
33
- } from "./chunk-QLGES2HC.js";
33
+ } from "./chunk-SNDZQ64K.js";
34
34
  import {
35
35
  scanServerActions
36
- } from "./chunk-MOT42NAH.js";
36
+ } from "./chunk-5OFPQK6N.js";
37
37
  import "./chunk-KT3MWNZG.js";
38
38
 
39
39
  // src/cli/commands/start.ts
@@ -612,4 +612,4 @@ export {
612
612
  resolveSsrEntry,
613
613
  startCommand
614
614
  };
615
- //# sourceMappingURL=start-UX2IPPSH.js.map
615
+ //# sourceMappingURL=start-R7XSQL5L.js.map
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -5,12 +5,12 @@ import {
5
5
  defineTheoIntegration,
6
6
  theoPlugin,
7
7
  theoPluginAsync
8
- } from "../chunk-RIBIAL7A.js";
8
+ } from "../chunk-5OKZY2VL.js";
9
9
  import "../chunk-7BIM27LV.js";
10
10
  import "../chunk-O4BLVPML.js";
11
11
  import "../chunk-CZM6WWWS.js";
12
12
  import "../chunk-2BQYEBCK.js";
13
- import "../chunk-7DHGV77J.js";
13
+ import "../chunk-7TOMTMHT.js";
14
14
  import "../chunk-PB4GR7EP.js";
15
15
  import "../chunk-GY5Q27BJ.js";
16
16
  import "../chunk-X2VVCJ4V.js";
@@ -7,15 +7,15 @@ import {
7
7
  defineTheoIntegration,
8
8
  theoPlugin,
9
9
  theoPluginAsync
10
- } from "./chunk-F7RLPDXW.js";
10
+ } from "./chunk-X2OLD264.js";
11
11
  import "./chunk-TPCT3MXV.js";
12
12
  import "./chunk-XP7YXRHO.js";
13
13
  import "./chunk-X4JAX2U3.js";
14
14
  import "./chunk-5ODOE6EF.js";
15
15
  import "./chunk-O7335ZGH.js";
16
16
  import "./chunk-WZ7CPVQB.js";
17
- import "./chunk-QLGES2HC.js";
18
- import "./chunk-MOT42NAH.js";
17
+ import "./chunk-SNDZQ64K.js";
18
+ import "./chunk-5OFPQK6N.js";
19
19
  import "./chunk-KT3MWNZG.js";
20
20
  export {
21
21
  IntegrationRouteCollisionError,
@@ -25,4 +25,4 @@ export {
25
25
  theoPlugin,
26
26
  theoPluginAsync
27
27
  };
28
- //# sourceMappingURL=vite-plugin-FTYXDKKG.js.map
28
+ //# sourceMappingURL=vite-plugin-6MPHTKIW.js.map
package/package.json CHANGED
@@ -1,11 +1,8 @@
1
1
  {
2
2
  "name": "theokit",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
- "scripts": {
7
- "build": "tsup"
8
- },
9
6
  "bin": {
10
7
  "theokit": "./dist/cli/index.js"
11
8
  },
@@ -102,11 +99,14 @@
102
99
  "@types/busboy": "^1.5.4",
103
100
  "@types/pg": "^8.20.0",
104
101
  "@types/picomatch": "^4.0.0",
105
- "@theokit/sdk": "workspace:*",
106
102
  "better-sqlite3": "^12.10.0",
107
103
  "db0": "^0.3.0",
108
104
  "pg": "^8.21.0",
109
105
  "pg-mem": "^3.0.14",
110
- "unstorage": "^1.10.0"
106
+ "unstorage": "^1.10.0",
107
+ "@theokit/sdk": "1.5.0"
108
+ },
109
+ "scripts": {
110
+ "build": "tsup"
111
111
  }
112
- }
112
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/vite-plugin/actions-virtual-module.ts"],"sourcesContent":["/**\n * Vite plugin: resolves `@theo/actions` virtual module and emits a typed\n * Proxy facade that calls `theoFetch('/_actions/<name>', body)` against the\n * server-side action handlers.\n *\n * Per plan g3-server-actions-and-useaction v1.2 § Phase 3 / T3.1 + ADR D4.\n * Astro `vite-plugin-actions.ts` modular pattern. Single focused plugin\n * (not monolithic), virtual module + `configureServer` watcher.\n *\n * Module shape emitted on client environment: thin proxy that forwards\n * `actions.<name>(input)` to `POST /_actions/<name>` with JSON or\n * FormData body. On server environment: re-export of the manifest for\n * SSR / module-loader access (T1.3 sub-C consumer).\n *\n * EC-15 (DOCUMENT): HMR uses Vite default invalidation — coarse but\n * correct. Optimization (fine-grained invalidation of only consumers of\n * `@theo/actions`) deferred to G3.1 if dev-server p95 reload > 500ms.\n */\nimport { existsSync, mkdirSync, renameSync, watch as fsWatch, writeFileSync } from 'node:fs'\nimport { dirname, join, posix, resolve } from 'node:path'\n\nimport type { Plugin, ViteDevServer } from 'vite'\n\nimport { scanServerActionsEnriched, type ActionManifestEntry } from '../server/scan/action-scan.js'\n\nconst VIRTUAL_ID = '@theo/actions'\nconst RESOLVED_ID = `\\0${VIRTUAL_ID}`\n\nexport interface ActionsVirtualModuleOptions {\n /** Path to server directory (where `actions/` lives). */\n serverDir: string\n /**\n * Optional `.theo/` output dir for emitting `actions.d.ts`. When provided,\n * the plugin writes an ambient `declare module '@theo/actions'` so TS in\n * consumer apps can resolve the virtual module import. Mirrors the G1\n * `app-typed-client` emit pattern.\n */\n distDir?: string\n}\n\nexport function actionsVirtualModule(opts: ActionsVirtualModuleOptions): Plugin {\n const { serverDir, distDir } = opts\n\n function emitActionsDts(): void {\n if (distDir === undefined) return\n const entries = safeScan(serverDir)\n const dtsPath = posix.join(resolve(distDir).replace(/\\\\/g, '/'), 'actions.d.ts')\n const content = generateActionsDts(entries)\n try {\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- build-time derived path\n mkdirSync(dirname(dtsPath), { recursive: true })\n const tmp = `${dtsPath}.${process.pid}.tmp`\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- build-time derived path\n writeFileSync(tmp, content)\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- build-time derived path\n renameSync(tmp, dtsPath)\n } catch (err) {\n console.error('[theokit:actions-virtual-module] dts emit error:', err)\n }\n }\n\n return {\n name: 'theo:actions-virtual-module',\n enforce: 'pre',\n configResolved() {\n emitActionsDts()\n },\n buildEnd() {\n emitActionsDts()\n },\n resolveId(id: string) {\n if (id === VIRTUAL_ID) return RESOLVED_ID\n return undefined\n },\n load(id: string) {\n if (id !== RESOLVED_ID) return undefined\n const entries = safeScan(serverDir)\n const ctx = this as unknown as { environment?: { name?: string } } | undefined\n const envName = ctx?.environment?.name\n const isClient = envName === 'client' || envName === undefined\n return isClient ? generateClientFacade(entries) : generateServerManifest(entries)\n },\n configureServer(server: ViteDevServer) {\n const actionsDir = join(serverDir, 'actions')\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- build-time derived path\n if (!existsSync(actionsDir)) return\n // EC-15: coarse invalidation — invalidate ALL modules on actions file change.\n // Optimization deferred per plan ADR D4 note.\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- build-time path\n const watcher = fsWatch(actionsDir, { recursive: true }, () => {\n emitActionsDts()\n const mod = server.moduleGraph.getModuleById(RESOLVED_ID)\n if (mod) {\n server.moduleGraph.invalidateModule(mod)\n }\n server.ws.send({ type: 'full-reload' })\n })\n server.httpServer?.once('close', () => {\n watcher.close()\n })\n },\n }\n}\n\n/**\n * Emit `.theo/actions.d.ts` — ambient declaration of `@theo/actions` so\n * consumer TS apps can `import { actions } from '@theo/actions'` and get\n * typed completions for each scanned action name. Each entry maps name to\n * a generic `(input: unknown) => Promise<{data, error}>` invoker — the full\n * input/output inference from defineAction would require either monomorphic\n * dts-bundle or virtual type emit (deferred to a future plan).\n */\nfunction generateActionsDts(entries: readonly ActionManifestEntry[]): string {\n const lines = entries\n .map(\n (entry) =>\n ` ${JSON.stringify(entry.name)}: (input: unknown) => Promise<{ data: unknown; error: undefined } | { data: undefined; error: { code: string; message: string; fields?: Record<string, string[]>; type?: string } }>`,\n )\n .join('\\n')\n return `// AUTO-GENERATED by @theo/actions virtual module. DO NOT EDIT MANUALLY.\ndeclare module '@theo/actions' {\n export const actions: {\n${lines}\n }\n}\n`\n}\n\nfunction safeScan(serverDir: string): ActionManifestEntry[] {\n try {\n return scanServerActionsEnriched(serverDir)\n } catch {\n // ActionScanError surfaces at build time; for HMR keep an empty manifest\n // so the dev server doesn't crash mid-edit.\n return []\n }\n}\n\n/**\n * Client-side module: emits a Proxy facade. For each action `name` in\n * manifest, `actions.<name>(input)` POSTs to `/_actions/<name>` with JSON\n * body (or FormData when input is a FormData instance) and parses the\n * `application/json+devalue` response via the runtime helper.\n */\nfunction generateClientFacade(entries: ActionManifestEntry[]): string {\n const entryLines = entries\n .map((entry) => ` ${JSON.stringify(entry.name)}: ${JSON.stringify(entry.urlPath)},`)\n .join('\\n')\n\n return `// AUTO-GENERATED by @theo/actions virtual module\n/* eslint-disable */\nconst ACTION_URL_MAP = {\n${entryLines}\n}\n\n// Devtools telemetry — fires in the SAME realm as the Overlay React tree\n// (browser), so the Actions tab updates immediately on each call.\n// The Overlay component installs \\`window.__theoDevtoolsDispatcher\\` on\n// mount (dev only; prod tree-shakes the Overlay entirely). Reading the\n// global avoids a cross-package dynamic import that Vite's virtual-module\n// resolver cannot trace. Same pattern as React DevTools'\n// \\`__REACT_DEVTOOLS_GLOBAL_HOOK__\\`.\nfunction emitTelemetry(name, startedAt, input, outcome) {\n if (typeof window === 'undefined') return\n const dispatcher = window.__theoDevtoolsDispatcher\n if (!dispatcher || typeof dispatcher.onActionCall !== 'function') return\n try {\n dispatcher.onActionCall({\n id: 'act-' + String(Date.now()) + '-' + Math.random().toString(36).slice(2, 8),\n timestamp: startedAt,\n name,\n input,\n output: outcome.status === 'success' ? outcome.data : undefined,\n error: outcome.status === 'error' ? outcome.error : undefined,\n durationMs: Date.now() - startedAt,\n status: outcome.status,\n })\n } catch (_) {\n // dispatcher threw — devtools UI bug; never bubble to consumer code\n }\n}\n\nasync function callAction(name, url, input) {\n const startedAt = Date.now()\n const isForm = typeof FormData !== 'undefined' && input instanceof FormData\n const headers = { 'x-theo-action': '1' }\n const body = isForm ? input : JSON.stringify(input ?? {})\n if (!isForm) headers['content-type'] = 'application/json'\n let response\n try {\n response = await fetch(url, { method: 'POST', headers, body, credentials: 'same-origin' })\n } catch (e) {\n const err = { code: 'NETWORK_ERROR', message: e && e.message ? e.message : 'fetch failed' }\n emitTelemetry(name, startedAt, input, { status: 'error', error: err })\n return { data: undefined, error: err }\n }\n const contentType = response.headers.get('content-type') ?? ''\n let result\n if (response.status === 204) {\n result = { data: undefined, error: undefined }\n } else if (contentType.startsWith('application/json+devalue')) {\n const text = await response.text()\n const { parse } = await import('devalue')\n result = { data: parse(text, { URL: (h) => new URL(h) }), error: undefined }\n } else if (contentType.startsWith('application/json')) {\n const json = await response.json()\n result = response.ok ? { data: json, error: undefined } : { data: undefined, error: json }\n } else {\n result = { data: undefined, error: { code: 'INTERNAL_SERVER_ERROR', message: await response.text() } }\n }\n emitTelemetry(name, startedAt, input, result.error\n ? { status: 'error', error: result.error }\n : { status: 'success', data: result.data })\n return result\n}\n\nexport const actions = new Proxy({}, {\n get(target, prop) {\n if (typeof prop !== 'string') return undefined\n const url = ACTION_URL_MAP[prop]\n if (!url) return undefined\n return (input) => callAction(prop, url, input)\n },\n})\n`\n}\n\n/**\n * Server-side module: re-exports the manifest entries for SSR / module-\n * loader consumption (T1.3 sub-C in action-execute.ts will route requests\n * via this manifest).\n */\nfunction generateServerManifest(entries: ActionManifestEntry[]): string {\n return `// AUTO-GENERATED by @theo/actions virtual module (server env)\n/* eslint-disable */\nexport const manifest = ${JSON.stringify(entries, null, 2)}\nexport const actions = manifest\n`\n}\n"],"mappings":"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","names":[]}