@rubytech/create-maxy-code 0.1.459 → 0.1.461

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 (189) hide show
  1. package/dist/__tests__/cron-heartbeat-registration.test.js +57 -28
  2. package/dist/__tests__/launchd-plist.test.js +26 -0
  3. package/dist/cron-registration.js +30 -8
  4. package/dist/index.js +50 -9
  5. package/dist/launchd-plist.js +1 -1
  6. package/dist/uninstall.js +9 -3
  7. package/package.json +1 -1
  8. package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js +116 -6
  9. package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js.map +1 -1
  10. package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.js +20 -0
  11. package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.js.map +1 -1
  12. package/payload/platform/lib/storage-broker/dist/__tests__/resource-limits.test.d.ts +2 -0
  13. package/payload/platform/lib/storage-broker/dist/__tests__/resource-limits.test.d.ts.map +1 -0
  14. package/payload/platform/lib/storage-broker/dist/__tests__/resource-limits.test.js +41 -0
  15. package/payload/platform/lib/storage-broker/dist/__tests__/resource-limits.test.js.map +1 -0
  16. package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts +1 -0
  17. package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
  18. package/payload/platform/lib/storage-broker/dist/cf-exec.js +116 -48
  19. package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
  20. package/payload/platform/lib/storage-broker/dist/index.d.ts +1 -0
  21. package/payload/platform/lib/storage-broker/dist/index.d.ts.map +1 -1
  22. package/payload/platform/lib/storage-broker/dist/index.js +1 -0
  23. package/payload/platform/lib/storage-broker/dist/index.js.map +1 -1
  24. package/payload/platform/lib/storage-broker/dist/object-limits.d.ts +27 -0
  25. package/payload/platform/lib/storage-broker/dist/object-limits.d.ts.map +1 -1
  26. package/payload/platform/lib/storage-broker/dist/object-limits.js +27 -7
  27. package/payload/platform/lib/storage-broker/dist/object-limits.js.map +1 -1
  28. package/payload/platform/lib/storage-broker/dist/resource-limits.d.ts +102 -0
  29. package/payload/platform/lib/storage-broker/dist/resource-limits.d.ts.map +1 -0
  30. package/payload/platform/lib/storage-broker/dist/resource-limits.js +105 -0
  31. package/payload/platform/lib/storage-broker/dist/resource-limits.js.map +1 -0
  32. package/payload/platform/lib/storage-broker/src/__tests__/cf-exec.test.ts +130 -7
  33. package/payload/platform/lib/storage-broker/src/__tests__/object-limits.test.ts +30 -0
  34. package/payload/platform/lib/storage-broker/src/__tests__/resource-limits.test.ts +49 -0
  35. package/payload/platform/lib/storage-broker/src/cf-exec.ts +129 -56
  36. package/payload/platform/lib/storage-broker/src/index.ts +1 -0
  37. package/payload/platform/lib/storage-broker/src/object-limits.ts +26 -6
  38. package/payload/platform/lib/storage-broker/src/resource-limits.ts +105 -0
  39. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +5 -4
  40. package/payload/platform/plugins/cloudflare/PLUGIN.md +3 -1
  41. package/payload/platform/plugins/cloudflare/bin/portal-enrol.mjs +96 -0
  42. package/payload/platform/plugins/cloudflare/mcp/__tests__/auth-route.test.ts +220 -0
  43. package/payload/platform/plugins/cloudflare/mcp/__tests__/authorize.test.ts +201 -0
  44. package/payload/platform/plugins/cloudflare/mcp/__tests__/file-routes.test.ts +178 -0
  45. package/payload/platform/plugins/cloudflare/mcp/__tests__/harness.test.ts +32 -0
  46. package/payload/platform/plugins/cloudflare/mcp/__tests__/passcode.test.ts +204 -0
  47. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-enrol.test.ts +207 -0
  48. package/payload/platform/plugins/cloudflare/mcp/__tests__/ratelimit.test.ts +77 -0
  49. package/payload/platform/plugins/cloudflare/mcp/__tests__/skill-contract.test.ts +46 -0
  50. package/payload/platform/plugins/cloudflare/mcp/__tests__/template-config.test.ts +55 -0
  51. package/payload/platform/plugins/cloudflare/mcp/__tests__/upload-route.test.ts +255 -0
  52. package/payload/platform/plugins/cloudflare/mcp/package.json +5 -2
  53. package/payload/platform/plugins/cloudflare/references/r2-object-storage.md +46 -0
  54. package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +125 -0
  55. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/authorize.ts +32 -0
  56. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/log.ts +12 -0
  57. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/passcode.mjs +193 -0
  58. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/ratelimit.ts +55 -0
  59. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/session.ts +85 -0
  60. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/types.ts +44 -0
  61. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/auth.ts +119 -0
  62. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/delete.ts +89 -0
  63. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/download.ts +70 -0
  64. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/files.ts +41 -0
  65. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/upload.ts +151 -0
  66. package/payload/platform/plugins/cloudflare/skills/data-portal/template/public/index.html +42 -0
  67. package/payload/platform/plugins/cloudflare/skills/data-portal/template/public/portal.css +113 -0
  68. package/payload/platform/plugins/cloudflare/skills/data-portal/template/public/portal.js +155 -0
  69. package/payload/platform/plugins/cloudflare/skills/data-portal/template/schema.sql +73 -0
  70. package/payload/platform/plugins/cloudflare/skills/data-portal/template/wrangler.toml +21 -0
  71. package/payload/platform/plugins/cloudflare/skills/site-deploy/SKILL.md +8 -0
  72. package/payload/platform/plugins/docs/references/outlook-guide.md +3 -3
  73. package/payload/platform/plugins/docs/references/voice-mirror-guide.md +1 -0
  74. package/payload/platform/plugins/filesystem/PLUGIN.md +0 -1
  75. package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.d.ts +14 -10
  76. package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.d.ts.map +1 -1
  77. package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.js +14 -10
  78. package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.js.map +1 -1
  79. package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
  80. package/payload/platform/plugins/outlook/PLUGIN.md +3 -5
  81. package/payload/platform/plugins/outlook/mcp/dist/__tests__/detach.test.d.ts +2 -0
  82. package/payload/platform/plugins/outlook/mcp/dist/__tests__/detach.test.d.ts.map +1 -0
  83. package/payload/platform/plugins/outlook/mcp/dist/__tests__/detach.test.js +75 -0
  84. package/payload/platform/plugins/outlook/mcp/dist/__tests__/detach.test.js.map +1 -0
  85. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-removal.test.d.ts +2 -0
  86. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-removal.test.d.ts.map +1 -0
  87. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-removal.test.js +187 -0
  88. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-removal.test.js.map +1 -0
  89. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.js +1 -1
  90. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.js.map +1 -1
  91. package/payload/platform/plugins/outlook/mcp/dist/index.js +3 -2
  92. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
  93. package/payload/platform/plugins/outlook/mcp/dist/lib/attachment-list.d.ts +43 -0
  94. package/payload/platform/plugins/outlook/mcp/dist/lib/attachment-list.d.ts.map +1 -0
  95. package/payload/platform/plugins/outlook/mcp/dist/lib/attachment-list.js +65 -0
  96. package/payload/platform/plugins/outlook/mcp/dist/lib/attachment-list.js.map +1 -0
  97. package/payload/platform/plugins/outlook/mcp/dist/lib/detach.d.ts +65 -0
  98. package/payload/platform/plugins/outlook/mcp/dist/lib/detach.d.ts.map +1 -0
  99. package/payload/platform/plugins/outlook/mcp/dist/lib/detach.js +99 -0
  100. package/payload/platform/plugins/outlook/mcp/dist/lib/detach.js.map +1 -0
  101. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.d.ts +6 -1
  102. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.d.ts.map +1 -1
  103. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.js.map +1 -1
  104. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts +42 -22
  105. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts.map +1 -1
  106. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js +59 -23
  107. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js.map +1 -1
  108. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-attachment.d.ts +15 -16
  109. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-attachment.d.ts.map +1 -1
  110. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-attachment.js +8 -41
  111. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-attachment.js.map +1 -1
  112. package/payload/platform/plugins/outlook/references/auth.md +1 -1
  113. package/payload/platform/plugins/outlook/references/graph-surfaces.md +7 -3
  114. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +1 -1
  115. package/payload/platform/plugins/storage-broker/PLUGIN.md +1 -1
  116. package/payload/platform/plugins/voice-mirror/PLUGIN.md +19 -7
  117. package/payload/platform/plugins/voice-mirror/mcp/dist/index.d.ts.map +1 -1
  118. package/payload/platform/plugins/voice-mirror/mcp/dist/index.js +35 -16
  119. package/payload/platform/plugins/voice-mirror/mcp/dist/index.js.map +1 -1
  120. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/admin-user.d.ts +31 -0
  121. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/admin-user.d.ts.map +1 -0
  122. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/admin-user.js +87 -0
  123. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/admin-user.js.map +1 -0
  124. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
  125. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js +111 -12
  126. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js.map +1 -1
  127. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-ingest-session-text.d.ts.map +1 -1
  128. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-ingest-session-text.js +2 -1
  129. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-ingest-session-text.js.map +1 -1
  130. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-record-feedback.d.ts.map +1 -1
  131. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-record-feedback.js +2 -1
  132. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-record-feedback.js.map +1 -1
  133. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
  134. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js +54 -21
  135. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
  136. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-tag-content.d.ts +2 -2
  137. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-tag-content.d.ts.map +1 -1
  138. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-tag-content.js +12 -3
  139. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-tag-content.js.map +1 -1
  140. package/payload/platform/plugins/voice-mirror/mcp/scripts/smoke.mjs +444 -0
  141. package/payload/platform/plugins/voice-mirror/skills/voice-mirror/SKILL.md +18 -2
  142. package/payload/platform/scripts/__tests__/logs-rotate.test.sh +256 -0
  143. package/payload/platform/scripts/__tests__/resume-tunnel.test.sh +79 -0
  144. package/payload/platform/scripts/logs-rotate.sh +204 -0
  145. package/payload/platform/scripts/resume-tunnel.sh +27 -0
  146. package/payload/platform/scripts/voice-author-key-audit.sh +155 -0
  147. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  148. package/payload/platform/services/claude-session-manager/dist/http-server.js +41 -5
  149. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  150. package/payload/platform/services/claude-session-manager/dist/index.d.ts +1 -0
  151. package/payload/platform/services/claude-session-manager/dist/index.d.ts.map +1 -1
  152. package/payload/platform/services/claude-session-manager/dist/index.js +22 -0
  153. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  154. package/payload/platform/services/claude-session-manager/dist/install-start-counter.d.ts +2 -0
  155. package/payload/platform/services/claude-session-manager/dist/install-start-counter.d.ts.map +1 -0
  156. package/payload/platform/services/claude-session-manager/dist/install-start-counter.js +12 -0
  157. package/payload/platform/services/claude-session-manager/dist/install-start-counter.js.map +1 -0
  158. package/payload/platform/services/claude-session-manager/dist/mcp-descriptor-resolve.d.ts +17 -0
  159. package/payload/platform/services/claude-session-manager/dist/mcp-descriptor-resolve.d.ts.map +1 -0
  160. package/payload/platform/services/claude-session-manager/dist/mcp-descriptor-resolve.js +88 -0
  161. package/payload/platform/services/claude-session-manager/dist/mcp-descriptor-resolve.js.map +1 -0
  162. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts +122 -9
  163. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts.map +1 -1
  164. package/payload/platform/services/claude-session-manager/dist/pty-census.js +214 -29
  165. package/payload/platform/services/claude-session-manager/dist/pty-census.js.map +1 -1
  166. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +0 -1
  167. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  168. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +36 -24
  169. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  170. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  171. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +13 -1
  172. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  173. package/payload/platform/services/claude-session-manager/dist/session-memory-cap.d.ts.map +1 -1
  174. package/payload/platform/services/claude-session-manager/dist/session-memory-cap.js +4 -2
  175. package/payload/platform/services/claude-session-manager/dist/session-memory-cap.js.map +1 -1
  176. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts +150 -0
  177. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts.map +1 -0
  178. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js +333 -0
  179. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js.map +1 -0
  180. package/payload/platform/services/claude-session-manager/dist/start-counter.d.ts +10 -0
  181. package/payload/platform/services/claude-session-manager/dist/start-counter.d.ts.map +1 -0
  182. package/payload/platform/services/claude-session-manager/dist/start-counter.js +55 -0
  183. package/payload/platform/services/claude-session-manager/dist/start-counter.js.map +1 -0
  184. package/payload/server/{chunk-Q6W4U6HL.js → chunk-JXWFVE5X.js} +83 -39
  185. package/payload/server/server.js +268 -73
  186. package/payload/server/{src-3I2RYZFB.js → src-4F37OHLK.js} +11 -1
  187. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.d.ts +0 -2
  188. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js +0 -215
  189. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js.map +0 -1
@@ -113,15 +113,19 @@ import {
113
113
  writeAdminUserAndPerson
114
114
  } from "./chunk-POBXIHOF.js";
115
115
  import {
116
+ D1_MAX_SQL_STATEMENT_BYTES,
117
+ D1_QUERY_MAX_BODY_BYTES,
118
+ R2_OBJECT_ENVELOPE_MAX_BODY_BYTES,
116
119
  R2_OBJECT_MAX_BYTES,
117
120
  R2_OBJECT_PUT_MAX_BODY_BYTES,
121
+ STORAGE_RESOURCE_NAME_MAX_BODY_BYTES,
118
122
  authorizeAccess,
119
123
  listResources,
120
124
  makeHouseCfExec,
121
125
  registerResource,
122
126
  resolveOwner,
123
127
  tooLargeMessage
124
- } from "./chunk-Q6W4U6HL.js";
128
+ } from "./chunk-JXWFVE5X.js";
125
129
  import {
126
130
  __commonJS,
127
131
  __toESM
@@ -6776,7 +6780,7 @@ ${result.result.text}` : result.result.text;
6776
6780
  spawnedAt: /* @__PURE__ */ new Date()
6777
6781
  });
6778
6782
  const replyP = deps.awaitReply(session_key, webchatTurnTimeoutMs());
6779
- await deps.handleInbound({
6783
+ const { spawn: spawn4 } = await deps.handleInbound({
6780
6784
  role: "public",
6781
6785
  accountId: account.accountId,
6782
6786
  key: session_key,
@@ -6789,6 +6793,7 @@ ${result.result.text}` : result.result.text;
6789
6793
  name: publicTitle
6790
6794
  }
6791
6795
  });
6796
+ if (spawn4) await spawn4;
6792
6797
  const reply = await replyP;
6793
6798
  if ("timeout" in reply) {
6794
6799
  controller.enqueue(
@@ -8745,6 +8750,49 @@ function log(action, kind, account, target, owner, result, reason) {
8745
8750
  function cfExec() {
8746
8751
  return makeHouseCfExec(platformRoot());
8747
8752
  }
8753
+ async function readJsonBody(c) {
8754
+ let parsed;
8755
+ try {
8756
+ parsed = await c.req.json();
8757
+ } catch (err) {
8758
+ if (err instanceof Error && err.name === "BodyLimitError") throw err;
8759
+ return { ok: false, res: c.json({ error: "invalid-json" }, 400) };
8760
+ }
8761
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
8762
+ return { ok: false, res: c.json({ error: "invalid-json" }, 400) };
8763
+ }
8764
+ return { ok: true, body: parsed };
8765
+ }
8766
+ function nameBodyLimit(kind) {
8767
+ return bodyLimit({
8768
+ maxSize: STORAGE_RESOURCE_NAME_MAX_BODY_BYTES,
8769
+ onError: (c) => {
8770
+ log("write", kind, caller(c) ?? "none", "*", null, "deny", "name-body-too-large");
8771
+ return c.json(
8772
+ {
8773
+ error: `request body exceeds the ${(STORAGE_RESOURCE_NAME_MAX_BODY_BYTES / 1024).toFixed(
8774
+ 1
8775
+ )} KiB (${STORAGE_RESOURCE_NAME_MAX_BODY_BYTES} bytes) limit for a storage resource create, which carries only a name.`
8776
+ },
8777
+ 413
8778
+ );
8779
+ }
8780
+ });
8781
+ }
8782
+ var d1QueryBodyLimit = bodyLimit({
8783
+ maxSize: D1_QUERY_MAX_BODY_BYTES,
8784
+ onError: (c) => {
8785
+ log("read", "d1", caller(c) ?? "none", "*", null, "deny", "sql-body-too-large");
8786
+ return c.json(
8787
+ {
8788
+ error: `request body exceeds the ${(D1_QUERY_MAX_BODY_BYTES / 1024 / 1024).toFixed(
8789
+ 1
8790
+ )} MiB (${D1_QUERY_MAX_BODY_BYTES} bytes) limit for a D1 query, which carries a database name and a SQL statement of at most ${D1_MAX_SQL_STATEMENT_BYTES} bytes.`
8791
+ },
8792
+ 413
8793
+ );
8794
+ }
8795
+ });
8748
8796
  app3.get("/d1/list", async (c) => {
8749
8797
  const account = caller(c);
8750
8798
  if (!account) return c.json({ error: "no-caller" }, 403);
@@ -8759,10 +8807,12 @@ app3.get("/d1/list", async (c) => {
8759
8807
  await session.close();
8760
8808
  }
8761
8809
  });
8762
- app3.post("/d1/create", async (c) => {
8810
+ app3.post("/d1/create", nameBodyLimit("d1"), async (c) => {
8763
8811
  const account = caller(c);
8764
8812
  if (!account) return c.json({ error: "no-caller" }, 403);
8765
- const { name } = await c.req.json();
8813
+ const parsed = await readJsonBody(c);
8814
+ if (!parsed.ok) return parsed.res;
8815
+ const { name } = parsed.body;
8766
8816
  if (!name || typeof name !== "string") return c.json({ error: "name-required" }, 400);
8767
8817
  const session = getSession();
8768
8818
  try {
@@ -8781,10 +8831,12 @@ app3.post("/d1/create", async (c) => {
8781
8831
  await session.close();
8782
8832
  }
8783
8833
  });
8784
- app3.post("/d1/query", async (c) => {
8834
+ app3.post("/d1/query", d1QueryBodyLimit, async (c) => {
8785
8835
  const account = caller(c);
8786
8836
  if (!account) return c.json({ error: "no-caller" }, 403);
8787
- const { name, sql } = await c.req.json();
8837
+ const parsed = await readJsonBody(c);
8838
+ if (!parsed.ok) return parsed.res;
8839
+ const { name, sql } = parsed.body;
8788
8840
  if (!name || typeof name !== "string") return c.json({ error: "name-required" }, 400);
8789
8841
  if (!sql || typeof sql !== "string") return c.json({ error: "sql-required" }, 400);
8790
8842
  const session = getSession();
@@ -8815,10 +8867,12 @@ app3.get("/r2/list", async (c) => {
8815
8867
  await session.close();
8816
8868
  }
8817
8869
  });
8818
- app3.post("/r2/create", async (c) => {
8870
+ app3.post("/r2/create", nameBodyLimit("r2"), async (c) => {
8819
8871
  const account = caller(c);
8820
8872
  if (!account) return c.json({ error: "no-caller" }, 403);
8821
- const { name } = await c.req.json();
8873
+ const parsed = await readJsonBody(c);
8874
+ if (!parsed.ok) return parsed.res;
8875
+ const { name } = parsed.body;
8822
8876
  if (!name || typeof name !== "string") return c.json({ error: "name-required" }, 400);
8823
8877
  const session = getSession();
8824
8878
  try {
@@ -8869,7 +8923,39 @@ function readKey(body) {
8869
8923
  const key = body.key;
8870
8924
  return typeof key === "string" && key.length > 0 ? key : null;
8871
8925
  }
8872
- app3.post("/r2/object/list", async (c) => {
8926
+ function envelopeBodyLimit(action) {
8927
+ return bodyLimit({
8928
+ maxSize: R2_OBJECT_ENVELOPE_MAX_BODY_BYTES,
8929
+ // Names the limit rather than the object: the body is deliberately unparsed
8930
+ // here, which is the whole point of the middleware, so the key is genuinely
8931
+ // unknown — as recorded for put in 1695. Stated in KiB with exact bytes rather
8932
+ // than the MiB the object messages use: 64 KiB renders as "0.1 MiB", which is
8933
+ // less legible, not more. The exact bytes are there for the same reason
8934
+ // tooLargeMessage carries them.
8935
+ //
8936
+ // The {error} body is the routes' convention, which the default's bare text
8937
+ // is not. On the content-length branch no body is read and no handler runs, so
8938
+ // this log line is the only trace the request ever existed.
8939
+ //
8940
+ // reason distinguishes this from put's body-too-large rather than reusing it.
8941
+ // They are different events refusing bodies ~2,100x apart, and put and delete
8942
+ // both log action=write, so a shared slug would make a 140 MB put denial and a
8943
+ // 65 KiB delete denial byte-identical — the same conflation the reason field
8944
+ // exists to prevent for ownership-vs-size.
8945
+ onError: (c) => {
8946
+ log(action, "r2", caller(c) ?? "none", "*", null, "deny", "envelope-too-large");
8947
+ return c.json(
8948
+ {
8949
+ error: `request body exceeds the ${(R2_OBJECT_ENVELOPE_MAX_BODY_BYTES / 1024).toFixed(
8950
+ 1
8951
+ )} KiB (${R2_OBJECT_ENVELOPE_MAX_BODY_BYTES} bytes) limit for an R2 object metadata envelope, which carries only a bucket and a key or prefix.`
8952
+ },
8953
+ 413
8954
+ );
8955
+ }
8956
+ });
8957
+ }
8958
+ app3.post("/r2/object/list", envelopeBodyLimit("list"), async (c) => {
8873
8959
  const gate = await objectGate(c, "list");
8874
8960
  if (!gate.ok) return gate.res;
8875
8961
  const prefix = gate.body.prefix;
@@ -8883,15 +8969,15 @@ app3.post("/r2/object/list", async (c) => {
8883
8969
  return c.json({ error: String(err) }, 500);
8884
8970
  }
8885
8971
  });
8886
- app3.post("/r2/object/get", async (c) => {
8972
+ app3.post("/r2/object/get", envelopeBodyLimit("read"), async (c) => {
8887
8973
  const gate = await objectGate(c, "read");
8888
8974
  if (!gate.ok) return gate.res;
8889
8975
  const key = readKey(gate.body);
8890
8976
  if (!key) return c.json({ error: "key-required" }, 400);
8891
8977
  try {
8892
8978
  const cf = await cfExec();
8893
- const listed = await cf.r2ObjectList(gate.bucket, key);
8894
- const size = listed.find((o) => o.key === key)?.size;
8979
+ const found = await cf.r2ObjectFind(gate.bucket, key);
8980
+ const size = found?.size;
8895
8981
  if (typeof size !== "number" || !Number.isFinite(size) || size < 0) {
8896
8982
  log("read", "r2", caller(c) ?? "none", key, caller(c), "deny", "size-unknown");
8897
8983
  return c.json(
@@ -8962,7 +9048,7 @@ app3.post(
8962
9048
  }
8963
9049
  }
8964
9050
  );
8965
- app3.post("/r2/object/delete", async (c) => {
9051
+ app3.post("/r2/object/delete", envelopeBodyLimit("write"), async (c) => {
8966
9052
  const gate = await objectGate(c, "write");
8967
9053
  if (!gate.ok) return gate.res;
8968
9054
  const key = readKey(gate.body);
@@ -8976,7 +9062,7 @@ app3.post("/r2/object/delete", async (c) => {
8976
9062
  });
8977
9063
  var storage_broker_default = app3;
8978
9064
  async function runStorageAudit(root) {
8979
- const { reconcileStorage } = await import("./src-3I2RYZFB.js");
9065
+ const { reconcileStorage } = await import("./src-4F37OHLK.js");
8980
9066
  const session = getSession();
8981
9067
  try {
8982
9068
  const cf = await makeHouseCfExec(root);
@@ -9901,6 +9987,78 @@ function pickActivity(entries, grown, nowMs, concurrencyWindowMs) {
9901
9987
  return { hex: newest.hex, lastEmitAt: newest.mtimeMs, count };
9902
9988
  }
9903
9989
 
9990
+ // server/routes/stream-lifecycle.ts
9991
+ var GAUGE_INTERVAL_MS = 6e4;
9992
+ function isArmed(timer2) {
9993
+ return timer2._destroyed !== true;
9994
+ }
9995
+ var Registration = class {
9996
+ constructor(connId, channel, startedAt) {
9997
+ this.connId = connId;
9998
+ this.channel = channel;
9999
+ this.startedAt = startedAt;
10000
+ }
10001
+ timers = [];
10002
+ closed = false;
10003
+ arm(timer2) {
10004
+ this.timers.push(timer2);
10005
+ return timer2;
10006
+ }
10007
+ teardown(reason) {
10008
+ if (this.closed) return false;
10009
+ this.closed = true;
10010
+ for (const t of this.timers) clearInterval(t);
10011
+ const stillArmed = this.timers.filter(isArmed).length;
10012
+ if (stillArmed > 0) {
10013
+ console.error(
10014
+ `[wa-stream] op=teardown-defect conn=${this.connId} channel=${this.channel} stillArmed=${stillArmed} reason=${reason}`
10015
+ );
10016
+ return true;
10017
+ }
10018
+ registry.delete(this);
10019
+ if (registry.size === 0) emitGauge();
10020
+ return true;
10021
+ }
10022
+ };
10023
+ var registry = /* @__PURE__ */ new Set();
10024
+ var gaugeTimer = null;
10025
+ function emitGauge() {
10026
+ const now = Date.now();
10027
+ const counts = { reader: 0, store: 0 };
10028
+ let oldestMs = 0;
10029
+ let stale = 0;
10030
+ for (const reg of [...registry]) {
10031
+ if (!reg.timers.some(isArmed)) {
10032
+ stale++;
10033
+ registry.delete(reg);
10034
+ continue;
10035
+ }
10036
+ counts[reg.channel]++;
10037
+ oldestMs = Math.max(oldestMs, now - reg.startedAt);
10038
+ }
10039
+ const armed = counts.reader + counts.store;
10040
+ console.log(
10041
+ `[wa-stream] op=gauge armed=${armed} reader=${counts.reader} store=${counts.store} oldestSec=${Math.floor(oldestMs / 1e3)} stale=${stale}`
10042
+ );
10043
+ if (armed === 0) stopGauge();
10044
+ }
10045
+ function startGauge() {
10046
+ if (gaugeTimer) return;
10047
+ gaugeTimer = setInterval(emitGauge, GAUGE_INTERVAL_MS);
10048
+ gaugeTimer.unref();
10049
+ }
10050
+ function stopGauge() {
10051
+ if (!gaugeTimer) return;
10052
+ clearInterval(gaugeTimer);
10053
+ gaugeTimer = null;
10054
+ }
10055
+ function openStream(connId, channel, startedAt) {
10056
+ const reg = new Registration(connId, channel, startedAt);
10057
+ registry.add(reg);
10058
+ startGauge();
10059
+ return reg;
10060
+ }
10061
+
9904
10062
  // app/admin-types.ts
9905
10063
  var ACCEPT_MIME = "image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,application/zip,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.text,text/rtf,application/rtf,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/vnd.oasis.opendocument.spreadsheet,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.ms-powerpoint,application/vnd.oasis.opendocument.presentation,audio/ogg,audio/opus,audio/mp4,audio/x-m4a,audio/mpeg,audio/webm,audio/wav,video/mp4,.docx,.odt,.rtf,.xlsx,.xls,.ods,.pptx,.ppt,.odp,.opus,.ogg,.m4a,.mp4,.mp3,.wav,.webm";
9906
10064
  var SUPPORTED_MIME_SET = new Set(ACCEPT_MIME.split(",").filter((t) => !t.startsWith(".")));
@@ -10209,6 +10367,8 @@ data: ${JSON.stringify(turn)}
10209
10367
  const connId = `${sessionId.slice(0, 8)}-${process.hrtime.bigint().toString(36).slice(-6)}`;
10210
10368
  const startedAt = Date.now();
10211
10369
  const lastEventId = c.req.header("Last-Event-ID");
10370
+ let teardown = () => {
10371
+ };
10212
10372
  const readable = new ReadableStream({
10213
10373
  start(controller) {
10214
10374
  const fileEnd0 = (() => {
@@ -10293,27 +10453,34 @@ data: ${JSON.stringify(obj)}
10293
10453
  actx.now = Date.now();
10294
10454
  runActivityTick(actx);
10295
10455
  };
10296
- const poll = setInterval(tick, 1e3);
10297
- const heartbeat = setInterval(() => {
10298
- try {
10299
- controller.enqueue(encoder.encode(": ping\n\n"));
10300
- console.log(`[wa-stream] op=heartbeat conn=${connId}`);
10301
- } catch {
10302
- }
10303
- }, 2e4);
10304
- c.req.raw.signal.addEventListener("abort", () => {
10456
+ const lifecycle = openStream(connId, "reader", startedAt);
10457
+ lifecycle.arm(setInterval(tick, 1e3));
10458
+ lifecycle.arm(
10459
+ setInterval(() => {
10460
+ try {
10461
+ controller.enqueue(encoder.encode(": ping\n\n"));
10462
+ console.log(`[wa-stream] op=heartbeat conn=${connId}`);
10463
+ } catch {
10464
+ teardown("heartbeat-dead-controller");
10465
+ }
10466
+ }, 2e4)
10467
+ );
10468
+ teardown = (reason) => {
10469
+ if (!lifecycle.teardown(reason)) return;
10305
10470
  watcher?.close();
10306
- clearInterval(poll);
10307
- clearInterval(heartbeat);
10308
10471
  if (actx.emittedHex !== null) {
10309
10472
  console.log(`[webchat-activity] op=clear key=${sessionKey} reason=stream-close`);
10310
10473
  }
10311
- console.log(`[wa-stream] op=close conn=${connId} ranMs=${Date.now() - startedAt} reason=client-abort`);
10474
+ console.log(`[wa-stream] op=close conn=${connId} ranMs=${Date.now() - startedAt} reason=${reason}`);
10312
10475
  try {
10313
10476
  controller.close();
10314
10477
  } catch {
10315
10478
  }
10316
- });
10479
+ };
10480
+ c.req.raw.signal.addEventListener("abort", () => teardown("client-abort"));
10481
+ },
10482
+ cancel() {
10483
+ teardown("client-cancel");
10317
10484
  }
10318
10485
  });
10319
10486
  return new Response(readable, {
@@ -10421,6 +10588,8 @@ app5.get("/store-stream", requireAdminSession, (c) => {
10421
10588
  }
10422
10589
  return turn;
10423
10590
  };
10591
+ let teardown = () => {
10592
+ };
10424
10593
  const readable = new ReadableStream({
10425
10594
  start(controller) {
10426
10595
  const send = (turn, id) => {
@@ -10518,23 +10687,30 @@ data: ${JSON.stringify(payload)}
10518
10687
  watcher = watch(file, drain);
10519
10688
  } catch {
10520
10689
  }
10521
- const poll = setInterval(drain, 1e3);
10522
- const heartbeat = setInterval(() => {
10523
- try {
10524
- controller.enqueue(encoder.encode(": ping\n\n"));
10525
- } catch {
10526
- }
10527
- }, 2e4);
10528
- c.req.raw.signal.addEventListener("abort", () => {
10690
+ const lifecycle = openStream(connId, "store", startedAt);
10691
+ lifecycle.arm(setInterval(drain, 1e3));
10692
+ lifecycle.arm(
10693
+ setInterval(() => {
10694
+ try {
10695
+ controller.enqueue(encoder.encode(": ping\n\n"));
10696
+ } catch {
10697
+ teardown("heartbeat-dead-controller");
10698
+ }
10699
+ }, 2e4)
10700
+ );
10701
+ teardown = (reason) => {
10702
+ if (!lifecycle.teardown(reason)) return;
10529
10703
  watcher?.close();
10530
- clearInterval(poll);
10531
- clearInterval(heartbeat);
10532
- console.log(`[wa-reader] op=store-close conn=${connId} ranMs=${Date.now() - startedAt}`);
10704
+ console.log(`[wa-reader] op=store-close conn=${connId} ranMs=${Date.now() - startedAt} reason=${reason}`);
10533
10705
  try {
10534
10706
  controller.close();
10535
10707
  } catch {
10536
10708
  }
10537
- });
10709
+ };
10710
+ c.req.raw.signal.addEventListener("abort", () => teardown("client-abort"));
10711
+ },
10712
+ cancel() {
10713
+ teardown("client-cancel");
10538
10714
  }
10539
10715
  });
10540
10716
  return new Response(readable, {
@@ -11706,7 +11882,7 @@ ${note}` : note;
11706
11882
  console.error(`[webchat:inbound] op=send-refused kind=${kind} reason=empty-text`);
11707
11883
  return c.json({ error: "text required" }, 400);
11708
11884
  }
11709
- console.log(`[webchat:inbound] op=send-accepted kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
11885
+ console.log(`[webchat:inbound] op=send-parsed kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
11710
11886
  }
11711
11887
  let deliveredIntId = null;
11712
11888
  if (deliverySessionId !== void 0 && await managerActivity(deliverySessionId) === "busy") {
@@ -11718,11 +11894,8 @@ ${note}` : note;
11718
11894
  deliveredIntId = outcome.intId;
11719
11895
  }
11720
11896
  const adminUserId = requesterUserId ?? void 0;
11721
- if (deliverySessionId !== void 0) {
11722
- await deps.handleInbound({ role: "admin", accountId: deliveryAccountId, key: deliveryKey, text, sessionId: deliverySessionId, adminUserId });
11723
- } else {
11724
- await deps.handleInbound({ role: "admin", accountId: bootstrapAccountId, key: deliveryKey, text, adminUserId });
11725
- }
11897
+ const inboundStartedAt = Date.now();
11898
+ const inbound = deliverySessionId !== void 0 ? await deps.handleInbound({ role: "admin", accountId: deliveryAccountId, key: deliveryKey, text, sessionId: deliverySessionId, adminUserId }) : await deps.handleInbound({ role: "admin", accountId: bootstrapAccountId, key: deliveryKey, text, adminUserId });
11726
11899
  if (deliveredIntId !== null) {
11727
11900
  console.log(`[webchat-interrupt] op=delivered intId=${deliveredIntId} sessionId=${deliverySessionId.slice(0, 8)}`);
11728
11901
  }
@@ -11739,7 +11912,9 @@ ${note}` : note;
11739
11912
  }
11740
11913
  const keyDisplay2 = deliveryKey.startsWith("session:") ? deliveryKey.slice(0, "session:".length + 8) : WEBCHAT_ADMIN_KEY;
11741
11914
  const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
11742
- console.error(`[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
11915
+ console.error(
11916
+ `[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"} acceptMs=${Date.now() - inboundStartedAt} spawn=${inbound.spawn !== null ? "triggered" : "none"}`
11917
+ );
11743
11918
  const turnTimer = setTimeout(() => {
11744
11919
  const now = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
11745
11920
  const grew = now !== null && (baseline === null || now > baseline);
@@ -24552,7 +24727,9 @@ var WebchatGateway = class _WebchatGateway {
24552
24727
  this.recovering = false;
24553
24728
  }
24554
24729
  }
24555
- /** Handle one inbound webchat message (browser POST → here). */
24730
+ /** Handle one inbound webchat message (browser POST → here). Resolves when
24731
+ * the hub holds the message; the cold-start spawn is returned as a handle
24732
+ * (Task 1715 — see WebchatInboundResult). */
24556
24733
  async handleInbound(input) {
24557
24734
  const bytes = Buffer.byteLength(input.text, "utf8");
24558
24735
  const hadSubscriber = this.hub.hasSubscriber(input.key);
@@ -24586,38 +24763,56 @@ var WebchatGateway = class _WebchatGateway {
24586
24763
  }
24587
24764
  const existing = this.publicSessions.get(input.key);
24588
24765
  if (existing) existing.lastActivityAt = Date.now();
24766
+ let spawn4 = null;
24589
24767
  if (!hadSubscriber && !this.spawning.has(input.key)) {
24590
24768
  this.spawning.add(input.key);
24591
24769
  console.error(`[webchat:inbound] op=spawn-trigger key=${input.key} role=${input.role}`);
24592
- try {
24593
- const spawned = await this.deps.ensureChannelSession({
24770
+ spawn4 = this.runSpawn(input);
24771
+ spawn4.catch(() => {
24772
+ });
24773
+ }
24774
+ return { spawn: spawn4 };
24775
+ }
24776
+ /** Task 1715 — the cold-start spawn, run off the accept's path. Rejects on a
24777
+ * failed spawn so the public caller's SSE still errors; logs op=spawn-failed
24778
+ * first, because on the admin path the 200 has already been returned and this
24779
+ * line is the only attribution the failure gets. */
24780
+ async runSpawn(input) {
24781
+ const startedAt = Date.now();
24782
+ try {
24783
+ const spawned = await this.deps.ensureChannelSession({
24784
+ accountId: input.accountId,
24785
+ key: input.key,
24786
+ role: input.role,
24787
+ gatewayUrl: this.deps.gatewayUrl,
24788
+ serverPath: this.deps.serverPath,
24789
+ // Task 800 — only present on a session-targeted launch, so the
24790
+ // default-path call shape stays byte-identical.
24791
+ ...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {},
24792
+ // The authenticated admin's userId on an admin bootstrap inbound; the
24793
+ // default-path call shape stays byte-identical when absent.
24794
+ ...input.adminUserId !== void 0 ? { adminUserId: input.adminUserId } : {},
24795
+ // Task 756 — public spawn params on a role:'public' inbound.
24796
+ ...input.public !== void 0 ? { public: input.public } : {}
24797
+ });
24798
+ if (input.role === "public" && input.public && spawned && "sessionId" in spawned) {
24799
+ this.publicSessions.set(input.key, {
24800
+ sessionId: spawned.sessionId,
24594
24801
  accountId: input.accountId,
24595
- key: input.key,
24596
- role: input.role,
24597
- gatewayUrl: this.deps.gatewayUrl,
24598
- serverPath: this.deps.serverPath,
24599
- // Task 800 — only present on a session-targeted launch, so the
24600
- // default-path call shape stays byte-identical.
24601
- ...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {},
24602
- // The authenticated admin's userId on an admin bootstrap inbound; the
24603
- // default-path call shape stays byte-identical when absent.
24604
- ...input.adminUserId !== void 0 ? { adminUserId: input.adminUserId } : {},
24605
- // Task 756 — public spawn params on a role:'public' inbound.
24606
- ...input.public !== void 0 ? { public: input.public } : {}
24802
+ agentSlug: input.public.agentSlug,
24803
+ sliceToken: input.public.sliceToken,
24804
+ personId: input.public.personId,
24805
+ lastActivityAt: Date.now()
24607
24806
  });
24608
- if (input.role === "public" && input.public && spawned && "sessionId" in spawned) {
24609
- this.publicSessions.set(input.key, {
24610
- sessionId: spawned.sessionId,
24611
- accountId: input.accountId,
24612
- agentSlug: input.public.agentSlug,
24613
- sliceToken: input.public.sliceToken,
24614
- personId: input.public.personId,
24615
- lastActivityAt: Date.now()
24616
- });
24617
- }
24618
- } finally {
24619
- this.spawning.delete(input.key);
24620
24807
  }
24808
+ } catch (err) {
24809
+ const reason = (err instanceof Error ? err.message : String(err)).replace(/\s+/g, " ");
24810
+ console.error(
24811
+ `[webchat:inbound] op=spawn-failed key=${keyDisplay(input.key)} role=${input.role} ms=${Date.now() - startedAt} reason=${reason}`
24812
+ );
24813
+ throw err;
24814
+ } finally {
24815
+ this.spawning.delete(input.key);
24621
24816
  }
24622
24817
  }
24623
24818
  };
@@ -1,7 +1,12 @@
1
1
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
2
2
  import {
3
+ D1_MAX_SQL_STATEMENT_BYTES,
4
+ D1_QUERY_MAX_BODY_BYTES,
5
+ JSON_STRING_WORST_CASE_EXPANSION,
6
+ R2_OBJECT_ENVELOPE_MAX_BODY_BYTES,
3
7
  R2_OBJECT_MAX_BYTES,
4
8
  R2_OBJECT_PUT_MAX_BODY_BYTES,
9
+ STORAGE_RESOURCE_NAME_MAX_BODY_BYTES,
5
10
  authorizeAccess,
6
11
  base64Ceiling,
7
12
  listResources,
@@ -15,11 +20,16 @@ import {
15
20
  stripAccountWideTokens,
16
21
  tooLargeMessage,
17
22
  validateMapping
18
- } from "./chunk-Q6W4U6HL.js";
23
+ } from "./chunk-JXWFVE5X.js";
19
24
  import "./chunk-PFF6I7KP.js";
20
25
  export {
26
+ D1_MAX_SQL_STATEMENT_BYTES,
27
+ D1_QUERY_MAX_BODY_BYTES,
28
+ JSON_STRING_WORST_CASE_EXPANSION,
29
+ R2_OBJECT_ENVELOPE_MAX_BODY_BYTES,
21
30
  R2_OBJECT_MAX_BYTES,
22
31
  R2_OBJECT_PUT_MAX_BODY_BYTES,
32
+ STORAGE_RESOURCE_NAME_MAX_BODY_BYTES,
23
33
  authorizeAccess,
24
34
  base64Ceiling,
25
35
  listResources,
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=pkce-flow.test.d.ts.map