@ricsam/r5d-worker 0.0.136 → 0.0.138

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 (240) hide show
  1. package/README.md +4 -94
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/mjs/main.mjs +46 -7537
  4. package/dist/mjs/package.json +1 -1
  5. package/dist/mjs/personal/action-scheduler.mjs +31 -0
  6. package/dist/mjs/personal/client.mjs +215 -0
  7. package/dist/mjs/personal/runtime.mjs +328 -0
  8. package/dist/mjs/personal/tcp.mjs +217 -0
  9. package/dist/mjs/runtime/adapter.mjs +42 -0
  10. package/dist/mjs/runtime/client.mjs +95 -0
  11. package/dist/mjs/runtime/daemon.mjs +131 -0
  12. package/dist/mjs/runtime/executor.mjs +436 -0
  13. package/dist/mjs/runtime/index.mjs +15 -0
  14. package/dist/mjs/runtime/protocol.mjs +139 -0
  15. package/dist/mjs/runtime/pty-host.mjs +156 -0
  16. package/dist/mjs/runtime/pty.mjs +127 -0
  17. package/dist/mjs/runtime/releases/artifacts.mjs +201 -0
  18. package/dist/mjs/runtime/releases/grants.mjs +93 -0
  19. package/dist/mjs/runtime/releases/main.mjs +101 -0
  20. package/dist/mjs/runtime/releases/manager.mjs +541 -0
  21. package/dist/mjs/runtime/releases/process.mjs +88 -0
  22. package/dist/mjs/runtime/releases/retirement.mjs +18 -0
  23. package/dist/mjs/runtime/releases/rpc-client.mjs +184 -0
  24. package/dist/mjs/runtime/releases/rpc-main.mjs +213 -0
  25. package/dist/mjs/runtime/releases/rpc-protocol.mjs +103 -0
  26. package/dist/mjs/runtime/storage.mjs +156 -0
  27. package/dist/mjs/runtime/workspace/artifacts.mjs +121 -0
  28. package/dist/mjs/runtime/workspace/authority.mjs +1355 -0
  29. package/dist/mjs/runtime/workspace/contracts.mjs +60 -0
  30. package/dist/mjs/runtime/workspace/file-write.mjs +23 -0
  31. package/dist/mjs/runtime/workspace/files.mjs +308 -0
  32. package/dist/mjs/runtime/workspace/http-body.mjs +45 -0
  33. package/dist/mjs/runtime/workspace/storage-client.mjs +59 -0
  34. package/dist/mjs/runtime/workspace/storage-wire.mjs +53 -0
  35. package/dist/types/main.d.ts +0 -1167
  36. package/dist/types/personal/action-scheduler.d.ts +23 -0
  37. package/dist/types/personal/client.d.ts +14 -0
  38. package/dist/types/personal/runtime.d.ts +121 -0
  39. package/dist/types/personal/tcp.d.ts +14 -0
  40. package/dist/types/runtime/client.d.ts +17 -0
  41. package/dist/types/runtime/daemon.d.ts +8 -0
  42. package/dist/types/runtime/executor.d.ts +35 -0
  43. package/dist/types/runtime/index.d.ts +5 -0
  44. package/dist/types/runtime/protocol.d.ts +544 -0
  45. package/dist/types/runtime/pty.d.ts +30 -0
  46. package/dist/types/runtime/releases/artifacts.d.ts +51 -0
  47. package/dist/types/runtime/releases/grants.d.ts +16 -0
  48. package/dist/types/runtime/releases/manager.d.ts +145 -0
  49. package/dist/types/runtime/releases/process.d.ts +14 -0
  50. package/dist/types/runtime/releases/retirement.d.ts +15 -0
  51. package/dist/types/runtime/releases/rpc-client.d.ts +52 -0
  52. package/dist/types/runtime/releases/rpc-main.d.ts +10 -0
  53. package/dist/types/runtime/releases/rpc-protocol.d.ts +1139 -0
  54. package/dist/types/runtime/storage.d.ts +21 -0
  55. package/dist/types/runtime/test-harness.d.ts +53 -0
  56. package/dist/types/runtime/workspace/artifacts.d.ts +30 -0
  57. package/dist/types/runtime/workspace/authority.d.ts +338 -0
  58. package/dist/types/runtime/workspace/contracts.d.ts +86 -0
  59. package/dist/types/runtime/workspace/file-write.d.ts +14 -0
  60. package/dist/types/runtime/workspace/files.d.ts +21 -0
  61. package/dist/types/runtime/workspace/http-body.d.ts +9 -0
  62. package/dist/types/runtime/workspace/storage-client.d.ts +23 -0
  63. package/dist/types/runtime/workspace/storage-wire.d.ts +138 -0
  64. package/package.json +8 -6
  65. package/dist/cjs/atomic-rename.cjs +0 -303
  66. package/dist/cjs/browser-upload.cjs +0 -73
  67. package/dist/cjs/cli-update.cjs +0 -108
  68. package/dist/cjs/command-launcher.cjs +0 -423
  69. package/dist/cjs/control-command-policy.cjs +0 -177
  70. package/dist/cjs/git-blob-hash.cjs +0 -41
  71. package/dist/cjs/git-identity.cjs +0 -39
  72. package/dist/cjs/git-process-environment.cjs +0 -133
  73. package/dist/cjs/inline-output.cjs +0 -62
  74. package/dist/cjs/main.cjs +0 -7511
  75. package/dist/cjs/managed-paths.cjs +0 -215
  76. package/dist/cjs/plan-lint.cjs +0 -165
  77. package/dist/cjs/plan-parser.cjs +0 -127
  78. package/dist/cjs/plan-paths.cjs +0 -53
  79. package/dist/cjs/port-forward-client.cjs +0 -206
  80. package/dist/cjs/process-tree.cjs +0 -117
  81. package/dist/cjs/project-checkout-garbage.cjs +0 -219
  82. package/dist/cjs/project-mirror-fetch-policy.cjs +0 -82
  83. package/dist/cjs/project-mirror-refs-token.cjs +0 -85
  84. package/dist/cjs/project-workspace-state.cjs +0 -972
  85. package/dist/cjs/project-worktrees.cjs +0 -1713
  86. package/dist/cjs/pty-output-coalescer.cjs +0 -87
  87. package/dist/cjs/recovery-journal-protocol.cjs +0 -56
  88. package/dist/cjs/recovery-journal-runtime.cjs +0 -133
  89. package/dist/cjs/recovery-journal-thread.cjs +0 -9
  90. package/dist/cjs/recovery-journal.cjs +0 -742
  91. package/dist/cjs/recovery-output-window.cjs +0 -77
  92. package/dist/cjs/recovery-protocol.cjs +0 -31
  93. package/dist/cjs/recovery-store.cjs +0 -252
  94. package/dist/cjs/registry-auth.cjs +0 -310
  95. package/dist/cjs/repository-transition-policy.cjs +0 -49
  96. package/dist/cjs/runtime-version.cjs +0 -88
  97. package/dist/cjs/session-file-mutations.cjs +0 -61
  98. package/dist/cjs/supervisor.cjs +0 -147
  99. package/dist/cjs/three-way-merge.cjs +0 -346
  100. package/dist/cjs/working-tree-mirror.cjs +0 -1872
  101. package/dist/cjs/workspace-automatic-sync-policy.cjs +0 -79
  102. package/dist/cjs/workspace-branch-incarnation-policy.cjs +0 -37
  103. package/dist/cjs/workspace-command-sync-policy.cjs +0 -112
  104. package/dist/cjs/workspace-command-targets.cjs +0 -63
  105. package/dist/cjs/workspace-filesystem-executor-thread.cjs +0 -36
  106. package/dist/cjs/workspace-filesystem-executor.cjs +0 -327
  107. package/dist/cjs/workspace-filesystem-job-types.cjs +0 -144
  108. package/dist/cjs/workspace-filesystem-jobs.cjs +0 -59
  109. package/dist/cjs/workspace-git-sync.cjs +0 -3450
  110. package/dist/cjs/workspace-hydration-ledger.cjs +0 -66
  111. package/dist/cjs/workspace-hydration-merge.cjs +0 -433
  112. package/dist/cjs/workspace-hydration-recovery-state.cjs +0 -53
  113. package/dist/cjs/workspace-incident-state.cjs +0 -37
  114. package/dist/cjs/workspace-merge-projection.cjs +0 -467
  115. package/dist/cjs/workspace-mount-boundary.cjs +0 -71
  116. package/dist/cjs/workspace-mount-hold-fence.cjs +0 -120
  117. package/dist/cjs/workspace-mutation-gate.cjs +0 -127
  118. package/dist/cjs/workspace-path-move.cjs +0 -195
  119. package/dist/cjs/workspace-preserve-only-policy.cjs +0 -36
  120. package/dist/cjs/workspace-project-config-policy.cjs +0 -53
  121. package/dist/cjs/workspace-projection-ledger.cjs +0 -81
  122. package/dist/cjs/workspace-publication-evidence.cjs +0 -46
  123. package/dist/cjs/workspace-sync-coalescer.cjs +0 -58
  124. package/dist/mjs/atomic-rename.mjs +0 -261
  125. package/dist/mjs/browser-upload.mjs +0 -42
  126. package/dist/mjs/command-launcher.mjs +0 -393
  127. package/dist/mjs/control-command-policy.mjs +0 -146
  128. package/dist/mjs/git-blob-hash.mjs +0 -16
  129. package/dist/mjs/git-identity.mjs +0 -15
  130. package/dist/mjs/git-process-environment.mjs +0 -105
  131. package/dist/mjs/inline-output.mjs +0 -37
  132. package/dist/mjs/managed-paths.mjs +0 -174
  133. package/dist/mjs/plan-lint.mjs +0 -129
  134. package/dist/mjs/plan-parser.mjs +0 -94
  135. package/dist/mjs/plan-paths.mjs +0 -25
  136. package/dist/mjs/port-forward-client.mjs +0 -172
  137. package/dist/mjs/project-checkout-garbage.mjs +0 -178
  138. package/dist/mjs/project-mirror-fetch-policy.mjs +0 -56
  139. package/dist/mjs/project-mirror-refs-token.mjs +0 -53
  140. package/dist/mjs/project-workspace-state.mjs +0 -937
  141. package/dist/mjs/project-worktrees.mjs +0 -1657
  142. package/dist/mjs/pty-output-coalescer.mjs +0 -61
  143. package/dist/mjs/recovery-journal-protocol.mjs +0 -30
  144. package/dist/mjs/recovery-journal-runtime.mjs +0 -112
  145. package/dist/mjs/recovery-journal-thread.mjs +0 -8
  146. package/dist/mjs/recovery-journal.mjs +0 -694
  147. package/dist/mjs/recovery-output-window.mjs +0 -53
  148. package/dist/mjs/recovery-protocol.mjs +0 -6
  149. package/dist/mjs/recovery-store.mjs +0 -217
  150. package/dist/mjs/registry-auth.mjs +0 -269
  151. package/dist/mjs/repository-transition-policy.mjs +0 -22
  152. package/dist/mjs/runtime-version.mjs +0 -54
  153. package/dist/mjs/session-file-mutations.mjs +0 -37
  154. package/dist/mjs/supervisor.mjs +0 -114
  155. package/dist/mjs/three-way-merge.mjs +0 -318
  156. package/dist/mjs/working-tree-mirror.mjs +0 -1817
  157. package/dist/mjs/workspace-automatic-sync-policy.mjs +0 -48
  158. package/dist/mjs/workspace-branch-incarnation-policy.mjs +0 -13
  159. package/dist/mjs/workspace-command-sync-policy.mjs +0 -84
  160. package/dist/mjs/workspace-command-targets.mjs +0 -37
  161. package/dist/mjs/workspace-filesystem-executor-thread.mjs +0 -38
  162. package/dist/mjs/workspace-filesystem-executor.mjs +0 -287
  163. package/dist/mjs/workspace-filesystem-job-types.mjs +0 -116
  164. package/dist/mjs/workspace-filesystem-jobs.mjs +0 -55
  165. package/dist/mjs/workspace-git-sync.mjs +0 -3407
  166. package/dist/mjs/workspace-hydration-ledger.mjs +0 -42
  167. package/dist/mjs/workspace-hydration-merge.mjs +0 -399
  168. package/dist/mjs/workspace-hydration-recovery-state.mjs +0 -29
  169. package/dist/mjs/workspace-incident-state.mjs +0 -12
  170. package/dist/mjs/workspace-merge-projection.mjs +0 -433
  171. package/dist/mjs/workspace-mount-boundary.mjs +0 -37
  172. package/dist/mjs/workspace-mount-hold-fence.mjs +0 -95
  173. package/dist/mjs/workspace-mutation-gate.mjs +0 -103
  174. package/dist/mjs/workspace-path-move.mjs +0 -160
  175. package/dist/mjs/workspace-preserve-only-policy.mjs +0 -11
  176. package/dist/mjs/workspace-project-config-policy.mjs +0 -27
  177. package/dist/mjs/workspace-projection-ledger.mjs +0 -57
  178. package/dist/mjs/workspace-publication-evidence.mjs +0 -21
  179. package/dist/mjs/workspace-sync-coalescer.mjs +0 -34
  180. package/dist/types/atomic-rename.d.ts +0 -78
  181. package/dist/types/browser-upload.d.ts +0 -7
  182. package/dist/types/command-launcher.d.ts +0 -104
  183. package/dist/types/control-command-policy.d.ts +0 -53
  184. package/dist/types/git-blob-hash.d.ts +0 -10
  185. package/dist/types/git-identity.d.ts +0 -9
  186. package/dist/types/git-process-environment.d.ts +0 -9
  187. package/dist/types/inline-output.d.ts +0 -3
  188. package/dist/types/managed-paths.d.ts +0 -19
  189. package/dist/types/plan-lint.d.ts +0 -16
  190. package/dist/types/plan-parser.d.ts +0 -38
  191. package/dist/types/plan-paths.d.ts +0 -36
  192. package/dist/types/port-forward-client.d.ts +0 -8
  193. package/dist/types/project-checkout-garbage.d.ts +0 -86
  194. package/dist/types/project-mirror-fetch-policy.d.ts +0 -84
  195. package/dist/types/project-mirror-refs-token.d.ts +0 -53
  196. package/dist/types/project-workspace-state.d.ts +0 -188
  197. package/dist/types/project-worktrees.d.ts +0 -397
  198. package/dist/types/pty-output-coalescer.d.ts +0 -20
  199. package/dist/types/recovery-journal-protocol.d.ts +0 -35
  200. package/dist/types/recovery-journal-runtime.d.ts +0 -12
  201. package/dist/types/recovery-journal-thread.d.ts +0 -1
  202. package/dist/types/recovery-journal.d.ts +0 -248
  203. package/dist/types/recovery-output-window.d.ts +0 -19
  204. package/dist/types/recovery-protocol.d.ts +0 -59
  205. package/dist/types/recovery-store.d.ts +0 -52
  206. package/dist/types/registry-auth.d.ts +0 -47
  207. package/dist/types/repository-transition-policy.d.ts +0 -26
  208. package/dist/types/runtime-version.d.ts +0 -1
  209. package/dist/types/session-file-mutations.d.ts +0 -22
  210. package/dist/types/supervisor-daemonized-fixture.d.ts +0 -1
  211. package/dist/types/supervisor-launcher-cleanup-fixture.d.ts +0 -1
  212. package/dist/types/supervisor-signal-fixture.d.ts +0 -1
  213. package/dist/types/supervisor.d.ts +0 -23
  214. package/dist/types/three-way-merge.d.ts +0 -77
  215. package/dist/types/working-tree-mirror.d.ts +0 -424
  216. package/dist/types/workspace-automatic-sync-policy.d.ts +0 -57
  217. package/dist/types/workspace-branch-incarnation-policy.d.ts +0 -14
  218. package/dist/types/workspace-command-sync-policy.d.ts +0 -57
  219. package/dist/types/workspace-command-targets.d.ts +0 -37
  220. package/dist/types/workspace-filesystem-executor-thread.d.ts +0 -1
  221. package/dist/types/workspace-filesystem-executor.d.ts +0 -123
  222. package/dist/types/workspace-filesystem-job-types.d.ts +0 -288
  223. package/dist/types/workspace-filesystem-jobs.d.ts +0 -7
  224. package/dist/types/workspace-git-sync.d.ts +0 -495
  225. package/dist/types/workspace-hydration-ledger.d.ts +0 -43
  226. package/dist/types/workspace-hydration-merge.d.ts +0 -95
  227. package/dist/types/workspace-hydration-recovery-state.d.ts +0 -10
  228. package/dist/types/workspace-incident-state.d.ts +0 -19
  229. package/dist/types/workspace-merge-projection.d.ts +0 -60
  230. package/dist/types/workspace-mount-boundary.d.ts +0 -10
  231. package/dist/types/workspace-mount-hold-fence.d.ts +0 -42
  232. package/dist/types/workspace-mutation-gate.d.ts +0 -42
  233. package/dist/types/workspace-path-move.d.ts +0 -21
  234. package/dist/types/workspace-preserve-only-policy.d.ts +0 -15
  235. package/dist/types/workspace-project-config-policy.d.ts +0 -48
  236. package/dist/types/workspace-projection-ledger.d.ts +0 -59
  237. package/dist/types/workspace-publication-evidence.d.ts +0 -17
  238. package/dist/types/workspace-sync-coalescer.d.ts +0 -28
  239. /package/dist/types/{credential-authority-lock-fixture.d.ts → runtime/adapter.d.ts} +0 -0
  240. /package/dist/types/{recovery-journal-stall-fixture.d.ts → runtime/releases/main.d.ts} +0 -0
@@ -0,0 +1,184 @@
1
+ import { createConnection } from "node:net";
2
+ import { lstatSync } from "node:fs";
3
+ import { randomUUID } from "node:crypto";
4
+ import { dirname } from "node:path";
5
+ import { z } from "zod";
6
+ import {
7
+ ExecutorError,
8
+ isStartNonAdmissionCode,
9
+ MAX_FRAME_BYTES,
10
+ ExecutorCommand
11
+ } from "../protocol.mjs";
12
+ import { canonicalDirectory } from "./artifacts.mjs";
13
+ import { digest } from "./grants.mjs";
14
+ import { DeliveryReceipt, ManagerRpcClientConfig } from "./rpc-protocol.mjs";
15
+ class ManagerRpcClient {
16
+ config;
17
+ constructor(config) {
18
+ this.config = ManagerRpcClientConfig.parse(config);
19
+ }
20
+ request(command) {
21
+ const c = this.config;
22
+ canonicalDirectory(dirname(c.socketPath));
23
+ const st = lstatSync(c.socketPath), requestId = randomUUID();
24
+ if (!st.isSocket() || st.uid !== process.getuid?.() || st.mode & 63)
25
+ return Promise.reject(new ExecutorError("insecure_manager_socket"));
26
+ const frame = JSON.stringify({
27
+ protocol: 1,
28
+ requestId,
29
+ installationId: c.installationId,
30
+ workerId: c.workerId,
31
+ auth: { principalId: c.principalId, token: c.token },
32
+ command
33
+ }) + "\n";
34
+ if (Buffer.byteLength(frame) > MAX_FRAME_BYTES) return Promise.reject(new ExecutorError("request_too_large"));
35
+ return new Promise((resolve, reject) => {
36
+ const socket = createConnection(c.socketPath);
37
+ let bytes = Buffer.alloc(0), done = false;
38
+ const finish = (error, result) => {
39
+ if (done) return;
40
+ done = true;
41
+ socket.destroy();
42
+ if (error) reject(error);
43
+ else resolve(result);
44
+ };
45
+ socket.setTimeout(c.timeoutMs, () => finish(new ExecutorError("manager_transport_unknown")));
46
+ socket.once("error", () => finish(new ExecutorError("manager_transport_unknown")));
47
+ socket.once("close", () => finish(new ExecutorError("manager_transport_unknown")));
48
+ socket.once("connect", () => socket.write(frame));
49
+ socket.on("data", (chunk) => {
50
+ bytes = Buffer.concat([bytes, chunk]);
51
+ if (bytes.length > MAX_FRAME_BYTES) {
52
+ finish(new ExecutorError("manager_response_invalid"));
53
+ return;
54
+ }
55
+ if (!bytes.includes(10)) return;
56
+ try {
57
+ const response = z.discriminatedUnion("ok", [
58
+ z.object({ requestId: z.literal(requestId), ok: z.literal(true), result: z.unknown() }).strict(),
59
+ z.object({
60
+ requestId: z.literal(requestId),
61
+ ok: z.literal(false),
62
+ error: z.object({ code: z.string(), rejectedBeforeAdmission: z.boolean() }).strict()
63
+ }).strict()
64
+ ]).parse(JSON.parse(bytes.toString("utf8")));
65
+ if (response.ok === true && Object.hasOwn(response, "result")) finish(void 0, response.result);
66
+ else
67
+ finish(
68
+ new ExecutorError(
69
+ response.ok === false ? response.error.code : "manager_response_invalid",
70
+ void 0,
71
+ response.ok === false && response.error.rejectedBeforeAdmission && command.method === "execute" && command.command.method === "start" && [
72
+ "candidate_not_ready",
73
+ "manager_delivery_busy",
74
+ "delivery_retention_full",
75
+ "release_manager_closed",
76
+ "manager_ipc_busy"
77
+ ].includes(response.error.code)
78
+ )
79
+ );
80
+ } catch {
81
+ finish(new ExecutorError("manager_response_invalid"));
82
+ }
83
+ });
84
+ });
85
+ }
86
+ probe() {
87
+ return this.request({ method: "probe", adapterId: this.config.adapterId, hello: this.config.hello });
88
+ }
89
+ async execute(callId, command) {
90
+ return DeliveryReceipt.parse(
91
+ await this.request({
92
+ method: "execute",
93
+ callId,
94
+ adapterId: this.config.adapterId,
95
+ hello: this.config.hello,
96
+ command: ExecutorCommand.parse(command)
97
+ })
98
+ );
99
+ }
100
+ async observe(command) {
101
+ return DeliveryReceipt.parse(
102
+ await this.request({
103
+ method: "observe",
104
+ adapterId: this.config.adapterId,
105
+ hello: this.config.hello,
106
+ command: ExecutorCommand.parse(command)
107
+ })
108
+ );
109
+ }
110
+ async receipt(callId) {
111
+ return DeliveryReceipt.parse(await this.request({ method: "receipt", callId }));
112
+ }
113
+ async acknowledge(callId, responseDigest, ackToken) {
114
+ return z.object({ callId: z.literal(callId), responseDigest: z.literal(responseDigest), acknowledged: z.literal(true) }).strict().parse(await this.request({ method: "acknowledge", callId, responseDigest, ackToken }));
115
+ }
116
+ }
117
+ class ManagedExecutorClient {
118
+ constructor(config, receiptSink, onAcknowledged) {
119
+ this.receiptSink = receiptSink;
120
+ this.onAcknowledged = onAcknowledged;
121
+ this.rpc = new ManagerRpcClient(config);
122
+ }
123
+ receiptSink;
124
+ onAcknowledged;
125
+ rpc;
126
+ get config() {
127
+ return this.rpc.config;
128
+ }
129
+ status() {
130
+ return this.rpc.probe();
131
+ }
132
+ async request(command) {
133
+ if (command.method === "status") return this.status();
134
+ if (!["start", "poll", "write", "resize", "cancel"].includes(command.method)) throw new ExecutorError("forbidden");
135
+ command = ExecutorCommand.parse(command);
136
+ const callId = command.method === "poll" ? null : `delivery-${digest(command)}`;
137
+ let receipt;
138
+ try {
139
+ receipt = callId === null ? await this.rpc.observe(command) : await this.rpc.execute(callId, command);
140
+ } catch (error2) {
141
+ if (command.method === "start" && error2 instanceof ExecutorError && error2.rejectedBeforeAdmission)
142
+ throw new ExecutorError("capacity_busy", void 0, true);
143
+ throw error2;
144
+ }
145
+ const identity = command.method === "start" ? command.operation : "run" in command ? command.run : null;
146
+ if ((callId !== null ? receipt.callId !== callId || receipt.deliveryKind !== "mutation" : !/^observation-[1-9][0-9]*$/.test(receipt.callId) || receipt.deliveryKind !== "observation") || receipt.adapterId !== this.config.adapterId || receipt.requesterId !== this.config.principalId || receipt.userId !== identity?.userId || receipt.sessionId !== identity?.sessionId || receipt.operationId !== identity?.operationId || receipt.commandDigest !== digest(command) || receipt.installationId !== this.config.installationId || receipt.workerId !== this.config.workerId || receipt.responseDigest !== digest({ callId: receipt.callId, commandDigest: receipt.commandDigest, state: receipt.state, outcome: receipt.outcome }))
147
+ throw new ExecutorError("manager_response_invalid");
148
+ if (this.receiptSink) await this.receiptSink(receipt);
149
+ if (receipt.state !== "completed" || receipt.outcome === null) throw new ExecutorError("manager_delivery_unknown");
150
+ if (this.receiptSink) {
151
+ try {
152
+ await this.rpc.acknowledge(receipt.callId, receipt.responseDigest, receipt.ackToken);
153
+ await this.onAcknowledged?.(receipt);
154
+ } catch {
155
+ }
156
+ }
157
+ if (receipt.outcome.ok) return receipt.outcome.result;
158
+ const error = receipt.outcome.error;
159
+ throw new ExecutorError(
160
+ error.code,
161
+ void 0,
162
+ command.method === "start" && isStartNonAdmissionCode(error.code) && error.rejectedBeforeAdmission
163
+ );
164
+ }
165
+ start(operation) {
166
+ return this.request({ method: "start", operation });
167
+ }
168
+ poll(run, stdoutOffset = 0, stderrOffset = 0, maxBytes = 32768) {
169
+ return this.request({ method: "poll", run, stdoutOffset, stderrOffset, maxBytes });
170
+ }
171
+ write(run, actionId, data, eof = false) {
172
+ return this.request({ method: "write", run, actionId, data, eof });
173
+ }
174
+ resize(run, actionId, cols, rows) {
175
+ return this.request({ method: "resize", run, actionId, cols, rows });
176
+ }
177
+ cancel(run, actionId) {
178
+ return this.request({ method: "cancel", run, actionId });
179
+ }
180
+ }
181
+ export {
182
+ ManagedExecutorClient,
183
+ ManagerRpcClient
184
+ };
@@ -0,0 +1,213 @@
1
+ import { chmodSync, constants, closeSync, fstatSync, lstatSync, openSync, readSync, unlinkSync } from "node:fs";
2
+ import { timingSafeEqual } from "node:crypto";
3
+ import { createServer } from "node:net";
4
+ import { dirname, join } from "node:path";
5
+ import { RuntimeId } from "@ricsam/r5d-api/runtime-protocol";
6
+ import { ExecutorError, MAX_FRAME_BYTES } from "../protocol.mjs";
7
+ import { WorkerAdapterReleases } from "./manager.mjs";
8
+ import { bytesHash, canonicalDirectory } from "./artifacts.mjs";
9
+ import { ManagerRequest, ManagerRpcConfig } from "./rpc-protocol.mjs";
10
+ function readManagerPrivateJson(path) {
11
+ canonicalDirectory(dirname(path));
12
+ const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
13
+ try {
14
+ const st = fstatSync(fd);
15
+ if (!st.isFile() || st.nlink !== 1 || st.uid !== process.getuid?.() || st.mode & 63 || st.size > MAX_FRAME_BYTES)
16
+ throw new ExecutorError("insecure_manager_config");
17
+ const bytes = Buffer.alloc(st.size + 1);
18
+ let offset = 0;
19
+ while (offset < bytes.length) {
20
+ const n = readSync(fd, bytes, offset, bytes.length - offset, null);
21
+ if (!n) break;
22
+ offset += n;
23
+ }
24
+ const after = fstatSync(fd);
25
+ if (offset !== st.size || after.size !== st.size || after.mtimeMs !== st.mtimeMs || after.ctimeMs !== st.ctimeMs)
26
+ throw new ExecutorError("manager_config_changed");
27
+ return JSON.parse(bytes.subarray(0, offset).toString("utf8"));
28
+ } finally {
29
+ closeSync(fd);
30
+ }
31
+ }
32
+ async function startManagerRpc(input) {
33
+ const config = ManagerRpcConfig.parse(input), manager = new WorkerAdapterReleases(config.manager);
34
+ const socketPath = join(manager.config.stateDir, "manager.sock"), sockets = /* @__PURE__ */ new Set();
35
+ let pending = 0;
36
+ const server = createServer((socket) => {
37
+ if (sockets.size >= 48) {
38
+ socket.destroy();
39
+ return;
40
+ }
41
+ sockets.add(socket);
42
+ socket.once("close", () => sockets.delete(socket));
43
+ socket.on("error", () => {
44
+ });
45
+ socket.setTimeout(15e3, () => socket.destroy());
46
+ let bytes = Buffer.alloc(0), received = false;
47
+ socket.on("data", (chunk) => {
48
+ if (received) {
49
+ socket.destroy();
50
+ return;
51
+ }
52
+ if (bytes.length + chunk.length > MAX_FRAME_BYTES) {
53
+ socket.destroy();
54
+ return;
55
+ }
56
+ bytes = Buffer.concat([bytes, chunk]);
57
+ const end = bytes.indexOf(10);
58
+ if (end < 0) return;
59
+ received = true;
60
+ if (end !== bytes.length - 1) {
61
+ socket.destroy();
62
+ return;
63
+ }
64
+ let requestId = null;
65
+ const execute = async () => {
66
+ const raw = JSON.parse(bytes.subarray(0, end).toString("utf8"));
67
+ requestId = RuntimeId.parse(raw?.requestId);
68
+ const request = ManagerRequest.parse(raw);
69
+ const principal = config.principals.find((p) => p.id === request.auth.principalId);
70
+ if (!timingSafeEqual(
71
+ Buffer.from(bytesHash(Buffer.from(request.auth.token)), "hex"),
72
+ Buffer.from(principal?.tokenHash ?? "0".repeat(64), "hex")
73
+ ) || !principal)
74
+ throw new ExecutorError("unauthenticated");
75
+ if (request.installationId !== manager.config.installationId || request.workerId !== manager.config.workerId)
76
+ throw new ExecutorError("wrong_installation");
77
+ const command = request.command;
78
+ const sessionAllowed = (userId, sessionId) => principal.sessions.some((scope) => scope.userId === userId && scope.sessionId === sessionId) || principal.role === "workspace" && principal.userIds?.includes(userId) === true;
79
+ if (command.method === "probe") return manager.probe(command.adapterId, command.hello);
80
+ if (command.method === "execute" || command.method === "observe") {
81
+ if (principal.role !== "workspace") throw new ExecutorError("forbidden");
82
+ const operation = command.command.method === "start" ? command.command.operation : "run" in command.command ? command.command.run : null;
83
+ if (!operation?.sessionId || !sessionAllowed(operation.userId, operation.sessionId)) throw new ExecutorError("forbidden");
84
+ if (pending > (command.command.method === "cancel" ? 44 : 40))
85
+ throw new ExecutorError("manager_ipc_busy", void 0, command.command.method === "start");
86
+ return command.method === "observe" ? manager.observe(command.adapterId, command.hello, principal.id, command.command) : manager.deliver(command.callId, command.adapterId, command.hello, principal.id, command.command);
87
+ }
88
+ if (command.method === "receipt" || command.method === "acknowledge") {
89
+ if (principal.role !== "workspace") throw new ExecutorError("forbidden");
90
+ const receipt = manager.delivery(command.callId);
91
+ if (receipt && (receipt.requesterId !== principal.id || !sessionAllowed(receipt.userId, receipt.sessionId)))
92
+ throw new ExecutorError("delivery_not_found");
93
+ if (command.method === "receipt") {
94
+ if (!receipt) throw new ExecutorError("delivery_not_found");
95
+ return receipt;
96
+ }
97
+ return manager.acknowledgeDelivery(command.callId, command.responseDigest, command.ackToken, principal.id);
98
+ }
99
+ if (principal.role !== "admin") throw new ExecutorError("forbidden");
100
+ switch (command.method) {
101
+ case "stage":
102
+ return manager.stage(command);
103
+ case "launch":
104
+ return manager.launch(command.adapterId);
105
+ case "stop-adapter":
106
+ return manager.stopAdapter(command.adapterId);
107
+ case "promote":
108
+ return manager.promote(command.adapterId, command.fence, command.validUntil);
109
+ case "retire":
110
+ return manager.retire(command.adapterId, command.retirementIntentDigest);
111
+ case "settle-unknown":
112
+ return manager.settleUnknownDelivery(command.callId, command.evidenceDigest);
113
+ case "reconcile":
114
+ return manager.reconcile();
115
+ case "status":
116
+ return {
117
+ managerInvocation: manager.invocation,
118
+ releases: manager.list().map((r) => ({
119
+ principalId: r.principalId,
120
+ phase: r.phase,
121
+ retirementCompletion: r.retirementCompletion,
122
+ hello: r.manifest.hello,
123
+ artifactDigest: r.artifactDigest,
124
+ drain: manager.deliveryDrain(r.principalId)
125
+ })),
126
+ transitions: manager.transitions()
127
+ };
128
+ }
129
+ };
130
+ pending++;
131
+ void execute().then(
132
+ (result) => {
133
+ const frame = JSON.stringify({ requestId, ok: true, result: result ?? null }) + "\n";
134
+ if (Buffer.byteLength(frame) > MAX_FRAME_BYTES) socket.destroy();
135
+ else socket.end(frame);
136
+ },
137
+ (error) => socket.end(
138
+ JSON.stringify({
139
+ requestId,
140
+ ok: false,
141
+ error: {
142
+ code: error instanceof ExecutorError ? error.code : "invalid_request",
143
+ rejectedBeforeAdmission: error instanceof ExecutorError && error.rejectedBeforeAdmission
144
+ }
145
+ }) + "\n"
146
+ )
147
+ ).finally(() => pending--);
148
+ });
149
+ });
150
+ try {
151
+ manager.bindRpcPrincipals(config.principals);
152
+ canonicalDirectory(manager.config.stateDir);
153
+ try {
154
+ const st = lstatSync(socketPath);
155
+ if (!st.isSocket() || st.uid !== process.getuid?.()) throw new ExecutorError("unsafe_manager_socket");
156
+ unlinkSync(socketPath);
157
+ } catch (error) {
158
+ if (error.code !== "ENOENT") throw error;
159
+ }
160
+ await new Promise((resolve, reject) => {
161
+ server.once("error", reject);
162
+ server.listen(socketPath, () => {
163
+ server.off("error", reject);
164
+ resolve();
165
+ });
166
+ });
167
+ chmodSync(socketPath, 384);
168
+ } catch (error) {
169
+ server.close();
170
+ await manager.close();
171
+ throw error;
172
+ }
173
+ let closing;
174
+ return {
175
+ manager,
176
+ socketPath,
177
+ get pending() {
178
+ return pending;
179
+ },
180
+ close() {
181
+ return closing ??= (async () => {
182
+ for (const socket of sockets) socket.destroy();
183
+ await new Promise((resolve) => server.close(() => resolve()));
184
+ await manager.close();
185
+ })();
186
+ }
187
+ };
188
+ }
189
+ if (import.meta.main) {
190
+ try {
191
+ if (process.argv.length !== 3) throw new ExecutorError("private_config_required");
192
+ const service = await startManagerRpc(ManagerRpcConfig.parse(readManagerPrivateJson(process.argv[2])));
193
+ console.log(JSON.stringify({ ready: true, pid: process.pid, protocol: 1 }));
194
+ let stopping = false;
195
+ const stop = () => {
196
+ if (stopping) return;
197
+ stopping = true;
198
+ void service.close().then(
199
+ () => process.exit(0),
200
+ () => process.exit(1)
201
+ );
202
+ };
203
+ process.once("SIGTERM", stop);
204
+ process.once("SIGINT", stop);
205
+ } catch {
206
+ console.error("Private adapter manager startup failed");
207
+ process.exitCode = 1;
208
+ }
209
+ }
210
+ export {
211
+ readManagerPrivateJson,
212
+ startManagerRpc
213
+ };
@@ -0,0 +1,103 @@
1
+ import { z } from "zod";
2
+ import { RuntimeHello, RuntimeId, OwnershipFence } from "@ricsam/r5d-api/runtime-protocol";
3
+ import { AdapterConfig, AdapterGrant, ExecutorCommand } from "../protocol.mjs";
4
+ import { AdapterManifest } from "./artifacts.mjs";
5
+ import { ReleaseManagerConfig } from "./manager.mjs";
6
+ const Absolute = z.string().startsWith("/").max(4096);
7
+ const ManagerRpcConfig = z.object({
8
+ manager: ReleaseManagerConfig,
9
+ principals: z.array(
10
+ z.object({
11
+ id: RuntimeId,
12
+ tokenHash: z.string().regex(/^[a-f0-9]{64}$/),
13
+ role: z.enum(["admin", "probe", "workspace"]),
14
+ sessions: z.array(z.object({ userId: RuntimeId, sessionId: RuntimeId }).strict()).max(100),
15
+ // Only the trusted catalog-authorizing workspace keeper receives these grants.
16
+ userIds: z.array(RuntimeId).max(1e3).optional()
17
+ }).strict()
18
+ ).min(1).max(100)
19
+ }).strict().refine(
20
+ (v) => new Set(v.principals.map((p) => p.id)).size === v.principals.length && new Set(v.principals.map((p) => p.tokenHash)).size === v.principals.length,
21
+ "Duplicate RPC principal/credential"
22
+ );
23
+ const ManagerRpcClientConfig = z.object({
24
+ socketPath: Absolute,
25
+ installationId: RuntimeId,
26
+ workerId: RuntimeId,
27
+ principalId: RuntimeId,
28
+ token: z.string().min(32).max(512),
29
+ adapterId: RuntimeId,
30
+ hello: RuntimeHello,
31
+ timeoutMs: z.number().int().min(100).max(6e4).default(1e4)
32
+ }).strict();
33
+ const ManagerCommand = z.discriminatedUnion("method", [
34
+ z.object({ method: z.literal("probe"), adapterId: RuntimeId, hello: RuntimeHello }).strict(),
35
+ z.object({ method: z.literal("execute"), adapterId: RuntimeId, hello: RuntimeHello, callId: RuntimeId, command: ExecutorCommand }).strict(),
36
+ z.object({ method: z.literal("observe"), adapterId: RuntimeId, hello: RuntimeHello, command: ExecutorCommand }).strict(),
37
+ z.object({ method: z.literal("receipt"), callId: RuntimeId }).strict(),
38
+ z.object({
39
+ method: z.literal("acknowledge"),
40
+ callId: RuntimeId,
41
+ responseDigest: z.string().regex(/^[a-f0-9]{64}$/),
42
+ ackToken: z.string().regex(/^[a-f0-9]{64}$/)
43
+ }).strict(),
44
+ z.object({
45
+ method: z.literal("stage"),
46
+ source: Absolute,
47
+ manifest: AdapterManifest,
48
+ approvalDigest: z.string(),
49
+ grant: AdapterGrant,
50
+ adapter: AdapterConfig
51
+ }).strict(),
52
+ z.object({ method: z.literal("launch"), adapterId: RuntimeId }).strict(),
53
+ z.object({ method: z.literal("stop-adapter"), adapterId: RuntimeId }).strict(),
54
+ z.object({ method: z.literal("promote"), adapterId: RuntimeId, fence: OwnershipFence, validUntil: z.number().int().positive() }).strict(),
55
+ z.object({
56
+ method: z.literal("retire"),
57
+ adapterId: RuntimeId,
58
+ retirementIntentDigest: z.string().regex(/^[a-f0-9]{64}$/).optional()
59
+ }).strict(),
60
+ z.object({ method: z.literal("settle-unknown"), callId: RuntimeId, evidenceDigest: z.string().regex(/^[a-f0-9]{64}$/) }).strict(),
61
+ z.object({ method: z.literal("status") }).strict(),
62
+ z.object({ method: z.literal("reconcile") }).strict()
63
+ ]);
64
+ const ManagerRequest = z.object({
65
+ protocol: z.literal(1),
66
+ requestId: RuntimeId,
67
+ installationId: RuntimeId,
68
+ workerId: RuntimeId,
69
+ auth: z.object({ principalId: RuntimeId, token: z.string().min(32).max(512) }).strict(),
70
+ command: ManagerCommand
71
+ }).strict();
72
+ const DeliveryOutcome = z.discriminatedUnion("ok", [
73
+ z.object({ ok: z.literal(true), result: z.unknown() }).strict(),
74
+ z.object({ ok: z.literal(false), error: z.object({ code: z.string(), rejectedBeforeAdmission: z.boolean() }).strict() }).strict()
75
+ ]);
76
+ const DeliveryReceipt = z.object({
77
+ callId: RuntimeId,
78
+ deliveryKind: z.enum(["mutation", "observation"]),
79
+ ackToken: z.string().regex(/^[a-f0-9]{64}$/),
80
+ installationId: RuntimeId,
81
+ workerId: RuntimeId,
82
+ adapterId: RuntimeId,
83
+ requesterId: RuntimeId,
84
+ userId: RuntimeId,
85
+ sessionId: RuntimeId,
86
+ operationId: RuntimeId,
87
+ commandDigest: z.string().regex(/^[a-f0-9]{64}$/),
88
+ state: z.enum(["pending", "completed", "unknown"]),
89
+ outcome: DeliveryOutcome.nullable(),
90
+ responseDigest: z.string().regex(/^[a-f0-9]{64}$/),
91
+ acknowledged: z.boolean()
92
+ }).strict().superRefine((receipt, ctx) => {
93
+ if (receipt.state === "completed" !== (receipt.outcome !== null) || receipt.outcome?.ok === true && !Object.hasOwn(receipt.outcome, "result"))
94
+ ctx.addIssue({ code: "custom", message: "Delivery state/payload mismatch" });
95
+ });
96
+ export {
97
+ DeliveryOutcome,
98
+ DeliveryReceipt,
99
+ ManagerCommand,
100
+ ManagerRequest,
101
+ ManagerRpcClientConfig,
102
+ ManagerRpcConfig
103
+ };
@@ -0,0 +1,156 @@
1
+ import { Database } from "bun:sqlite";
2
+ import {
3
+ closeSync,
4
+ constants,
5
+ fstatSync,
6
+ fsyncSync,
7
+ lstatSync,
8
+ mkdirSync,
9
+ openSync,
10
+ readFileSync,
11
+ readSync,
12
+ rmSync,
13
+ writeSync
14
+ } from "node:fs";
15
+ import { join } from "node:path";
16
+ import { ExecutorError } from "./protocol.mjs";
17
+ function privateDirectory(path) {
18
+ mkdirSync(path, { mode: 448, recursive: true });
19
+ const stat = lstatSync(path);
20
+ if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || stat.mode & 63)
21
+ throw new ExecutorError("insecure_directory");
22
+ }
23
+ function readPrivateJson(path) {
24
+ const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
25
+ try {
26
+ const stat = fstatSync(fd);
27
+ if (!stat.isFile() || stat.uid !== process.getuid?.() || stat.mode & 63 || stat.size > 1024 * 1024)
28
+ throw new ExecutorError("insecure_config");
29
+ return JSON.parse(readFileSync(fd, "utf8"));
30
+ } finally {
31
+ closeSync(fd);
32
+ }
33
+ }
34
+ function privateDatabase(path) {
35
+ try {
36
+ closeSync(openSync(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 384));
37
+ } catch (error) {
38
+ if (error.code !== "EEXIST") throw error;
39
+ }
40
+ for (const file of [path, `${path}-journal`, `${path}-wal`, `${path}-shm`]) {
41
+ try {
42
+ const stat = lstatSync(file);
43
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1 || stat.uid !== process.getuid?.() || stat.mode & 63)
44
+ throw new ExecutorError("insecure_store_file");
45
+ } catch (error) {
46
+ if (error.code !== "ENOENT") throw error;
47
+ }
48
+ }
49
+ return new Database(path);
50
+ }
51
+ class ExecutorStore {
52
+ constructor(root, installationId, workerId) {
53
+ this.root = root;
54
+ privateDirectory(root);
55
+ this.lock = privateDatabase(join(root, "authority.lock.sqlite"));
56
+ try {
57
+ this.lock.exec(
58
+ "PRAGMA busy_timeout=0; PRAGMA locking_mode=EXCLUSIVE; BEGIN EXCLUSIVE; CREATE TABLE IF NOT EXISTS keeper_lock (id INTEGER)"
59
+ );
60
+ } catch {
61
+ this.lock.close();
62
+ throw new ExecutorError("executor_already_running");
63
+ }
64
+ try {
65
+ this.db = privateDatabase(join(root, "receipts.sqlite"));
66
+ this.db.exec(`PRAGMA journal_mode=WAL; PRAGMA synchronous=FULL; PRAGMA foreign_keys=ON;
67
+ CREATE TABLE IF NOT EXISTS identity (id INTEGER PRIMARY KEY CHECK (id=1), installation TEXT NOT NULL, worker TEXT NOT NULL, version INTEGER NOT NULL);
68
+ CREATE TABLE IF NOT EXISTS authority (id INTEGER PRIMARY KEY CHECK (id=1), fence TEXT NOT NULL, valid_until INTEGER NOT NULL);
69
+ CREATE TABLE IF NOT EXISTS runs (id TEXT PRIMARY KEY, receipt TEXT NOT NULL);
70
+ CREATE TABLE IF NOT EXISTS actions (run_id TEXT NOT NULL REFERENCES runs(id), id TEXT NOT NULL, hash TEXT NOT NULL, state TEXT NOT NULL, PRIMARY KEY(run_id,id));`);
71
+ const identity = this.db.query("SELECT * FROM identity WHERE id=1").get();
72
+ if (identity && (identity.installation !== installationId || identity.worker !== workerId || identity.version !== 1))
73
+ throw new ExecutorError("wrong_store_identity");
74
+ if (!identity) this.db.query("INSERT INTO identity VALUES (1,?,?,1)").run(installationId, workerId);
75
+ privateDirectory(join(root, "output"));
76
+ privateDirectory(join(root, "secrets"));
77
+ for (const receipt of this.all()) {
78
+ if (receipt.state === "accepted" || receipt.state === "running") {
79
+ receipt.state = "unknown";
80
+ receipt.reason = "executor_restarted_reconciliation_required";
81
+ this.put(receipt);
82
+ }
83
+ }
84
+ this.db.exec("UPDATE actions SET state='unknown' WHERE state='accepted'; UPDATE authority SET valid_until=0");
85
+ rmSync(join(root, "secrets"), { recursive: true });
86
+ privateDirectory(join(root, "secrets"));
87
+ } catch (error) {
88
+ this.db?.close();
89
+ this.lock.close();
90
+ throw error;
91
+ }
92
+ }
93
+ root;
94
+ db;
95
+ lock;
96
+ all() {
97
+ return this.db.query("SELECT receipt FROM runs").all().map((row) => JSON.parse(row.receipt));
98
+ }
99
+ get(id) {
100
+ const row = this.db.query("SELECT receipt FROM runs WHERE id=?").get(id);
101
+ return row ? JSON.parse(row.receipt) : null;
102
+ }
103
+ put(receipt) {
104
+ this.db.query("INSERT INTO runs VALUES (?,?) ON CONFLICT(id) DO UPDATE SET receipt=excluded.receipt").run(receipt.operationId, JSON.stringify(receipt));
105
+ }
106
+ outputPath(id, stream) {
107
+ return join(this.root, "output", `${id}.${stream}`);
108
+ }
109
+ append(id, stream, data) {
110
+ const fd = openSync(
111
+ this.outputPath(id, stream),
112
+ constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW,
113
+ 384
114
+ );
115
+ try {
116
+ let offset = 0;
117
+ while (offset < data.length) offset += writeSync(fd, data, offset);
118
+ fsyncSync(fd);
119
+ const directory = openSync(join(this.root, "output"), constants.O_RDONLY | constants.O_DIRECTORY);
120
+ try {
121
+ fsyncSync(directory);
122
+ } finally {
123
+ closeSync(directory);
124
+ }
125
+ } finally {
126
+ closeSync(fd);
127
+ }
128
+ }
129
+ read(id, stream, offset, end, max) {
130
+ if (offset > end) throw new ExecutorError("invalid_offset");
131
+ const buffer = Buffer.alloc(Math.min(end - offset, max));
132
+ if (buffer.length) {
133
+ const fd = openSync(this.outputPath(id, stream), constants.O_RDONLY | constants.O_NOFOLLOW);
134
+ try {
135
+ let n = 0;
136
+ while (n < buffer.length) {
137
+ const read = readSync(fd, buffer, n, buffer.length - n, offset + n);
138
+ if (!read) throw new ExecutorError("output_truncated");
139
+ n += read;
140
+ }
141
+ } finally {
142
+ closeSync(fd);
143
+ }
144
+ }
145
+ return { base64: buffer.toString("base64"), nextOffset: offset + buffer.length };
146
+ }
147
+ close() {
148
+ this.db.close();
149
+ this.lock.close();
150
+ }
151
+ }
152
+ export {
153
+ ExecutorStore,
154
+ privateDirectory,
155
+ readPrivateJson
156
+ };