@nhtio/adk 0.1.0-master-f0aa531d

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 (297) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +3 -0
  3. package/batteries/index.d.ts +28 -0
  4. package/batteries/llm/index.d.ts +11 -0
  5. package/batteries/llm/openai_chat_completions/adapter.cjs +916 -0
  6. package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -0
  7. package/batteries/llm/openai_chat_completions/adapter.d.ts +101 -0
  8. package/batteries/llm/openai_chat_completions/adapter.mjs +914 -0
  9. package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -0
  10. package/batteries/llm/openai_chat_completions/exceptions.cjs +89 -0
  11. package/batteries/llm/openai_chat_completions/exceptions.cjs.map +1 -0
  12. package/batteries/llm/openai_chat_completions/exceptions.d.ts +97 -0
  13. package/batteries/llm/openai_chat_completions/exceptions.mjs +81 -0
  14. package/batteries/llm/openai_chat_completions/exceptions.mjs.map +1 -0
  15. package/batteries/llm/openai_chat_completions/helpers.cjs +819 -0
  16. package/batteries/llm/openai_chat_completions/helpers.cjs.map +1 -0
  17. package/batteries/llm/openai_chat_completions/helpers.d.ts +233 -0
  18. package/batteries/llm/openai_chat_completions/helpers.mjs +783 -0
  19. package/batteries/llm/openai_chat_completions/helpers.mjs.map +1 -0
  20. package/batteries/llm/openai_chat_completions/index.d.ts +27 -0
  21. package/batteries/llm/openai_chat_completions/types.cjs +1 -0
  22. package/batteries/llm/openai_chat_completions/types.d.ts +524 -0
  23. package/batteries/llm/openai_chat_completions/types.mjs +0 -0
  24. package/batteries/llm/openai_chat_completions/validation.cjs +190 -0
  25. package/batteries/llm/openai_chat_completions/validation.cjs.map +1 -0
  26. package/batteries/llm/openai_chat_completions/validation.d.ts +31 -0
  27. package/batteries/llm/openai_chat_completions/validation.mjs +187 -0
  28. package/batteries/llm/openai_chat_completions/validation.mjs.map +1 -0
  29. package/batteries/llm/openai_chat_completions.cjs +51 -0
  30. package/batteries/llm/openai_chat_completions.mjs +5 -0
  31. package/batteries/llm/webllm_chat_completions/adapter.cjs +658 -0
  32. package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -0
  33. package/batteries/llm/webllm_chat_completions/adapter.d.ts +103 -0
  34. package/batteries/llm/webllm_chat_completions/adapter.mjs +656 -0
  35. package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -0
  36. package/batteries/llm/webllm_chat_completions/exceptions.cjs +70 -0
  37. package/batteries/llm/webllm_chat_completions/exceptions.cjs.map +1 -0
  38. package/batteries/llm/webllm_chat_completions/exceptions.d.ts +74 -0
  39. package/batteries/llm/webllm_chat_completions/exceptions.mjs +65 -0
  40. package/batteries/llm/webllm_chat_completions/exceptions.mjs.map +1 -0
  41. package/batteries/llm/webllm_chat_completions/helpers.cjs +38 -0
  42. package/batteries/llm/webllm_chat_completions/helpers.d.ts +6 -0
  43. package/batteries/llm/webllm_chat_completions/helpers.mjs +2 -0
  44. package/batteries/llm/webllm_chat_completions/index.d.ts +25 -0
  45. package/batteries/llm/webllm_chat_completions/types.d.ts +31 -0
  46. package/batteries/llm/webllm_chat_completions/validation.cjs +115 -0
  47. package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -0
  48. package/batteries/llm/webllm_chat_completions/validation.d.ts +8 -0
  49. package/batteries/llm/webllm_chat_completions/validation.mjs +112 -0
  50. package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -0
  51. package/batteries/llm/webllm_chat_completions.cjs +50 -0
  52. package/batteries/llm/webllm_chat_completions.mjs +6 -0
  53. package/batteries/llm.cjs +63 -0
  54. package/batteries/llm.mjs +10 -0
  55. package/batteries/storage/flydrive/index.d.ts +167 -0
  56. package/batteries/storage/flydrive.cjs +249 -0
  57. package/batteries/storage/flydrive.cjs.map +1 -0
  58. package/batteries/storage/flydrive.mjs +249 -0
  59. package/batteries/storage/flydrive.mjs.map +1 -0
  60. package/batteries/storage/in_memory/index.d.ts +106 -0
  61. package/batteries/storage/in_memory.cjs +121 -0
  62. package/batteries/storage/in_memory.cjs.map +1 -0
  63. package/batteries/storage/in_memory.mjs +119 -0
  64. package/batteries/storage/in_memory.mjs.map +1 -0
  65. package/batteries/storage/index.d.ts +18 -0
  66. package/batteries/storage/opfs/index.d.ts +299 -0
  67. package/batteries/storage/opfs.cjs +368 -0
  68. package/batteries/storage/opfs.cjs.map +1 -0
  69. package/batteries/storage/opfs.mjs +366 -0
  70. package/batteries/storage/opfs.mjs.map +1 -0
  71. package/batteries/storage.cjs +4 -0
  72. package/batteries/storage.mjs +2 -0
  73. package/batteries/tools/color/index.d.ts +37 -0
  74. package/batteries/tools/color.cjs +659 -0
  75. package/batteries/tools/color.cjs.map +1 -0
  76. package/batteries/tools/color.mjs +655 -0
  77. package/batteries/tools/color.mjs.map +1 -0
  78. package/batteries/tools/comparison/index.d.ts +29 -0
  79. package/batteries/tools/comparison.cjs +171 -0
  80. package/batteries/tools/comparison.cjs.map +1 -0
  81. package/batteries/tools/comparison.mjs +168 -0
  82. package/batteries/tools/comparison.mjs.map +1 -0
  83. package/batteries/tools/data_structure/index.d.ts +30 -0
  84. package/batteries/tools/data_structure.cjs +270 -0
  85. package/batteries/tools/data_structure.cjs.map +1 -0
  86. package/batteries/tools/data_structure.mjs +267 -0
  87. package/batteries/tools/data_structure.mjs.map +1 -0
  88. package/batteries/tools/datetime_extended/index.d.ts +51 -0
  89. package/batteries/tools/datetime_extended.cjs +309 -0
  90. package/batteries/tools/datetime_extended.cjs.map +1 -0
  91. package/batteries/tools/datetime_extended.mjs +302 -0
  92. package/batteries/tools/datetime_extended.mjs.map +1 -0
  93. package/batteries/tools/datetime_math/index.d.ts +36 -0
  94. package/batteries/tools/datetime_math.cjs +175 -0
  95. package/batteries/tools/datetime_math.cjs.map +1 -0
  96. package/batteries/tools/datetime_math.mjs +171 -0
  97. package/batteries/tools/datetime_math.mjs.map +1 -0
  98. package/batteries/tools/encoding/index.d.ts +36 -0
  99. package/batteries/tools/encoding.cjs +156 -0
  100. package/batteries/tools/encoding.cjs.map +1 -0
  101. package/batteries/tools/encoding.mjs +152 -0
  102. package/batteries/tools/encoding.mjs.map +1 -0
  103. package/batteries/tools/formatting/index.d.ts +28 -0
  104. package/batteries/tools/formatting.cjs +120 -0
  105. package/batteries/tools/formatting.cjs.map +1 -0
  106. package/batteries/tools/formatting.mjs +117 -0
  107. package/batteries/tools/formatting.mjs.map +1 -0
  108. package/batteries/tools/geo_basics/index.d.ts +33 -0
  109. package/batteries/tools/geo_basics.cjs +136 -0
  110. package/batteries/tools/geo_basics.cjs.map +1 -0
  111. package/batteries/tools/geo_basics.mjs +132 -0
  112. package/batteries/tools/geo_basics.mjs.map +1 -0
  113. package/batteries/tools/index.d.ts +32 -0
  114. package/batteries/tools/math/index.d.ts +37 -0
  115. package/batteries/tools/math.cjs +136 -0
  116. package/batteries/tools/math.cjs.map +1 -0
  117. package/batteries/tools/math.mjs +133 -0
  118. package/batteries/tools/math.mjs.map +1 -0
  119. package/batteries/tools/memory/index.d.ts +73 -0
  120. package/batteries/tools/memory.cjs +193 -0
  121. package/batteries/tools/memory.cjs.map +1 -0
  122. package/batteries/tools/memory.mjs +187 -0
  123. package/batteries/tools/memory.mjs.map +1 -0
  124. package/batteries/tools/parsing/index.d.ts +47 -0
  125. package/batteries/tools/parsing.cjs +191 -0
  126. package/batteries/tools/parsing.cjs.map +1 -0
  127. package/batteries/tools/parsing.mjs +185 -0
  128. package/batteries/tools/parsing.mjs.map +1 -0
  129. package/batteries/tools/retrievables/index.d.ts +81 -0
  130. package/batteries/tools/retrievables.cjs +215 -0
  131. package/batteries/tools/retrievables.cjs.map +1 -0
  132. package/batteries/tools/retrievables.mjs +209 -0
  133. package/batteries/tools/retrievables.mjs.map +1 -0
  134. package/batteries/tools/standing_instructions/index.d.ts +64 -0
  135. package/batteries/tools/standing_instructions.cjs +126 -0
  136. package/batteries/tools/standing_instructions.cjs.map +1 -0
  137. package/batteries/tools/standing_instructions.mjs +121 -0
  138. package/batteries/tools/standing_instructions.mjs.map +1 -0
  139. package/batteries/tools/statistics/index.d.ts +46 -0
  140. package/batteries/tools/statistics.cjs +253 -0
  141. package/batteries/tools/statistics.cjs.map +1 -0
  142. package/batteries/tools/statistics.mjs +248 -0
  143. package/batteries/tools/statistics.mjs.map +1 -0
  144. package/batteries/tools/string_processing/index.d.ts +29 -0
  145. package/batteries/tools/string_processing.cjs +154 -0
  146. package/batteries/tools/string_processing.cjs.map +1 -0
  147. package/batteries/tools/string_processing.mjs +151 -0
  148. package/batteries/tools/string_processing.mjs.map +1 -0
  149. package/batteries/tools/structured_data/index.d.ts +34 -0
  150. package/batteries/tools/structured_data.cjs +189 -0
  151. package/batteries/tools/structured_data.cjs.map +1 -0
  152. package/batteries/tools/structured_data.mjs +185 -0
  153. package/batteries/tools/structured_data.mjs.map +1 -0
  154. package/batteries/tools/text_analysis/index.d.ts +31 -0
  155. package/batteries/tools/text_analysis.cjs +120 -0
  156. package/batteries/tools/text_analysis.cjs.map +1 -0
  157. package/batteries/tools/text_analysis.mjs +117 -0
  158. package/batteries/tools/text_analysis.mjs.map +1 -0
  159. package/batteries/tools/text_comparison/index.d.ts +28 -0
  160. package/batteries/tools/text_comparison.cjs +96 -0
  161. package/batteries/tools/text_comparison.cjs.map +1 -0
  162. package/batteries/tools/text_comparison.mjs +93 -0
  163. package/batteries/tools/text_comparison.mjs.map +1 -0
  164. package/batteries/tools/time/index.d.ts +27 -0
  165. package/batteries/tools/time.cjs +63 -0
  166. package/batteries/tools/time.cjs.map +1 -0
  167. package/batteries/tools/time.mjs +60 -0
  168. package/batteries/tools/time.mjs.map +1 -0
  169. package/batteries/tools/unit_conversion/index.d.ts +19 -0
  170. package/batteries/tools/unit_conversion.cjs +452 -0
  171. package/batteries/tools/unit_conversion.cjs.map +1 -0
  172. package/batteries/tools/unit_conversion.mjs +450 -0
  173. package/batteries/tools/unit_conversion.mjs.map +1 -0
  174. package/batteries/tools.cjs +80 -0
  175. package/batteries/tools.mjs +21 -0
  176. package/batteries.cjs +142 -0
  177. package/batteries.mjs +30 -0
  178. package/chunk-KmRHZBOW.js +35 -0
  179. package/common-DeZaonK1.mjs +208 -0
  180. package/common-DeZaonK1.mjs.map +1 -0
  181. package/common-Od8edUXU.js +232 -0
  182. package/common-Od8edUXU.js.map +1 -0
  183. package/common.cjs +31 -0
  184. package/common.d.ts +108 -0
  185. package/common.mjs +8 -0
  186. package/dispatch_runner-9j6bXHL3.mjs +1609 -0
  187. package/dispatch_runner-9j6bXHL3.mjs.map +1 -0
  188. package/dispatch_runner-CsoH0nld.js +1627 -0
  189. package/dispatch_runner-CsoH0nld.js.map +1 -0
  190. package/dispatch_runner.cjs +3 -0
  191. package/dispatch_runner.d.ts +17 -0
  192. package/dispatch_runner.mjs +2 -0
  193. package/exceptions-D5YrO9Vm.js +280 -0
  194. package/exceptions-D5YrO9Vm.js.map +1 -0
  195. package/exceptions-NrzIHw_R.mjs +244 -0
  196. package/exceptions-NrzIHw_R.mjs.map +1 -0
  197. package/exceptions.cjs +33 -0
  198. package/exceptions.d.ts +52 -0
  199. package/exceptions.mjs +3 -0
  200. package/factories.cjs +4 -0
  201. package/factories.d.ts +39 -0
  202. package/factories.mjs +2 -0
  203. package/forge.cjs +9 -0
  204. package/forge.d.ts +49 -0
  205. package/forge.mjs +5 -0
  206. package/guards.cjs +96 -0
  207. package/guards.cjs.map +1 -0
  208. package/guards.d.ts +83 -0
  209. package/guards.mjs +72 -0
  210. package/guards.mjs.map +1 -0
  211. package/index.cjs +107 -0
  212. package/index.cjs.map +1 -0
  213. package/index.d.ts +18 -0
  214. package/index.mjs +31 -0
  215. package/index.mjs.map +1 -0
  216. package/lib/classes/artifact_tool.d.ts +129 -0
  217. package/lib/classes/base_exception.d.ts +83 -0
  218. package/lib/classes/identity.d.ts +71 -0
  219. package/lib/classes/media.d.ts +326 -0
  220. package/lib/classes/memory.d.ts +72 -0
  221. package/lib/classes/message.d.ts +137 -0
  222. package/lib/classes/registry.d.ts +79 -0
  223. package/lib/classes/retrievable.d.ts +100 -0
  224. package/lib/classes/spooled_artifact.d.ts +296 -0
  225. package/lib/classes/spooled_json_artifact.d.ts +158 -0
  226. package/lib/classes/spooled_markdown_artifact.d.ts +202 -0
  227. package/lib/classes/thought.d.ts +142 -0
  228. package/lib/classes/tokenizable.d.ts +124 -0
  229. package/lib/classes/tool.d.ts +228 -0
  230. package/lib/classes/tool_call.d.ts +190 -0
  231. package/lib/classes/tool_registry.d.ts +159 -0
  232. package/lib/classes/turn_gate.d.ts +109 -0
  233. package/lib/contracts/dispatch_context.d.ts +345 -0
  234. package/lib/contracts/media_reader.d.ts +60 -0
  235. package/lib/contracts/spool_reader.d.ts +80 -0
  236. package/lib/contracts/spooled_artifact_constructor.d.ts +38 -0
  237. package/lib/contracts/turn_runner_config.d.ts +101 -0
  238. package/lib/contracts/turn_runner_context.d.ts +267 -0
  239. package/lib/dispatch_runner.d.ts +98 -0
  240. package/lib/exceptions/runtime.d.ts +370 -0
  241. package/lib/helpers/media_readers.d.ts +39 -0
  242. package/lib/turn_runner.d.ts +144 -0
  243. package/lib/types/dispatch_context.d.ts +233 -0
  244. package/lib/types/dispatch_runner.d.ts +387 -0
  245. package/lib/types/turn_runner.d.ts +322 -0
  246. package/lib/utils/canonical_json.d.ts +18 -0
  247. package/lib/utils/exceptions.d.ts +78 -0
  248. package/lib/utils/guards.d.ts +32 -0
  249. package/lib/utils/validation.d.ts +77 -0
  250. package/package.json +334 -0
  251. package/runtime-BJVkrGQe.js +519 -0
  252. package/runtime-BJVkrGQe.js.map +1 -0
  253. package/runtime-CrEPIFgr.mjs +346 -0
  254. package/runtime-CrEPIFgr.mjs.map +1 -0
  255. package/skills/adk-assembly/SKILL.md +109 -0
  256. package/skills/adk-assembly/references/assembly-contract.md +66 -0
  257. package/skills/adk-assembly/references/executors-tools-pipelines-events.md +113 -0
  258. package/skills/adk-assembly/references/first-integration.md +93 -0
  259. package/skills/adk-assembly/references/storage-and-context.md +102 -0
  260. package/spooled_artifact-C5ZtGxuJ.mjs +544 -0
  261. package/spooled_artifact-C5ZtGxuJ.mjs.map +1 -0
  262. package/spooled_artifact-Cm9Te22K.js +568 -0
  263. package/spooled_artifact-Cm9Te22K.js.map +1 -0
  264. package/spooled_artifact.cjs +7 -0
  265. package/spooled_artifact.d.ts +40 -0
  266. package/spooled_artifact.mjs +3 -0
  267. package/spooled_markdown_artifact-BpUJol0W.mjs +771 -0
  268. package/spooled_markdown_artifact-BpUJol0W.mjs.map +1 -0
  269. package/spooled_markdown_artifact-RRB113sy.js +786 -0
  270. package/spooled_markdown_artifact-RRB113sy.js.map +1 -0
  271. package/thought-CDb457b4.mjs +470 -0
  272. package/thought-CDb457b4.mjs.map +1 -0
  273. package/thought-DuN2PgdO.js +494 -0
  274. package/thought-DuN2PgdO.js.map +1 -0
  275. package/tool-COSeH8I6.js +302 -0
  276. package/tool-COSeH8I6.js.map +1 -0
  277. package/tool-D2WB1EA1.mjs +296 -0
  278. package/tool-D2WB1EA1.mjs.map +1 -0
  279. package/tool_call-BKyyxGaZ.mjs +578 -0
  280. package/tool_call-BKyyxGaZ.mjs.map +1 -0
  281. package/tool_call-DFgzcVcU.js +608 -0
  282. package/tool_call-DFgzcVcU.js.map +1 -0
  283. package/tool_registry-Dkfprsck.js +641 -0
  284. package/tool_registry-Dkfprsck.js.map +1 -0
  285. package/tool_registry-DqLOyGyG.mjs +592 -0
  286. package/tool_registry-DqLOyGyG.mjs.map +1 -0
  287. package/turn_runner-CMm2BHdX.js +615 -0
  288. package/turn_runner-CMm2BHdX.js.map +1 -0
  289. package/turn_runner-y7eyEcJH.mjs +603 -0
  290. package/turn_runner-y7eyEcJH.mjs.map +1 -0
  291. package/turn_runner.cjs +3 -0
  292. package/turn_runner.d.ts +21 -0
  293. package/turn_runner.mjs +2 -0
  294. package/types.cjs +1 -0
  295. package/types.d.ts +56 -0
  296. package/types.mjs +0 -0
  297. package/vite-env.d.ts +23 -0
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Browser-only Origin Private File System storage for spooled artifacts.
3
+ *
4
+ * @module @nhtio/adk/batteries/storage/opfs
5
+ *
6
+ * @remarks
7
+ * Opt-in **browser-only** storage battery backed by the
8
+ * [Origin Private File System](https://developer.mozilla.org/docs/Web/API/File_System_API/Origin_private_file_system)
9
+ * (OPFS). Provides {@link OpfsSpoolReader} (a {@link @nhtio/adk!SpoolReader} over a `OpfsFileHandle`)
10
+ * and {@link OpfsSpoolStore} (a `write(callId, bytes) → reader` persistence layer that wraps an
11
+ * OPFS directory).
12
+ *
13
+ * The reader has two modes selected lazily on first method invocation based on the size of the
14
+ * underlying file:
15
+ *
16
+ * - **Eager mode** — when `file.size` is below `streamThresholdBytes` (default 10 MiB), the
17
+ * reader calls `file.text()` once, splits the content on `\n`, and caches lines + byte count.
18
+ * All subsequent calls resolve from memory.
19
+ * - **Streaming mode** — when `file.size` meets or exceeds the threshold, the reader streams the
20
+ * file once via `file.stream().getReader()` to build a line-offset index (`number[]` of byte
21
+ * offsets per line), then serves each `line(i)` request by slicing the underlying `Blob` —
22
+ * `Blob.slice(start, end).text()` decodes only the requested range, no head-of-file scan.
23
+ * Caps RAM at one index + one line buffer regardless of file size.
24
+ *
25
+ * The store auto-selects its write API by execution scope:
26
+ *
27
+ * - In **worker scopes** (`self instanceof WorkerGlobalScope`), it acquires a
28
+ * `FileSystemSyncAccessHandle` and writes synchronously. Sync handles are the only API
29
+ * available in workers and the fastest path for the spool-write hot path.
30
+ * - On the **main thread**, it uses `OpfsFileHandle.createWritable()` and the async
31
+ * stream API. Sync access handles are not exposed on the main thread.
32
+ *
33
+ * This module assumes a browser-equivalent runtime — `navigator.storage`,
34
+ * `OpfsFileHandle`, `TextEncoder`/`TextDecoder`, and `Blob` must all exist. It must not
35
+ * be imported from Node code; do so and you will fail at resolve time when `navigator` is
36
+ * referenced.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'
41
+ *
42
+ * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })
43
+ * const reader = await store.write(callId, bytes)
44
+ * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact
45
+ * const artifact = new Ctor(reader)
46
+ * ```
47
+ */
48
+ import type { SpoolReader } from "../../../common";
49
+ /**
50
+ * Minimal subset of the
51
+ * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)
52
+ * `OpfsFileHandle` interface that this module touches at runtime. Structurally compatible
53
+ * with the DOM-lib `OpfsFileHandle` — at call sites you pass real OPFS handles directly.
54
+ */
55
+ export interface OpfsFileHandle {
56
+ readonly kind: 'file';
57
+ readonly name: string;
58
+ getFile(): Promise<OpfsFile>;
59
+ createWritable(): Promise<OpfsWritableFileStream>;
60
+ }
61
+ /**
62
+ * Minimal subset of the
63
+ * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)
64
+ * `OpfsDirectoryHandle` interface that this module touches at runtime. Structurally
65
+ * compatible with the DOM-lib `OpfsDirectoryHandle` — at call sites you pass real OPFS
66
+ * handles directly.
67
+ */
68
+ export interface OpfsDirectoryHandle {
69
+ readonly kind: 'directory';
70
+ readonly name: string;
71
+ getFileHandle(name: string, options?: {
72
+ create?: boolean;
73
+ }): Promise<OpfsFileHandle>;
74
+ getDirectoryHandle(name: string, options?: {
75
+ create?: boolean;
76
+ }): Promise<OpfsDirectoryHandle>;
77
+ removeEntry(name: string, options?: {
78
+ recursive?: boolean;
79
+ }): Promise<void>;
80
+ }
81
+ /**
82
+ * Minimal subset of the DOM `FileSystemWritableFileStream` interface used by the OPFS battery's
83
+ * main-thread write path.
84
+ */
85
+ export interface OpfsWritableFileStream {
86
+ write(data: Uint8Array | ArrayBufferView | ArrayBuffer | string): Promise<void>;
87
+ close(): Promise<void>;
88
+ }
89
+ /**
90
+ * Minimal subset of the DOM `Blob` interface used by {@link OpfsSpoolReader} streaming-mode
91
+ * random-access reads. Real OPFS handles return a `File` here; we narrow to the methods we
92
+ * actually call.
93
+ */
94
+ export interface OpfsBlob {
95
+ readonly size: number;
96
+ slice(start?: number, end?: number, contentType?: string): OpfsBlob;
97
+ text(): Promise<string>;
98
+ stream(): OpfsReadableStream;
99
+ }
100
+ /**
101
+ * Minimal subset of the DOM `File` interface used by {@link OpfsSpoolReader}.
102
+ */
103
+ export interface OpfsFile extends OpfsBlob {
104
+ readonly name: string;
105
+ }
106
+ /**
107
+ * Minimal subset of the DOM `ReadableStream<Uint8Array>` interface used by streaming-mode
108
+ * index construction.
109
+ */
110
+ export interface OpfsReadableStream {
111
+ getReader(): OpfsReadableStreamReader;
112
+ }
113
+ /**
114
+ * Minimal subset of the DOM `ReadableStreamDefaultReader<Uint8Array>` interface used by
115
+ * streaming-mode index construction.
116
+ */
117
+ export interface OpfsReadableStreamReader {
118
+ read(): Promise<{
119
+ done: false;
120
+ value: Uint8Array;
121
+ } | {
122
+ done: true;
123
+ value: undefined;
124
+ }>;
125
+ releaseLock(): void;
126
+ }
127
+ /**
128
+ * Constructor options for {@link OpfsSpoolReader}.
129
+ */
130
+ export interface OpfsSpoolReaderOptions {
131
+ /**
132
+ * Byte-length threshold that switches between eager and streaming modes.
133
+ *
134
+ * @remarks
135
+ * - Below the threshold → eager (whole-file in memory).
136
+ * - At or above the threshold → streaming (line-offset index + per-line slice reads).
137
+ *
138
+ * Set to `0` to force streaming mode; set to `Number.POSITIVE_INFINITY` to force eager mode.
139
+ *
140
+ * @defaultValue `10 * 1024 * 1024` (10 MiB)
141
+ */
142
+ streamThresholdBytes?: number;
143
+ }
144
+ /**
145
+ * Reads an OPFS-backed file as a {@link @nhtio/adk!SpoolReader}.
146
+ *
147
+ * @remarks
148
+ * Constructor is **not** async — but the first method call awaits a private readiness promise
149
+ * that fetches the underlying `File` (and in eager mode, its contents). Subsequent calls reuse
150
+ * the cached state. This keeps construction call sites synchronous while still doing real I/O
151
+ * lazily.
152
+ *
153
+ * All four `SpoolReader` methods on this reader return promises. The `SpoolReader` contract
154
+ * supports both sync and async return; consumers of `SpooledArtifact` handle either.
155
+ */
156
+ export declare class OpfsSpoolReader implements SpoolReader {
157
+ #private;
158
+ constructor(handle: OpfsFileHandle, opts?: OpfsSpoolReaderOptions);
159
+ /**
160
+ * Returns `true` if `value` is an {@link OpfsSpoolReader} instance.
161
+ *
162
+ * @remarks
163
+ * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.
164
+ *
165
+ * @param value - The value to test.
166
+ * @returns `true` when `value` is an {@link OpfsSpoolReader} instance.
167
+ */
168
+ static isOpfsSpoolReader(value: unknown): value is OpfsSpoolReader;
169
+ line(index: number): Promise<string | undefined>;
170
+ byteLength(): Promise<number>;
171
+ lineCount(): Promise<number>;
172
+ /**
173
+ * Returns the full underlying content as a single decoded string, byte-faithful to the source.
174
+ *
175
+ * @remarks
176
+ * In **eager mode** the content is already cached at first-call load and this method is
177
+ * effectively a property access. In **streaming mode** there is no cache: the file is re-read
178
+ * (as a single `File.text()` call) on every invocation. Use `SpooledArtifact.asString()`
179
+ * judiciously on large streaming-mode artifacts.
180
+ */
181
+ readAll(): Promise<string>;
182
+ }
183
+ /**
184
+ * Constructor options for {@link OpfsSpoolStore}.
185
+ */
186
+ export interface OpfsSpoolStoreOptions {
187
+ /**
188
+ * Optional thunk that resolves the {@link OpfsDirectoryHandle} used as the store root.
189
+ *
190
+ * @remarks
191
+ * When omitted, the store resolves the root via `navigator.storage.getDirectory()` on its
192
+ * first filesystem call. Override for tests (to point at a per-suite subdirectory) or to
193
+ * scope the store to a nested directory inside OPFS.
194
+ *
195
+ * The thunk is invoked at most once per store; the returned handle is memoised.
196
+ */
197
+ directory?: () => Promise<OpfsDirectoryHandle>;
198
+ /**
199
+ * Optional filename prefix prepended to every `callId`.
200
+ *
201
+ * @remarks
202
+ * Prefix is a **filename prefix**, not a subdirectory — `keyPrefix: 'agent-runs/'` produces
203
+ * a file literally named `agent-runs/<callId>` at the root, not a nested directory. (OPFS
204
+ * filenames may not contain `/`, so use a non-`/` separator like `-` if you want a flat
205
+ * namespace.) This mirrors the `keyPrefix` semantics in the flydrive and in-memory batteries.
206
+ *
207
+ * @defaultValue `""`
208
+ */
209
+ keyPrefix?: string;
210
+ /**
211
+ * Default `streamThresholdBytes` for readers produced by `write()` and `read()`. Individual
212
+ * calls may override via their own `opts` argument.
213
+ *
214
+ * @defaultValue `10 * 1024 * 1024` (10 MiB)
215
+ */
216
+ streamThresholdBytes?: number;
217
+ }
218
+ /**
219
+ * "Give bytes, get a reader" persistence layer over an OPFS directory.
220
+ *
221
+ * @remarks
222
+ * `write(callId, bytes)` resolves the root directory (lazily, on first call), opens or creates
223
+ * the file named `keyPrefix + callId`, then writes via the API matching the current scope:
224
+ * a `FileSystemSyncAccessHandle` in worker scopes, `OpfsFileHandle.createWritable()` on
225
+ * the main thread. A fresh {@link OpfsSpoolReader} pointed at the same file is returned.
226
+ *
227
+ * `read(callId)` returns a reader without re-writing; `delete(callId)` removes the entry.
228
+ *
229
+ * The store is otherwise stateless — it owns no in-memory cache of writes. Multiple
230
+ * `OpfsSpoolStore` instances sharing the same root directory and key prefix see the same data.
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'
235
+ *
236
+ * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })
237
+ *
238
+ * const bytes = await tool.executor(ctx)(args)
239
+ * const reader = await store.write(callId, bytes)
240
+ * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact
241
+ * const artifact = new Ctor(reader)
242
+ * ```
243
+ */
244
+ export declare class OpfsSpoolStore {
245
+ #private;
246
+ constructor(opts?: OpfsSpoolStoreOptions);
247
+ /**
248
+ * Returns `true` if `value` is an {@link OpfsSpoolStore} instance.
249
+ *
250
+ * @remarks
251
+ * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.
252
+ *
253
+ * @param value - The value to test.
254
+ * @returns `true` when `value` is an {@link OpfsSpoolStore} instance.
255
+ */
256
+ static isOpfsSpoolStore(value: unknown): value is OpfsSpoolStore;
257
+ /**
258
+ * Persists `bytes` under `callId` and returns a reader bound to the stored key.
259
+ *
260
+ * @param callId - Identifier used to retrieve the bytes via {@link OpfsSpoolStore.read}.
261
+ * @param bytes - The bytes to store, as a `string` or `Uint8Array`.
262
+ * @param opts - Per-call override for `streamThresholdBytes`.
263
+ * @returns An {@link OpfsSpoolReader} over the stored bytes.
264
+ */
265
+ write(callId: string, bytes: string | Uint8Array, opts?: OpfsSpoolReaderOptions): Promise<OpfsSpoolReader>;
266
+ /**
267
+ * Returns a reader over the bytes previously written under `callId`.
268
+ *
269
+ * @remarks
270
+ * Returns `undefined` if the file does not exist.
271
+ *
272
+ * @param callId - Identifier supplied to a prior {@link OpfsSpoolStore.write} call.
273
+ * @param opts - Per-call override for `streamThresholdBytes`.
274
+ * @returns An {@link OpfsSpoolReader}, or `undefined` if the key is missing.
275
+ */
276
+ read(callId: string, opts?: OpfsSpoolReaderOptions): Promise<OpfsSpoolReader | undefined>;
277
+ /**
278
+ * Removes the entry under `callId`.
279
+ *
280
+ * @param callId - Identifier whose entry should be removed.
281
+ * @returns `true` if the entry existed and was removed; `false` if it didn't exist.
282
+ */
283
+ delete(callId: string): Promise<boolean>;
284
+ /**
285
+ * Returns `true` if a file is present under `callId`.
286
+ *
287
+ * @param callId - Identifier to test.
288
+ * @returns `true` when the file exists, `false` otherwise.
289
+ */
290
+ has(callId: string): Promise<boolean>;
291
+ /**
292
+ * Returns the full filename for a given `callId` (i.e. `keyPrefix + callId`).
293
+ *
294
+ * @remarks
295
+ * Useful for tests or for callers that want to interact with the underlying OPFS directory
296
+ * directly.
297
+ */
298
+ keyFor(callId: string): string;
299
+ }
@@ -0,0 +1,368 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_tool_registry = require("../../tool_registry-Dkfprsck.js");
3
+ require("../../guards.cjs");
4
+ //#region src/batteries/storage/opfs/index.ts
5
+ /**
6
+ * Browser-only Origin Private File System storage for spooled artifacts.
7
+ *
8
+ * @module @nhtio/adk/batteries/storage/opfs
9
+ *
10
+ * @remarks
11
+ * Opt-in **browser-only** storage battery backed by the
12
+ * [Origin Private File System](https://developer.mozilla.org/docs/Web/API/File_System_API/Origin_private_file_system)
13
+ * (OPFS). Provides {@link OpfsSpoolReader} (a {@link @nhtio/adk!SpoolReader} over a `OpfsFileHandle`)
14
+ * and {@link OpfsSpoolStore} (a `write(callId, bytes) → reader` persistence layer that wraps an
15
+ * OPFS directory).
16
+ *
17
+ * The reader has two modes selected lazily on first method invocation based on the size of the
18
+ * underlying file:
19
+ *
20
+ * - **Eager mode** — when `file.size` is below `streamThresholdBytes` (default 10 MiB), the
21
+ * reader calls `file.text()` once, splits the content on `\n`, and caches lines + byte count.
22
+ * All subsequent calls resolve from memory.
23
+ * - **Streaming mode** — when `file.size` meets or exceeds the threshold, the reader streams the
24
+ * file once via `file.stream().getReader()` to build a line-offset index (`number[]` of byte
25
+ * offsets per line), then serves each `line(i)` request by slicing the underlying `Blob` —
26
+ * `Blob.slice(start, end).text()` decodes only the requested range, no head-of-file scan.
27
+ * Caps RAM at one index + one line buffer regardless of file size.
28
+ *
29
+ * The store auto-selects its write API by execution scope:
30
+ *
31
+ * - In **worker scopes** (`self instanceof WorkerGlobalScope`), it acquires a
32
+ * `FileSystemSyncAccessHandle` and writes synchronously. Sync handles are the only API
33
+ * available in workers and the fastest path for the spool-write hot path.
34
+ * - On the **main thread**, it uses `OpfsFileHandle.createWritable()` and the async
35
+ * stream API. Sync access handles are not exposed on the main thread.
36
+ *
37
+ * This module assumes a browser-equivalent runtime — `navigator.storage`,
38
+ * `OpfsFileHandle`, `TextEncoder`/`TextDecoder`, and `Blob` must all exist. It must not
39
+ * be imported from Node code; do so and you will fail at resolve time when `navigator` is
40
+ * referenced.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'
45
+ *
46
+ * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })
47
+ * const reader = await store.write(callId, bytes)
48
+ * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact
49
+ * const artifact = new Ctor(reader)
50
+ * ```
51
+ */
52
+ var DEFAULT_STREAM_THRESHOLD_BYTES = 10 * 1024 * 1024;
53
+ var LF = 10;
54
+ var isNonNegativeFiniteNumber = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0;
55
+ /**
56
+ * Returns `true` when the current global scope is a Web Worker (`DedicatedWorkerGlobalScope`,
57
+ * `SharedWorkerGlobalScope`, or `ServiceWorkerGlobalScope` all inherit from `WorkerGlobalScope`).
58
+ *
59
+ * @remarks
60
+ * The check is needed at runtime because `FileSystemSyncAccessHandle` is only exposed in worker
61
+ * scopes — calling it from the main thread throws. We pick the write strategy based on the
62
+ * answer here.
63
+ *
64
+ * @internal
65
+ */
66
+ var isWorkerScope = () => {
67
+ if (typeof WorkerGlobalScope === "undefined") return false;
68
+ return self instanceof WorkerGlobalScope;
69
+ };
70
+ /**
71
+ * Reads an OPFS-backed file as a {@link @nhtio/adk!SpoolReader}.
72
+ *
73
+ * @remarks
74
+ * Constructor is **not** async — but the first method call awaits a private readiness promise
75
+ * that fetches the underlying `File` (and in eager mode, its contents). Subsequent calls reuse
76
+ * the cached state. This keeps construction call sites synchronous while still doing real I/O
77
+ * lazily.
78
+ *
79
+ * All four `SpoolReader` methods on this reader return promises. The `SpoolReader` contract
80
+ * supports both sync and async return; consumers of `SpooledArtifact` handle either.
81
+ */
82
+ var OpfsSpoolReader = class OpfsSpoolReader {
83
+ #handle;
84
+ #threshold;
85
+ #ready;
86
+ constructor(handle, opts = {}) {
87
+ this.#handle = handle;
88
+ const raw = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES;
89
+ if (typeof raw !== "number" || Number.isNaN(raw) || raw < 0) throw new TypeError(`OpfsSpoolReader: streamThresholdBytes must be a non-negative number or Infinity, got ${String(raw)}`);
90
+ this.#threshold = raw;
91
+ }
92
+ /**
93
+ * Returns `true` if `value` is an {@link OpfsSpoolReader} instance.
94
+ *
95
+ * @remarks
96
+ * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.
97
+ *
98
+ * @param value - The value to test.
99
+ * @returns `true` when `value` is an {@link OpfsSpoolReader} instance.
100
+ */
101
+ static isOpfsSpoolReader(value) {
102
+ return require_tool_registry.isInstanceOf(value, "OpfsSpoolReader", OpfsSpoolReader);
103
+ }
104
+ async line(index) {
105
+ const state = await this.#load();
106
+ if (state.mode === "eager") return state.lines[index];
107
+ if (index < 0 || index >= state.offsets.length - 1) return void 0;
108
+ return this.#readRange(state.file, state.offsets[index], state.offsets[index + 1]);
109
+ }
110
+ async byteLength() {
111
+ return (await this.#load()).bytes;
112
+ }
113
+ async lineCount() {
114
+ const state = await this.#load();
115
+ return state.mode === "eager" ? state.lines.length : state.offsets.length - 1;
116
+ }
117
+ /**
118
+ * Returns the full underlying content as a single decoded string, byte-faithful to the source.
119
+ *
120
+ * @remarks
121
+ * In **eager mode** the content is already cached at first-call load and this method is
122
+ * effectively a property access. In **streaming mode** there is no cache: the file is re-read
123
+ * (as a single `File.text()` call) on every invocation. Use `SpooledArtifact.asString()`
124
+ * judiciously on large streaming-mode artifacts.
125
+ */
126
+ async readAll() {
127
+ const state = await this.#load();
128
+ if (state.mode === "eager") return state.content;
129
+ return state.file.text();
130
+ }
131
+ /**
132
+ * Lazily initialise the reader's mode-specific state. Called by every public method; the
133
+ * promise is cached so the work runs at most once.
134
+ */
135
+ #load() {
136
+ if (!this.#ready) this.#ready = this.#init();
137
+ return this.#ready;
138
+ }
139
+ async #init() {
140
+ const file = await this.#handle.getFile();
141
+ const bytes = file.size;
142
+ if (!isNonNegativeFiniteNumber(bytes)) throw new Error(`OpfsSpoolReader: file handle returned a non-finite size (${String(bytes)})`);
143
+ if (bytes < this.#threshold) {
144
+ const content = await file.text();
145
+ return {
146
+ mode: "eager",
147
+ lines: content === "" ? [] : content.split("\n"),
148
+ bytes,
149
+ content
150
+ };
151
+ }
152
+ return this.#buildStreamingIndex(file, bytes);
153
+ }
154
+ async #buildStreamingIndex(file, bytes) {
155
+ if (bytes === 0) return {
156
+ mode: "streaming",
157
+ file,
158
+ offsets: [0],
159
+ bytes
160
+ };
161
+ const offsets = [0];
162
+ let position = 0;
163
+ let lastByte = -1;
164
+ const reader = file.stream().getReader();
165
+ try {
166
+ for (;;) {
167
+ const { done, value } = await reader.read();
168
+ if (done) break;
169
+ for (const byte of value) {
170
+ position++;
171
+ if (byte === LF) offsets.push(position);
172
+ lastByte = byte;
173
+ }
174
+ }
175
+ } finally {
176
+ reader.releaseLock();
177
+ }
178
+ if (lastByte === LF) offsets.push(position);
179
+ else if (offsets[offsets.length - 1] !== position) offsets.push(position);
180
+ return {
181
+ mode: "streaming",
182
+ file,
183
+ offsets,
184
+ bytes
185
+ };
186
+ }
187
+ /**
188
+ * Slices the byte range `[start, end)` from the backing file and returns it as a UTF-8
189
+ * string, stripping a trailing `\n` if present.
190
+ *
191
+ * @remarks
192
+ * `Blob.slice` is O(1) metadata; `Blob.text()` only decodes the slice. The line-offset index
193
+ * brackets each line *with* its trailing LF (so `offsets[i+1]` points at the start of the
194
+ * next line) and the `SpoolReader` contract returns lines *without* their trailing newline,
195
+ * so we strip a single trailing LF if present.
196
+ */
197
+ async #readRange(file, start, end) {
198
+ if (start === end) return "";
199
+ const text = await file.slice(start, end).text();
200
+ if (text.length > 0 && text.charCodeAt(text.length - 1) === LF) return text.slice(0, -1);
201
+ return text;
202
+ }
203
+ };
204
+ /**
205
+ * "Give bytes, get a reader" persistence layer over an OPFS directory.
206
+ *
207
+ * @remarks
208
+ * `write(callId, bytes)` resolves the root directory (lazily, on first call), opens or creates
209
+ * the file named `keyPrefix + callId`, then writes via the API matching the current scope:
210
+ * a `FileSystemSyncAccessHandle` in worker scopes, `OpfsFileHandle.createWritable()` on
211
+ * the main thread. A fresh {@link OpfsSpoolReader} pointed at the same file is returned.
212
+ *
213
+ * `read(callId)` returns a reader without re-writing; `delete(callId)` removes the entry.
214
+ *
215
+ * The store is otherwise stateless — it owns no in-memory cache of writes. Multiple
216
+ * `OpfsSpoolStore` instances sharing the same root directory and key prefix see the same data.
217
+ *
218
+ * @example
219
+ * ```ts
220
+ * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'
221
+ *
222
+ * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })
223
+ *
224
+ * const bytes = await tool.executor(ctx)(args)
225
+ * const reader = await store.write(callId, bytes)
226
+ * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact
227
+ * const artifact = new Ctor(reader)
228
+ * ```
229
+ */
230
+ var OpfsSpoolStore = class OpfsSpoolStore {
231
+ #resolveRoot;
232
+ #prefix;
233
+ #defaultThreshold;
234
+ #root;
235
+ constructor(opts = {}) {
236
+ this.#resolveRoot = opts.directory ?? (() => navigator.storage.getDirectory());
237
+ this.#prefix = opts.keyPrefix ?? "";
238
+ this.#defaultThreshold = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES;
239
+ }
240
+ /**
241
+ * Returns `true` if `value` is an {@link OpfsSpoolStore} instance.
242
+ *
243
+ * @remarks
244
+ * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.
245
+ *
246
+ * @param value - The value to test.
247
+ * @returns `true` when `value` is an {@link OpfsSpoolStore} instance.
248
+ */
249
+ static isOpfsSpoolStore(value) {
250
+ return require_tool_registry.isInstanceOf(value, "OpfsSpoolStore", OpfsSpoolStore);
251
+ }
252
+ /**
253
+ * Persists `bytes` under `callId` and returns a reader bound to the stored key.
254
+ *
255
+ * @param callId - Identifier used to retrieve the bytes via {@link OpfsSpoolStore.read}.
256
+ * @param bytes - The bytes to store, as a `string` or `Uint8Array`.
257
+ * @param opts - Per-call override for `streamThresholdBytes`.
258
+ * @returns An {@link OpfsSpoolReader} over the stored bytes.
259
+ */
260
+ async write(callId, bytes, opts) {
261
+ const name = this.#keyFor(callId);
262
+ const handle = await (await this.#getRoot()).getFileHandle(name, { create: true });
263
+ const payload = typeof bytes === "string" ? new TextEncoder().encode(bytes) : bytes;
264
+ if (isWorkerScope()) await this.#writeViaSyncHandle(handle, payload);
265
+ else await this.#writeViaWritable(handle, payload);
266
+ return new OpfsSpoolReader(handle, { streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold });
267
+ }
268
+ /**
269
+ * Returns a reader over the bytes previously written under `callId`.
270
+ *
271
+ * @remarks
272
+ * Returns `undefined` if the file does not exist.
273
+ *
274
+ * @param callId - Identifier supplied to a prior {@link OpfsSpoolStore.write} call.
275
+ * @param opts - Per-call override for `streamThresholdBytes`.
276
+ * @returns An {@link OpfsSpoolReader}, or `undefined` if the key is missing.
277
+ */
278
+ async read(callId, opts) {
279
+ const name = this.#keyFor(callId);
280
+ const root = await this.#getRoot();
281
+ let handle;
282
+ try {
283
+ handle = await root.getFileHandle(name);
284
+ } catch (err) {
285
+ if (this.#isNotFoundError(err)) return void 0;
286
+ throw err;
287
+ }
288
+ return new OpfsSpoolReader(handle, { streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold });
289
+ }
290
+ /**
291
+ * Removes the entry under `callId`.
292
+ *
293
+ * @param callId - Identifier whose entry should be removed.
294
+ * @returns `true` if the entry existed and was removed; `false` if it didn't exist.
295
+ */
296
+ async delete(callId) {
297
+ const name = this.#keyFor(callId);
298
+ const root = await this.#getRoot();
299
+ try {
300
+ await root.removeEntry(name);
301
+ return true;
302
+ } catch (err) {
303
+ if (this.#isNotFoundError(err)) return false;
304
+ throw err;
305
+ }
306
+ }
307
+ /**
308
+ * Returns `true` if a file is present under `callId`.
309
+ *
310
+ * @param callId - Identifier to test.
311
+ * @returns `true` when the file exists, `false` otherwise.
312
+ */
313
+ async has(callId) {
314
+ const name = this.#keyFor(callId);
315
+ const root = await this.#getRoot();
316
+ try {
317
+ await root.getFileHandle(name);
318
+ return true;
319
+ } catch (err) {
320
+ if (this.#isNotFoundError(err)) return false;
321
+ throw err;
322
+ }
323
+ }
324
+ /**
325
+ * Returns the full filename for a given `callId` (i.e. `keyPrefix + callId`).
326
+ *
327
+ * @remarks
328
+ * Useful for tests or for callers that want to interact with the underlying OPFS directory
329
+ * directly.
330
+ */
331
+ keyFor(callId) {
332
+ return this.#keyFor(callId);
333
+ }
334
+ #keyFor(callId) {
335
+ return this.#prefix + callId;
336
+ }
337
+ async #getRoot() {
338
+ if (!this.#root) this.#root = await this.#resolveRoot();
339
+ return this.#root;
340
+ }
341
+ async #writeViaSyncHandle(handle, payload) {
342
+ const sync = await handle.createSyncAccessHandle();
343
+ try {
344
+ sync.truncate(0);
345
+ sync.write(payload, { at: 0 });
346
+ sync.flush();
347
+ } finally {
348
+ sync.close();
349
+ }
350
+ }
351
+ async #writeViaWritable(handle, payload) {
352
+ const writable = await handle.createWritable();
353
+ try {
354
+ await writable.write(payload);
355
+ } finally {
356
+ await writable.close();
357
+ }
358
+ }
359
+ #isNotFoundError(err) {
360
+ if (err === null || typeof err !== "object") return false;
361
+ return err.name === "NotFoundError";
362
+ }
363
+ };
364
+ //#endregion
365
+ exports.OpfsSpoolReader = OpfsSpoolReader;
366
+ exports.OpfsSpoolStore = OpfsSpoolStore;
367
+
368
+ //# sourceMappingURL=opfs.cjs.map