@wenathlan/saddle 2.0.151 → 2.0.153

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 (293) hide show
  1. package/README.md +3 -3
  2. package/biome.jsonc +12 -5
  3. package/dist/App.d.ts +5 -0
  4. package/dist/App.js +52 -0
  5. package/dist/Sol/Sol.d.ts +3 -0
  6. package/dist/Sol/Sol.js +46 -0
  7. package/dist/Sol/agentbrowser/agentbrowser.d.ts +9 -0
  8. package/dist/Sol/agentbrowser/agentbrowser.js +121 -0
  9. package/dist/Sol/architecture/architecture.d.ts +9 -0
  10. package/dist/Sol/architecture/architecture.js +93 -0
  11. package/dist/Sol/compute/compute.d.ts +9 -0
  12. package/dist/Sol/compute/compute.js +22 -0
  13. package/dist/Sol/console/console.d.ts +15 -0
  14. package/dist/Sol/console/console.js +292 -0
  15. package/dist/Sol/dashboard/dashboard.d.ts +10 -0
  16. package/dist/Sol/dashboard/dashboard.js +181 -0
  17. package/dist/Sol/docs/docs.d.ts +9 -0
  18. package/dist/Sol/docs/docs.js +28 -0
  19. package/dist/Sol/home/home.d.ts +35 -0
  20. package/dist/Sol/home/home.js +239 -0
  21. package/dist/Sol/integrations/integrations.d.ts +9 -0
  22. package/dist/Sol/integrations/integrations.js +83 -0
  23. package/dist/Sol/intro/intro.d.ts +7 -0
  24. package/dist/Sol/intro/intro.js +102 -0
  25. package/dist/Sol/login/login.d.ts +16 -0
  26. package/dist/Sol/login/login.js +49 -0
  27. package/dist/Sol/notfound/notfound.d.ts +9 -0
  28. package/dist/Sol/notfound/notfound.js +15 -0
  29. package/dist/Sol/onboarding/onboarding.d.ts +25 -0
  30. package/dist/Sol/onboarding/onboarding.js +60 -0
  31. package/dist/Sol/playground/playground.d.ts +9 -0
  32. package/dist/Sol/playground/playground.js +127 -0
  33. package/dist/Sol/register/register.d.ts +16 -0
  34. package/dist/Sol/register/register.js +193 -0
  35. package/dist/Sol/shell/Shell.d.ts +124 -0
  36. package/dist/Sol/shell/Shell.js +335 -0
  37. package/dist/Sol/wingets/ComputeBootladder.d.ts +6 -0
  38. package/dist/Sol/wingets/ComputeBootladder.js +71 -0
  39. package/dist/Sol/wingets/ComputeModalitycatalog.d.ts +7 -0
  40. package/dist/Sol/wingets/ComputeModalitycatalog.js +71 -0
  41. package/dist/Sol/wingets/ConsoleApibadge.d.ts +7 -0
  42. package/dist/Sol/wingets/ConsoleApibadge.js +5 -0
  43. package/dist/Sol/wingets/ConsoleEdgelaw.d.ts +6 -0
  44. package/dist/Sol/wingets/ConsoleEdgelaw.js +36 -0
  45. package/dist/Sol/wingets/ConsoleEventstimeline.d.ts +19 -0
  46. package/dist/Sol/wingets/ConsoleEventstimeline.js +12 -0
  47. package/dist/Sol/wingets/ConsoleSnapshotcontrols.d.ts +8 -0
  48. package/dist/Sol/wingets/ConsoleSnapshotcontrols.js +8 -0
  49. package/dist/Sol/wingets/ConsoleSpecpanel.d.ts +21 -0
  50. package/dist/Sol/wingets/ConsoleSpecpanel.js +75 -0
  51. package/dist/Sol/wingets/ConsoleTerminal.d.ts +22 -0
  52. package/dist/Sol/wingets/ConsoleTerminal.js +77 -0
  53. package/dist/Sol/wingets/DashboardAccountpanel.d.ts +18 -0
  54. package/dist/Sol/wingets/DashboardAccountpanel.js +65 -0
  55. package/dist/Sol/wingets/DashboardAdminpanel.d.ts +6 -0
  56. package/dist/Sol/wingets/DashboardAdminpanel.js +90 -0
  57. package/dist/Sol/wingets/DashboardAuditlog.d.ts +8 -0
  58. package/dist/Sol/wingets/DashboardAuditlog.js +50 -0
  59. package/dist/Sol/wingets/DashboardCreatesandboxform.d.ts +10 -0
  60. package/dist/Sol/wingets/DashboardCreatesandboxform.js +71 -0
  61. package/dist/Sol/wingets/DashboardEventstimeline.d.ts +8 -0
  62. package/dist/Sol/wingets/DashboardEventstimeline.js +83 -0
  63. package/dist/Sol/wingets/DashboardGlobalsandboxestable.d.ts +8 -0
  64. package/dist/Sol/wingets/DashboardGlobalsandboxestable.js +57 -0
  65. package/dist/Sol/wingets/DashboardMeshnodestable.d.ts +8 -0
  66. package/dist/Sol/wingets/DashboardMeshnodestable.js +103 -0
  67. package/dist/Sol/wingets/DashboardSandboxlist.d.ts +10 -0
  68. package/dist/Sol/wingets/DashboardSandboxlist.js +163 -0
  69. package/dist/Sol/wingets/DashboardUserstable.d.ts +8 -0
  70. package/dist/Sol/wingets/DashboardUserstable.js +78 -0
  71. package/dist/Sol/wingets/HomeEntrygate.d.ts +23 -0
  72. package/dist/Sol/wingets/HomeEntrygate.js +73 -0
  73. package/dist/Sol/wingets/HomeMetricstrip.d.ts +9 -0
  74. package/dist/Sol/wingets/HomeMetricstrip.js +4 -0
  75. package/dist/Sol/wingets/HomeRuntimediagram.d.ts +1 -0
  76. package/dist/Sol/wingets/HomeRuntimediagram.js +22 -0
  77. package/dist/Sol/wingets/LoginForm.d.ts +19 -0
  78. package/dist/Sol/wingets/LoginForm.js +141 -0
  79. package/dist/Sol/wingets/RegisterPasswordconfirm.d.ts +13 -0
  80. package/dist/Sol/wingets/RegisterPasswordconfirm.js +16 -0
  81. package/dist/Sol/wingets/RegisterPasswordmeter.d.ts +19 -0
  82. package/dist/Sol/wingets/RegisterPasswordmeter.js +65 -0
  83. package/dist/Sol/wingets/RegisterUsernamerules.d.ts +11 -0
  84. package/dist/Sol/wingets/RegisterUsernamerules.js +16 -0
  85. package/dist/Sol/wingets/index.d.ts +39 -0
  86. package/dist/Sol/wingets/index.js +39 -0
  87. package/dist/alternatives.d.ts +508 -0
  88. package/dist/alternatives.js +950 -0
  89. package/dist/api.d.ts +154 -0
  90. package/dist/api.js +174 -0
  91. package/dist/auth.d.ts +268 -0
  92. package/dist/auth.js +476 -0
  93. package/dist/automation.d.ts +425 -0
  94. package/dist/automation.js +566 -0
  95. package/dist/browser.d.ts +561 -0
  96. package/dist/browser.js +1058 -0
  97. package/dist/capacitor.config.d.ts +45 -0
  98. package/dist/capacitor.config.js +48 -0
  99. package/dist/catalog.d.ts +43 -0
  100. package/dist/catalog.js +44 -0
  101. package/dist/cli.d.ts +16 -0
  102. package/dist/cli.js +168 -0
  103. package/dist/communication.d.ts +181 -0
  104. package/dist/communication.js +376 -0
  105. package/dist/compute.d.ts +1160 -0
  106. package/dist/compute.js +2272 -0
  107. package/dist/dashboardlib.d.ts +58 -0
  108. package/dist/dashboardlib.js +161 -0
  109. package/dist/db.d.ts +569 -0
  110. package/dist/db.js +1080 -0
  111. package/dist/distribution.d.ts +528 -0
  112. package/dist/distribution.js +810 -0
  113. package/dist/drizzle.config.d.ts +20 -0
  114. package/dist/drizzle.config.js +18 -0
  115. package/dist/edgelandes.d.ts +70 -0
  116. package/dist/edgelandes.host.d.ts +26 -0
  117. package/dist/edgelandes.host.js +1089 -0
  118. package/dist/edgelandes.inproc.d.ts +27 -0
  119. package/dist/edgelandes.inproc.js +952 -0
  120. package/dist/edgelandes.js +1133 -0
  121. package/dist/edgelandes.ninety.d.ts +31 -0
  122. package/dist/edgelandes.ninety.js +174 -0
  123. package/dist/edgelandes.virtual.d.ts +25 -0
  124. package/dist/edgelandes.virtual.js +629 -0
  125. package/dist/edgeplane.d.ts +114 -0
  126. package/dist/edgeplane.js +305 -0
  127. package/dist/examplelocaljob.d.ts +1 -0
  128. package/{docs/example-localjob.ts → dist/examplelocaljob.js} +0 -1
  129. package/dist/execution.d.ts +529 -0
  130. package/dist/execution.js +760 -0
  131. package/dist/family.d.ts +16 -0
  132. package/dist/family.js +42 -0
  133. package/dist/familyurl.d.ts +21 -0
  134. package/dist/familyurl.js +24 -0
  135. package/dist/format.d.ts +18 -0
  136. package/dist/format.js +59 -0
  137. package/dist/foundation.d.ts +172 -0
  138. package/dist/foundation.js +312 -0
  139. package/dist/index.d.ts +735 -0
  140. package/dist/index.js +1020 -0
  141. package/dist/integration.d.ts +235 -0
  142. package/dist/integration.js +228 -0
  143. package/dist/intelligence.d.ts +93 -0
  144. package/dist/intelligence.js +144 -0
  145. package/dist/isolation.d.ts +128 -0
  146. package/dist/isolation.js +95 -0
  147. package/dist/labels.d.ts +665 -0
  148. package/dist/labels.js +751 -0
  149. package/dist/localauth.d.ts +127 -0
  150. package/dist/localauth.js +413 -0
  151. package/dist/media.d.ts +343 -0
  152. package/dist/media.js +985 -0
  153. package/dist/mesh.d.ts +177 -0
  154. package/dist/mesh.js +468 -0
  155. package/dist/modalityregistry.d.ts +109 -0
  156. package/dist/modalityregistry.js +1386 -0
  157. package/dist/modes.d.ts +358 -0
  158. package/dist/modes.js +133 -0
  159. package/dist/onboardingstate.d.ts +79 -0
  160. package/dist/onboardingstate.js +282 -0
  161. package/dist/orchestrator.d.ts +1338 -0
  162. package/dist/orchestrator.js +4310 -0
  163. package/dist/packager/targetcli.js +4 -0
  164. package/dist/paths.d.ts +2 -0
  165. package/dist/paths.js +14 -0
  166. package/dist/performance.d.ts +415 -0
  167. package/dist/performance.js +826 -0
  168. package/dist/quantum.d.ts +809 -0
  169. package/dist/quantum.js +2072 -0
  170. package/dist/render.d.ts +380 -0
  171. package/dist/render.js +1072 -0
  172. package/dist/runall.d.ts +2 -0
  173. package/dist/runall.js +39 -0
  174. package/dist/runtimeprobe.d.ts +4 -0
  175. package/dist/runtimeprobe.js +8 -0
  176. package/dist/sandbox.d.ts +355 -0
  177. package/dist/sandbox.js +1721 -0
  178. package/dist/sandboxenvprofile.d.ts +29 -0
  179. package/dist/sandboxenvprofile.js +89 -0
  180. package/dist/sandboxprofile.d.ts +137 -0
  181. package/dist/sandboxprofile.js +241 -0
  182. package/dist/sandboxqueue.d.ts +108 -0
  183. package/dist/sandboxqueue.js +201 -0
  184. package/dist/sandboxquota.d.ts +121 -0
  185. package/dist/sandboxquota.js +236 -0
  186. package/dist/scheduler.d.ts +595 -0
  187. package/dist/scheduler.js +1258 -0
  188. package/dist/scriptlanes.d.ts +182 -0
  189. package/dist/scriptlanes.js +660 -0
  190. package/dist/scripts.buildengine.d.ts +1 -0
  191. package/dist/scripts.buildengine.js +39 -0
  192. package/dist/scripts.securitygate.d.ts +1 -0
  193. package/dist/scripts.securitygate.js +68 -0
  194. package/dist/scripts.validateflatnative.d.ts +1 -0
  195. package/dist/scripts.validateflatnative.js +72 -0
  196. package/dist/security.d.ts +500 -0
  197. package/dist/security.js +1169 -0
  198. package/dist/seedcatalog.d.ts +13 -0
  199. package/dist/seedcatalog.js +46 -0
  200. package/dist/server.d.ts +20 -0
  201. package/dist/server.js +53 -0
  202. package/dist/speccatalog.d.ts +31 -0
  203. package/dist/speccatalog.js +163 -0
  204. package/dist/tiers.d.ts +1001 -0
  205. package/dist/tiers.js +2169 -0
  206. package/dist/utils.d.ts +2 -0
  207. package/dist/utils.js +5 -0
  208. package/dist/vaulthandoff.d.ts +141 -0
  209. package/dist/vaulthandoff.js +444 -0
  210. package/dist/virtual.d.ts +640 -0
  211. package/dist/virtual.js +1284 -0
  212. package/dist/virtualcpu.d.ts +315 -0
  213. package/dist/virtualcpu.js +1180 -0
  214. package/dist/virtualgpu.d.ts +344 -0
  215. package/dist/virtualgpu.js +1000 -0
  216. package/dist/virtualization.d.ts +606 -0
  217. package/dist/virtualization.js +1186 -0
  218. package/dist/virtualmemory.d.ts +817 -0
  219. package/dist/virtualmemory.js +1795 -0
  220. package/dist/vite.config.d.ts +3 -0
  221. package/dist/vite.config.js +43 -0
  222. package/dist/vitest.config.d.ts +2 -0
  223. package/dist/vitest.config.js +25 -0
  224. package/dist/webserver.d.ts +166 -0
  225. package/dist/webserver.js +2226 -0
  226. package/dist/workloadlaw.d.ts +133 -0
  227. package/dist/workloadlaw.js +193 -0
  228. package/docs/artifactavailability.md +2 -2
  229. package/docs/{containerplatforms-2.1.0.md → containerplatforms.2.1.0.md} +1 -1
  230. package/docs/{documentmap-1.8.12.md → documentmap.1.8.12.md} +1 -1
  231. package/docs/ninety.modalities.md +108 -0
  232. package/docs/planning.ninety.md +391 -0
  233. package/docs/{releasenotes-1.8.13.md → releasenotes.1.8.13.md} +2 -2
  234. package/docs/{releasenotes-1.8.14.md → releasenotes.1.8.14.md} +1 -1
  235. package/docs/{repo-synthesis-1.8.16.md → repo.synthesis.1.8.16.md} +1 -1
  236. package/docs/{todo-1.8.15.md → todo.1.8.15.md} +1 -1
  237. package/docs/{todo-1.8.16.md → todo.1.8.16.md} +5 -5
  238. package/docs/todo.md +2 -2
  239. package/docs/workloadlaw.md +104 -0
  240. package/index.ts +1 -1
  241. package/manifest.json +1 -1
  242. package/modalityregistry.ts +1371 -34
  243. package/orchestrator.ts +1 -1
  244. package/package.json +78 -33
  245. package/docs/CONVERSA.txt +0 -1523
  246. package/docs/architecture-1.8.19.png +0 -0
  247. package/docs/assets/architecture.svg +0 -45
  248. package/docs/assets/saddle-browser-trace.webp +0 -0
  249. package/docs/assets/saddle-hero-bridge.webp +0 -0
  250. package/docs/assets/saddle-mark.webp +0 -0
  251. package/docs/assets/saddle-runtime-map.webp +0 -0
  252. package/docs/assets/saddlemark.svg +0 -13
  253. package/docs/saddle.archive.1.8.17.tar.gz.gpg +0 -0
  254. /package/docs/{architecture-1.8.19.md → architecture.1.8.19.md} +0 -0
  255. /package/docs/{architecture-1.8.19.mmd → architecture.1.8.19.mmd} +0 -0
  256. /package/docs/{artifactresearch-1.8.9.md → artifactresearch.1.8.9.md} +0 -0
  257. /package/docs/{batches-1816-1820.md → batches.1816.to.1820.md} +0 -0
  258. /package/docs/{brancharchive-2026-08-18.md → brancharchive.2026.08.18.md} +0 -0
  259. /package/docs/{containerplatforms-1.8.17.md → containerplatforms.1.8.17.md} +0 -0
  260. /package/docs/{e2ugh-engine.md → e2ugh.engine.md} +0 -0
  261. /package/docs/{flatbuildresearch-1.8.11.md → flatbuildresearch.1.8.11.md} +0 -0
  262. /package/docs/{licenseaudit-1.8.12.md → licenseaudit.1.8.12.md} +0 -0
  263. /package/docs/{mobileconversionresearch-1.8.10.md → mobileconversionresearch.1.8.10.md} +0 -0
  264. /package/docs/{native-wrappers.md → native.wrappers.md} +0 -0
  265. /package/docs/{nativeidentityresearch-1.8.11.md → nativeidentityresearch.1.8.11.md} +0 -0
  266. /package/docs/{releasenotes-1.8.12.md → releasenotes.1.8.12.md} +0 -0
  267. /package/docs/{releasenotes-1.8.15.md → releasenotes.1.8.15.md} +0 -0
  268. /package/docs/{releasenotes-1.8.16.md → releasenotes.1.8.16.md} +0 -0
  269. /package/docs/{releasenotes-1.8.17.md → releasenotes.1.8.17.md} +0 -0
  270. /package/docs/{releasenotes-1.8.18.md → releasenotes.1.8.18.md} +0 -0
  271. /package/docs/{releasenotes-1.8.19.md → releasenotes.1.8.19.md} +0 -0
  272. /package/docs/{reorganization-1.8.8.md → reorganization.1.8.8.md} +0 -0
  273. /package/docs/{reorganization-1.8.9.md → reorganization.1.8.9.md} +0 -0
  274. /package/docs/{repo-analysis-1.8.21.json → repo.analysis.1.8.21.json} +0 -0
  275. /package/docs/{repo-candidates-1.8.21.jsonl → repo.candidates.1.8.21.jsonl} +0 -0
  276. /package/docs/{repo-research-1.8.16.md → repo.research.1.8.16.md} +0 -0
  277. /package/docs/{repo-research-1.8.21.md → repo.research.1.8.21.md} +0 -0
  278. /package/docs/{repo-selected-1.8.21.json → repo.selected.1.8.21.json} +0 -0
  279. /package/docs/{repo-synthesis-1.8.21.md → repo.synthesis.1.8.21.md} +0 -0
  280. /package/docs/{research-1.8.18-isolation.md → research.1.8.18.isolation.md} +0 -0
  281. /package/docs/{research-1.8.19-virtual-browser.md → research.1.8.19.virtual.browser.md} +0 -0
  282. /package/docs/{scanningresearch-1.8.11.md → scanningresearch.1.8.11.md} +0 -0
  283. /package/docs/{securityaudit-1.8.7.md → securityaudit.1.8.7.md} +0 -0
  284. /package/docs/{securityreferences-1.8.11.md → securityreferences.1.8.11.md} +0 -0
  285. /package/docs/{securityresearch-1.8.11.md → securityresearch.1.8.11.md} +0 -0
  286. /package/docs/{signingresearch-1.8.12.md → signingresearch.1.8.12.md} +0 -0
  287. /package/docs/{tauri-glib-risk-1.8.11.md → tauri.glib.risk.1.8.11.md} +0 -0
  288. /package/docs/{todo-1.8.18.md → todo.1.8.18.md} +0 -0
  289. /package/docs/{todo-1.8.19.md → todo.1.8.19.md} +0 -0
  290. /package/docs/{toolchainresearch-1.8.9.md → toolchainresearch.1.8.9.md} +0 -0
  291. /package/docs/{web-duplicatecleanup.md → web.duplicatecleanup.md} +0 -0
  292. /package/docs/{web-ideas.md → web.ideas.md} +0 -0
  293. /package/docs/{workflowimprovements-2026-08-19.md → workflowimprovements.2026.08.19.md} +0 -0
@@ -0,0 +1,2 @@
1
+ import { type ClassValue } from 'clsx';
2
+ export declare function cn(...inputs: ClassValue[]): string;
package/dist/utils.js ADDED
@@ -0,0 +1,5 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
@@ -0,0 +1,141 @@
1
+ /**
2
+ * vaulthandoff.ts — the vault storage handoff of the saddle engine: every
3
+ * edge artifact lands in the better sqlite vault store server-side, the
4
+ * internal api serves objects by id, and the faun download of the raw
5
+ * database stays blocked.
6
+ *
7
+ * the saddle edge plane owns processing and the vault owns storage; this
8
+ * module is the seam between them. a sink opens (or creates) a
9
+ * better-sqlite3 database — the storage engine the vault app itself runs
10
+ * on, with the native node:sqlite driver as the runtime fallback — and
11
+ * lands every artifact of an edge run as one parameterized row of the
12
+ * edgeartifacts table. no artifact ever persists in the visitor browser
13
+ * and no raw database file is ever served as a static download: objects
14
+ * answer over the internal api path /api/v1/vault/objects/<runid> only,
15
+ * and the faun guard refuses any path that targets a raw database file.
16
+ *
17
+ * contexts (7): driver, errors, schema, sink, adapter, faun, visitor.
18
+ *
19
+ * rules: lowercase identifiers, english jsdoc in third person, no emoji,
20
+ * try/catch on every fallible path with the standardized {code,message}
21
+ * error shape, prepared statements memoized once per sink instance, the
22
+ * file mode 0o600 right after open (the house pattern of db.ts).
23
+ */
24
+ /** one edge artifact handed to the vault store: the run id is the object
25
+ * id the internal api serves, the modality names the edge lane that
26
+ * produced the artifact and the bytes ride the blob cell (text artifacts
27
+ * stay text cells so the roundtrip preserves the caller's shape). */
28
+ export type VaultArtifact = {
29
+ runid: string;
30
+ modality: string;
31
+ mime: string;
32
+ bytes: Uint8Array | string;
33
+ createdat: number;
34
+ };
35
+ /** the adapter put envelope: the key is the run id and the data is bytes,
36
+ * text or an async iterable of chunks (collectbytes folds the chunks). */
37
+ export type VaultPut = {
38
+ key?: string;
39
+ data?: Uint8Array | string | AsyncIterable<Uint8Array>;
40
+ modality?: string;
41
+ contenttype?: string;
42
+ createdat?: number;
43
+ metadata?: Record<string, unknown>;
44
+ };
45
+ /** the stored object manifest every adapter method answers with (the
46
+ * foundation artifactmanifest shape: key, sizebytes, sha256, contenttype,
47
+ * createdat and metadata). */
48
+ export type VaultManifest = {
49
+ key: string;
50
+ sizebytes: number;
51
+ sha256: string;
52
+ contenttype: string;
53
+ createdat: number;
54
+ metadata: Record<string, unknown>;
55
+ };
56
+ /** the write receipt of putartifact. */
57
+ export type VaultReceipt = {
58
+ runid: string;
59
+ size: number;
60
+ };
61
+ /** the store usage counters of counts. */
62
+ export type VaultCounts = {
63
+ artifacts: number;
64
+ bytes: number;
65
+ };
66
+ /** the faun guard verdict: blocked true when the path targets a raw
67
+ * database download, carrying the machine readable code and the house
68
+ * message; blocked false carries no code. */
69
+ export type FaunVerdict = {
70
+ blocked: boolean;
71
+ code?: string;
72
+ message?: string;
73
+ };
74
+ /** the sink: the storageadapter surface (put, get, head, delete, list)
75
+ * of virtual.ts plus the artifact table api, the internal object url,
76
+ * the usage counters and the connection close. */
77
+ export type VaultSink = {
78
+ driver: string;
79
+ dbpath: string;
80
+ putartifact(artifact: VaultArtifact): VaultReceipt;
81
+ getartifact(runid: string): VaultArtifact | null;
82
+ artifacturl(runid: string): string;
83
+ counts(): VaultCounts;
84
+ put(input?: VaultPut): Promise<VaultManifest>;
85
+ get(key: string): Promise<Uint8Array>;
86
+ head(key: string): Promise<VaultManifest | null>;
87
+ delete(key: string): Promise<boolean>;
88
+ list(prefix?: string): Promise<VaultManifest[]>;
89
+ close(): void;
90
+ [Symbol.dispose](): void;
91
+ };
92
+ /** the standardized vault error: the machine readable code plus the
93
+ * non-enumerable internal detail, built on the house saddleerror. */
94
+ export type VaultError = Error & {
95
+ code: string;
96
+ internal?: string;
97
+ };
98
+ /**
99
+ * opens (or creates) the vault store and returns the sink: the
100
+ * storageadapter surface of virtual.ts (put, get, head, delete, list)
101
+ * plus the artifact table api. better-sqlite3 is the primary driver and
102
+ * the native node:sqlite driver answers when the better driver fails at
103
+ * runtime; the database file is tightened to mode 0o600 right after
104
+ * open because the store carries edge artifacts server-side only.
105
+ *
106
+ * @param options the store options; path defaults to ":memory:".
107
+ * @returns the vault sink.
108
+ */
109
+ export declare function vaultsink(options?: {
110
+ path?: string;
111
+ }): VaultSink;
112
+ /**
113
+ * the faun law guard: a raw database file is never served as a static
114
+ * download. the verdict blocks any path that ends with .db, .sqlite or
115
+ * .sqlite3 (case-insensitive) or matches the faun/vault database
116
+ * patterns; everything else — the internal object api, the edge run
117
+ * api, plain pages — passes.
118
+ *
119
+ * @param path the request path under review.
120
+ * @returns the verdict with the FAUN_DOWNLOAD_BLOCKED code when blocked.
121
+ */
122
+ export declare function faunblock(path: string): FaunVerdict;
123
+ /**
124
+ * maps the faun guard over route paths for route-level assertions.
125
+ *
126
+ * @param paths the request paths under review.
127
+ * @returns one verdict per path, in order.
128
+ */
129
+ export declare function faunblockroutes(paths: readonly string[]): FaunVerdict[];
130
+ /**
131
+ * the visitor store law: artifacts never persist in the visitor
132
+ * browser. the assertion throws the standardized VISITOR_STORE_REFUSED
133
+ * error when the scope carries any browser storage surface; a clean
134
+ * scope answers { clean: true }.
135
+ *
136
+ * @param scope the scope under review (a store map, a config object).
137
+ * @returns { clean: true } when the scope is browser-store free.
138
+ */
139
+ export declare function assertvisitorstorefree(scope: Record<string, unknown>): {
140
+ clean: true;
141
+ };
@@ -0,0 +1,444 @@
1
+ /**
2
+ * vaulthandoff.ts — the vault storage handoff of the saddle engine: every
3
+ * edge artifact lands in the better sqlite vault store server-side, the
4
+ * internal api serves objects by id, and the faun download of the raw
5
+ * database stays blocked.
6
+ *
7
+ * the saddle edge plane owns processing and the vault owns storage; this
8
+ * module is the seam between them. a sink opens (or creates) a
9
+ * better-sqlite3 database — the storage engine the vault app itself runs
10
+ * on, with the native node:sqlite driver as the runtime fallback — and
11
+ * lands every artifact of an edge run as one parameterized row of the
12
+ * edgeartifacts table. no artifact ever persists in the visitor browser
13
+ * and no raw database file is ever served as a static download: objects
14
+ * answer over the internal api path /api/v1/vault/objects/<runid> only,
15
+ * and the faun guard refuses any path that targets a raw database file.
16
+ *
17
+ * contexts (7): driver, errors, schema, sink, adapter, faun, visitor.
18
+ *
19
+ * rules: lowercase identifiers, english jsdoc in third person, no emoji,
20
+ * try/catch on every fallible path with the standardized {code,message}
21
+ * error shape, prepared statements memoized once per sink instance, the
22
+ * file mode 0o600 right after open (the house pattern of db.ts).
23
+ */
24
+ import { Buffer } from "node:buffer";
25
+ import { chmodSync } from "node:fs";
26
+ import { createRequire } from "node:module";
27
+ import { DatabaseSync } from "node:sqlite";
28
+ import { artifactmanifest, artifactnotfound, idfactory, saddleerror, sha256, systemclock } from "./foundation.js";
29
+ import { collectbytes, storageadapter } from "./virtual.js";
30
+ /* ════════════════════════════════════════════════════════════════════ */
31
+ /* context: errors — the {code,message} shape of the handoff surface */
32
+ /* ════════════════════════════════════════════════════════════════════ */
33
+ /** the public messages keyed by code: static strings only, safe to
34
+ * surface because they never carry driver or filesystem detail. */
35
+ const publicmessages = {
36
+ "vault-open-failed": "vault store unavailable",
37
+ "vault-schema-failed": "vault store unavailable",
38
+ "vault-prepare-failed": "vault store error",
39
+ "vault-sink-failed": "vault store error",
40
+ VISITOR_STORE_REFUSED: "browser storage is refused on the artifact path",
41
+ };
42
+ /**
43
+ * builds the standardized vault error: the internal detail is logged
44
+ * server-side only and the thrown error exposes the public message and
45
+ * the machine-readable code (the dberror pattern of db.ts).
46
+ *
47
+ * @param code machine readable code.
48
+ * @param internal the server-side diagnostic detail.
49
+ * @returns the decorated error.
50
+ */
51
+ function vaulterror(code, internal) {
52
+ if (typeof internal === "string" && internal.length > 0) {
53
+ console.error(`[vaulthandoff] ${code}: ${internal}`);
54
+ }
55
+ const error = saddleerror(publicmessages[code] ?? code, { code });
56
+ Object.defineProperty(error, "internal", {
57
+ value: typeof internal === "string" ? internal : "",
58
+ enumerable: false,
59
+ writable: false,
60
+ configurable: false,
61
+ });
62
+ return error;
63
+ }
64
+ /** renders one unknown failure as diagnostic text. */
65
+ function errortext(error) {
66
+ return error instanceof Error ? error.message : String(error);
67
+ }
68
+ /**
69
+ * opens the vault store: better-sqlite3 first (the storage engine the
70
+ * vault app itself runs on), the native node:sqlite driver only when the
71
+ * better driver fails at runtime. the busy timeout pragma follows the
72
+ * house pattern of db.ts.
73
+ *
74
+ * @param path the database path (":memory:" keeps the store in ram).
75
+ * @returns the opened database and the driver name that served it.
76
+ */
77
+ function opendatabase(path) {
78
+ try {
79
+ // the better driver loads lazily through createRequire so a host
80
+ // whose install skipped the native binding (the ci lane installs
81
+ // with ignore-scripts) degrades to the native driver instead of
82
+ // crashing the module graph at import time.
83
+ const require = createRequire(import.meta.url);
84
+ const BetterSqlite = require("better-sqlite3");
85
+ const database = new BetterSqlite(path);
86
+ database.exec("pragma busy_timeout = 2000;");
87
+ return { database, driver: "better-sqlite3" };
88
+ }
89
+ catch (better) {
90
+ try {
91
+ const database = new DatabaseSync(path);
92
+ database.exec("pragma busy_timeout = 2000;");
93
+ return { database, driver: "node:sqlite" };
94
+ }
95
+ catch (native) {
96
+ throw vaulterror("vault-open-failed", `opening "${path}" with better-sqlite3 failed: ${errortext(better)}; the node:sqlite fallback failed: ${errortext(native)}`);
97
+ }
98
+ }
99
+ }
100
+ /* ════════════════════════════════════════════════════════════════════ */
101
+ /* context: schema — the edgeartifacts table */
102
+ /* ════════════════════════════════════════════════════════════════════ */
103
+ /** the one table of the handoff store: every edge artifact is one row,
104
+ * keyed by the run id the internal api serves objects by. */
105
+ const schema = `
106
+ create table if not exists edgeartifacts (
107
+ runid text primary key,
108
+ modality text not null,
109
+ mime text not null,
110
+ bytes blob not null,
111
+ size integer not null,
112
+ createdat integer not null
113
+ );
114
+ `;
115
+ /** the upsert of putartifact: a repeated run id refreshes the row
116
+ * instead of duplicating it (the run is the object identity). */
117
+ const upsertsql = "insert into edgeartifacts (runid, modality, mime, bytes, size, createdat) values (?, ?, ?, ?, ?, ?) " +
118
+ "on conflict(runid) do update set modality = excluded.modality, mime = excluded.mime, " +
119
+ "bytes = excluded.bytes, size = excluded.size, createdat = excluded.createdat";
120
+ /** the row projection every read answers with. */
121
+ const selectsql = "select runid, modality, mime, bytes, createdat from edgeartifacts";
122
+ /** the internal api root the object url law pins: artifacts answer over
123
+ * /api/v1/vault/objects/<runid> and never over a file path. */
124
+ const objectapiroot = "/api/v1/vault/objects";
125
+ /* ════════════════════════════════════════════════════════════════════ */
126
+ /* context: sink — the vault storage handoff of the saddle engine */
127
+ /* ════════════════════════════════════════════════════════════════════ */
128
+ /**
129
+ * opens (or creates) the vault store and returns the sink: the
130
+ * storageadapter surface of virtual.ts (put, get, head, delete, list)
131
+ * plus the artifact table api. better-sqlite3 is the primary driver and
132
+ * the native node:sqlite driver answers when the better driver fails at
133
+ * runtime; the database file is tightened to mode 0o600 right after
134
+ * open because the store carries edge artifacts server-side only.
135
+ *
136
+ * @param options the store options; path defaults to ":memory:".
137
+ * @returns the vault sink.
138
+ */
139
+ export function vaultsink(options = {}) {
140
+ const path = typeof options?.path === "string" && options.path.length > 0 ? options.path : ":memory:";
141
+ const opened = opendatabase(path);
142
+ const database = opened.database;
143
+ if (path !== ":memory:") {
144
+ try {
145
+ chmodSync(path, 0o600);
146
+ }
147
+ catch {
148
+ /* the mode is best effort on exotic filesystems */
149
+ }
150
+ }
151
+ try {
152
+ database.exec(schema);
153
+ }
154
+ catch (error) {
155
+ throw vaulterror("vault-schema-failed", `creating the edgeartifacts table failed: ${errortext(error)}`);
156
+ }
157
+ /** prepared statements memoized once per sink instance, keyed by sql. */
158
+ const statements = new Map();
159
+ function stmt(sql) {
160
+ try {
161
+ let prepared = statements.get(sql);
162
+ if (prepared === undefined) {
163
+ prepared = database.prepare(sql);
164
+ statements.set(sql, prepared);
165
+ }
166
+ return prepared;
167
+ }
168
+ catch (error) {
169
+ throw vaulterror("vault-prepare-failed", `preparing "${sql.slice(0, 48)}" failed: ${errortext(error)}`);
170
+ }
171
+ }
172
+ const clock = systemclock();
173
+ const ids = idfactory();
174
+ const encoder = new TextEncoder();
175
+ /**
176
+ * writes (or refreshes) one edge artifact row; an empty run id mints
177
+ * one so the receipt always carries the object identity.
178
+ *
179
+ * @param artifact the artifact envelope.
180
+ * @returns the write receipt.
181
+ */
182
+ function putartifact(artifact) {
183
+ try {
184
+ const given = typeof artifact?.runid === "string" ? artifact.runid : "";
185
+ const runid = given.length > 0 ? given : ids.next("edge");
186
+ const modality = String(artifact?.modality ?? "edge");
187
+ const mime = String(artifact?.mime ?? "application/octet-stream");
188
+ const payload = artifact?.bytes ?? "";
189
+ const data = payload instanceof Uint8Array ? payload : String(payload);
190
+ const size = payload instanceof Uint8Array ? payload.byteLength : Buffer.byteLength(String(payload), "utf8");
191
+ const createdat = Number(artifact?.createdat ?? clock.now()) || 0;
192
+ stmt(upsertsql).run(runid, modality, mime, data, size, createdat);
193
+ return { runid, size };
194
+ }
195
+ catch (error) {
196
+ throw vaulterror("vault-sink-failed", `writing the artifact failed: ${errortext(error)}`);
197
+ }
198
+ }
199
+ /**
200
+ * reads one edge artifact row back; byte artifacts answer as plain
201
+ * uint8arrays and text artifacts answer as text, so the roundtrip
202
+ * preserves the caller's shape.
203
+ *
204
+ * @param runid the run id (the object identity).
205
+ * @returns the artifact or null when absent.
206
+ */
207
+ function getartifact(runid) {
208
+ try {
209
+ const row = stmt(`${selectsql} where runid = ?`).get(String(runid ?? ""));
210
+ if (row === undefined) {
211
+ return null;
212
+ }
213
+ return {
214
+ runid: String(row.runid),
215
+ modality: String(row.modality),
216
+ mime: String(row.mime),
217
+ bytes: row.bytes instanceof Uint8Array ? new Uint8Array(row.bytes) : String(row.bytes ?? ""),
218
+ createdat: Number(row.createdat) || 0,
219
+ };
220
+ }
221
+ catch (error) {
222
+ throw vaulterror("vault-sink-failed", `reading the artifact failed: ${errortext(error)}`);
223
+ }
224
+ }
225
+ /**
226
+ * the internal api object url: /api/v1/vault/objects/<runid>. the url
227
+ * is always an internal api path — never a file path and never a
228
+ * static download of the raw database.
229
+ *
230
+ * @param runid the run id (the object identity).
231
+ * @returns the internal api path string.
232
+ */
233
+ function artifacturl(runid) {
234
+ return `${objectapiroot}/${encodeURIComponent(String(runid ?? ""))}`;
235
+ }
236
+ /**
237
+ * the store usage counters: the artifact rows and the summed bytes.
238
+ *
239
+ * @returns the counts.
240
+ */
241
+ function counts() {
242
+ try {
243
+ const row = stmt("select count(*) as artifacts, coalesce(sum(size), 0) as bytes from edgeartifacts").get();
244
+ return { artifacts: Number(row?.artifacts ?? 0) || 0, bytes: Number(row?.bytes ?? 0) || 0 };
245
+ }
246
+ catch (error) {
247
+ throw vaulterror("vault-sink-failed", `counting the store failed: ${errortext(error)}`);
248
+ }
249
+ }
250
+ /** projects one artifact into the manifest shape of the family. */
251
+ function manifestof(artifact) {
252
+ return artifactmanifest({
253
+ key: artifact.runid,
254
+ sizebytes: artifact.bytes instanceof Uint8Array ? artifact.bytes.byteLength : Buffer.byteLength(artifact.bytes, "utf8"),
255
+ sha256: sha256(artifact.bytes),
256
+ contenttype: artifact.mime,
257
+ createdat: artifact.createdat,
258
+ metadata: {},
259
+ });
260
+ }
261
+ /**
262
+ * writes one artifact through the storageadapter envelope: the key is
263
+ * the run id, the data is bytes, text or an async iterable of chunks
264
+ * and the receipt is the manifest of the stored object. metadata rides
265
+ * the write manifest only (the localstorage precedent: the table keeps
266
+ * the durable columns the handoff law pins).
267
+ *
268
+ * @param input the put envelope.
269
+ * @returns the manifest of the stored object.
270
+ */
271
+ async function put(input = {}) {
272
+ const key = String(input?.key ?? "");
273
+ if (key.length === 0) {
274
+ throw new TypeError("vault sink key is required (the run id of the artifact)");
275
+ }
276
+ const raw = input?.data ?? new Uint8Array();
277
+ const data = raw instanceof Uint8Array || typeof raw === "string" ? raw : await collectbytes(raw);
278
+ const contenttype = String(input?.contenttype ?? "application/octet-stream");
279
+ const createdat = Number(input?.createdat ?? clock.now()) || 0;
280
+ putartifact({
281
+ runid: key,
282
+ modality: String(input?.modality ?? "edge"),
283
+ mime: contenttype,
284
+ bytes: data,
285
+ createdat,
286
+ });
287
+ return artifactmanifest({
288
+ key,
289
+ sizebytes: data instanceof Uint8Array ? data.byteLength : Buffer.byteLength(data, "utf8"),
290
+ sha256: sha256(data),
291
+ contenttype,
292
+ createdat,
293
+ metadata: input?.metadata,
294
+ });
295
+ }
296
+ /**
297
+ * reads the bytes of one stored object; a missing key answers the
298
+ * family artifactnotfound error (the ARTIFACT_NOT_FOUND code).
299
+ *
300
+ * @param key the run id.
301
+ * @returns the stored bytes.
302
+ */
303
+ async function get(key) {
304
+ const artifact = getartifact(String(key ?? ""));
305
+ if (artifact === null) {
306
+ throw artifactnotfound(String(key ?? ""));
307
+ }
308
+ return artifact.bytes instanceof Uint8Array ? artifact.bytes : encoder.encode(artifact.bytes);
309
+ }
310
+ /**
311
+ * reads the manifest of one stored object without the bytes.
312
+ *
313
+ * @param key the run id.
314
+ * @returns the manifest or null when absent.
315
+ */
316
+ async function head(key) {
317
+ const artifact = getartifact(String(key ?? ""));
318
+ return artifact === null ? null : manifestof(artifact);
319
+ }
320
+ /**
321
+ * removes one stored object.
322
+ *
323
+ * @param key the run id.
324
+ * @returns true when a row was removed.
325
+ */
326
+ async function remove(key) {
327
+ try {
328
+ const result = stmt("delete from edgeartifacts where runid = ?").run(String(key ?? ""));
329
+ return Number(result?.changes ?? 0) > 0;
330
+ }
331
+ catch (error) {
332
+ throw vaulterror("vault-sink-failed", `deleting the artifact failed: ${errortext(error)}`);
333
+ }
334
+ }
335
+ /**
336
+ * lists the manifests of every stored object whose run id carries the
337
+ * prefix, ordered by run id; the bytes stay out of the projection.
338
+ *
339
+ * @param prefix the run id prefix filter.
340
+ * @returns the manifests.
341
+ */
342
+ async function list(prefix = "") {
343
+ try {
344
+ const marker = String(prefix ?? "");
345
+ const rows = stmt(`${selectsql} order by runid asc`).all();
346
+ return rows
347
+ .filter((row) => String(row.runid).startsWith(marker))
348
+ .map((row) => manifestof({
349
+ runid: String(row.runid),
350
+ modality: String(row.modality),
351
+ mime: String(row.mime),
352
+ bytes: row.bytes instanceof Uint8Array ? new Uint8Array(row.bytes) : String(row.bytes ?? ""),
353
+ createdat: Number(row.createdat) || 0,
354
+ }));
355
+ }
356
+ catch (error) {
357
+ throw vaulterror("vault-sink-failed", `listing the store failed: ${errortext(error)}`);
358
+ }
359
+ }
360
+ return {
361
+ driver: opened.driver,
362
+ dbpath: path,
363
+ putartifact,
364
+ getartifact,
365
+ artifacturl,
366
+ counts,
367
+ ...storageadapter({ put, get, head, delete: remove, list }),
368
+ /** closes the connection (idempotent). */
369
+ close() {
370
+ try {
371
+ database.close();
372
+ }
373
+ catch {
374
+ /* closing twice or after dispose is a no-op */
375
+ }
376
+ },
377
+ /** explicit resource management: `using` support for node >= 24. */
378
+ [Symbol.dispose]() {
379
+ this.close();
380
+ },
381
+ };
382
+ }
383
+ /* ════════════════════════════════════════════════════════════════════ */
384
+ /* context: faun — the raw database download guard */
385
+ /* ════════════════════════════════════════════════════════════════════ */
386
+ /** the raw database file extensions the guard refuses (case-insensitive). */
387
+ const rawdatabaseextensions = /\.(db|sqlite3?)$/i;
388
+ /** the faun path patterns: any faun lane and any vault database file. */
389
+ const faunpathpatterns = [/\/faun/i, /\/vault.*\.db/i];
390
+ /**
391
+ * the faun law guard: a raw database file is never served as a static
392
+ * download. the verdict blocks any path that ends with .db, .sqlite or
393
+ * .sqlite3 (case-insensitive) or matches the faun/vault database
394
+ * patterns; everything else — the internal object api, the edge run
395
+ * api, plain pages — passes.
396
+ *
397
+ * @param path the request path under review.
398
+ * @returns the verdict with the FAUN_DOWNLOAD_BLOCKED code when blocked.
399
+ */
400
+ export function faunblock(path) {
401
+ const target = String(path ?? "");
402
+ const rawdownload = rawdatabaseextensions.test(target) || faunpathpatterns.some((pattern) => pattern.test(target));
403
+ if (!rawdownload) {
404
+ return { blocked: false };
405
+ }
406
+ return {
407
+ blocked: true,
408
+ code: "FAUN_DOWNLOAD_BLOCKED",
409
+ message: "a raw database file is never a static download: the vault serves objects over the internal api only",
410
+ };
411
+ }
412
+ /**
413
+ * maps the faun guard over route paths for route-level assertions.
414
+ *
415
+ * @param paths the request paths under review.
416
+ * @returns one verdict per path, in order.
417
+ */
418
+ export function faunblockroutes(paths) {
419
+ return paths.map((path) => faunblock(path));
420
+ }
421
+ /* ════════════════════════════════════════════════════════════════════ */
422
+ /* context: visitor — the no-browser-storage law of the artifact path */
423
+ /* ════════════════════════════════════════════════════════════════════ */
424
+ /** the browser storage surfaces the artifact path refuses. */
425
+ const visitorstoresurfaces = ["localStorage", "sessionStorage", "indexedDB"];
426
+ /**
427
+ * the visitor store law: artifacts never persist in the visitor
428
+ * browser. the assertion throws the standardized VISITOR_STORE_REFUSED
429
+ * error when the scope carries any browser storage surface; a clean
430
+ * scope answers { clean: true }.
431
+ *
432
+ * @param scope the scope under review (a store map, a config object).
433
+ * @returns { clean: true } when the scope is browser-store free.
434
+ */
435
+ export function assertvisitorstorefree(scope) {
436
+ const carried = visitorstoresurfaces.filter((surface) => {
437
+ const value = scope?.[surface];
438
+ return value !== undefined && value !== null;
439
+ });
440
+ if (carried.length > 0) {
441
+ throw vaulterror("VISITOR_STORE_REFUSED", `the scope carries browser storage: ${carried.join(", ")}`);
442
+ }
443
+ return { clean: true };
444
+ }