@wenathlan/saddle 1.8.18 → 2.0.2

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 (802) hide show
  1. package/Dockerfile +1339 -0
  2. package/README.md +33 -12
  3. package/alternatives.ts +1218 -0
  4. package/biome.json +153 -0
  5. package/boards.json +1517 -0
  6. package/compute.ts +3144 -0
  7. package/cores.json +1801 -0
  8. package/dist/acquisition.d.ts +359 -0
  9. package/dist/acquisition.d.ts.map +1 -0
  10. package/dist/acquisition.js +629 -0
  11. package/dist/acquisition.js.map +1 -0
  12. package/dist/alternatives.d.ts +509 -0
  13. package/dist/alternatives.d.ts.map +1 -0
  14. package/dist/alternatives.js +951 -0
  15. package/dist/alternatives.js.map +1 -0
  16. package/dist/automation.d.ts +426 -0
  17. package/dist/automation.d.ts.map +1 -0
  18. package/dist/automation.js +561 -0
  19. package/dist/automation.js.map +1 -0
  20. package/dist/browser.d.ts +562 -0
  21. package/dist/browser.d.ts.map +1 -0
  22. package/dist/browser.js +1057 -0
  23. package/dist/browser.js.map +1 -0
  24. package/dist/capacitor.config.d.ts +13 -0
  25. package/dist/capacitor.config.d.ts.map +1 -0
  26. package/dist/capacitor.config.js +26 -0
  27. package/dist/capacitor.config.js.map +1 -0
  28. package/dist/cli.d.ts +17 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +111 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/communication.d.ts +192 -0
  33. package/dist/communication.d.ts.map +1 -0
  34. package/dist/communication.js +418 -0
  35. package/dist/communication.js.map +1 -0
  36. package/dist/compute.d.ts +1161 -0
  37. package/dist/compute.d.ts.map +1 -0
  38. package/dist/compute.js +2273 -0
  39. package/dist/compute.js.map +1 -0
  40. package/dist/distribution.d.ts +529 -0
  41. package/dist/distribution.d.ts.map +1 -0
  42. package/dist/distribution.js +811 -0
  43. package/dist/distribution.js.map +1 -0
  44. package/dist/execution.d.ts +530 -0
  45. package/dist/execution.d.ts.map +1 -0
  46. package/dist/execution.js +761 -0
  47. package/dist/execution.js.map +1 -0
  48. package/dist/format.d.ts +19 -0
  49. package/dist/format.d.ts.map +1 -0
  50. package/dist/format.js +60 -0
  51. package/dist/format.js.map +1 -0
  52. package/dist/foundation.d.ts +176 -0
  53. package/dist/foundation.d.ts.map +1 -0
  54. package/dist/foundation.js +309 -0
  55. package/dist/foundation.js.map +1 -0
  56. package/dist/index.d.ts +733 -123
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +1018 -123
  59. package/dist/index.js.map +1 -1
  60. package/dist/integration.d.ts +236 -0
  61. package/dist/integration.d.ts.map +1 -0
  62. package/dist/integration.js +236 -0
  63. package/dist/integration.js.map +1 -0
  64. package/dist/intelligence.d.ts +94 -0
  65. package/dist/intelligence.d.ts.map +1 -0
  66. package/dist/intelligence.js +145 -0
  67. package/dist/intelligence.js.map +1 -0
  68. package/dist/{isolation/contracts.d.ts → isolation.d.ts} +12 -1
  69. package/dist/isolation.d.ts.map +1 -0
  70. package/dist/{isolation/contracts.js → isolation.js} +13 -1
  71. package/dist/isolation.js.map +1 -0
  72. package/dist/media.d.ts +344 -0
  73. package/dist/media.d.ts.map +1 -0
  74. package/dist/media.js +986 -0
  75. package/dist/media.js.map +1 -0
  76. package/dist/modes.d.ts +359 -0
  77. package/dist/modes.d.ts.map +1 -0
  78. package/dist/modes.js +134 -0
  79. package/dist/modes.js.map +1 -0
  80. package/dist/{library/public.d.ts → operations.d.ts} +15 -1
  81. package/dist/operations.d.ts.map +1 -0
  82. package/dist/{library/public.js → operations.js} +18 -7
  83. package/dist/operations.js.map +1 -0
  84. package/dist/orchestrator.d.ts +1339 -0
  85. package/dist/orchestrator.d.ts.map +1 -0
  86. package/dist/orchestrator.js +4308 -0
  87. package/dist/orchestrator.js.map +1 -0
  88. package/dist/performance.d.ts +416 -0
  89. package/dist/performance.d.ts.map +1 -0
  90. package/dist/performance.js +827 -0
  91. package/dist/performance.js.map +1 -0
  92. package/dist/quantum.d.ts +810 -0
  93. package/dist/quantum.d.ts.map +1 -0
  94. package/dist/quantum.js +2073 -0
  95. package/dist/quantum.js.map +1 -0
  96. package/dist/render.d.ts +381 -0
  97. package/dist/render.d.ts.map +1 -0
  98. package/dist/render.js +1073 -0
  99. package/dist/render.js.map +1 -0
  100. package/dist/scheduler.d.ts +596 -0
  101. package/dist/scheduler.d.ts.map +1 -0
  102. package/dist/scheduler.js +1259 -0
  103. package/dist/scheduler.js.map +1 -0
  104. package/dist/security.d.ts +501 -0
  105. package/dist/security.d.ts.map +1 -0
  106. package/dist/security.js +1170 -0
  107. package/dist/security.js.map +1 -0
  108. package/dist/server.d.ts +21 -0
  109. package/dist/server.d.ts.map +1 -0
  110. package/dist/{server/node.js → server.js} +16 -2
  111. package/dist/server.js.map +1 -0
  112. package/dist/tiers.d.ts +1002 -0
  113. package/dist/tiers.d.ts.map +1 -0
  114. package/dist/tiers.js +2165 -0
  115. package/dist/tiers.js.map +1 -0
  116. package/dist/virtual.d.ts +641 -0
  117. package/dist/virtual.d.ts.map +1 -0
  118. package/dist/virtual.js +1285 -0
  119. package/dist/virtual.js.map +1 -0
  120. package/dist/virtualcpu.d.ts +316 -0
  121. package/dist/virtualcpu.d.ts.map +1 -0
  122. package/dist/virtualcpu.js +1180 -0
  123. package/dist/virtualcpu.js.map +1 -0
  124. package/dist/virtualgpu.d.ts +345 -0
  125. package/dist/virtualgpu.d.ts.map +1 -0
  126. package/dist/virtualgpu.js +1000 -0
  127. package/dist/virtualgpu.js.map +1 -0
  128. package/dist/virtualization.d.ts +607 -0
  129. package/dist/virtualization.d.ts.map +1 -0
  130. package/dist/virtualization.js +1187 -0
  131. package/dist/virtualization.js.map +1 -0
  132. package/dist/virtualmemory.d.ts +818 -0
  133. package/dist/virtualmemory.d.ts.map +1 -0
  134. package/dist/virtualmemory.js +1796 -0
  135. package/dist/virtualmemory.js.map +1 -0
  136. package/dist/webscrape.d.ts +720 -0
  137. package/dist/webscrape.d.ts.map +1 -0
  138. package/dist/webscrape.js +2697 -0
  139. package/dist/webscrape.js.map +1 -0
  140. package/docker.config +769 -0
  141. package/docs/CONVERSA.txt +1523 -0
  142. package/docs/alternatives.md +499 -0
  143. package/docs/architecture-1.8.19.md +76 -0
  144. package/docs/architecture-1.8.19.mmd +33 -0
  145. package/docs/architecture-1.8.19.png +0 -0
  146. package/docs/architecture.md +355 -0
  147. package/docs/brancharchive-2026-08-18.md +18 -0
  148. package/docs/browser.md +7 -0
  149. package/docs/consolidation.md +70 -0
  150. package/docs/e2ugh-engine.md +528 -0
  151. package/{dist/examples/localjob.js → docs/example-localjob.ts} +3 -3
  152. package/{dist/examples/publicapi.js → docs/example-publicapi.ts} +2 -2
  153. package/docs/hardware.md +342 -0
  154. package/docs/optimization.md +126 -0
  155. package/docs/performance.md +499 -0
  156. package/docs/planning.1.8.18.md +94 -0
  157. package/docs/planning.1.8.19.md +49 -0
  158. package/docs/releasenotes-1.8.19.md +35 -0
  159. package/docs/research-1.8.19-virtual-browser.md +27 -0
  160. package/docs/security.md +454 -0
  161. package/docs/todo-1.8.18.md +12 -0
  162. package/docs/todo-1.8.19.md +241 -0
  163. package/docs/viability.md +777 -0
  164. package/docs/virtualization.md +335 -0
  165. package/docs/web-duplicatecleanup.md +9 -0
  166. package/docs/web-ideas.md +106 -0
  167. package/docs/workflowimprovements-2026-08-19.md +70 -0
  168. package/gpumonitor.cpp +1543 -0
  169. package/gpus.json +2408 -0
  170. package/index.ts +1478 -0
  171. package/media.ts +1337 -0
  172. package/mttg.config +1549 -0
  173. package/orchestrator.ts +5462 -0
  174. package/package.json +304 -56
  175. package/passage.config +1331 -0
  176. package/performance.ts +1049 -0
  177. package/processors.json +2217 -0
  178. package/qemu.config +1062 -0
  179. package/qemubridge.py +1340 -0
  180. package/quantum.ts +2393 -0
  181. package/render.ts +1325 -0
  182. package/scheduler.ts +1600 -0
  183. package/security.ts +1449 -0
  184. package/tiers.ts +2871 -0
  185. package/tsconfig.json +29 -0
  186. package/virtualcpu.ts +1273 -0
  187. package/virtualgpu.ts +1181 -0
  188. package/virtualhardware.c +1011 -0
  189. package/virtualhardware.json +739 -0
  190. package/virtualization.ts +1628 -0
  191. package/virtualizationcore.cpp +4635 -0
  192. package/virtualmemory.ts +2303 -0
  193. package/vm.config.json +1910 -0
  194. package/{extension → web/extension}/manifest.json +1 -1
  195. package/web/readme.md +382 -0
  196. package/web/tsconfig.json +25 -0
  197. package/dist/adapters/forge.d.ts +0 -17
  198. package/dist/adapters/forge.d.ts.map +0 -1
  199. package/dist/adapters/forge.js +0 -19
  200. package/dist/adapters/forge.js.map +0 -1
  201. package/dist/adapters/forgejo.d.ts +0 -49
  202. package/dist/adapters/forgejo.d.ts.map +0 -1
  203. package/dist/adapters/forgejo.js +0 -8
  204. package/dist/adapters/forgejo.js.map +0 -1
  205. package/dist/adapters/github.d.ts +0 -12
  206. package/dist/adapters/github.d.ts.map +0 -1
  207. package/dist/adapters/github.js +0 -20
  208. package/dist/adapters/github.js.map +0 -1
  209. package/dist/adapters/gitlab.d.ts +0 -17
  210. package/dist/adapters/gitlab.d.ts.map +0 -1
  211. package/dist/adapters/gitlab.js +0 -10
  212. package/dist/adapters/gitlab.js.map +0 -1
  213. package/dist/adapters/huggingface.d.ts +0 -17
  214. package/dist/adapters/huggingface.d.ts.map +0 -1
  215. package/dist/adapters/huggingface.js +0 -6
  216. package/dist/adapters/huggingface.js.map +0 -1
  217. package/dist/adapters/socket.d.ts +0 -11
  218. package/dist/adapters/socket.d.ts.map +0 -1
  219. package/dist/adapters/socket.js +0 -17
  220. package/dist/adapters/socket.js.map +0 -1
  221. package/dist/adapters/transport.d.ts +0 -7
  222. package/dist/adapters/transport.d.ts.map +0 -1
  223. package/dist/adapters/transport.js +0 -36
  224. package/dist/adapters/transport.js.map +0 -1
  225. package/dist/ai/chunk.d.ts +0 -2
  226. package/dist/ai/chunk.d.ts.map +0 -1
  227. package/dist/ai/chunk.js +0 -36
  228. package/dist/ai/chunk.js.map +0 -1
  229. package/dist/ai/llmstxt.d.ts +0 -6
  230. package/dist/ai/llmstxt.d.ts.map +0 -1
  231. package/dist/ai/llmstxt.js +0 -12
  232. package/dist/ai/llmstxt.js.map +0 -1
  233. package/dist/ai/provenance.d.ts +0 -22
  234. package/dist/ai/provenance.d.ts.map +0 -1
  235. package/dist/ai/provenance.js +0 -25
  236. package/dist/ai/provenance.js.map +0 -1
  237. package/dist/ai/rag.d.ts +0 -26
  238. package/dist/ai/rag.d.ts.map +0 -1
  239. package/dist/ai/rag.js +0 -22
  240. package/dist/ai/rag.js.map +0 -1
  241. package/dist/ai/tokens.d.ts +0 -15
  242. package/dist/ai/tokens.d.ts.map +0 -1
  243. package/dist/ai/tokens.js +0 -9
  244. package/dist/ai/tokens.js.map +0 -1
  245. package/dist/api/auth.d.ts +0 -16
  246. package/dist/api/auth.d.ts.map +0 -1
  247. package/dist/api/auth.js +0 -19
  248. package/dist/api/auth.js.map +0 -1
  249. package/dist/api/contracts.d.ts +0 -28
  250. package/dist/api/contracts.d.ts.map +0 -1
  251. package/dist/api/contracts.js +0 -14
  252. package/dist/api/contracts.js.map +0 -1
  253. package/dist/api/control.d.ts +0 -10
  254. package/dist/api/control.d.ts.map +0 -1
  255. package/dist/api/control.js +0 -35
  256. package/dist/api/control.js.map +0 -1
  257. package/dist/api/http.d.ts +0 -7
  258. package/dist/api/http.d.ts.map +0 -1
  259. package/dist/api/http.js +0 -12
  260. package/dist/api/http.js.map +0 -1
  261. package/dist/api/rate.d.ts +0 -28
  262. package/dist/api/rate.d.ts.map +0 -1
  263. package/dist/api/rate.js +0 -36
  264. package/dist/api/rate.js.map +0 -1
  265. package/dist/api/security.d.ts +0 -12
  266. package/dist/api/security.d.ts.map +0 -1
  267. package/dist/api/security.js +0 -56
  268. package/dist/api/security.js.map +0 -1
  269. package/dist/api/service.d.ts +0 -5
  270. package/dist/api/service.d.ts.map +0 -1
  271. package/dist/api/service.js +0 -70
  272. package/dist/api/service.js.map +0 -1
  273. package/dist/apps/registry.d.ts +0 -33
  274. package/dist/apps/registry.d.ts.map +0 -1
  275. package/dist/apps/registry.js +0 -24
  276. package/dist/apps/registry.js.map +0 -1
  277. package/dist/binary/archive.d.ts +0 -27
  278. package/dist/binary/archive.d.ts.map +0 -1
  279. package/dist/binary/archive.js +0 -46
  280. package/dist/binary/archive.js.map +0 -1
  281. package/dist/binary/build.d.ts +0 -29
  282. package/dist/binary/build.d.ts.map +0 -1
  283. package/dist/binary/build.js +0 -17
  284. package/dist/binary/build.js.map +0 -1
  285. package/dist/binary/transform.d.ts +0 -70
  286. package/dist/binary/transform.d.ts.map +0 -1
  287. package/dist/binary/transform.js +0 -105
  288. package/dist/binary/transform.js.map +0 -1
  289. package/dist/bot/adapter.d.ts +0 -5
  290. package/dist/bot/adapter.d.ts.map +0 -1
  291. package/dist/bot/adapter.js +0 -11
  292. package/dist/bot/adapter.js.map +0 -1
  293. package/dist/bot/bot.d.ts +0 -28
  294. package/dist/bot/bot.d.ts.map +0 -1
  295. package/dist/bot/bot.js +0 -52
  296. package/dist/bot/bot.js.map +0 -1
  297. package/dist/bot/commands.d.ts +0 -8
  298. package/dist/bot/commands.d.ts.map +0 -1
  299. package/dist/bot/commands.js +0 -19
  300. package/dist/bot/commands.js.map +0 -1
  301. package/dist/bot/permissions.d.ts +0 -13
  302. package/dist/bot/permissions.d.ts.map +0 -1
  303. package/dist/bot/permissions.js +0 -16
  304. package/dist/bot/permissions.js.map +0 -1
  305. package/dist/browser/actions.d.ts +0 -33
  306. package/dist/browser/actions.d.ts.map +0 -1
  307. package/dist/browser/actions.js +0 -44
  308. package/dist/browser/actions.js.map +0 -1
  309. package/dist/browser/agent.d.ts +0 -21
  310. package/dist/browser/agent.d.ts.map +0 -1
  311. package/dist/browser/agent.js +0 -13
  312. package/dist/browser/agent.js.map +0 -1
  313. package/dist/browser/context.d.ts +0 -43
  314. package/dist/browser/context.d.ts.map +0 -1
  315. package/dist/browser/context.js +0 -54
  316. package/dist/browser/context.js.map +0 -1
  317. package/dist/browser/fingerprint.d.ts +0 -4
  318. package/dist/browser/fingerprint.d.ts.map +0 -1
  319. package/dist/browser/fingerprint.js +0 -12
  320. package/dist/browser/fingerprint.js.map +0 -1
  321. package/dist/browser/index.d.ts +0 -11
  322. package/dist/browser/index.d.ts.map +0 -1
  323. package/dist/browser/index.js +0 -11
  324. package/dist/browser/index.js.map +0 -1
  325. package/dist/browser/playwright.d.ts +0 -11
  326. package/dist/browser/playwright.d.ts.map +0 -1
  327. package/dist/browser/playwright.js +0 -24
  328. package/dist/browser/playwright.js.map +0 -1
  329. package/dist/browser/recorder.d.ts +0 -21
  330. package/dist/browser/recorder.d.ts.map +0 -1
  331. package/dist/browser/recorder.js +0 -58
  332. package/dist/browser/recorder.js.map +0 -1
  333. package/dist/browser/session.d.ts +0 -14
  334. package/dist/browser/session.d.ts.map +0 -1
  335. package/dist/browser/session.js +0 -21
  336. package/dist/browser/session.js.map +0 -1
  337. package/dist/browser/snapshot.d.ts +0 -69
  338. package/dist/browser/snapshot.d.ts.map +0 -1
  339. package/dist/browser/snapshot.js +0 -133
  340. package/dist/browser/snapshot.js.map +0 -1
  341. package/dist/captcha/contract.d.ts +0 -35
  342. package/dist/captcha/contract.d.ts.map +0 -1
  343. package/dist/captcha/contract.js +0 -17
  344. package/dist/captcha/contract.js.map +0 -1
  345. package/dist/captcha/evidence.d.ts +0 -10
  346. package/dist/captcha/evidence.d.ts.map +0 -1
  347. package/dist/captcha/evidence.js +0 -9
  348. package/dist/captcha/evidence.js.map +0 -1
  349. package/dist/captcha/guard.d.ts +0 -23
  350. package/dist/captcha/guard.d.ts.map +0 -1
  351. package/dist/captcha/guard.js +0 -12
  352. package/dist/captcha/guard.js.map +0 -1
  353. package/dist/cli/main.d.ts +0 -4
  354. package/dist/cli/main.d.ts.map +0 -1
  355. package/dist/cli/main.js +0 -46
  356. package/dist/cli/main.js.map +0 -1
  357. package/dist/core/errors.d.ts +0 -84
  358. package/dist/core/errors.d.ts.map +0 -1
  359. package/dist/core/errors.js +0 -54
  360. package/dist/core/errors.js.map +0 -1
  361. package/dist/core/events.d.ts +0 -9
  362. package/dist/core/events.d.ts.map +0 -1
  363. package/dist/core/events.js +0 -21
  364. package/dist/core/events.js.map +0 -1
  365. package/dist/core/hash.d.ts +0 -10
  366. package/dist/core/hash.d.ts.map +0 -1
  367. package/dist/core/hash.js +0 -82
  368. package/dist/core/hash.js.map +0 -1
  369. package/dist/core/ids.d.ts +0 -10
  370. package/dist/core/ids.d.ts.map +0 -1
  371. package/dist/core/ids.js +0 -15
  372. package/dist/core/ids.js.map +0 -1
  373. package/dist/delivery/manifest.d.ts +0 -35
  374. package/dist/delivery/manifest.d.ts.map +0 -1
  375. package/dist/delivery/manifest.js +0 -68
  376. package/dist/delivery/manifest.js.map +0 -1
  377. package/dist/deploy/index.d.ts +0 -6
  378. package/dist/deploy/index.d.ts.map +0 -1
  379. package/dist/deploy/index.js +0 -6
  380. package/dist/deploy/index.js.map +0 -1
  381. package/dist/dispatch/resumable.d.ts +0 -102
  382. package/dist/dispatch/resumable.d.ts.map +0 -1
  383. package/dist/dispatch/resumable.js +0 -64
  384. package/dist/dispatch/resumable.js.map +0 -1
  385. package/dist/dispatch/workflow.d.ts +0 -6
  386. package/dist/dispatch/workflow.d.ts.map +0 -1
  387. package/dist/dispatch/workflow.js +0 -37
  388. package/dist/dispatch/workflow.js.map +0 -1
  389. package/dist/domain/artifacts.d.ts +0 -12
  390. package/dist/domain/artifacts.d.ts.map +0 -1
  391. package/dist/domain/artifacts.js +0 -14
  392. package/dist/domain/artifacts.js.map +0 -1
  393. package/dist/domain/jobs.d.ts +0 -12
  394. package/dist/domain/jobs.d.ts.map +0 -1
  395. package/dist/domain/jobs.js +0 -20
  396. package/dist/domain/jobs.js.map +0 -1
  397. package/dist/domain/providers.d.ts +0 -10
  398. package/dist/domain/providers.d.ts.map +0 -1
  399. package/dist/domain/providers.js +0 -8
  400. package/dist/domain/providers.js.map +0 -1
  401. package/dist/domain/runtime.d.ts +0 -14
  402. package/dist/domain/runtime.d.ts.map +0 -1
  403. package/dist/domain/runtime.js +0 -10
  404. package/dist/domain/runtime.js.map +0 -1
  405. package/dist/domain/sessions.d.ts +0 -12
  406. package/dist/domain/sessions.d.ts.map +0 -1
  407. package/dist/domain/sessions.js +0 -57
  408. package/dist/domain/sessions.js.map +0 -1
  409. package/dist/examples/localjob.d.ts +0 -2
  410. package/dist/examples/localjob.d.ts.map +0 -1
  411. package/dist/examples/localjob.js.map +0 -1
  412. package/dist/examples/publicapi.d.ts +0 -2
  413. package/dist/examples/publicapi.d.ts.map +0 -1
  414. package/dist/examples/publicapi.js.map +0 -1
  415. package/dist/extension/build.d.ts +0 -9
  416. package/dist/extension/build.d.ts.map +0 -1
  417. package/dist/extension/build.js +0 -85
  418. package/dist/extension/build.js.map +0 -1
  419. package/dist/extension/content.d.ts +0 -6
  420. package/dist/extension/content.d.ts.map +0 -1
  421. package/dist/extension/content.js +0 -135
  422. package/dist/extension/content.js.map +0 -1
  423. package/dist/extension/index.d.ts +0 -7
  424. package/dist/extension/index.d.ts.map +0 -1
  425. package/dist/extension/index.js +0 -7
  426. package/dist/extension/index.js.map +0 -1
  427. package/dist/extension/pagebridge.d.ts +0 -6
  428. package/dist/extension/pagebridge.d.ts.map +0 -1
  429. package/dist/extension/pagebridge.js +0 -42
  430. package/dist/extension/pagebridge.js.map +0 -1
  431. package/dist/extension/permissions.d.ts +0 -26
  432. package/dist/extension/permissions.d.ts.map +0 -1
  433. package/dist/extension/permissions.js +0 -28
  434. package/dist/extension/permissions.js.map +0 -1
  435. package/dist/extension/popup.d.ts +0 -5
  436. package/dist/extension/popup.d.ts.map +0 -1
  437. package/dist/extension/popup.js +0 -26
  438. package/dist/extension/popup.js.map +0 -1
  439. package/dist/extension/protocol.d.ts +0 -58
  440. package/dist/extension/protocol.d.ts.map +0 -1
  441. package/dist/extension/protocol.js +0 -101
  442. package/dist/extension/protocol.js.map +0 -1
  443. package/dist/extension/serviceworker.d.ts +0 -25
  444. package/dist/extension/serviceworker.d.ts.map +0 -1
  445. package/dist/extension/serviceworker.js +0 -102
  446. package/dist/extension/serviceworker.js.map +0 -1
  447. package/dist/extension/worker.d.ts +0 -28
  448. package/dist/extension/worker.d.ts.map +0 -1
  449. package/dist/extension/worker.js +0 -22
  450. package/dist/extension/worker.js.map +0 -1
  451. package/dist/format/check.d.ts +0 -8
  452. package/dist/format/check.d.ts.map +0 -1
  453. package/dist/format/check.js +0 -38
  454. package/dist/format/check.js.map +0 -1
  455. package/dist/isolation/contracts.d.ts.map +0 -1
  456. package/dist/isolation/contracts.js.map +0 -1
  457. package/dist/library/public.d.ts.map +0 -1
  458. package/dist/library/public.js.map +0 -1
  459. package/dist/mcp/browser.d.ts +0 -9
  460. package/dist/mcp/browser.d.ts.map +0 -1
  461. package/dist/mcp/browser.js +0 -13
  462. package/dist/mcp/browser.js.map +0 -1
  463. package/dist/mcp/server.d.ts +0 -35
  464. package/dist/mcp/server.d.ts.map +0 -1
  465. package/dist/mcp/server.js +0 -40
  466. package/dist/mcp/server.js.map +0 -1
  467. package/dist/mcp/transport.d.ts +0 -7
  468. package/dist/mcp/transport.d.ts.map +0 -1
  469. package/dist/mcp/transport.js +0 -17
  470. package/dist/mcp/transport.js.map +0 -1
  471. package/dist/memory/bridge.d.ts +0 -14
  472. package/dist/memory/bridge.d.ts.map +0 -1
  473. package/dist/memory/bridge.js +0 -16
  474. package/dist/memory/bridge.js.map +0 -1
  475. package/dist/memory/engine.d.ts +0 -38
  476. package/dist/memory/engine.d.ts.map +0 -1
  477. package/dist/memory/engine.js +0 -109
  478. package/dist/memory/engine.js.map +0 -1
  479. package/dist/memory/modes.d.ts +0 -43
  480. package/dist/memory/modes.d.ts.map +0 -1
  481. package/dist/memory/modes.js +0 -66
  482. package/dist/memory/modes.js.map +0 -1
  483. package/dist/memory/objects.d.ts +0 -21
  484. package/dist/memory/objects.d.ts.map +0 -1
  485. package/dist/memory/objects.js +0 -20
  486. package/dist/memory/objects.js.map +0 -1
  487. package/dist/memory/planner.d.ts +0 -66
  488. package/dist/memory/planner.d.ts.map +0 -1
  489. package/dist/memory/planner.js +0 -108
  490. package/dist/memory/planner.js.map +0 -1
  491. package/dist/memory/targets.d.ts +0 -78
  492. package/dist/memory/targets.d.ts.map +0 -1
  493. package/dist/memory/targets.js +0 -29
  494. package/dist/memory/targets.js.map +0 -1
  495. package/dist/memory/transforms.d.ts +0 -19
  496. package/dist/memory/transforms.d.ts.map +0 -1
  497. package/dist/memory/transforms.js +0 -14
  498. package/dist/memory/transforms.js.map +0 -1
  499. package/dist/modes/matrix.d.ts +0 -23
  500. package/dist/modes/matrix.d.ts.map +0 -1
  501. package/dist/modes/matrix.js +0 -18
  502. package/dist/modes/matrix.js.map +0 -1
  503. package/dist/modes/modes.d.ts +0 -33
  504. package/dist/modes/modes.d.ts.map +0 -1
  505. package/dist/modes/modes.js +0 -15
  506. package/dist/modes/modes.js.map +0 -1
  507. package/dist/modes/resolve.d.ts +0 -96
  508. package/dist/modes/resolve.d.ts.map +0 -1
  509. package/dist/modes/resolve.js +0 -48
  510. package/dist/modes/resolve.js.map +0 -1
  511. package/dist/observability/metrics.d.ts +0 -14
  512. package/dist/observability/metrics.d.ts.map +0 -1
  513. package/dist/observability/metrics.js +0 -18
  514. package/dist/observability/metrics.js.map +0 -1
  515. package/dist/packager/manifest.d.ts +0 -66
  516. package/dist/packager/manifest.d.ts.map +0 -1
  517. package/dist/packager/manifest.js +0 -94
  518. package/dist/packager/manifest.js.map +0 -1
  519. package/dist/packager/publish.d.ts +0 -51
  520. package/dist/packager/publish.d.ts.map +0 -1
  521. package/dist/packager/publish.js +0 -18
  522. package/dist/packager/publish.js.map +0 -1
  523. package/dist/packager/targetcli.d.ts +0 -7
  524. package/dist/packager/targetcli.d.ts.map +0 -1
  525. package/dist/packager/targetcli.js +0 -22
  526. package/dist/packager/targetcli.js.map +0 -1
  527. package/dist/persistence/adapter.d.ts +0 -5
  528. package/dist/persistence/adapter.d.ts.map +0 -1
  529. package/dist/persistence/adapter.js +0 -11
  530. package/dist/persistence/adapter.js.map +0 -1
  531. package/dist/persistence/drizzle.d.ts +0 -2
  532. package/dist/persistence/drizzle.d.ts.map +0 -1
  533. package/dist/persistence/drizzle.js +0 -12
  534. package/dist/persistence/drizzle.js.map +0 -1
  535. package/dist/persistence/memory.d.ts +0 -2
  536. package/dist/persistence/memory.d.ts.map +0 -1
  537. package/dist/persistence/memory.js +0 -27
  538. package/dist/persistence/memory.js.map +0 -1
  539. package/dist/persistence/migrations.d.ts +0 -19
  540. package/dist/persistence/migrations.d.ts.map +0 -1
  541. package/dist/persistence/migrations.js +0 -13
  542. package/dist/persistence/migrations.js.map +0 -1
  543. package/dist/persistence/prisma.d.ts +0 -2
  544. package/dist/persistence/prisma.d.ts.map +0 -1
  545. package/dist/persistence/prisma.js +0 -25
  546. package/dist/persistence/prisma.js.map +0 -1
  547. package/dist/persistence/schema.d.ts +0 -63
  548. package/dist/persistence/schema.d.ts.map +0 -1
  549. package/dist/persistence/schema.js +0 -28
  550. package/dist/persistence/schema.js.map +0 -1
  551. package/dist/persistence/sql.d.ts +0 -3
  552. package/dist/persistence/sql.d.ts.map +0 -1
  553. package/dist/persistence/sql.js +0 -37
  554. package/dist/persistence/sql.js.map +0 -1
  555. package/dist/protocol/blocks.d.ts +0 -10
  556. package/dist/protocol/blocks.d.ts.map +0 -1
  557. package/dist/protocol/blocks.js +0 -26
  558. package/dist/protocol/blocks.js.map +0 -1
  559. package/dist/protocol/json.d.ts +0 -6
  560. package/dist/protocol/json.d.ts.map +0 -1
  561. package/dist/protocol/json.js +0 -6
  562. package/dist/protocol/json.js.map +0 -1
  563. package/dist/protocol/ndjson.d.ts +0 -3
  564. package/dist/protocol/ndjson.d.ts.map +0 -1
  565. package/dist/protocol/ndjson.js +0 -20
  566. package/dist/protocol/ndjson.js.map +0 -1
  567. package/dist/protocol/sse.d.ts +0 -7
  568. package/dist/protocol/sse.d.ts.map +0 -1
  569. package/dist/protocol/sse.js +0 -25
  570. package/dist/protocol/sse.js.map +0 -1
  571. package/dist/proxy/pool.d.ts +0 -9
  572. package/dist/proxy/pool.d.ts.map +0 -1
  573. package/dist/proxy/pool.js +0 -27
  574. package/dist/proxy/pool.js.map +0 -1
  575. package/dist/queue/idempotency.d.ts +0 -10
  576. package/dist/queue/idempotency.d.ts.map +0 -1
  577. package/dist/queue/idempotency.js +0 -13
  578. package/dist/queue/idempotency.js.map +0 -1
  579. package/dist/queue/persistent.d.ts +0 -14
  580. package/dist/queue/persistent.d.ts.map +0 -1
  581. package/dist/queue/persistent.js +0 -66
  582. package/dist/queue/persistent.js.map +0 -1
  583. package/dist/queue/queue.d.ts +0 -7
  584. package/dist/queue/queue.d.ts.map +0 -1
  585. package/dist/queue/queue.js +0 -55
  586. package/dist/queue/queue.js.map +0 -1
  587. package/dist/queue/saga.d.ts +0 -5
  588. package/dist/queue/saga.d.ts.map +0 -1
  589. package/dist/queue/saga.js +0 -20
  590. package/dist/queue/saga.js.map +0 -1
  591. package/dist/release/assets.d.ts +0 -144
  592. package/dist/release/assets.d.ts.map +0 -1
  593. package/dist/release/assets.js +0 -157
  594. package/dist/release/assets.js.map +0 -1
  595. package/dist/release/evidence.d.ts +0 -92
  596. package/dist/release/evidence.d.ts.map +0 -1
  597. package/dist/release/evidence.js +0 -148
  598. package/dist/release/evidence.js.map +0 -1
  599. package/dist/release/verify.d.ts +0 -12
  600. package/dist/release/verify.d.ts.map +0 -1
  601. package/dist/release/verify.js +0 -112
  602. package/dist/release/verify.js.map +0 -1
  603. package/dist/runners/chain.d.ts +0 -125
  604. package/dist/runners/chain.d.ts.map +0 -1
  605. package/dist/runners/chain.js +0 -95
  606. package/dist/runners/chain.js.map +0 -1
  607. package/dist/runners/health.d.ts +0 -36
  608. package/dist/runners/health.d.ts.map +0 -1
  609. package/dist/runners/health.js +0 -26
  610. package/dist/runners/health.js.map +0 -1
  611. package/dist/runners/heartbeat.d.ts +0 -23
  612. package/dist/runners/heartbeat.d.ts.map +0 -1
  613. package/dist/runners/heartbeat.js +0 -29
  614. package/dist/runners/heartbeat.js.map +0 -1
  615. package/dist/runners/inprocess.d.ts +0 -17
  616. package/dist/runners/inprocess.d.ts.map +0 -1
  617. package/dist/runners/inprocess.js +0 -20
  618. package/dist/runners/inprocess.js.map +0 -1
  619. package/dist/runners/scheduler.d.ts +0 -5
  620. package/dist/runners/scheduler.d.ts.map +0 -1
  621. package/dist/runners/scheduler.js +0 -19
  622. package/dist/runners/scheduler.js.map +0 -1
  623. package/dist/runtime/abort.d.ts +0 -8
  624. package/dist/runtime/abort.d.ts.map +0 -1
  625. package/dist/runtime/abort.js +0 -13
  626. package/dist/runtime/abort.js.map +0 -1
  627. package/dist/runtime/compatibility.d.ts +0 -37
  628. package/dist/runtime/compatibility.d.ts.map +0 -1
  629. package/dist/runtime/compatibility.js +0 -10
  630. package/dist/runtime/compatibility.js.map +0 -1
  631. package/dist/runtime/detect.d.ts +0 -13
  632. package/dist/runtime/detect.d.ts.map +0 -1
  633. package/dist/runtime/detect.js +0 -18
  634. package/dist/runtime/detect.js.map +0 -1
  635. package/dist/runtime/engine.d.ts +0 -20
  636. package/dist/runtime/engine.d.ts.map +0 -1
  637. package/dist/runtime/engine.js +0 -61
  638. package/dist/runtime/engine.js.map +0 -1
  639. package/dist/runtime/retry.d.ts +0 -19
  640. package/dist/runtime/retry.d.ts.map +0 -1
  641. package/dist/runtime/retry.js +0 -54
  642. package/dist/runtime/retry.js.map +0 -1
  643. package/dist/runtime/worker.d.ts +0 -10
  644. package/dist/runtime/worker.d.ts.map +0 -1
  645. package/dist/runtime/worker.js +0 -25
  646. package/dist/runtime/worker.js.map +0 -1
  647. package/dist/scrape/cache.d.ts +0 -45
  648. package/dist/scrape/cache.d.ts.map +0 -1
  649. package/dist/scrape/cache.js +0 -45
  650. package/dist/scrape/cache.js.map +0 -1
  651. package/dist/scrape/crawl.d.ts +0 -47
  652. package/dist/scrape/crawl.d.ts.map +0 -1
  653. package/dist/scrape/crawl.js +0 -114
  654. package/dist/scrape/crawl.js.map +0 -1
  655. package/dist/scrape/extract.d.ts +0 -63
  656. package/dist/scrape/extract.d.ts.map +0 -1
  657. package/dist/scrape/extract.js +0 -47
  658. package/dist/scrape/extract.js.map +0 -1
  659. package/dist/scrape/normalize.d.ts +0 -52
  660. package/dist/scrape/normalize.d.ts.map +0 -1
  661. package/dist/scrape/normalize.js +0 -102
  662. package/dist/scrape/normalize.js.map +0 -1
  663. package/dist/scrape/robots.d.ts +0 -37
  664. package/dist/scrape/robots.d.ts.map +0 -1
  665. package/dist/scrape/robots.js +0 -71
  666. package/dist/scrape/robots.js.map +0 -1
  667. package/dist/scrape/schema.d.ts +0 -23
  668. package/dist/scrape/schema.d.ts.map +0 -1
  669. package/dist/scrape/schema.js +0 -92
  670. package/dist/scrape/schema.js.map +0 -1
  671. package/dist/scrape/scraper.d.ts +0 -6
  672. package/dist/scrape/scraper.d.ts.map +0 -1
  673. package/dist/scrape/scraper.js +0 -46
  674. package/dist/scrape/scraper.js.map +0 -1
  675. package/dist/scrape/semantic.d.ts +0 -25
  676. package/dist/scrape/semantic.d.ts.map +0 -1
  677. package/dist/scrape/semantic.js +0 -27
  678. package/dist/scrape/semantic.js.map +0 -1
  679. package/dist/server/node.d.ts +0 -7
  680. package/dist/server/node.d.ts.map +0 -1
  681. package/dist/server/node.js.map +0 -1
  682. package/dist/sessions/file.d.ts +0 -25
  683. package/dist/sessions/file.d.ts.map +0 -1
  684. package/dist/sessions/file.js +0 -13
  685. package/dist/sessions/file.js.map +0 -1
  686. package/dist/sessions/replay.d.ts +0 -9
  687. package/dist/sessions/replay.d.ts.map +0 -1
  688. package/dist/sessions/replay.js +0 -70
  689. package/dist/sessions/replay.js.map +0 -1
  690. package/dist/sessions/store.d.ts +0 -25
  691. package/dist/sessions/store.d.ts.map +0 -1
  692. package/dist/sessions/store.js +0 -13
  693. package/dist/sessions/store.js.map +0 -1
  694. package/dist/storage/adapter.d.ts +0 -5
  695. package/dist/storage/adapter.d.ts.map +0 -1
  696. package/dist/storage/adapter.js +0 -11
  697. package/dist/storage/adapter.js.map +0 -1
  698. package/dist/storage/cache.d.ts +0 -23
  699. package/dist/storage/cache.d.ts.map +0 -1
  700. package/dist/storage/cache.js +0 -79
  701. package/dist/storage/cache.js.map +0 -1
  702. package/dist/storage/checksum.d.ts +0 -3
  703. package/dist/storage/checksum.d.ts.map +0 -1
  704. package/dist/storage/checksum.js +0 -19
  705. package/dist/storage/checksum.js.map +0 -1
  706. package/dist/storage/chunked.d.ts +0 -21
  707. package/dist/storage/chunked.d.ts.map +0 -1
  708. package/dist/storage/chunked.js +0 -67
  709. package/dist/storage/chunked.js.map +0 -1
  710. package/dist/storage/content.d.ts +0 -24
  711. package/dist/storage/content.d.ts.map +0 -1
  712. package/dist/storage/content.js +0 -44
  713. package/dist/storage/content.js.map +0 -1
  714. package/dist/storage/filehosting.d.ts +0 -2
  715. package/dist/storage/filehosting.d.ts.map +0 -1
  716. package/dist/storage/filehosting.js +0 -24
  717. package/dist/storage/filehosting.js.map +0 -1
  718. package/dist/storage/githubcontents.d.ts +0 -2
  719. package/dist/storage/githubcontents.d.ts.map +0 -1
  720. package/dist/storage/githubcontents.js +0 -29
  721. package/dist/storage/githubcontents.js.map +0 -1
  722. package/dist/storage/index.d.ts +0 -12
  723. package/dist/storage/index.d.ts.map +0 -1
  724. package/dist/storage/index.js +0 -12
  725. package/dist/storage/index.js.map +0 -1
  726. package/dist/storage/local.d.ts +0 -2
  727. package/dist/storage/local.d.ts.map +0 -1
  728. package/dist/storage/local.js +0 -72
  729. package/dist/storage/local.js.map +0 -1
  730. package/dist/storage/memory.d.ts +0 -6
  731. package/dist/storage/memory.d.ts.map +0 -1
  732. package/dist/storage/memory.js +0 -36
  733. package/dist/storage/memory.js.map +0 -1
  734. package/dist/storage/pool.d.ts +0 -95
  735. package/dist/storage/pool.d.ts.map +0 -1
  736. package/dist/storage/pool.js +0 -202
  737. package/dist/storage/pool.js.map +0 -1
  738. package/dist/storage/s3compatible.d.ts +0 -3
  739. package/dist/storage/s3compatible.d.ts.map +0 -1
  740. package/dist/storage/s3compatible.js +0 -70
  741. package/dist/storage/s3compatible.js.map +0 -1
  742. package/dist/storage/sync.d.ts +0 -47
  743. package/dist/storage/sync.d.ts.map +0 -1
  744. package/dist/storage/sync.js +0 -75
  745. package/dist/storage/sync.js.map +0 -1
  746. package/dist/surfaces/adapters.d.ts +0 -97
  747. package/dist/surfaces/adapters.d.ts.map +0 -1
  748. package/dist/surfaces/adapters.js +0 -50
  749. package/dist/surfaces/adapters.js.map +0 -1
  750. package/dist/surfaces/controls.d.ts +0 -18
  751. package/dist/surfaces/controls.d.ts.map +0 -1
  752. package/dist/surfaces/controls.js +0 -45
  753. package/dist/surfaces/controls.js.map +0 -1
  754. package/dist/surfaces/manifest.d.ts +0 -68
  755. package/dist/surfaces/manifest.d.ts.map +0 -1
  756. package/dist/surfaces/manifest.js +0 -42
  757. package/dist/surfaces/manifest.js.map +0 -1
  758. package/dist/surfaces/n8n.d.ts +0 -25
  759. package/dist/surfaces/n8n.d.ts.map +0 -1
  760. package/dist/surfaces/n8n.js +0 -31
  761. package/dist/surfaces/n8n.js.map +0 -1
  762. package/dist/surfaces/operations.d.ts +0 -32
  763. package/dist/surfaces/operations.d.ts.map +0 -1
  764. package/dist/surfaces/operations.js +0 -53
  765. package/dist/surfaces/operations.js.map +0 -1
  766. package/dist/surfaces/requirements.d.ts +0 -29
  767. package/dist/surfaces/requirements.d.ts.map +0 -1
  768. package/dist/surfaces/requirements.js +0 -50
  769. package/dist/surfaces/requirements.js.map +0 -1
  770. package/dist/surfaces/targets.d.ts +0 -196
  771. package/dist/surfaces/targets.d.ts.map +0 -1
  772. package/dist/surfaces/targets.js +0 -27
  773. package/dist/surfaces/targets.js.map +0 -1
  774. package/dist/webhook/delivery.d.ts +0 -18
  775. package/dist/webhook/delivery.d.ts.map +0 -1
  776. package/dist/webhook/delivery.js +0 -36
  777. package/dist/webhook/delivery.js.map +0 -1
  778. package/dist/webhook/receiver.d.ts +0 -26
  779. package/dist/webhook/receiver.d.ts.map +0 -1
  780. package/dist/webhook/receiver.js +0 -24
  781. package/dist/webhook/receiver.js.map +0 -1
  782. package/dist/webhook/signature.d.ts +0 -3
  783. package/dist/webhook/signature.d.ts.map +0 -1
  784. package/dist/webhook/signature.js +0 -7
  785. package/dist/webhook/signature.js.map +0 -1
  786. package/dist/workflow/manifest.d.ts +0 -22
  787. package/dist/workflow/manifest.d.ts.map +0 -1
  788. package/dist/workflow/manifest.js +0 -21
  789. package/dist/workflow/manifest.js.map +0 -1
  790. package/dist/workflow/registry.d.ts +0 -7
  791. package/dist/workflow/registry.d.ts.map +0 -1
  792. package/dist/workflow/registry.js +0 -18
  793. package/dist/workflow/registry.js.map +0 -1
  794. package/dist/workflow/templates.d.ts +0 -6
  795. package/dist/workflow/templates.d.ts.map +0 -1
  796. package/dist/workflow/templates.js +0 -18
  797. package/dist/workflow/templates.js.map +0 -1
  798. package/dist/workflow/triggers.d.ts +0 -64
  799. package/dist/workflow/triggers.d.ts.map +0 -1
  800. package/dist/workflow/triggers.js +0 -99
  801. package/dist/workflow/triggers.js.map +0 -1
  802. /package/{extension/README.md → docs/extension.md} +0 -0
@@ -0,0 +1,1285 @@
1
+ /**
2
+ * virtual.ts — isolation, internal memory, storage and optional persistence contracts.
3
+ *
4
+ * This file is the v2.0.0 grand-merge consolidation of the former nested
5
+ * folders of the repository (memory, storage, persistence) into the single
6
+ * root-level domain file of the saddle family standard: one optimized
7
+ * TypeScript file per correlated domain, ordinal sections, JSDoc on every
8
+ * block, intra-domain imports dissolved, cross-domain imports rewritten to
9
+ * ./<domain>.js. Every capability of every source file is preserved here;
10
+ * the pure re-export barrels (storage/index.ts) folded their surface into this file directly.
11
+ */
12
+ import { mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
13
+ import { dirname, join, relative, resolve, sep } from "node:path";
14
+ import { tmpdir } from "node:os";
15
+ import { artifactmanifest, artifactnotfound, sha256, syncresult, validationerror, workingset } from "./foundation.js";
16
+ /* ════════════════════════════════════════════════════════════════════ */
17
+ /* Section 2: memory/objects.ts — memory objects and compute results are serializable contracts between storage and runtime. */
18
+ /* ════════════════════════════════════════════════════════════════════ */
19
+ /**
20
+ * memory objects and compute results are serializable contracts between storage and runtime.
21
+ */
22
+ export function memoryobject(options = {}) {
23
+ const buffer = tobytes(options.buffer ?? options.data ?? new Uint8Array(0));
24
+ return { id: options.id ?? `memory${Date.now().toString(36)}`, buffer, size: buffer.byteLength, type: options.type ?? "application/octet-stream", createdat: options.createdat ?? Date.now(), metadata: { ...(options.metadata ?? {}) } };
25
+ }
26
+ export function computeresult(options = {}) {
27
+ return { id: options.id ?? `result${Date.now().toString(36)}`, payload: options.payload, mimetype: options.mimetype, metadata: { ...(options.metadata ?? {}) }, processingtimems: options.processingtimems ?? 0, memoryusedbytes: options.memoryusedbytes ?? 0 };
28
+ }
29
+ export function tobytes(value) {
30
+ if (value instanceof Uint8Array)
31
+ return value;
32
+ if (value instanceof ArrayBuffer)
33
+ return new Uint8Array(value);
34
+ if (typeof value === "string")
35
+ return new TextEncoder().encode(value);
36
+ return new TextEncoder().encode(JSON.stringify(value));
37
+ }
38
+ /* ════════════════════════════════════════════════════════════════════ */
39
+ /* Section 3: memory/transforms.ts — transforms annotate byte movement without pretending remote storage is physical vram. */
40
+ /* ════════════════════════════════════════════════════════════════════ */
41
+ /**
42
+ * transforms annotate byte movement without pretending remote storage is physical vram.
43
+ */
44
+ export function transformtocompute(value, options = {}) {
45
+ const started = performance.now();
46
+ const object = memoryobject({ ...options, buffer: value?.buffer ?? value });
47
+ return { ...object, processingtimems: performance.now() - started, memoryusedbytes: object.size };
48
+ }
49
+ export function transformtostorage(value, options = {}) {
50
+ const payload = tobytes(value?.payload ?? value?.buffer ?? value);
51
+ return computeresult({ id: value?.id, payload, mimetype: options.mimetype ?? value?.mimetype ?? "application/octet-stream", metadata: options.metadata ?? value?.metadata, processingtimems: value?.processingtimems, memoryusedbytes: payload.byteLength });
52
+ }
53
+ /* ════════════════════════════════════════════════════════════════════ */
54
+ /* Section 4: memory/modes.ts — memory modes expose the same byte contract with different backing choices. */
55
+ /* ════════════════════════════════════════════════════════════════════ */
56
+ /**
57
+ * memory modes expose the same byte contract with different backing choices.
58
+ */
59
+ export function internalmemory(initial = {}) {
60
+ const values = new Map(Object.entries(initial).map(([key, value]) => [key, modetobytes(value)]));
61
+ return {
62
+ mode: "internal",
63
+ async put(key, value) { values.set(key, modetobytes(value)); return { key, bytes: values.get(key).byteLength }; },
64
+ async get(key) { return values.get(key) ?? null; },
65
+ async delete(key) { values.delete(key); },
66
+ async list() { return [...values.keys()]; }
67
+ };
68
+ }
69
+ export function externalmemory(storage) {
70
+ if (!storage?.put || !storage?.get)
71
+ throw new TypeError("external memory requires storage adapter");
72
+ return {
73
+ mode: "external",
74
+ async put(key, value) { return storage.put({ key, data: modetobytes(value) }); },
75
+ async get(key) { try {
76
+ return await storage.get(key);
77
+ }
78
+ catch (error) {
79
+ if (error.code === "ARTIFACT_NOT_FOUND")
80
+ return null;
81
+ throw error;
82
+ } },
83
+ async delete(key) { return storage.delete(key); },
84
+ async list(prefix) { return storage.list(prefix); }
85
+ };
86
+ }
87
+ export function physicalmemory(options = {}) {
88
+ if (!options.path)
89
+ throw new TypeError("physical memory requires a path");
90
+ return { mode: "physical", path: options.path, put: options.put, get: options.get, delete: options.delete, list: options.list };
91
+ }
92
+ export function vectorizedmemory() {
93
+ const vectors = new Map();
94
+ return {
95
+ mode: "vectorized",
96
+ async put(key, vector) { assertvector(vector); vectors.set(key, [...vector]); return { key, dimensions: vector.length }; },
97
+ async get(key) { return vectors.get(key) ?? null; },
98
+ async average(keys) { const selected = keys.map((key) => vectors.get(key)).filter(Boolean); if (!selected.length)
99
+ return null; const size = selected[0].length; const result = Array.from({ length: size }, () => 0); for (const vector of selected)
100
+ for (let index = 0; index < size; index += 1)
101
+ result[index] += vector[index] / selected.length; return result; },
102
+ async list() { return [...vectors.keys()]; }
103
+ };
104
+ }
105
+ export function librarymemory(factory) {
106
+ if (typeof factory !== "function")
107
+ throw new TypeError("library memory requires a factory");
108
+ return { mode: "library", async load(options) { return factory(options); } };
109
+ }
110
+ function modetobytes(value) {
111
+ if (value instanceof Uint8Array)
112
+ return value;
113
+ if (typeof value === "string")
114
+ return new TextEncoder().encode(value);
115
+ return new TextEncoder().encode(JSON.stringify(value));
116
+ }
117
+ function assertvector(vector) {
118
+ if (!Array.isArray(vector) || vector.length === 0 || vector.some((value) => !Number.isFinite(value)))
119
+ throw new TypeError("vector must be a non empty numeric array");
120
+ }
121
+ /* ════════════════════════════════════════════════════════════════════ */
122
+ /* Section 5: memory/targets.ts — storage targets describe provider intent without importing a provider client. */
123
+ /* ════════════════════════════════════════════════════════════════════ */
124
+ /**
125
+ * storage targets describe provider intent without importing a provider client.
126
+ */
127
+ const types = new Set(["github", "gitlab", "forgejo", "gitea", "huggingface", "kaggle", "modelscope", "filehosting"]);
128
+ export function targetfactory(type, options = {}) {
129
+ if (!types.has(type))
130
+ throw new TypeError(`unknown memory target: ${type}`);
131
+ if (type === "github" || type === "gitlab" || type === "forgejo" || type === "gitea")
132
+ return { type, platform: type, owner: options.owner, repo: options.repo, branch: options.branch ?? "main", path: options.path, token: options.token };
133
+ if (type === "huggingface")
134
+ return { type, space: options.space, revision: options.revision ?? "main", path: options.path, token: options.token };
135
+ if (type === "kaggle")
136
+ return { type, dataset: options.dataset, sslverification: options.sslverification ?? true, path: options.path, token: options.token };
137
+ if (type === "modelscope")
138
+ return { type, namespace: options.namespace, repo: options.repo, revision: options.revision ?? "master", path: options.path, token: options.token };
139
+ return { type, host: options.host, path: options.path, method: options.method ?? "s3compatible", token: options.token };
140
+ }
141
+ export function targeturi(target) {
142
+ if (target.type === "github" || target.type === "gitlab" || target.type === "forgejo" || target.type === "gitea")
143
+ return `${target.type}://${target.owner}/${target.repo}/${target.path}`;
144
+ if (target.type === "huggingface")
145
+ return `hf://${target.space}/${target.path}`;
146
+ if (target.type === "kaggle")
147
+ return `kaggle://${target.dataset}/${target.path}`;
148
+ if (target.type === "modelscope")
149
+ return `modelscope://${target.namespace}/${target.repo}/${target.path}`;
150
+ return `${target.method}://${target.host}/${target.path}`;
151
+ }
152
+ /* ════════════════════════════════════════════════════════════════════ */
153
+ /* Section 6: memory/engine.ts — memory engine loads from the first backend, persists to every backend and */
154
+ /* ════════════════════════════════════════════════════════════════════ */
155
+ /**
156
+ * memory engine loads from the first backend, persists to every backend and
157
+ * bounds the hot working set without changing the default unbounded behavior.
158
+ */
159
+ /** Creates a storage-backed memory engine with optional LRU working-set limits. */
160
+ export function memoryengine(options = {}) {
161
+ const backends = options.backends ?? [];
162
+ const maxentries = limit(options.maxentries, "maxentries");
163
+ const maxbytes = limit(options.maxbytes, "maxbytes");
164
+ const values = new Map();
165
+ let usedbytes = 0;
166
+ let hits = 0;
167
+ let misses = 0;
168
+ let evictions = 0;
169
+ async function load(key) {
170
+ if (!key)
171
+ throw new TypeError("memory key is required");
172
+ if (values.has(key)) {
173
+ hits += 1;
174
+ return touch(key);
175
+ }
176
+ misses += 1;
177
+ let last;
178
+ for (const backend of backends) {
179
+ try {
180
+ const value = await backend.get(key);
181
+ if (value == null)
182
+ continue;
183
+ const object = memoryobject({ id: key, buffer: value.data ?? value, type: value.contenttype ?? value.type, metadata: value.metadata });
184
+ cache(key, object);
185
+ return object;
186
+ }
187
+ catch (error) {
188
+ last = error;
189
+ }
190
+ }
191
+ if (last)
192
+ throw new Error(`memory engine load failed for key "${key}": ${last.message}`, { cause: last });
193
+ throw new Error(`memory engine load failed for key "${key}": not found`);
194
+ }
195
+ async function persist(key, data, options = {}) {
196
+ if (!key)
197
+ throw new TypeError("memory key is required");
198
+ const payload = tobytes(data?.payload ?? data?.buffer ?? data);
199
+ const object = memoryobject({ id: key, buffer: payload, type: options.mimetype ?? data?.mimetype, metadata: options.metadata ?? data?.metadata });
200
+ for (const backend of backends)
201
+ await backend.put(key, { data: object.buffer, contenttype: object.type, metadata: object.metadata });
202
+ cache(key, object);
203
+ return object;
204
+ }
205
+ function release(key) {
206
+ const object = values.get(key);
207
+ if (object)
208
+ usedbytes -= object.buffer.byteLength;
209
+ values.delete(key);
210
+ }
211
+ async function safeload(key) { try {
212
+ return { success: true, data: await load(key) };
213
+ }
214
+ catch (error) {
215
+ return { success: false, error };
216
+ } }
217
+ async function sync(key, options = {}) {
218
+ const sourceindex = Number(options.sourceindex ?? 0);
219
+ const source = backends[sourceindex];
220
+ if (!source)
221
+ throw new TypeError("memory sync source backend is missing");
222
+ const targets = backends.filter((_backend, index) => index !== sourceindex);
223
+ return syncbackends(source, targets, key, options);
224
+ }
225
+ function capabilities() { return backends.map((backend, index) => ({ index, capabilities: storagecapabilities(backend) })); }
226
+ function stats() { return { entries: values.size, bytes: usedbytes, hits, misses, evictions, maxentries, maxbytes }; }
227
+ return { load, persist, release, safeload, sync, capabilities, stats, transformtocompute, transformtostorage, list() { return [...values.keys()]; } };
228
+ function cache(key, object) {
229
+ const previous = values.get(key);
230
+ if (previous)
231
+ usedbytes -= previous.buffer.byteLength;
232
+ values.delete(key);
233
+ if (object.buffer.byteLength > maxbytes || maxentries === 0)
234
+ return;
235
+ values.set(key, object);
236
+ usedbytes += object.buffer.byteLength;
237
+ while (values.size > maxentries || usedbytes > maxbytes) {
238
+ const oldest = values.keys().next().value;
239
+ const evicted = values.get(oldest);
240
+ values.delete(oldest);
241
+ usedbytes -= evicted.buffer.byteLength;
242
+ evictions += 1;
243
+ }
244
+ }
245
+ function touch(key) {
246
+ const object = values.get(key);
247
+ values.delete(key);
248
+ values.set(key, object);
249
+ return object;
250
+ }
251
+ }
252
+ function limit(value, name) {
253
+ if (value === undefined)
254
+ return Infinity;
255
+ const numeric = Number(value);
256
+ if (!Number.isInteger(numeric) || numeric < 0)
257
+ throw new TypeError(`${name} must be a non-negative integer`);
258
+ return numeric;
259
+ }
260
+ /* ════════════════════════════════════════════════════════════════════ */
261
+ /* Section 7: memory/planner.ts — working-set planning keeps host memory operations declarative and caller-executed. */
262
+ /* ════════════════════════════════════════════════════════════════════ */
263
+ /**
264
+ * working-set planning keeps host memory operations declarative and caller-executed.
265
+ */
266
+ /** Validates a serializable working-set capacity budget. */
267
+ export function workingbudget(input = {}) {
268
+ return Object.freeze({ maxbytes: plannerlimit(input.maxbytes, "working-set maxbytes"), maxentries: plannerlimit(input.maxentries, "working-set maxentries"), maxage: optionalnonnegative(input.maxage, "working-set maxage") });
269
+ }
270
+ /** Selects bounded working-set candidates without materializing data or probing a host. */
271
+ export function workingadmission(items, options = {}) {
272
+ if (!Array.isArray(items))
273
+ throw new TypeError("working-set items must be an array");
274
+ const budget = workingbudget(options.budget);
275
+ const now = Number(options.now ?? Date.now());
276
+ if (!Number.isFinite(now) || now < 0)
277
+ throw new TypeError("working-set now is invalid");
278
+ const policy = validpolicy(options.policy ?? "lru");
279
+ const normalized = normalizeitems(items);
280
+ const admitted = [];
281
+ const deferred = [];
282
+ let usedbytes = 0;
283
+ for (const item of rank(normalized, policy)) {
284
+ const expired = item.expiresat !== null && item.expiresat <= now;
285
+ const overbytes = usedbytes + item.sizebytes > budget.maxbytes;
286
+ const overentries = admitted.length >= budget.maxentries;
287
+ if (expired || overbytes || overentries)
288
+ deferred.push(Object.freeze({ ...item, reason: expired ? "expired" : overbytes ? "bytebudget" : "entrybudget" }));
289
+ else {
290
+ admitted.push(item);
291
+ usedbytes += item.sizebytes;
292
+ }
293
+ }
294
+ return Object.freeze({ version: 1, policy, budget, usedbytes, admitted: Object.freeze(admitted), deferred: Object.freeze(deferred) });
295
+ }
296
+ /** Produces a host bridge plan that an explicit privileged adapter may execute. */
297
+ export function bridgeplan(input = {}) {
298
+ const operation = String(input.operation ?? "");
299
+ if (!bridgeoperations.includes(operation))
300
+ throw new TypeError("working-set bridge operation is invalid");
301
+ const sizebytes = plannerpositive(input.sizebytes, "working-set bridge sizebytes");
302
+ const capabilities = new Set(Array.isArray(input.capabilities) ? input.capabilities.map((value) => String(value)) : []);
303
+ const supported = capabilities.has(operation);
304
+ return Object.freeze({ version: 1, operation, sizebytes, state: supported ? "caller-executes" : "unsupported", preconditions: Object.freeze(supported ? ["explicit-consent", "host-adapter", "rollback-plan", "capacity-check"] : []), cleanup: Object.freeze({ required: supported, owner: "caller" }) });
305
+ }
306
+ /** Validates a materialized object record without reading storage or the local filesystem. */
307
+ export function materializationrecord(input = {}) {
308
+ const id = String(input.id ?? "");
309
+ const sha256 = String(input.sha256 ?? "").toLowerCase();
310
+ if (!id)
311
+ throw new TypeError("working-set materialization id is required");
312
+ if (!/^[a-f0-9]{64}$/.test(sha256))
313
+ throw new TypeError("working-set materialization sha256 is invalid");
314
+ return Object.freeze({ version: 1, id, sha256, sizebytes: plannerpositive(input.sizebytes, "working-set materialization sizebytes"), tier: validtier(input.tier ?? "l3"), state: validstate(input.state ?? "planned"), createdat: nonnegative(input.createdat ?? Date.now(), "working-set materialization createdat") });
315
+ }
316
+ /** Tracks materialization transitions and emits caller-owned cleanup plans without deleting resources. */
317
+ export function materializationledger(input = {}) {
318
+ const records = new Map();
319
+ const clock = typeof input.clock === "function" ? input.clock : () => Date.now();
320
+ function add(record) { const normalized = materializationrecord(record); if (records.has(normalized.id))
321
+ throw new TypeError(`working-set materialization id is duplicated: ${normalized.id}`); records.set(normalized.id, normalized); return normalized; }
322
+ function transition(id, state) { const current = records.get(String(id)); if (!current)
323
+ throw new TypeError("working-set materialization is unknown"); const next = validstate(state); if (!allowedtransition(current.state, next))
324
+ throw new TypeError(`working-set materialization transition is invalid: ${current.state} to ${next}`); const output = Object.freeze({ ...current, state: next, updatedat: nonnegative(clock(), "working-set materialization updatedat") }); records.set(output.id, output); return output; }
325
+ function cleanupplan(id) { const current = records.get(String(id)); if (!current)
326
+ throw new TypeError("working-set materialization is unknown"); return Object.freeze({ version: 1, id: current.id, sha256: current.sha256, state: "caller-cleans", reason: current.state === "cleaned" ? "already-cleaned" : "release-working-set" }); }
327
+ return Object.freeze({ add, transition, cleanupplan, list: () => Object.freeze([...records.values()]) });
328
+ }
329
+ const bridgeoperations = Object.freeze(["temporaryfile", "mmap", "tmpfs", "zram", "swap"]);
330
+ const policies = new Set(["lru", "sizeaware", "ttlfirst"]);
331
+ const tiers = new Set(["l1", "l2", "l3", "l4"]);
332
+ const states = new Set(["planned", "prepared", "verified", "released", "cleaned", "failed"]);
333
+ function normalizeitems(input) {
334
+ const ids = new Set();
335
+ return input.map((value, index) => {
336
+ const id = String(value?.id ?? "");
337
+ if (!id || ids.has(id))
338
+ throw new TypeError("working-set item id must be unique");
339
+ ids.add(id);
340
+ return Object.freeze({ id, sizebytes: plannerpositive(value.sizebytes, "working-set item sizebytes"), priority: Number(value.priority ?? 0), lastusedat: nonnegative(value.lastusedat ?? 0, "working-set item lastusedat"), expiresat: value.expiresat === undefined ? null : nonnegative(value.expiresat, "working-set item expiresat"), index });
341
+ });
342
+ }
343
+ function rank(items, policy) {
344
+ return [...items].sort((left, right) => {
345
+ if (right.priority !== left.priority)
346
+ return right.priority - left.priority;
347
+ if (policy === "lru" && right.lastusedat !== left.lastusedat)
348
+ return right.lastusedat - left.lastusedat;
349
+ if (policy === "sizeaware" && left.sizebytes !== right.sizebytes)
350
+ return left.sizebytes - right.sizebytes;
351
+ if (policy === "ttlfirst" && (left.expiresat ?? Infinity) !== (right.expiresat ?? Infinity))
352
+ return (left.expiresat ?? Infinity) - (right.expiresat ?? Infinity);
353
+ return left.index - right.index;
354
+ });
355
+ }
356
+ function plannerlimit(value, name) { return value === undefined ? Infinity : nonnegative(value, name); }
357
+ function plannerpositive(value, name) { const numeric = nonnegative(value, name); if (numeric < 1)
358
+ throw new TypeError(`${name} must be plannerpositive`); return numeric; }
359
+ function nonnegative(value, name) { const numeric = Number(value); if (!Number.isSafeInteger(numeric) || numeric < 0)
360
+ throw new TypeError(`${name} must be a non-negative safe integer`); return numeric; }
361
+ function optionalnonnegative(value, name) { return value === undefined ? null : nonnegative(value, name); }
362
+ function validpolicy(value) { if (!policies.has(value))
363
+ throw new TypeError("working-set policy is invalid"); return value; }
364
+ function validtier(value) { if (!tiers.has(value))
365
+ throw new TypeError("working-set tier is invalid"); return value; }
366
+ function validstate(value) { if (!states.has(value))
367
+ throw new TypeError("working-set materialization state is invalid"); return value; }
368
+ function allowedtransition(current, next) { if (next === "failed")
369
+ return current !== "cleaned"; return new Set(["planned:prepared", "prepared:verified", "verified:released", "released:cleaned"]).has(`${current}:${next}`); }
370
+ /* ════════════════════════════════════════════════════════════════════ */
371
+ /* Section 8: memory/bridge.ts — memory bridges materialize and clear temporary working sets. */
372
+ /* ════════════════════════════════════════════════════════════════════ */
373
+ /**
374
+ * memory bridges materialize and clear temporary working sets.
375
+ */
376
+ export function localmemory(options = {}) {
377
+ const base = options.base ?? tmpdir();
378
+ return {
379
+ async prepare(job) { const location = await mkdtemp(join(base, "saddlejob")); return workingset(job.id, location, join(location, "resultbin")); },
380
+ async sync(set, bytes) { await mkdir(set.location, { recursive: true }); await writeFile(set.resultpath, bytes); return syncresult(bytes.byteLength, set.resultpath); },
381
+ async cleanup(set) { await rm(set.location, { recursive: true, force: true }); }
382
+ };
383
+ }
384
+ /* ════════════════════════════════════════════════════════════════════ */
385
+ /* Section 9: storage/adapter.ts — storage adapters keep remote services out of the engine core. */
386
+ /* ════════════════════════════════════════════════════════════════════ */
387
+ /**
388
+ * storage adapters keep remote services out of the engine core.
389
+ */
390
+ export function storageadapter(methods) {
391
+ const required = ["put", "get", "head", "delete", "list"];
392
+ for (const name of required)
393
+ if (typeof methods?.[name] !== "function")
394
+ throw new TypeError(`storage adapter requires ${name}`);
395
+ return methods;
396
+ }
397
+ /* ════════════════════════════════════════════════════════════════════ */
398
+ /* Section 10: storage/memory.ts — memory storage keeps bytes in a bounded process-local map for browser workers, Deno, Bun and tests. */
399
+ /* ════════════════════════════════════════════════════════════════════ */
400
+ /**
401
+ * memory storage keeps bytes in a bounded process-local map for browser workers, Deno, Bun and tests.
402
+ */
403
+ /** Creates a transport-neutral in-memory storage adapter with optional capacity limits. */
404
+ export function memorystorage(options = {}) {
405
+ const values = new Map();
406
+ const maxbytes = options.maxbytes === undefined ? Number.POSITIVE_INFINITY : Number(options.maxbytes);
407
+ if ((!Number.isFinite(maxbytes) && maxbytes !== Number.POSITIVE_INFINITY) || maxbytes < 0)
408
+ throw new TypeError("memory storage maxbytes is invalid");
409
+ let usedbytes = 0;
410
+ function manifest(key, data, input = {}) { return artifactmanifest({ key, sizebytes: data.byteLength, sha256: sha256(data), contenttype: input.contenttype ?? "application/octet-stream", createdat: input.createdat ?? Date.now(), metadata: input.metadata }); }
411
+ function copy(value) { return new Uint8Array(value); }
412
+ function ensurecapacity(previous, next) { if (usedbytes - previous + next > maxbytes) {
413
+ const error = new Error("memory storage capacity exceeded");
414
+ error.code = "STORAGE_CAPACITY";
415
+ throw error;
416
+ } }
417
+ return storageadapter({
418
+ async put(input = {}) { const key = String(input.key ?? ""); if (!key)
419
+ throw new TypeError("memory storage key is required"); const data = copy(input.data ?? new Uint8Array()); const previous = values.get(key)?.data?.byteLength ?? 0; ensurecapacity(previous, data.byteLength); const item = { data, manifest: manifest(key, data, input) }; values.set(key, item); usedbytes += data.byteLength - previous; return { ...item.manifest }; },
420
+ async get(key) { const item = values.get(String(key)); if (!item) {
421
+ const error = new Error(`artifact not found: ${key}`);
422
+ error.code = "ARTIFACT_NOT_FOUND";
423
+ throw error;
424
+ } return copy(item.data); },
425
+ async head(key) { const item = values.get(String(key)); return item ? { ...item.manifest } : null; },
426
+ async delete(key) { const value = values.get(String(key)); if (!value)
427
+ return false; values.delete(String(key)); usedbytes -= value.data.byteLength; return true; },
428
+ async list(prefix = "") { return [...values].filter(([key]) => key.startsWith(String(prefix))).map(([, value]) => ({ ...value.manifest })); },
429
+ usage() { return { usedbytes, maxbytes }; }
430
+ });
431
+ }
432
+ /* ════════════════════════════════════════════════════════════════════ */
433
+ /* Section 11: storage/cache.ts — tiered cache keeps a bounded hot tier and an optional persistent cold tier with stale-while-revalidate. */
434
+ /* ════════════════════════════════════════════════════════════════════ */
435
+ /**
436
+ * tiered cache keeps a bounded hot tier and an optional persistent cold tier with stale-while-revalidate.
437
+ */
438
+ /** Creates a cache with caller supplied encode, decode, clock and persistent storage policies. */
439
+ export function tieredcache(options = {}) {
440
+ const hot = new Map();
441
+ const maxentries = Number(options.maxentries ?? 256);
442
+ const ttl = Number(options.ttl ?? 300000);
443
+ const stale = Number(options.stale ?? ttl);
444
+ const now = options.now ?? (() => Date.now());
445
+ const cold = options.storage;
446
+ const encode = options.encode ?? ((value) => new TextEncoder().encode(JSON.stringify(value)));
447
+ const decode = options.decode ?? ((bytes) => JSON.parse(new TextDecoder().decode(bytes)));
448
+ const stats = { hits: 0, misses: 0, stalehits: 0, evictions: 0, revalidations: 0 };
449
+ function readhot(key) {
450
+ const item = hot.get(key);
451
+ if (!item)
452
+ return null;
453
+ const current = now();
454
+ if (current <= item.expires) {
455
+ stats.hits += 1;
456
+ return { value: item.value, fresh: true };
457
+ }
458
+ if (current <= item.stale) {
459
+ stats.stalehits += 1;
460
+ return { value: item.value, fresh: false };
461
+ }
462
+ hot.delete(key);
463
+ return null;
464
+ }
465
+ function writehot(key, value, options = {}) {
466
+ if (hot.size >= maxentries && !hot.has(key)) {
467
+ hot.delete(hot.keys().next().value);
468
+ stats.evictions += 1;
469
+ }
470
+ const current = now();
471
+ hot.set(key, { value, expires: current + Number(options.ttl ?? ttl), stale: current + Number(options.stale ?? stale) });
472
+ return value;
473
+ }
474
+ async function get(key, options = {}) {
475
+ const hotvalue = readhot(key);
476
+ if (hotvalue?.fresh || (hotvalue && options.allowstale !== false))
477
+ return hotvalue.value;
478
+ if (!cold) {
479
+ stats.misses += 1;
480
+ return null;
481
+ }
482
+ try {
483
+ const value = decode(await cold.get(key));
484
+ writehot(key, value, options);
485
+ return value;
486
+ }
487
+ catch {
488
+ stats.misses += 1;
489
+ return null;
490
+ }
491
+ }
492
+ async function set(key, value, valueoptions = {}) { writehot(key, value, valueoptions); if (cold)
493
+ await cold.put({ key, data: encode(value), contenttype: "application/json" }); return value; }
494
+ async function getorload(key, loader, options = {}) {
495
+ if (typeof loader !== "function")
496
+ throw new TypeError("cache loader must be a function");
497
+ const current = readhot(key);
498
+ if (current?.fresh)
499
+ return current.value;
500
+ if (current && options.allowstale !== false) {
501
+ stats.revalidations += 1;
502
+ Promise.resolve(loader()).then((value) => set(key, value, options)).catch(() => undefined);
503
+ return current.value;
504
+ }
505
+ const value = await loader();
506
+ return set(key, value, options);
507
+ }
508
+ async function remove(key) { hot.delete(key); await cold?.delete?.(key); }
509
+ function clear() { hot.clear(); }
510
+ function inspect() { return { ...stats, hotentries: hot.size, maxentries, ttl, stale }; }
511
+ return { get, set, getorload, delete: remove, clear, inspect };
512
+ }
513
+ /* ════════════════════════════════════════════════════════════════════ */
514
+ /* Section 12: storage/checksum.ts — byte collection and hashing are grouped because every storage adapter uses them. */
515
+ /* ════════════════════════════════════════════════════════════════════ */
516
+ /**
517
+ * byte collection and hashing are grouped because every storage adapter uses them.
518
+ */
519
+ export { sha256 };
520
+ export async function collectbytes(input) {
521
+ if (input instanceof Uint8Array)
522
+ return input;
523
+ const chunks = [];
524
+ let size = 0;
525
+ for await (const chunk of input) {
526
+ chunks.push(chunk);
527
+ size += chunk.byteLength;
528
+ }
529
+ const output = new Uint8Array(size);
530
+ let offset = 0;
531
+ for (const chunk of chunks) {
532
+ output.set(chunk, offset);
533
+ offset += chunk.byteLength;
534
+ }
535
+ return output;
536
+ }
537
+ /* ════════════════════════════════════════════════════════════════════ */
538
+ /* Section 13: storage/content.ts — content addressed storage deduplicates immutable bytes while keeping logical references separate. */
539
+ /* ════════════════════════════════════════════════════════════════════ */
540
+ /**
541
+ * content addressed storage deduplicates immutable bytes while keeping logical references separate.
542
+ */
543
+ /** Creates a content-addressed view over a caller supplied storage adapter. */
544
+ export function contentstorage(storage, options = {}) {
545
+ const objectprefix = options.objectprefix ?? "objects";
546
+ const refprefix = options.refprefix ?? "refs";
547
+ const encode = options.encode ?? ((value) => new TextEncoder().encode(JSON.stringify(value)));
548
+ const decode = options.decode ?? ((bytes) => JSON.parse(new TextDecoder().decode(bytes)));
549
+ if (typeof storage?.put !== "function" || typeof storage?.get !== "function" || typeof storage?.head !== "function")
550
+ throw new TypeError("content storage requires put, get and head");
551
+ async function put(input = {}) {
552
+ const data = await collectbytes(input.data);
553
+ const digest = sha256(data);
554
+ const objectkey = `${objectprefix}/${digest}`;
555
+ if (!(await storage.head(objectkey)))
556
+ await storage.put({ key: objectkey, data, contenttype: input.contenttype, metadata: { ...(input.metadata ?? {}), immutable: "true", sha256: digest } });
557
+ const reference = { version: 1, key: String(input.key), objectkey, sha256: digest, sizebytes: data.byteLength, contenttype: input.contenttype ?? "application/octet-stream", metadata: { ...(input.metadata ?? {}) } };
558
+ await storage.put({ key: `${refprefix}/${input.key}`, data: encode(reference), contenttype: "application/json" });
559
+ return reference;
560
+ }
561
+ async function get(key) {
562
+ const reference = decode(await storage.get(`${refprefix}/${key}`));
563
+ return storage.get(reference.objectkey);
564
+ }
565
+ async function head(key) {
566
+ try {
567
+ return decode(await storage.get(`${refprefix}/${key}`));
568
+ }
569
+ catch {
570
+ return null;
571
+ }
572
+ }
573
+ async function remove(key) {
574
+ const reference = await head(key);
575
+ if (!reference)
576
+ return false;
577
+ await storage.delete?.(`${refprefix}/${key}`);
578
+ return true;
579
+ }
580
+ return { put, get, head, delete: remove, capabilities: { immutableobjects: true, dedupe: true, references: true } };
581
+ }
582
+ /* ════════════════════════════════════════════════════════════════════ */
583
+ /* Section 14: storage/sync.ts — storage synchronization compares versioned manifests and keeps conflict policy explicit. */
584
+ /* ════════════════════════════════════════════════════════════════════ */
585
+ /**
586
+ * storage synchronization compares versioned manifests and keeps conflict policy explicit.
587
+ */
588
+ /** Describes capabilities exposed by a storage adapter without forcing optional methods. */
589
+ export function storagecapabilities(storage) {
590
+ return Object.freeze({ range: typeof storage?.getrange === "function", conditional: typeof storage?.putifmatch === "function", metadata: typeof storage?.head === "function", delete: typeof storage?.delete === "function" });
591
+ }
592
+ /** Creates a comparable object manifest from bytes and caller metadata. */
593
+ export async function objectmanifest(key, data, options = {}) {
594
+ const bytes = await collectbytes(data);
595
+ return { version: 1, key: String(key), sizebytes: bytes.byteLength, sha256: sha256(bytes), updatedat: Number(options.updatedat ?? Date.now()), etag: options.etag ?? sha256(bytes), metadata: { ...(options.metadata ?? {}) } };
596
+ }
597
+ /** Compares two manifests and classifies an update or conflict. */
598
+ export function comparemanifests(local, remote) {
599
+ if (!local && !remote)
600
+ return { state: "empty" };
601
+ if (!local)
602
+ return { state: "remoteonly", remote };
603
+ if (!remote)
604
+ return { state: "localonly", local };
605
+ if (local.sha256 === remote.sha256)
606
+ return { state: "identical", local, remote };
607
+ if (local.updatedat > remote.updatedat)
608
+ return { state: "localnewer", local, remote };
609
+ if (remote.updatedat > local.updatedat)
610
+ return { state: "remotenewer", local, remote };
611
+ return { state: "conflict", local, remote };
612
+ }
613
+ /** Synchronizes one logical object between two adapters with explicit conflict handling. */
614
+ export async function syncobject(source, target, key, options = {}) {
615
+ if (typeof source?.head !== "function" || typeof source?.get !== "function" || typeof target?.head !== "function" || typeof target?.put !== "function")
616
+ throw new TypeError("sync requires source and target head, get and put");
617
+ const sourcehead = await source.head(key);
618
+ const targethead = await target.head(key);
619
+ const comparison = comparemanifests(normalizemanifest(sourcehead, key), normalizemanifest(targethead, key));
620
+ if (["empty", "identical"].includes(comparison.state))
621
+ return { key: String(key), state: comparison.state, manifest: comparison.local ?? comparison.remote };
622
+ if (comparison.state === "conflict" && typeof options.resolve !== "function") {
623
+ const error = new Error(`storage conflict for key: ${key}`);
624
+ error.code = "STORAGE_CONFLICT";
625
+ error.retryable = false;
626
+ throw error;
627
+ }
628
+ if (comparison.state === "conflict") {
629
+ const choice = await options.resolve(comparison);
630
+ if (!["source", "target"].includes(choice))
631
+ throw new TypeError("sync conflict resolver must return source or target");
632
+ if (choice === "target")
633
+ return { key: String(key), state: "kepttarget", manifest: comparison.remote };
634
+ }
635
+ const data = await source.get(key);
636
+ const manifest = await objectmanifest(key, data, { updatedat: comparison.local?.updatedat ?? Date.now(), metadata: sourcehead?.metadata });
637
+ await target.put({ key: String(key), data, contenttype: sourcehead?.contenttype, metadata: { ...(sourcehead?.metadata ?? {}), sha256: manifest.sha256, updatedat: String(manifest.updatedat) } });
638
+ return { key: String(key), state: comparison.state === "conflict" ? "resolvedsource" : "copied", manifest };
639
+ }
640
+ /** Synchronizes one object to multiple backends and returns each outcome. */
641
+ export async function syncbackends(source, targets = [], key, options = {}) {
642
+ if (!Array.isArray(targets))
643
+ throw new TypeError("sync targets must be an array");
644
+ const results = [];
645
+ for (const target of targets) {
646
+ try {
647
+ results.push(await syncobject(source, target, key, options));
648
+ }
649
+ catch (error) {
650
+ results.push({ key: String(key), state: "failed", code: error.code ?? "STORAGE_SYNC_FAILED", message: error.message });
651
+ if (options.stoponerror)
652
+ break;
653
+ }
654
+ }
655
+ return results;
656
+ }
657
+ function normalizemanifest(value, key) { return value ? { ...value, key: String(value.key ?? key), sha256: value.sha256 ?? value.etag, updatedat: Number(value.updatedat ?? 0) } : null; }
658
+ /* ════════════════════════════════════════════════════════════════════ */
659
+ /* Section 15: storage/chunked.ts — chunked storage keeps large payloads split without forcing a database blob. */
660
+ /* ════════════════════════════════════════════════════════════════════ */
661
+ /**
662
+ * chunked storage keeps large payloads split without forcing a database blob.
663
+ */
664
+ export function chunkedstorage(storage, options = {}) {
665
+ const chunkbytes = options.chunkbytes;
666
+ if (!Number.isInteger(chunkbytes) || chunkbytes < 1)
667
+ throw new TypeError("chunkbytes must be a positive integer");
668
+ return {
669
+ async put(input) {
670
+ const data = await collectbytes(input.data);
671
+ const chunks = [];
672
+ for (let offset = 0; offset < data.byteLength; offset += chunkbytes) {
673
+ const index = chunks.length;
674
+ const key = `${input.key}/chunk${String(index).padStart(8, "0")}`;
675
+ const part = data.slice(offset, Math.min(offset + chunkbytes, data.byteLength));
676
+ const manifest = await storage.put({ key, data: part, contenttype: input.contenttype, metadata: { parent: input.key, index: String(index) } });
677
+ chunks.push({ key, sizebytes: part.byteLength, sha256: manifest.sha256 });
678
+ }
679
+ const manifest = { version: 1, key: input.key, sizebytes: data.byteLength, chunks, chunkbytes, sha256: sha256(data), contenttype: input.contenttype ?? "application/octet-stream", status: "complete", completed: chunks.length, updatedat: Date.now(), metadata: { ...(input.metadata ?? {}) } };
680
+ await storage.put({ key: `${input.key}/manifest`, data: new TextEncoder().encode(JSON.stringify(manifest)), contenttype: "application/json" });
681
+ return manifest;
682
+ },
683
+ async get(key) {
684
+ const raw = await storage.get(`${key}/manifest`);
685
+ const manifest = JSON.parse(new TextDecoder().decode(raw));
686
+ const parts = await Promise.all(manifest.chunks.map((chunk) => storage.get(chunk.key)));
687
+ const output = new Uint8Array(manifest.sizebytes);
688
+ let offset = 0;
689
+ for (const part of parts) {
690
+ output.set(part, offset);
691
+ offset += part.byteLength;
692
+ }
693
+ return output;
694
+ },
695
+ async getrange(key, start = 0, end) {
696
+ const manifest = await this.head(key);
697
+ if (!manifest)
698
+ throw new Error(`chunk manifest not found: ${key}`);
699
+ const from = Math.max(0, Number(start));
700
+ const to = Math.min(manifest.sizebytes, end === undefined ? manifest.sizebytes : Number(end));
701
+ if (!Number.isInteger(from) || !Number.isInteger(to) || from > to)
702
+ throw new TypeError("chunk range is invalid");
703
+ if (from === to)
704
+ return new Uint8Array();
705
+ const first = Math.floor(from / manifest.chunkbytes);
706
+ const last = Math.ceil(to / manifest.chunkbytes) - 1;
707
+ const parts = await Promise.all(manifest.chunks.slice(first, last + 1).map((chunk) => storage.get(chunk.key)));
708
+ const output = new Uint8Array(to - from);
709
+ let offset = 0;
710
+ for (let index = 0; index < parts.length; index += 1) {
711
+ const chunkstart = (first + index) * manifest.chunkbytes;
712
+ const begin = Math.max(from, chunkstart);
713
+ const finish = Math.min(to, chunkstart + parts[index].byteLength);
714
+ output.set(parts[index].slice(begin - chunkstart, finish - chunkstart), offset);
715
+ offset += finish - begin;
716
+ }
717
+ return output;
718
+ },
719
+ async head(key) { const raw = await storage.get(`${key}/manifest`).catch(() => null); return raw ? JSON.parse(new TextDecoder().decode(raw)) : null; },
720
+ async delete(key) { const manifest = await this.head(key); if (!manifest)
721
+ return; for (const chunk of manifest.chunks)
722
+ await storage.delete(chunk.key); await storage.delete(`${key}/manifest`); },
723
+ async list(prefix) { return storage.list(prefix); }
724
+ };
725
+ }
726
+ /* ════════════════════════════════════════════════════════════════════ */
727
+ /* Section 16: storage/local.ts — local storage is explicit, temporary friendly, and protected against traversal. */
728
+ /* ════════════════════════════════════════════════════════════════════ */
729
+ /**
730
+ * local storage is explicit, temporary friendly, and protected against traversal.
731
+ */
732
+ export function localstorage(root) {
733
+ const base = resolve(root);
734
+ function safepath(key) {
735
+ const normalized = String(key ?? "").replaceAll("\\", "/");
736
+ if (!normalized || normalized.startsWith("/") || normalized.split("/").includes(".."))
737
+ throw validationerror("storage key is not safe", { key });
738
+ const path = resolve(base, normalized);
739
+ if (path !== base && !path.startsWith(`${base}${sep}`))
740
+ throw validationerror("storage key escapes adapter root", { key });
741
+ return path;
742
+ }
743
+ function manifest(key, data, contenttype, metadata) {
744
+ return artifactmanifest({ key, sizebytes: data.byteLength, sha256: sha256(data), contenttype, createdat: Date.now(), metadata });
745
+ }
746
+ async function walk(directory, keys) {
747
+ let entries;
748
+ try {
749
+ entries = await readdir(directory, { withFileTypes: true });
750
+ }
751
+ catch (error) {
752
+ if (error.code === "ENOENT")
753
+ return;
754
+ throw error;
755
+ }
756
+ for (const entry of entries) {
757
+ const path = join(directory, entry.name);
758
+ if (entry.isDirectory())
759
+ await walk(path, keys);
760
+ else
761
+ keys.push(relative(base, path).split(sep).join("/"));
762
+ }
763
+ }
764
+ return storageadapter({
765
+ async put(input) { const path = safepath(input.key); const data = await collectbytes(input.data); await mkdir(dirname(path), { recursive: true }); await writeFile(path, data); return manifest(input.key, data, input.contenttype ?? "application/octet-stream", input.metadata); },
766
+ async get(key) { try {
767
+ return await readFile(safepath(key));
768
+ }
769
+ catch (error) {
770
+ if (error.code === "ENOENT")
771
+ throw artifactnotfound(key);
772
+ throw error;
773
+ } },
774
+ async head(key) { try {
775
+ const data = await this.get(key);
776
+ const file = await stat(safepath(key));
777
+ return manifest(key, data, "application/octet-stream", { mtime: String(file.mtimeMs) });
778
+ }
779
+ catch (error) {
780
+ if (error.name === "saddleerror" && error.code === "ARTIFACT_NOT_FOUND")
781
+ return null;
782
+ throw error;
783
+ } },
784
+ async delete(key) { try {
785
+ await rm(safepath(key));
786
+ }
787
+ catch (error) {
788
+ if (error.code !== "ENOENT")
789
+ throw error;
790
+ } },
791
+ async list(prefix = "") { const keys = []; await walk(safepath(prefix || "."), keys); return Promise.all(keys.map((key) => this.head(key))); }
792
+ });
793
+ }
794
+ /* ════════════════════════════════════════════════════════════════════ */
795
+ /* Section 17: storage/pool.ts — storage pools combine caller-owned adapters without selecting a provider or creating background work. */
796
+ /* ════════════════════════════════════════════════════════════════════ */
797
+ /**
798
+ * storage pools combine caller-owned adapters without selecting a provider or creating background work.
799
+ */
800
+ /** Creates a deterministic pool over explicit caller-owned storage adapters. */
801
+ export function storagepool(options = {}) {
802
+ const members = normalizemembers(options.members);
803
+ const clock = typeof options.clock === "function" ? options.clock : () => Date.now();
804
+ const metrics = { reads: 0, writes: 0, hits: 0, misses: 0, mismatches: 0, bytes: 0, attempts: 0, elapsedms: 0 };
805
+ async function read(key, options = {}) {
806
+ const normalizedkey = requiredkey(key);
807
+ const expectedsha = optionalsha(options.sha256);
808
+ const attempts = [];
809
+ const startedat = Number(clock());
810
+ const selected = selectable(members, options.memberids);
811
+ const budget = operationbudget(options.budget, selected.length);
812
+ metrics.reads += 1;
813
+ for (const member of selected.slice(0, budget.maxattempts)) {
814
+ if (options.signal?.aborted)
815
+ throw poolerror("STORAGE_POOL_ABORTED", "storage pool read was aborted", { key: normalizedkey, attempts });
816
+ if (elapsed(clock, startedat) > budget.maxmilliseconds)
817
+ throw poolerror("STORAGE_POOL_TIME_BUDGET", "storage pool read time budget was exceeded", { key: normalizedkey, attempts });
818
+ try {
819
+ metrics.attempts += 1;
820
+ const manifest = await optionalhead(member.storage, normalizedkey);
821
+ const raw = await member.storage.get(normalizedkey);
822
+ const data = await collectbytes(raw?.data ?? raw);
823
+ if (data.byteLength > budget.maxbytes)
824
+ throw poolerror("STORAGE_POOL_BYTE_BUDGET", "storage pool read byte budget was exceeded", { key: normalizedkey, memberid: member.id, maxbytes: budget.maxbytes, sizebytes: data.byteLength });
825
+ const actualsha = sha256(data);
826
+ const requiredsha = expectedsha ?? manifest?.sha256;
827
+ if (requiredsha && actualsha !== requiredsha) {
828
+ metrics.mismatches += 1;
829
+ throw poolerror("STORAGE_POOL_DIGEST_MISMATCH", "storage pool read digest did not match", { key: normalizedkey, memberid: member.id, expectedsha: requiredsha, actualsha });
830
+ }
831
+ metrics.hits += 1;
832
+ metrics.bytes += data.byteLength;
833
+ metrics.elapsedms += elapsed(clock, startedat);
834
+ return Object.freeze({ version: 1, key: normalizedkey, memberid: member.id, data, sha256: actualsha, verified: Boolean(requiredsha), manifest: manifest ?? null, attempts: Object.freeze(attempts), budget, readat: Number(clock()) });
835
+ }
836
+ catch (error) {
837
+ attempts.push(attempt(member.id, error));
838
+ }
839
+ }
840
+ metrics.misses += 1;
841
+ metrics.elapsedms += elapsed(clock, startedat);
842
+ throw poolerror("STORAGE_POOL_READ_FAILED", "storage pool could not read a verified object", { key: normalizedkey, attempts });
843
+ }
844
+ async function put(input = {}, options = {}) {
845
+ const key = requiredkey(input.key);
846
+ const data = await collectbytes(input.data);
847
+ const digest = sha256(data);
848
+ const selected = writeselection(selectable(members, options.memberids), options.mode);
849
+ const budget = operationbudget(options.budget, selected.length);
850
+ if (data.byteLength > budget.maxbytes)
851
+ throw poolerror("STORAGE_POOL_BYTE_BUDGET", "storage pool write byte budget was exceeded", { key, maxbytes: budget.maxbytes, sizebytes: data.byteLength });
852
+ const quorum = positiveinteger(options.quorum ?? 1, "storage pool quorum");
853
+ if (quorum > selected.length)
854
+ throw new RangeError("storage pool quorum exceeds selected members");
855
+ const results = [];
856
+ metrics.writes += 1;
857
+ const startedat = Number(clock());
858
+ for (const member of selected.slice(0, budget.maxattempts)) {
859
+ if (options.signal?.aborted) {
860
+ results.push({ memberid: member.id, state: "skipped", code: "STORAGE_POOL_ABORTED" });
861
+ break;
862
+ }
863
+ if (elapsed(clock, startedat) > budget.maxmilliseconds) {
864
+ results.push({ memberid: member.id, state: "skipped", code: "STORAGE_POOL_TIME_BUDGET" });
865
+ break;
866
+ }
867
+ try {
868
+ metrics.attempts += 1;
869
+ const manifest = await member.storage.put({ ...input, key, data: new Uint8Array(data), metadata: { ...(input.metadata ?? {}), sha256: digest } });
870
+ if (manifest?.sha256 && manifest.sha256 !== digest)
871
+ throw poolerror("STORAGE_POOL_DIGEST_MISMATCH", "storage pool write digest did not match", { key, memberid: member.id, expectedsha: digest, actualsha: manifest.sha256 });
872
+ results.push({ memberid: member.id, state: "written", manifest: manifest ?? null });
873
+ }
874
+ catch (error) {
875
+ results.push({ memberid: member.id, state: "failed", code: error?.code ?? "STORAGE_POOL_WRITE_FAILED", message: String(error?.message ?? error) });
876
+ }
877
+ }
878
+ const written = results.filter((result) => result.state === "written");
879
+ metrics.bytes += data.byteLength * written.length;
880
+ metrics.elapsedms += elapsed(clock, startedat);
881
+ const output = Object.freeze({ version: 1, key, sha256: digest, sizebytes: data.byteLength, mode: options.mode ?? "fanout", quorum, state: written.length === selected.length ? "complete" : "partial", results: Object.freeze(results), written: written.length, budget, writtenat: Number(clock()) });
882
+ if (written.length < quorum)
883
+ throw poolerror("STORAGE_POOL_QUORUM_FAILED", "storage pool write quorum was not met", output);
884
+ return output;
885
+ }
886
+ async function readrange(key, start, end, options = {}) {
887
+ const normalizedkey = requiredkey(key);
888
+ const range = validrange(start, end);
889
+ const expectedsha = optionalsha(options.sha256);
890
+ const attempts = [];
891
+ const selected = selectable(members, options.memberids);
892
+ const budget = operationbudget(options.budget, selected.length);
893
+ const startedat = Number(clock());
894
+ metrics.reads += 1;
895
+ for (const member of selected.slice(0, budget.maxattempts)) {
896
+ if (options.signal?.aborted)
897
+ throw poolerror("STORAGE_POOL_ABORTED", "storage pool range read was aborted", { key: normalizedkey, range, attempts });
898
+ if (elapsed(clock, startedat) > budget.maxmilliseconds)
899
+ throw poolerror("STORAGE_POOL_TIME_BUDGET", "storage pool range read time budget was exceeded", { key: normalizedkey, range, attempts });
900
+ if (typeof member.storage.getrange !== "function") {
901
+ attempts.push({ memberid: member.id, code: "STORAGE_POOL_RANGE_UNSUPPORTED", message: "storage pool member does not support range reads" });
902
+ continue;
903
+ }
904
+ try {
905
+ metrics.attempts += 1;
906
+ const data = await collectbytes(await member.storage.getrange(normalizedkey, range.start, range.end));
907
+ if (data.byteLength !== range.end - range.start)
908
+ throw poolerror("STORAGE_POOL_RANGE_SIZE", "storage pool range result size did not match", { key: normalizedkey, range, memberid: member.id, sizebytes: data.byteLength });
909
+ const actualsha = sha256(data);
910
+ if (expectedsha && actualsha !== expectedsha)
911
+ throw poolerror("STORAGE_POOL_DIGEST_MISMATCH", "storage pool range digest did not match", { key: normalizedkey, range, memberid: member.id, expectedsha, actualsha });
912
+ metrics.hits += 1;
913
+ metrics.bytes += data.byteLength;
914
+ metrics.elapsedms += elapsed(clock, startedat);
915
+ return Object.freeze({ version: 1, key: normalizedkey, range, memberid: member.id, data, sha256: actualsha, verified: Boolean(expectedsha), attempts: Object.freeze(attempts), budget, readat: Number(clock()) });
916
+ }
917
+ catch (error) {
918
+ attempts.push(attempt(member.id, error));
919
+ }
920
+ }
921
+ metrics.misses += 1;
922
+ metrics.elapsedms += elapsed(clock, startedat);
923
+ throw poolerror("STORAGE_POOL_RANGE_FAILED", "storage pool could not read the requested range", { key: normalizedkey, range, attempts });
924
+ }
925
+ function repairplan(key, options = {}) {
926
+ const normalizedkey = requiredkey(key);
927
+ const sourceid = String(options.sourceid ?? "");
928
+ if (!members.some((member) => member.id === sourceid))
929
+ throw new TypeError("storage pool repair source member is unknown");
930
+ return Object.freeze({ version: 1, key: normalizedkey, sourceid, sha256: optionalsha(options.sha256), targets: selectable(members, options.memberids).filter((member) => member.id !== sourceid).map((member) => member.id), action: "caller-executes" });
931
+ }
932
+ function restoreplan(key, options = {}) {
933
+ const normalizedkey = requiredkey(key);
934
+ const selected = selectable(members, options.memberids);
935
+ const evidence = new Map((options.replicas ?? []).map((value) => [String(value?.memberid ?? ""), value?.verified === true]));
936
+ const candidates = selected.map((member) => ({ memberid: member.id, verified: evidence.get(member.id) === true })).sort((left, right) => Number(right.verified) - Number(left.verified) || left.memberid.localeCompare(right.memberid));
937
+ return Object.freeze({ version: 1, key: normalizedkey, sha256: optionalsha(options.sha256), action: "caller-restores", candidates: Object.freeze(candidates) });
938
+ }
939
+ return Object.freeze({ read, readrange, put, repairplan, restoreplan, members: () => members.map(describe), capabilities: () => members.map((member) => ({ id: member.id, priority: member.priority, capabilities: storagecapabilities(member.storage) })), metrics: () => ({ ...metrics }) });
940
+ }
941
+ function normalizemembers(input) {
942
+ if (!Array.isArray(input) || input.length === 0)
943
+ throw new TypeError("storage pool members must be a non-empty array");
944
+ const ids = new Set();
945
+ const members = input.map((value, index) => {
946
+ const id = String(value?.id ?? "");
947
+ if (!id)
948
+ throw new TypeError("storage pool member id is required");
949
+ if (ids.has(id))
950
+ throw new TypeError(`storage pool member id is duplicated: ${id}`);
951
+ ids.add(id);
952
+ if (typeof value?.storage?.get !== "function" || typeof value?.storage?.put !== "function")
953
+ throw new TypeError(`storage pool member requires get and put: ${id}`);
954
+ const priority = Number(value.priority ?? index);
955
+ if (!Number.isFinite(priority))
956
+ throw new TypeError(`storage pool member priority is invalid: ${id}`);
957
+ return Object.freeze({ id, storage: value.storage, priority });
958
+ });
959
+ return Object.freeze(members.sort((left, right) => left.priority - right.priority || left.id.localeCompare(right.id)));
960
+ }
961
+ function selectable(members, ids) {
962
+ if (ids === undefined)
963
+ return members;
964
+ if (!Array.isArray(ids) || ids.length === 0)
965
+ throw new TypeError("storage pool memberids must be a non-empty array");
966
+ const expected = new Set(ids.map((id) => String(id)));
967
+ const selected = members.filter((member) => expected.has(member.id));
968
+ if (selected.length !== expected.size)
969
+ throw new TypeError("storage pool memberids include an unknown member");
970
+ return selected;
971
+ }
972
+ function writeselection(members, mode = "fanout") {
973
+ const normalized = String(mode);
974
+ if (!new Set(["primary", "mirror", "fanout"]).has(normalized))
975
+ throw new TypeError("storage pool write mode is invalid");
976
+ return normalized === "primary" ? members.slice(0, 1) : members;
977
+ }
978
+ async function optionalhead(storage, key) { return typeof storage.head === "function" ? await storage.head(key) : null; }
979
+ function describe(member) { return Object.freeze({ id: member.id, priority: member.priority }); }
980
+ function requiredkey(value) { const key = String(value ?? ""); if (!key)
981
+ throw new TypeError("storage pool key is required"); return key; }
982
+ function optionalsha(value) { if (value === undefined || value === null)
983
+ return null; const digest = String(value); if (!/^[a-f0-9]{64}$/i.test(digest))
984
+ throw new TypeError("storage pool sha256 is invalid"); return digest.toLowerCase(); }
985
+ function positiveinteger(value, name) { const numeric = Number(value); if (!Number.isInteger(numeric) || numeric < 1)
986
+ throw new TypeError(`${name} must be a positive integer`); return numeric; }
987
+ function operationbudget(input = {}, fallbackattempts) { const budget = input ?? {}; return Object.freeze({ maxattempts: positiveinteger(budget.maxattempts ?? fallbackattempts, "storage pool budget maxattempts"), maxbytes: nonnegativebudget(budget.maxbytes, "storage pool budget maxbytes"), maxmilliseconds: nonnegativebudget(budget.maxmilliseconds, "storage pool budget maxmilliseconds") }); }
988
+ function nonnegativebudget(value, name) { if (value === undefined)
989
+ return Infinity; const numeric = Number(value); if (!Number.isSafeInteger(numeric) || numeric < 0)
990
+ throw new TypeError(`${name} must be a non-negative safe integer`); return numeric; }
991
+ function elapsed(clock, startedat) { return Math.max(0, Number(clock()) - startedat); }
992
+ function validrange(start, end) { const from = nonnegativebudget(start, "storage pool range start"); const to = nonnegativebudget(end, "storage pool range end"); if (!Number.isFinite(from) || !Number.isFinite(to) || to < from)
993
+ throw new TypeError("storage pool range is invalid"); return Object.freeze({ start: from, end: to }); }
994
+ function attempt(memberid, error) { return { memberid, code: error?.code ?? "STORAGE_POOL_READ_FAILED", message: String(error?.message ?? error) }; }
995
+ function poolerror(code, message, detail) { const error = new Error(message); error.code = code; error.detail = detail; return error; }
996
+ /* ════════════════════════════════════════════════════════════════════ */
997
+ /* Section 18: storage/s3compatible.ts — s3 compatible storage stays open by accepting a caller supplied signer. */
998
+ /* ════════════════════════════════════════════════════════════════════ */
999
+ /**
1000
+ * s3 compatible storage stays open by accepting a caller supplied signer.
1001
+ * List operations use the S3 ListObjectsV2 contract without owning credentials.
1002
+ */
1003
+ /** Creates an S3-compatible adapter with signed CRUD and paginated listing. */
1004
+ export function s3compatible(options = {}) {
1005
+ if (!options.endpoint || !options.bucket || typeof options.sign !== "function")
1006
+ throw new TypeError("s3 compatible storage requires endpoint bucket and sign");
1007
+ const endpoint = new URL(options.endpoint);
1008
+ const fetcher = options.fetcher ?? fetch;
1009
+ async function request(method, key, body, query = {}) {
1010
+ const signed = await options.sign({ method, endpoint, bucket: options.bucket, key, query, body });
1011
+ const url = new URL(signed.url, endpoint);
1012
+ if (!url.search && Object.keys(query).length)
1013
+ for (const [name, value] of Object.entries(query))
1014
+ url.searchParams.set(name, String(value));
1015
+ const response = await fetcher(url, { method, headers: signed.headers, body });
1016
+ if (!response.ok)
1017
+ throw new Error(`storage request failed with ${response.status}`);
1018
+ return response;
1019
+ }
1020
+ return storageadapter({
1021
+ async put(input) { const data = await (input.data instanceof Uint8Array ? input.data : await collectbytes(input.data)); await request("PUT", input.key, data); return { key: input.key, sizebytes: data.byteLength, sha256: await sha256(data), contenttype: input.contenttype ?? "application/octet-stream", createdat: Date.now(), metadata: { ...(input.metadata ?? {}) } }; },
1022
+ async get(key) { const response = await request("GET", key); return new Uint8Array(await response.arrayBuffer()); },
1023
+ async head(key) { try {
1024
+ const response = await request("HEAD", key);
1025
+ return { key, sizebytes: Number(response.headers.get("content-length") ?? 0), sha256: response.headers.get("etag") ?? "", contenttype: response.headers.get("content-type") ?? "application/octet-stream", createdat: Date.now(), metadata: {} };
1026
+ }
1027
+ catch {
1028
+ return null;
1029
+ } },
1030
+ async delete(key) { await request("DELETE", key); },
1031
+ async list(prefix = "", listoptions = {}) {
1032
+ const maxkeys = Math.max(1, Math.min(1000, Number(listoptions.maxkeys ?? options.maxkeys ?? 1000)));
1033
+ const maxpages = Math.max(1, Number(listoptions.maxpages ?? options.maxpages ?? 100));
1034
+ const entries = [];
1035
+ let continuation = listoptions.continuationToken;
1036
+ for (let page = 0; page < maxpages; page += 1) {
1037
+ const query = { "list-type": "2", prefix, "max-keys": maxkeys };
1038
+ if (continuation)
1039
+ query["continuation-token"] = continuation;
1040
+ const response = await request("GET", "", undefined, query);
1041
+ const parsed = parseListXml(await response.text());
1042
+ entries.push(...parsed.entries);
1043
+ if (!parsed.truncated || !parsed.nextToken)
1044
+ return entries;
1045
+ if (parsed.nextToken === continuation)
1046
+ throw new Error("s3 list continuation token did not advance");
1047
+ continuation = parsed.nextToken;
1048
+ }
1049
+ return entries;
1050
+ },
1051
+ });
1052
+ }
1053
+ function parseListXml(xml) {
1054
+ const entries = [];
1055
+ for (const block of xml.match(/<Contents\b[\s\S]*?<\/Contents>/gi) ?? []) {
1056
+ const key = xmlvalue(block, "Key");
1057
+ if (!key)
1058
+ continue;
1059
+ const etag = xmlvalue(block, "ETag");
1060
+ entries.push({ key, sizebytes: Number(xmlvalue(block, "Size") ?? 0), sha256: etag?.replace(/^"|"$/g, "") ?? "", contenttype: "application/octet-stream", createdat: Date.now(), metadata: { etag, lastmodified: xmlvalue(block, "LastModified"), storageclass: xmlvalue(block, "StorageClass") } });
1061
+ }
1062
+ const truncated = xmlvalue(xml, "IsTruncated") === "true";
1063
+ return { entries, truncated, nextToken: xmlvalue(xml, "NextContinuationToken") };
1064
+ }
1065
+ function xmlvalue(xml, name) { const match = String(xml).match(new RegExp(`<${name}>([\\s\\S]*?)</${name}>`, "i")); return match ? decodexml(match[1].trim()) : undefined; }
1066
+ /** Single-pass XML entity decode: the pattern never re-examines its own output, so a double-escaped `&amp;lt;` decodes once to the literal text `&lt;` and never again to `<`. */
1067
+ const XMLENTITIES = { amp: "&", lt: "<", gt: ">", quot: '"', "#39": "'" };
1068
+ function decodexml(value) { return String(value).replace(/&(amp|lt|gt|quot|#39);/g, (whole, entity) => XMLENTITIES[entity] ?? whole); }
1069
+ /* ════════════════════════════════════════════════════════════════════ */
1070
+ /* Section 19: storage/githubcontents.ts — github contents storage maps artifacts to repository files through an injected token. */
1071
+ /* ════════════════════════════════════════════════════════════════════ */
1072
+ /**
1073
+ * github contents storage maps artifacts to repository files through an injected token.
1074
+ */
1075
+ export function githubcontents(options = {}) {
1076
+ if (!options.baseurl || !options.owner || !options.repo || typeof options.token !== "function")
1077
+ throw new TypeError("github contents requires baseurl owner repo and token");
1078
+ const fetcher = options.fetcher ?? fetch;
1079
+ async function request(method, key, body) { const token = await options.token(); const response = await fetcher(new URL(`/repos/${options.owner}/${options.repo}/contents/${key}`, options.baseurl), { method, headers: { accept: "application/vnd.github+json", authorization: `Bearer ${token}`, "content-type": "application/json" }, body: body ? JSON.stringify(body) : undefined }); if (!response.ok)
1080
+ throw new Error(`github contents request failed with ${response.status}`); return response; }
1081
+ return storageadapter({
1082
+ async put(input) { const data = await collectbytes(input.data); let sha; try {
1083
+ sha = (await (await request("GET", input.key)).json()).sha;
1084
+ }
1085
+ catch { } const response = await request("PUT", input.key, { message: input.message ?? `saddle write ${input.key}`, content: Buffer.from(data).toString("base64"), branch: options.branch ?? "main", sha }); const result = await response.json(); return { key: input.key, sizebytes: data.byteLength, sha256: sha256(data), contenttype: input.contenttype ?? "application/octet-stream", createdat: Date.now(), metadata: { url: result.content?.download_url, commit: result.commit?.sha, ...(input.metadata ?? {}) } }; },
1086
+ async get(key) { const result = await (await request("GET", key)).json(); return new Uint8Array(Buffer.from(result.content.replaceAll("\n", ""), "base64")); },
1087
+ async head(key) { try {
1088
+ const result = await (await request("GET", key)).json();
1089
+ return { key, sizebytes: result.size, sha256: result.sha ?? "", contenttype: "application/octet-stream", createdat: Date.now(), metadata: { url: result.download_url } };
1090
+ }
1091
+ catch {
1092
+ return null;
1093
+ } },
1094
+ async delete(key) { const result = await (await request("GET", key)).json(); await request("DELETE", key, { message: `saddle delete ${key}`, sha: result.sha, branch: options.branch ?? "main" }); },
1095
+ async list(prefix = "") { const result = await (await request("GET", prefix)).json(); return (Array.isArray(result) ? result : []).filter((item) => item.type === "file").map((item) => ({ key: item.path, sizebytes: item.size, sha256: item.sha, contenttype: "application/octet-stream", createdat: Date.now(), metadata: { url: item.download_url } })); }
1096
+ });
1097
+ }
1098
+ /* ════════════════════════════════════════════════════════════════════ */
1099
+ /* Section 20: storage/filehosting.ts — file hosting adapter accepts a caller supplied request function for s3compatible or webdav. */
1100
+ /* ════════════════════════════════════════════════════════════════════ */
1101
+ /**
1102
+ * file hosting adapter accepts a caller supplied request function for s3compatible or webdav.
1103
+ */
1104
+ export function filehosting(options = {}) {
1105
+ if (!options.host || typeof options.request !== "function")
1106
+ throw new TypeError("file hosting requires host and request");
1107
+ const method = options.method ?? "s3compatible";
1108
+ return storageadapter({
1109
+ async put(input) { const data = await collectbytes(input.data); await options.request({ method: method === "webdav" ? "PUT" : "put", url: new URL(input.key, options.host).href, data, headers: { "content-type": input.contenttype ?? "application/octet-stream" } }); return { key: input.key, sizebytes: data.byteLength, sha256: sha256(data), contenttype: input.contenttype ?? "application/octet-stream", createdat: Date.now(), metadata: input.metadata ?? {} }; },
1110
+ async get(key) { const result = await options.request({ method: method === "webdav" ? "GET" : "get", url: new URL(key, options.host).href }); return result.data ?? result; },
1111
+ async head(key) { try {
1112
+ const result = await options.request({ method: "head", url: new URL(key, options.host).href });
1113
+ return { key, sizebytes: Number(result.headers?.["content-length"] ?? 0), sha256: result.headers?.etag ?? "", contenttype: result.headers?.["content-type"] ?? "application/octet-stream", createdat: Date.now(), metadata: {} };
1114
+ }
1115
+ catch {
1116
+ return null;
1117
+ } },
1118
+ async delete(key) { await options.request({ method: method === "webdav" ? "DELETE" : "delete", url: new URL(key, options.host).href }); },
1119
+ async list(prefix = "") { const result = await options.request({ method: method === "webdav" ? "PROPFIND" : "list", url: new URL(prefix, options.host).href }); return result.items ?? []; }
1120
+ });
1121
+ }
1122
+ /* ════════════════════════════════════════════════════════════════════ */
1123
+ /* Section 21: persistence/schema.ts — the schema descriptor is neutral so prisma drizzle mysql2 or another driver can map it. */
1124
+ /* ════════════════════════════════════════════════════════════════════ */
1125
+ /**
1126
+ * the schema descriptor is neutral so prisma drizzle mysql2 or another driver can map it.
1127
+ */
1128
+ export const schemadefinition = Object.freeze({
1129
+ jobs: { id: "text primary key", name: "text", status: "text", priority: "integer", input: "json", outputkey: "text", createdat: "integer", updatedat: "integer" },
1130
+ events: { id: "text primary key", jobid: "text", type: "text", at: "integer", data: "json" },
1131
+ sessions: { id: "text primary key", version: "integer", agentname: "text", originurl: "text", seed: "text", status: "text", startedat: "integer", finishedat: "integer", events: "json" },
1132
+ artifacts: { key: "text primary key", sizebytes: "bigint", sha256: "text", contenttype: "text", createdat: "integer", metadata: "json" },
1133
+ chunks: { id: "text primary key", artifactkey: "text", index: "integer", offset: "bigint", sizebytes: "integer", sha256: "text", storagekey: "text" },
1134
+ queueitems: { id: "text primary key", status: "text", attempts: "integer", payload: "json", result: "json", error: "json", createdat: "bigint", updatedat: "bigint" }
1135
+ });
1136
+ export function schemasql(options = {}) {
1137
+ const dialect = options.dialect ?? "mysql";
1138
+ const json = dialect === "postgres" ? "jsonb" : "json";
1139
+ const bigint = dialect === "sqlite" ? "integer" : "bigint";
1140
+ return [
1141
+ `create table if not exists jobs (id text primary key, name text not null, status text not null, priority integer not null, input ${json}, outputkey text, createdat ${bigint} not null, updatedat ${bigint} not null)`,
1142
+ `create table if not exists events (id text primary key, jobid text not null, type text not null, at ${bigint} not null, data ${json} not null)`,
1143
+ `create table if not exists sessions (id text primary key, version integer not null, agentname text not null, originurl text not null, seed text not null, status text not null, startedat ${bigint} not null, finishedat ${bigint}, events ${json} not null)`,
1144
+ `create table if not exists artifacts (key text primary key, sizebytes ${bigint} not null, sha256 text not null, contenttype text not null, createdat ${bigint} not null, metadata ${json} not null)`,
1145
+ `create table if not exists chunks (id text primary key, artifactkey text not null, chunkindex integer not null, byteoffset ${bigint} not null, sizebytes integer not null, sha256 text not null, storagekey text not null)`,
1146
+ `create table if not exists queueitems (id text primary key, status text not null, attempts integer not null, payload ${json} not null, result ${json}, error ${json}, createdat ${bigint} not null, updatedat ${bigint} not null)`
1147
+ ];
1148
+ }
1149
+ export function prismaschema() {
1150
+ return `model job { id String @id name String status String priority Int input Json? outputkey String? createdat BigInt updatedat BigInt }\nmodel event { id String @id jobid String type String at BigInt data Json }\nmodel session { id String @id version Int agentname String originurl String seed String status String startedat BigInt finishedat BigInt? events Json }\nmodel artifact { key String @id sizebytes BigInt sha256 String contenttype String createdat BigInt metadata Json }\nmodel chunk { id String @id artifactkey String chunkindex Int byteoffset BigInt sizebytes Int sha256 String storagekey String }`;
1151
+ }
1152
+ /* ════════════════════════════════════════════════════════════════════ */
1153
+ /* Section 22: persistence/adapter.ts — persistence adapters keep database and remote state outside the runtime core. */
1154
+ /* ════════════════════════════════════════════════════════════════════ */
1155
+ /**
1156
+ * persistence adapters keep database and remote state outside the runtime core.
1157
+ */
1158
+ export function persistenceadapter(methods) {
1159
+ const required = ["savejob", "getjob", "updatejob", "listjobs", "saveevent", "listevents", "savesession", "readsession", "saveartifact", "getartifact", "savechunk", "getchunks"];
1160
+ for (const name of required)
1161
+ if (typeof methods?.[name] !== "function")
1162
+ throw new TypeError(`persistence adapter requires ${name}`);
1163
+ return methods;
1164
+ }
1165
+ /* ════════════════════════════════════════════════════════════════════ */
1166
+ /* Section 23: persistence/memory.ts — memory persistence is the local baseline for tests and offline operation. */
1167
+ /* ════════════════════════════════════════════════════════════════════ */
1168
+ /**
1169
+ * memory persistence is the local baseline for tests and offline operation.
1170
+ */
1171
+ export function memorypersistence() {
1172
+ const jobs = new Map();
1173
+ const events = new Map();
1174
+ const sessions = new Map();
1175
+ const artifacts = new Map();
1176
+ const chunks = new Map();
1177
+ return persistenceadapter({
1178
+ async savejob(job) { jobs.set(job.id, structuredClone(job)); return jobs.get(job.id); },
1179
+ async getjob(id) { return jobs.get(id) ? structuredClone(jobs.get(id)) : null; },
1180
+ async updatejob(id, patch) { const current = jobs.get(id); if (!current)
1181
+ return null; const next = { ...current, ...patch, updatedat: Date.now() }; jobs.set(id, next); return structuredClone(next); },
1182
+ async listjobs(filter = {}) { return [...jobs.values()].filter((job) => Object.entries(filter).every(([key, value]) => job[key] === value)).map((job) => structuredClone(job)); },
1183
+ async saveevent(event) { const list = events.get(event.jobid) ?? []; list.push(structuredClone(event)); events.set(event.jobid, list); return event; },
1184
+ async listevents(jobid) { return (events.get(jobid) ?? []).map((event) => structuredClone(event)); },
1185
+ async savesession(session) { sessions.set(session.id, structuredClone(session)); return structuredClone(session); },
1186
+ async readsession(id) { return sessions.get(id) ? structuredClone(sessions.get(id)) : null; },
1187
+ async saveartifact(artifact) { artifacts.set(artifact.key, structuredClone(artifact)); return structuredClone(artifact); },
1188
+ async getartifact(key) { return artifacts.get(key) ? structuredClone(artifacts.get(key)) : null; },
1189
+ async savechunk(chunk) { chunks.set(chunk.id, structuredClone(chunk)); return structuredClone(chunk); },
1190
+ async getchunks(artifactkey) { return [...chunks.values()].filter((chunk) => chunk.artifactkey === artifactkey).sort((left, right) => left.index - right.index).map((chunk) => structuredClone(chunk)); }
1191
+ });
1192
+ }
1193
+ /* ════════════════════════════════════════════════════════════════════ */
1194
+ /* Section 24: persistence/sql.ts — sql persistence keeps query execution injected for mysql2 drizzle or another sql client. */
1195
+ /* ════════════════════════════════════════════════════════════════════ */
1196
+ /**
1197
+ * sql persistence keeps query execution injected for mysql2 drizzle or another sql client.
1198
+ */
1199
+ export function sqlpersistence(options = {}) {
1200
+ if (typeof options.query !== "function")
1201
+ throw new TypeError("sql persistence requires query");
1202
+ const table = options.table ?? { jobs: "jobs", events: "events", sessions: "sessions", artifacts: "artifacts", chunks: "chunks" };
1203
+ async function one(statement, values = []) { const result = await options.query(statement, values); return result?.rows?.[0] ?? result?.[0]?.[0] ?? result?.[0] ?? null; }
1204
+ async function many(statement, values = []) { const result = await options.query(statement, values); return result?.rows ?? result?.[0] ?? result ?? []; }
1205
+ return persistenceadapter({
1206
+ async savejob(job) { await options.query(`insert into ${table.jobs} (id,name,status,priority,input,outputkey,createdat,updatedat) values (?,?,?,?,?,?,?,?)`, [job.id, job.name, job.status, job.priority, JSON.stringify(job.input ?? null), job.outputkey ?? null, job.createdat, job.updatedat ?? job.createdat]); return job; },
1207
+ async getjob(id) { const row = await one(`select * from ${table.jobs} where id = ?`, [id]); return row ? normalizejob(row) : null; },
1208
+ async updatejob(id, patch) { const current = await this.getjob(id); if (!current)
1209
+ return null; const next = { ...current, ...patch, updatedat: Date.now() }; await options.query(`update ${table.jobs} set status = ?, priority = ?, input = ?, outputkey = ?, updatedat = ? where id = ?`, [next.status, next.priority, JSON.stringify(next.input ?? null), next.outputkey ?? null, next.updatedat, id]); return next; },
1210
+ async listjobs(filter = {}) { const rows = await many(`select * from ${table.jobs} order by createdat desc`, []); return rows.map(normalizejob).filter((job) => Object.entries(filter).every(([key, value]) => job[key] === value)); },
1211
+ async saveevent(event) { await options.query(`insert into ${table.events} (id,jobid,type,at,data) values (?,?,?,?,?)`, [event.id, event.jobid, event.type, event.at, JSON.stringify(event.data ?? {})]); return event; },
1212
+ async listevents(jobid) { return (await many(`select * from ${table.events} where jobid = ? order by at asc`, [jobid])).map((row) => ({ ...row, data: parsejson(row.data) })); },
1213
+ async savesession(session) { await options.query(`insert into ${table.sessions} (id,version,agentname,originurl,seed,status,startedat,finishedat,events) values (?,?,?,?,?,?,?,?,?)`, [session.id, session.version, session.agentname, session.originurl, session.seed, session.status, session.startedat, session.finishedat ?? null, JSON.stringify(session.events ?? [])]); return session; },
1214
+ async readsession(id) { const row = await one(`select * from ${table.sessions} where id = ?`, [id]); return row ? { ...row, events: parsejson(row.events) } : null; },
1215
+ async saveartifact(artifact) { await options.query(`insert into ${table.artifacts} (key,sizebytes,sha256,contenttype,createdat,metadata) values (?,?,?,?,?,?)`, [artifact.key, artifact.sizebytes, artifact.sha256, artifact.contenttype, artifact.createdat, JSON.stringify(artifact.metadata ?? {})]); return artifact; },
1216
+ async getartifact(key) { const row = await one(`select * from ${table.artifacts} where key = ?`, [key]); return row ? { ...row, metadata: parsejson(row.metadata) } : null; },
1217
+ async savechunk(chunk) { await options.query(`insert into ${table.chunks} (id,artifactkey,chunkindex,byteoffset,sizebytes,sha256,storagekey) values (?,?,?,?,?,?,?)`, [chunk.id, chunk.artifactkey, chunk.index, chunk.offset, chunk.sizebytes, chunk.sha256, chunk.storagekey]); return chunk; },
1218
+ async getchunks(artifactkey) { return (await many(`select * from ${table.chunks} where artifactkey = ? order by chunkindex asc`, [artifactkey])).map((row) => ({ ...row, index: row.index ?? row.chunkindex, offset: row.offset ?? row.byteoffset })); }
1219
+ });
1220
+ }
1221
+ export function mysql2persistence(pool, options = {}) { if (typeof pool?.execute !== "function")
1222
+ throw new TypeError("mysql2 pool requires execute"); return sqlpersistence({ ...options, query: async (statement, values) => pool.execute(statement, values) }); }
1223
+ function normalizejob(row) { return { ...row, input: parsejson(row.input) }; }
1224
+ function parsejson(value) { if (value == null || typeof value === "object")
1225
+ return value; try {
1226
+ return JSON.parse(value);
1227
+ }
1228
+ catch {
1229
+ return value;
1230
+ } }
1231
+ /* ════════════════════════════════════════════════════════════════════ */
1232
+ /* Section 25: persistence/drizzle.ts — drizzle persistence accepts a small repository object generated by the caller's schema. */
1233
+ /* ════════════════════════════════════════════════════════════════════ */
1234
+ /**
1235
+ * drizzle persistence accepts a small repository object generated by the caller's schema.
1236
+ */
1237
+ export function drizzlepersistence(repository) {
1238
+ const required = ["savejob", "getjob", "updatejob", "listjobs", "saveevent", "listevents", "savesession", "readsession", "saveartifact", "getartifact", "savechunk", "getchunks"];
1239
+ for (const name of required)
1240
+ if (typeof repository?.[name] !== "function")
1241
+ throw new TypeError(`drizzle repository requires ${name}`);
1242
+ return persistenceadapter(repository);
1243
+ }
1244
+ /* ════════════════════════════════════════════════════════════════════ */
1245
+ /* Section 26: persistence/prisma.ts — prisma persistence maps model delegates through an explicit model configuration. */
1246
+ /* ════════════════════════════════════════════════════════════════════ */
1247
+ /**
1248
+ * prisma persistence maps model delegates through an explicit model configuration.
1249
+ */
1250
+ export function prismapersistence(client, options = {}) {
1251
+ const models = { jobs: options.jobs ?? client?.job, events: options.events ?? client?.event, sessions: options.sessions ?? client?.session, artifacts: options.artifacts ?? client?.artifact, chunks: options.chunks ?? client?.chunk };
1252
+ for (const [name, model] of Object.entries(models))
1253
+ if (!model)
1254
+ throw new TypeError(`prisma model is missing: ${name}`);
1255
+ return persistenceadapter({
1256
+ async savejob(job) { return models.jobs.upsert({ where: { id: job.id }, create: job, update: job }); },
1257
+ async getjob(id) { return models.jobs.findUnique({ where: { id } }); },
1258
+ async updatejob(id, patch) { return models.jobs.update({ where: { id }, data: { ...patch, updatedat: Date.now() } }); },
1259
+ async listjobs(filter = {}) { return models.jobs.findMany({ where: filter, orderBy: { createdat: "desc" } }); },
1260
+ async saveevent(event) { return models.events.create({ data: event }); },
1261
+ async listevents(jobid) { return models.events.findMany({ where: { jobid }, orderBy: { at: "asc" } }); },
1262
+ async savesession(session) { return models.sessions.upsert({ where: { id: session.id }, create: session, update: session }); },
1263
+ async readsession(id) { return models.sessions.findUnique({ where: { id } }); },
1264
+ async saveartifact(artifact) { return models.artifacts.upsert({ where: { key: artifact.key }, create: artifact, update: artifact }); },
1265
+ async getartifact(key) { return models.artifacts.findUnique({ where: { key } }); },
1266
+ async savechunk(chunk) { return models.chunks.upsert({ where: { id: chunk.id }, create: chunk, update: chunk }); },
1267
+ async getchunks(artifactkey) { return models.chunks.findMany({ where: { artifactkey }, orderBy: { index: "asc" } }); }
1268
+ });
1269
+ }
1270
+ /* ════════════════════════════════════════════════════════════════════ */
1271
+ /* Section 27: persistence/migrations.ts — migration plans stay neutral so Prisma, Drizzle, MySQL2, Turso, and another SQL driver can map them. */
1272
+ /* ════════════════════════════════════════════════════════════════════ */
1273
+ /**
1274
+ * migration plans stay neutral so Prisma, Drizzle, MySQL2, Turso, and another SQL driver can map them.
1275
+ */
1276
+ export const migrationlist = Object.freeze([
1277
+ { version: 1, name: "baseoperational", tables: ["jobs", "events", "sessions", "artifacts", "chunks"] },
1278
+ { version: 2, name: "persistentqueue", tables: ["queueitems"] },
1279
+ { version: 3, name: "webhookdeliveries", tables: ["webhookdeliveries"] }
1280
+ ]);
1281
+ /** Returns pending migration statements for a dialect. */
1282
+ export function migrationplan(options = {}) { const current = options.current ?? 0; const dialect = options.dialect ?? "mysql"; return migrationlist.filter((migration) => migration.version > current).map((migration) => ({ ...migration, statements: migration.version === 2 ? [`create table if not exists queueitems (id text primary key, status text not null, attempts integer not null, payload json not null, result json, error json, createdat bigint not null, updatedat bigint not null)`] : migration.version === 3 ? [`create table if not exists webhookdeliveries (id text primary key, event text not null, receivedat bigint not null, processedat bigint, payload json not null)`] : [], dialect })); }
1283
+ /** Returns the latest schema version. */
1284
+ export function latestmigration() { return migrationlist.at(-1)?.version ?? 0; }
1285
+ //# sourceMappingURL=virtual.js.map