@secure-exec/core 0.2.1 → 0.3.0-rc.1

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 (248) hide show
  1. package/README.md +5 -5
  2. package/dist/binary.d.ts +4 -0
  3. package/dist/binary.js +25 -0
  4. package/dist/bytes.d.ts +2 -0
  5. package/dist/bytes.js +6 -0
  6. package/dist/callbacks.d.ts +41 -0
  7. package/dist/callbacks.js +94 -0
  8. package/dist/cargo.d.ts +2 -0
  9. package/dist/cargo.js +142 -0
  10. package/dist/correlation.d.ts +10 -0
  11. package/dist/correlation.js +49 -0
  12. package/dist/descriptors.d.ts +34 -0
  13. package/dist/descriptors.js +37 -0
  14. package/dist/event-buffer.d.ts +90 -0
  15. package/dist/event-buffer.js +313 -0
  16. package/dist/ext.d.ts +7 -0
  17. package/dist/ext.js +13 -0
  18. package/dist/filesystem.d.ts +41 -0
  19. package/dist/filesystem.js +70 -0
  20. package/dist/frame-payload-codec.d.ts +8 -0
  21. package/dist/frame-payload-codec.js +14 -0
  22. package/dist/frame-rpc.d.ts +38 -0
  23. package/dist/frame-rpc.js +73 -0
  24. package/dist/frame-stream.d.ts +27 -0
  25. package/dist/frame-stream.js +99 -0
  26. package/dist/framing.d.ts +7 -0
  27. package/dist/framing.js +22 -0
  28. package/dist/generated/AcpLimitsConfig.d.ts +4 -0
  29. package/dist/generated/AcpLimitsConfig.js +2 -0
  30. package/dist/generated/CreateVmConfig.d.ts +19 -0
  31. package/dist/generated/FsPermissionRule.d.ts +6 -0
  32. package/dist/generated/FsPermissionRuleSet.d.ts +6 -0
  33. package/dist/generated/FsPermissionRuleSet.js +1 -0
  34. package/dist/generated/FsPermissionScope.d.ts +3 -0
  35. package/dist/generated/FsPermissionScope.js +1 -0
  36. package/dist/generated/HttpLimitsConfig.d.ts +3 -0
  37. package/dist/generated/HttpLimitsConfig.js +2 -0
  38. package/dist/generated/JsModuleResolution.d.ts +1 -0
  39. package/dist/generated/JsModuleResolution.js +2 -0
  40. package/dist/generated/JsRuntimeConfig.d.ts +26 -0
  41. package/dist/generated/JsRuntimeConfig.js +1 -0
  42. package/dist/generated/JsRuntimeLimitsConfig.d.ts +7 -0
  43. package/dist/generated/JsRuntimeLimitsConfig.js +2 -0
  44. package/dist/generated/JsRuntimePlatform.d.ts +1 -0
  45. package/dist/generated/JsRuntimePlatform.js +2 -0
  46. package/dist/generated/MountPluginDescriptor.d.ts +4 -0
  47. package/dist/generated/MountPluginDescriptor.js +2 -0
  48. package/dist/generated/NativeRootFilesystemConfig.d.ts +5 -0
  49. package/dist/generated/NativeRootFilesystemConfig.js +1 -0
  50. package/dist/generated/PatternPermissionRule.d.ts +6 -0
  51. package/dist/generated/PatternPermissionRule.js +1 -0
  52. package/dist/generated/PatternPermissionRuleSet.d.ts +6 -0
  53. package/dist/generated/PatternPermissionRuleSet.js +1 -0
  54. package/dist/generated/PatternPermissionScope.d.ts +3 -0
  55. package/dist/generated/PatternPermissionScope.js +1 -0
  56. package/dist/generated/PermissionMode.d.ts +1 -0
  57. package/dist/generated/PermissionMode.js +2 -0
  58. package/dist/generated/PermissionsPolicy.d.ts +10 -0
  59. package/dist/generated/PermissionsPolicy.js +1 -0
  60. package/dist/generated/PluginLimitsConfig.d.ts +4 -0
  61. package/dist/generated/PluginLimitsConfig.js +2 -0
  62. package/dist/generated/PythonLimitsConfig.d.ts +5 -0
  63. package/dist/generated/PythonLimitsConfig.js +2 -0
  64. package/dist/generated/ResourceLimitsConfig.d.ts +22 -0
  65. package/dist/generated/ResourceLimitsConfig.js +2 -0
  66. package/dist/generated/RootFilesystemConfig.d.ts +9 -0
  67. package/dist/generated/RootFilesystemConfig.js +1 -0
  68. package/dist/generated/RootFilesystemEntry.d.ts +13 -0
  69. package/dist/generated/RootFilesystemEntry.js +1 -0
  70. package/dist/generated/RootFilesystemEntryEncoding.d.ts +1 -0
  71. package/dist/generated/RootFilesystemEntryEncoding.js +2 -0
  72. package/dist/generated/RootFilesystemEntryKind.d.ts +1 -0
  73. package/dist/generated/RootFilesystemEntryKind.js +2 -0
  74. package/dist/generated/RootFilesystemLowerDescriptor.d.ts +7 -0
  75. package/dist/generated/RootFilesystemLowerDescriptor.js +1 -0
  76. package/dist/generated/RootFilesystemMode.d.ts +1 -0
  77. package/dist/generated/RootFilesystemMode.js +2 -0
  78. package/dist/generated/ToolLimitsConfig.d.ts +10 -0
  79. package/dist/generated/ToolLimitsConfig.js +2 -0
  80. package/dist/generated/VmDnsConfig.d.ts +6 -0
  81. package/dist/generated/VmDnsConfig.js +2 -0
  82. package/dist/generated/VmLimitsConfig.d.ts +18 -0
  83. package/dist/generated/VmLimitsConfig.js +1 -0
  84. package/dist/generated/VmListenPolicyConfig.d.ts +5 -0
  85. package/dist/generated/VmListenPolicyConfig.js +2 -0
  86. package/dist/generated/WasmLimitsConfig.d.ts +5 -0
  87. package/dist/generated/WasmLimitsConfig.js +2 -0
  88. package/dist/generated-protocol.d.ts +1037 -0
  89. package/dist/generated-protocol.js +2887 -0
  90. package/dist/index.d.ts +24 -62
  91. package/dist/index.js +24 -53
  92. package/dist/json.d.ts +2 -0
  93. package/dist/json.js +20 -0
  94. package/dist/kernel-proxy.d.ts +149 -0
  95. package/dist/kernel-proxy.js +1733 -0
  96. package/dist/native-client.d.ts +41 -0
  97. package/dist/native-client.js +124 -0
  98. package/dist/node-runtime.d.ts +443 -0
  99. package/dist/node-runtime.js +569 -0
  100. package/dist/numbers.d.ts +1 -0
  101. package/dist/numbers.js +8 -0
  102. package/dist/ownership.d.ts +18 -0
  103. package/dist/ownership.js +77 -0
  104. package/dist/permissions.d.ts +29 -0
  105. package/dist/permissions.js +68 -0
  106. package/dist/process.d.ts +35 -0
  107. package/dist/process.js +125 -0
  108. package/dist/protocol-client.d.ts +46 -0
  109. package/dist/protocol-client.js +180 -0
  110. package/dist/protocol-frames.d.ts +68 -0
  111. package/dist/protocol-frames.js +139 -0
  112. package/dist/protocol-maps.d.ts +28 -0
  113. package/dist/protocol-maps.js +217 -0
  114. package/dist/protocol-schema.d.ts +10 -0
  115. package/dist/protocol-schema.js +11 -0
  116. package/dist/request-payloads.d.ts +137 -0
  117. package/dist/request-payloads.js +210 -0
  118. package/dist/response-payloads.d.ts +107 -0
  119. package/dist/response-payloads.js +161 -0
  120. package/dist/sidecar-client.d.ts +242 -0
  121. package/dist/sidecar-client.js +797 -0
  122. package/dist/state.d.ts +40 -0
  123. package/dist/state.js +44 -0
  124. package/dist/test-runtime.d.ts +526 -0
  125. package/dist/test-runtime.js +2119 -0
  126. package/dist/vm-config.d.ts +31 -0
  127. package/dist/vm-config.js +1 -0
  128. package/fixtures/alpine-defaults.json +520 -0
  129. package/fixtures/base-filesystem.json +528 -0
  130. package/package.json +193 -115
  131. package/LICENSE +0 -191
  132. package/dist/bridge-setup.d.ts +0 -6
  133. package/dist/bridge-setup.js +0 -9
  134. package/dist/esm-compiler.d.ts +0 -18
  135. package/dist/esm-compiler.js +0 -72
  136. package/dist/fs-helpers.d.ts +0 -23
  137. package/dist/fs-helpers.js +0 -41
  138. package/dist/generated/isolate-runtime.d.ts +0 -19
  139. package/dist/generated/isolate-runtime.js +0 -21
  140. package/dist/generated/polyfills.d.ts +0 -82
  141. package/dist/generated/polyfills.js +0 -82
  142. package/dist/isolate-runtime/apply-custom-global-policy.js +0 -53
  143. package/dist/isolate-runtime/apply-timing-mitigation-freeze.js +0 -130
  144. package/dist/isolate-runtime/apply-timing-mitigation-off.js +0 -14
  145. package/dist/isolate-runtime/bridge-attach.js +0 -29
  146. package/dist/isolate-runtime/bridge-initial-globals.js +0 -385
  147. package/dist/isolate-runtime/eval-script-result.js +0 -8
  148. package/dist/isolate-runtime/global-exposure-helpers.js +0 -36
  149. package/dist/isolate-runtime/init-commonjs-module-globals.js +0 -28
  150. package/dist/isolate-runtime/override-process-cwd.js +0 -8
  151. package/dist/isolate-runtime/override-process-env.js +0 -8
  152. package/dist/isolate-runtime/require-setup.js +0 -4153
  153. package/dist/isolate-runtime/set-commonjs-file-globals.js +0 -36
  154. package/dist/isolate-runtime/set-stdin-data.js +0 -10
  155. package/dist/isolate-runtime/setup-dynamic-import.js +0 -123
  156. package/dist/isolate-runtime/setup-fs-facade.js +0 -87
  157. package/dist/kernel/command-registry.d.ts +0 -44
  158. package/dist/kernel/command-registry.js +0 -114
  159. package/dist/kernel/device-backend.d.ts +0 -14
  160. package/dist/kernel/device-backend.js +0 -251
  161. package/dist/kernel/device-layer.d.ts +0 -12
  162. package/dist/kernel/device-layer.js +0 -271
  163. package/dist/kernel/dns-cache.d.ts +0 -29
  164. package/dist/kernel/dns-cache.js +0 -52
  165. package/dist/kernel/fd-table.d.ts +0 -84
  166. package/dist/kernel/fd-table.js +0 -278
  167. package/dist/kernel/file-lock.d.ts +0 -34
  168. package/dist/kernel/file-lock.js +0 -122
  169. package/dist/kernel/host-adapter.d.ts +0 -50
  170. package/dist/kernel/host-adapter.js +0 -8
  171. package/dist/kernel/index.d.ts +0 -36
  172. package/dist/kernel/index.js +0 -34
  173. package/dist/kernel/kernel.d.ts +0 -9
  174. package/dist/kernel/kernel.js +0 -1415
  175. package/dist/kernel/mount-table.d.ts +0 -75
  176. package/dist/kernel/mount-table.js +0 -353
  177. package/dist/kernel/permissions.d.ts +0 -36
  178. package/dist/kernel/permissions.js +0 -150
  179. package/dist/kernel/pipe-manager.d.ts +0 -64
  180. package/dist/kernel/pipe-manager.js +0 -267
  181. package/dist/kernel/proc-backend.d.ts +0 -30
  182. package/dist/kernel/proc-backend.js +0 -428
  183. package/dist/kernel/proc-layer.d.ts +0 -11
  184. package/dist/kernel/proc-layer.js +0 -507
  185. package/dist/kernel/process-table.d.ts +0 -126
  186. package/dist/kernel/process-table.js +0 -651
  187. package/dist/kernel/pty.d.ts +0 -109
  188. package/dist/kernel/pty.js +0 -552
  189. package/dist/kernel/socket-table.d.ts +0 -312
  190. package/dist/kernel/socket-table.js +0 -1188
  191. package/dist/kernel/timer-table.d.ts +0 -54
  192. package/dist/kernel/timer-table.js +0 -108
  193. package/dist/kernel/types.d.ts +0 -541
  194. package/dist/kernel/types.js +0 -98
  195. package/dist/kernel/user.d.ts +0 -29
  196. package/dist/kernel/user.js +0 -35
  197. package/dist/kernel/vfs.d.ts +0 -82
  198. package/dist/kernel/vfs.js +0 -25
  199. package/dist/kernel/wait.d.ts +0 -45
  200. package/dist/kernel/wait.js +0 -112
  201. package/dist/kernel/wstatus.d.ts +0 -21
  202. package/dist/kernel/wstatus.js +0 -33
  203. package/dist/module-resolver.d.ts +0 -29
  204. package/dist/module-resolver.js +0 -314
  205. package/dist/package-bundler.d.ts +0 -41
  206. package/dist/package-bundler.js +0 -497
  207. package/dist/runtime-driver.d.ts +0 -66
  208. package/dist/shared/api-types.d.ts +0 -83
  209. package/dist/shared/bridge-contract.d.ts +0 -772
  210. package/dist/shared/bridge-contract.js +0 -169
  211. package/dist/shared/console-formatter.d.ts +0 -22
  212. package/dist/shared/console-formatter.js +0 -161
  213. package/dist/shared/constants.d.ts +0 -3
  214. package/dist/shared/constants.js +0 -3
  215. package/dist/shared/errors.d.ts +0 -16
  216. package/dist/shared/errors.js +0 -21
  217. package/dist/shared/esm-utils.d.ts +0 -28
  218. package/dist/shared/esm-utils.js +0 -97
  219. package/dist/shared/global-exposure.d.ts +0 -38
  220. package/dist/shared/global-exposure.js +0 -876
  221. package/dist/shared/in-memory-fs.d.ts +0 -16
  222. package/dist/shared/in-memory-fs.js +0 -115
  223. package/dist/shared/permissions.d.ts +0 -36
  224. package/dist/shared/permissions.js +0 -314
  225. package/dist/shared/require-setup.d.ts +0 -6
  226. package/dist/shared/require-setup.js +0 -9
  227. package/dist/test/block-store-conformance.d.ts +0 -34
  228. package/dist/test/block-store-conformance.js +0 -251
  229. package/dist/test/metadata-store-conformance.d.ts +0 -37
  230. package/dist/test/metadata-store-conformance.js +0 -646
  231. package/dist/test/vfs-conformance.d.ts +0 -65
  232. package/dist/test/vfs-conformance.js +0 -842
  233. package/dist/types.d.ts +0 -98
  234. package/dist/types.js +0 -6
  235. package/dist/vfs/chunked-vfs.d.ts +0 -66
  236. package/dist/vfs/chunked-vfs.js +0 -1290
  237. package/dist/vfs/host-block-store.d.ts +0 -19
  238. package/dist/vfs/host-block-store.js +0 -97
  239. package/dist/vfs/memory-block-store.d.ts +0 -16
  240. package/dist/vfs/memory-block-store.js +0 -45
  241. package/dist/vfs/memory-metadata.d.ts +0 -75
  242. package/dist/vfs/memory-metadata.js +0 -528
  243. package/dist/vfs/sqlite-metadata.d.ts +0 -91
  244. package/dist/vfs/sqlite-metadata.js +0 -582
  245. package/dist/vfs/types.d.ts +0 -210
  246. package/dist/vfs/types.js +0 -8
  247. /package/dist/{runtime-driver.js → generated/CreateVmConfig.js} +0 -0
  248. /package/dist/{shared/api-types.js → generated/FsPermissionRule.js} +0 -0
@@ -1,528 +0,0 @@
1
- /**
2
- * Pure JS Map-based FsMetadataStore for ephemeral VMs and tests.
3
- *
4
- * All data lives in memory. Root inode (ino=1, type='directory') is created
5
- * at construction time. transaction() just calls the callback directly since
6
- * single-threaded JS has no interleaving risk within synchronous sections.
7
- *
8
- * Optionally supports versioning when `{ versioning: true }` is passed to
9
- * the constructor. Version retention (automatic cleanup of old versions)
10
- * defaults to false. There is intentionally no background cleanup task;
11
- * callers are expected to prune versions explicitly via ChunkedVFS.
12
- */
13
- import { KernelError } from "../kernel/types.js";
14
- const SYMLOOP_MAX = 40;
15
- const S_IFREG = 0o100000;
16
- const S_IFDIR = 0o040000;
17
- const S_IFLNK = 0o120000;
18
- export class InMemoryMetadataStore {
19
- nextIno = 2;
20
- inodes = new Map();
21
- dentries = new Map();
22
- symlinkTargets = new Map();
23
- chunks = new Map();
24
- versioningEnabled;
25
- versions = new Map();
26
- constructor(options) {
27
- this.versioningEnabled = options?.versioning ?? false;
28
- const now = Date.now();
29
- const rootInode = {
30
- ino: 1,
31
- type: "directory",
32
- mode: S_IFDIR | 0o755,
33
- uid: 0,
34
- gid: 0,
35
- size: 0,
36
- nlink: 2,
37
- atimeMs: now,
38
- mtimeMs: now,
39
- ctimeMs: now,
40
- birthtimeMs: now,
41
- storageMode: "inline",
42
- inlineContent: null,
43
- };
44
- this.inodes.set(1, rootInode);
45
- this.dentries.set(1, new Map());
46
- }
47
- // -- Transactions --
48
- async transaction(fn) {
49
- return fn();
50
- }
51
- // -- Inode lifecycle --
52
- async createInode(attrs) {
53
- const ino = this.nextIno++;
54
- const now = Date.now();
55
- let mode = attrs.mode;
56
- if (attrs.type === "file")
57
- mode |= S_IFREG;
58
- else if (attrs.type === "directory")
59
- mode |= S_IFDIR;
60
- else if (attrs.type === "symlink")
61
- mode |= S_IFLNK;
62
- const meta = {
63
- ino,
64
- type: attrs.type,
65
- mode,
66
- uid: attrs.uid,
67
- gid: attrs.gid,
68
- size: 0,
69
- nlink: 0,
70
- atimeMs: now,
71
- mtimeMs: now,
72
- ctimeMs: now,
73
- birthtimeMs: now,
74
- storageMode: "inline",
75
- inlineContent: null,
76
- };
77
- this.inodes.set(ino, meta);
78
- if (attrs.type === "directory") {
79
- this.dentries.set(ino, new Map());
80
- }
81
- if (attrs.type === "symlink" && attrs.symlinkTarget !== undefined) {
82
- this.symlinkTargets.set(ino, attrs.symlinkTarget);
83
- }
84
- return ino;
85
- }
86
- async getInode(ino) {
87
- const meta = this.inodes.get(ino);
88
- if (!meta)
89
- return null;
90
- return { ...meta };
91
- }
92
- async updateInode(ino, updates) {
93
- const meta = this.inodes.get(ino);
94
- if (!meta)
95
- return;
96
- Object.assign(meta, updates);
97
- }
98
- async deleteInode(ino) {
99
- this.inodes.delete(ino);
100
- this.dentries.delete(ino);
101
- this.symlinkTargets.delete(ino);
102
- this.chunks.delete(ino);
103
- }
104
- // -- Directory entries --
105
- async lookup(parentIno, name) {
106
- const dir = this.dentries.get(parentIno);
107
- if (!dir)
108
- return null;
109
- const entry = dir.get(name);
110
- return entry ? entry.childIno : null;
111
- }
112
- async createDentry(parentIno, name, childIno, type) {
113
- let dir = this.dentries.get(parentIno);
114
- if (!dir) {
115
- dir = new Map();
116
- this.dentries.set(parentIno, dir);
117
- }
118
- if (dir.has(name)) {
119
- throw new KernelError("EEXIST", `'${name}' already exists in directory`);
120
- }
121
- dir.set(name, { childIno, type });
122
- }
123
- async removeDentry(parentIno, name) {
124
- const dir = this.dentries.get(parentIno);
125
- if (dir) {
126
- dir.delete(name);
127
- }
128
- }
129
- async listDir(parentIno) {
130
- const dir = this.dentries.get(parentIno);
131
- if (!dir)
132
- return [];
133
- const result = [];
134
- for (const [name, entry] of dir) {
135
- result.push({ name, ino: entry.childIno, type: entry.type });
136
- }
137
- return result;
138
- }
139
- async listDirWithStats(parentIno) {
140
- const dir = this.dentries.get(parentIno);
141
- if (!dir)
142
- return [];
143
- const result = [];
144
- for (const [name, entry] of dir) {
145
- const meta = this.inodes.get(entry.childIno);
146
- if (meta) {
147
- result.push({ name, ino: entry.childIno, type: entry.type, stat: { ...meta } });
148
- }
149
- }
150
- return result;
151
- }
152
- async renameDentry(srcParentIno, srcName, dstParentIno, dstName) {
153
- const srcDir = this.dentries.get(srcParentIno);
154
- if (!srcDir)
155
- return;
156
- const entry = srcDir.get(srcName);
157
- if (!entry)
158
- return;
159
- srcDir.delete(srcName);
160
- let dstDir = this.dentries.get(dstParentIno);
161
- if (!dstDir) {
162
- dstDir = new Map();
163
- this.dentries.set(dstParentIno, dstDir);
164
- }
165
- dstDir.set(dstName, entry);
166
- }
167
- // -- Path resolution --
168
- async resolvePath(path) {
169
- return this.resolvePathSync(path);
170
- }
171
- async resolveParentPath(path) {
172
- const components = splitPathComponents(path);
173
- if (components.length === 0) {
174
- throw new KernelError("ENOENT", `cannot resolve parent of root`);
175
- }
176
- const name = components[components.length - 1];
177
- const parentComponents = components.slice(0, -1);
178
- const parentIno = this.resolveComponentsCore(parentComponents, 0);
179
- return { parentIno, name };
180
- }
181
- // -- Symlinks --
182
- async readSymlink(ino) {
183
- const target = this.symlinkTargets.get(ino);
184
- if (target === undefined) {
185
- throw new KernelError("EINVAL", `inode ${ino} is not a symlink`);
186
- }
187
- return target;
188
- }
189
- // -- Chunk mapping --
190
- async getChunkKey(ino, chunkIndex) {
191
- const map = this.chunks.get(ino);
192
- if (!map)
193
- return null;
194
- return map.get(chunkIndex) ?? null;
195
- }
196
- async setChunkKey(ino, chunkIndex, key) {
197
- let map = this.chunks.get(ino);
198
- if (!map) {
199
- map = new Map();
200
- this.chunks.set(ino, map);
201
- }
202
- map.set(chunkIndex, key);
203
- }
204
- async getAllChunkKeys(ino) {
205
- const map = this.chunks.get(ino);
206
- if (!map)
207
- return [];
208
- const entries = [];
209
- for (const [chunkIndex, key] of map) {
210
- entries.push({ chunkIndex, key });
211
- }
212
- entries.sort((a, b) => a.chunkIndex - b.chunkIndex);
213
- return entries;
214
- }
215
- async deleteAllChunks(ino) {
216
- const map = this.chunks.get(ino);
217
- if (!map)
218
- return [];
219
- const keys = Array.from(map.values());
220
- this.chunks.delete(ino);
221
- return keys;
222
- }
223
- async deleteChunksFrom(ino, startIndex) {
224
- const map = this.chunks.get(ino);
225
- if (!map)
226
- return [];
227
- const deleted = [];
228
- for (const [idx, key] of map) {
229
- if (idx >= startIndex) {
230
- deleted.push(key);
231
- map.delete(idx);
232
- }
233
- }
234
- return deleted;
235
- }
236
- // -- Synchronous accessors (for prepareOpenSync in kernel) --
237
- resolvePathSync(path) {
238
- const components = splitPathComponents(path);
239
- return this.resolveComponentsCore(components, 0);
240
- }
241
- lookupSync(parentIno, name) {
242
- const dir = this.dentries.get(parentIno);
243
- if (!dir)
244
- return null;
245
- const entry = dir.get(name);
246
- return entry ? entry.childIno : null;
247
- }
248
- getInodeSync(ino) {
249
- const meta = this.inodes.get(ino);
250
- if (!meta)
251
- return null;
252
- return { ...meta };
253
- }
254
- createInodeSync(attrs) {
255
- const ino = this.nextIno++;
256
- const now = Date.now();
257
- let mode = attrs.mode;
258
- if (attrs.type === "file")
259
- mode |= S_IFREG;
260
- else if (attrs.type === "directory")
261
- mode |= S_IFDIR;
262
- else if (attrs.type === "symlink")
263
- mode |= S_IFLNK;
264
- const meta = {
265
- ino,
266
- type: attrs.type,
267
- mode,
268
- uid: attrs.uid,
269
- gid: attrs.gid,
270
- size: 0,
271
- nlink: 0,
272
- atimeMs: now,
273
- mtimeMs: now,
274
- ctimeMs: now,
275
- birthtimeMs: now,
276
- storageMode: "inline",
277
- inlineContent: null,
278
- };
279
- this.inodes.set(ino, meta);
280
- if (attrs.type === "directory") {
281
- this.dentries.set(ino, new Map());
282
- }
283
- if (attrs.type === "symlink" && attrs.symlinkTarget !== undefined) {
284
- this.symlinkTargets.set(ino, attrs.symlinkTarget);
285
- }
286
- return ino;
287
- }
288
- updateInodeSync(ino, updates) {
289
- const meta = this.inodes.get(ino);
290
- if (!meta)
291
- return;
292
- Object.assign(meta, updates);
293
- }
294
- createDentrySync(parentIno, name, childIno, type) {
295
- let dir = this.dentries.get(parentIno);
296
- if (!dir) {
297
- dir = new Map();
298
- this.dentries.set(parentIno, dir);
299
- }
300
- if (dir.has(name)) {
301
- throw new KernelError("EEXIST", `'${name}' already exists in directory`);
302
- }
303
- dir.set(name, { childIno, type });
304
- }
305
- deleteAllChunksSync(ino) {
306
- const map = this.chunks.get(ino);
307
- if (!map)
308
- return [];
309
- const keys = Array.from(map.values());
310
- this.chunks.delete(ino);
311
- return keys;
312
- }
313
- // -- Versioning --
314
- // No background cleanup task is implemented. This is intentional; callers
315
- // prune versions explicitly via ChunkedVFS.pruneVersions(). Version
316
- // retention defaults to false (no automatic cleanup).
317
- async createVersion(ino) {
318
- if (!this.versioningEnabled) {
319
- throw new Error("versioning is not enabled");
320
- }
321
- const meta = this.inodes.get(ino);
322
- if (!meta) {
323
- throw new KernelError("ENOENT", `inode ${ino} not found`);
324
- }
325
- const records = this.versions.get(ino) ?? [];
326
- const version = records.length > 0 ? records[records.length - 1].version + 1 : 1;
327
- const chunkMap = [];
328
- const inoChunks = this.chunks.get(ino);
329
- if (inoChunks) {
330
- for (const [chunkIndex, key] of inoChunks) {
331
- chunkMap.push({ chunkIndex, key });
332
- }
333
- chunkMap.sort((a, b) => a.chunkIndex - b.chunkIndex);
334
- }
335
- const record = {
336
- version,
337
- size: meta.size,
338
- createdAt: Date.now(),
339
- storageMode: meta.storageMode,
340
- inlineContent: meta.inlineContent ? new Uint8Array(meta.inlineContent) : null,
341
- chunkMap,
342
- };
343
- records.push(record);
344
- this.versions.set(ino, records);
345
- return version;
346
- }
347
- async getVersion(ino, version) {
348
- if (!this.versioningEnabled) {
349
- throw new Error("versioning is not enabled");
350
- }
351
- const records = this.versions.get(ino);
352
- if (!records)
353
- return null;
354
- const record = records.find((r) => r.version === version);
355
- if (!record)
356
- return null;
357
- return {
358
- version: record.version,
359
- size: record.size,
360
- createdAt: record.createdAt,
361
- storageMode: record.storageMode,
362
- inlineContent: record.inlineContent ? new Uint8Array(record.inlineContent) : null,
363
- };
364
- }
365
- async listVersions(ino) {
366
- if (!this.versioningEnabled) {
367
- throw new Error("versioning is not enabled");
368
- }
369
- const records = this.versions.get(ino) ?? [];
370
- return records
371
- .map((r) => ({
372
- version: r.version,
373
- size: r.size,
374
- createdAt: r.createdAt,
375
- storageMode: r.storageMode,
376
- inlineContent: r.inlineContent ? new Uint8Array(r.inlineContent) : null,
377
- }))
378
- .reverse();
379
- }
380
- async getVersionChunkMap(ino, version) {
381
- if (!this.versioningEnabled) {
382
- throw new Error("versioning is not enabled");
383
- }
384
- const records = this.versions.get(ino);
385
- if (!records)
386
- return [];
387
- const record = records.find((r) => r.version === version);
388
- if (!record)
389
- return [];
390
- return record.chunkMap.map((e) => ({ chunkIndex: e.chunkIndex, key: e.key }));
391
- }
392
- async deleteVersions(ino, versions) {
393
- if (!this.versioningEnabled) {
394
- throw new Error("versioning is not enabled");
395
- }
396
- if (versions.length === 0)
397
- return [];
398
- const records = this.versions.get(ino);
399
- if (!records)
400
- return [];
401
- const versionSet = new Set(versions);
402
- // Collect block keys from versions being deleted.
403
- const deletedBlockKeys = new Set();
404
- for (const r of records) {
405
- if (versionSet.has(r.version)) {
406
- for (const e of r.chunkMap) {
407
- deletedBlockKeys.add(e.key);
408
- }
409
- }
410
- }
411
- // Remove the version records.
412
- const remaining = records.filter((r) => !versionSet.has(r.version));
413
- this.versions.set(ino, remaining);
414
- if (deletedBlockKeys.size === 0)
415
- return [];
416
- // Find keys still referenced by remaining versions.
417
- const referencedKeys = new Set();
418
- for (const r of remaining) {
419
- for (const e of r.chunkMap) {
420
- referencedKeys.add(e.key);
421
- }
422
- }
423
- // Also check the current chunk map.
424
- const currentChunks = this.chunks.get(ino);
425
- if (currentChunks) {
426
- for (const key of currentChunks.values()) {
427
- referencedKeys.add(key);
428
- }
429
- }
430
- // Return orphaned keys.
431
- const orphanedKeys = [];
432
- for (const key of deletedBlockKeys) {
433
- if (!referencedKeys.has(key)) {
434
- orphanedKeys.push(key);
435
- }
436
- }
437
- return orphanedKeys;
438
- }
439
- async restoreVersion(ino, version) {
440
- if (!this.versioningEnabled) {
441
- throw new Error("versioning is not enabled");
442
- }
443
- const records = this.versions.get(ino);
444
- const record = records?.find((r) => r.version === version);
445
- if (!record) {
446
- throw new KernelError("ENOENT", `version ${version} not found for inode ${ino}`);
447
- }
448
- // Clear current chunk map.
449
- this.chunks.delete(ino);
450
- // Restore chunk map from version.
451
- if (record.chunkMap.length > 0) {
452
- const map = new Map();
453
- for (const entry of record.chunkMap) {
454
- map.set(entry.chunkIndex, entry.key);
455
- }
456
- this.chunks.set(ino, map);
457
- }
458
- // Restore inode metadata from version.
459
- const meta = this.inodes.get(ino);
460
- if (meta) {
461
- meta.size = record.size;
462
- meta.storageMode = record.storageMode;
463
- meta.inlineContent = record.inlineContent ? new Uint8Array(record.inlineContent) : null;
464
- meta.mtimeMs = Date.now();
465
- meta.ctimeMs = Date.now();
466
- }
467
- }
468
- // -- Internal helpers --
469
- resolveComponentsCore(components, symlinkDepth) {
470
- let currentIno = 1; // root
471
- for (let i = 0; i < components.length; i++) {
472
- const name = components[i];
473
- const meta = this.inodes.get(currentIno);
474
- if (!meta || meta.type !== "directory") {
475
- throw new KernelError("ENOENT", `no such file or directory: component '${name}'`);
476
- }
477
- const dir = this.dentries.get(currentIno);
478
- if (!dir) {
479
- throw new KernelError("ENOENT", `no such file or directory: component '${name}'`);
480
- }
481
- const entry = dir.get(name);
482
- if (!entry) {
483
- throw new KernelError("ENOENT", `no such file or directory: '${name}'`);
484
- }
485
- currentIno = entry.childIno;
486
- // Follow symlinks.
487
- const childMeta = this.inodes.get(currentIno);
488
- if (childMeta && childMeta.type === "symlink") {
489
- if (symlinkDepth >= SYMLOOP_MAX) {
490
- throw new KernelError("ELOOP", "too many levels of symbolic links");
491
- }
492
- const target = this.symlinkTargets.get(currentIno);
493
- if (!target) {
494
- throw new KernelError("ENOENT", "dangling symlink");
495
- }
496
- // Resolve symlink target relative to current position.
497
- const targetComponents = splitPathComponents(target);
498
- const remaining = components.slice(i + 1);
499
- const fullComponents = target.startsWith("/")
500
- ? [...targetComponents, ...remaining]
501
- : [
502
- ...this.getPathComponents(currentIno, components.slice(0, i)),
503
- ...targetComponents,
504
- ...remaining,
505
- ];
506
- return this.resolveComponentsCore(fullComponents, symlinkDepth + 1);
507
- }
508
- }
509
- return currentIno;
510
- }
511
- /**
512
- * Get the parent path components for resolving a relative symlink.
513
- * We need to reconstruct the parent directory path from the components
514
- * we have already resolved (everything before the symlink).
515
- */
516
- getPathComponents(_symlinkIno, parentComponents) {
517
- return parentComponents;
518
- }
519
- }
520
- // ---------------------------------------------------------------------------
521
- // Helpers
522
- // ---------------------------------------------------------------------------
523
- function splitPathComponents(path) {
524
- if (!path || path === "/")
525
- return [];
526
- const normalized = path.startsWith("/") ? path.slice(1) : path;
527
- return normalized.split("/").filter((c) => c.length > 0);
528
- }
@@ -1,91 +0,0 @@
1
- /**
2
- * SQLite-backed FsMetadataStore for persistent local and cloud storage.
3
- *
4
- * All data is stored in four tables: inodes, dentries, symlinks, chunks.
5
- * Root inode (ino=1, type='directory') is created at initialization.
6
- * transaction() wraps in BEGIN/COMMIT, rolls back on error.
7
- * resolvePath uses iterative SELECT queries with ELOOP limit of 40.
8
- *
9
- * Usage:
10
- * const store = new SqliteMetadataStore({ dbPath: ':memory:' });
11
- * // or: new SqliteMetadataStore({ dbPath: '/tmp/metadata.db' });
12
- *
13
- * The store implements the FsMetadataStore interface and can be composed
14
- * with any FsBlockStore via createChunkedVfs() to form a full VirtualFileSystem.
15
- */
16
- import type { CreateInodeAttrs, DentryInfo, DentryStatInfo, FsMetadataStore, FsMetadataStoreVersioning, InodeMeta, InodeType, VersionMeta } from "./types.js";
17
- export interface SqliteMetadataStoreOptions {
18
- /** Path to the SQLite database file. Use ':memory:' for in-memory. */
19
- dbPath: string;
20
- /** Enable file versioning support. Default: false. */
21
- versioning?: boolean;
22
- }
23
- export declare class SqliteMetadataStore implements FsMetadataStore, FsMetadataStoreVersioning {
24
- private db;
25
- private versioningEnabled;
26
- private stmtGetInode;
27
- private stmtUpdateInode;
28
- private stmtDeleteInode;
29
- private stmtDeleteSymlink;
30
- private stmtDeleteChunks;
31
- private stmtDeleteDentriesForParent;
32
- private stmtLookup;
33
- private stmtCreateDentry;
34
- private stmtRemoveDentry;
35
- private stmtListDir;
36
- private stmtListDirWithStats;
37
- private stmtGetSymlink;
38
- private stmtGetChunkKey;
39
- private stmtSetChunkKey;
40
- private stmtLookupFull;
41
- private stmtGetAllChunkKeys;
42
- private stmtDeleteAllChunks;
43
- private stmtDeleteChunksFrom;
44
- private stmtDeleteChunksFromDel;
45
- private stmtRenameDentry;
46
- private stmtCreateVersion;
47
- private stmtGetVersion;
48
- private stmtListVersions;
49
- private stmtGetVersionChunkMap;
50
- private stmtDeleteVersion;
51
- private stmtMaxVersion;
52
- constructor(options: SqliteMetadataStoreOptions);
53
- private initSchema;
54
- private rowToInodeMeta;
55
- private savepointCounter;
56
- transaction<T>(fn: () => Promise<T>): Promise<T>;
57
- createInode(attrs: CreateInodeAttrs): Promise<number>;
58
- getInode(ino: number): Promise<InodeMeta | null>;
59
- updateInode(ino: number, updates: Partial<InodeMeta>): Promise<void>;
60
- deleteInode(ino: number): Promise<void>;
61
- lookup(parentIno: number, name: string): Promise<number | null>;
62
- createDentry(parentIno: number, name: string, childIno: number, type: InodeType): Promise<void>;
63
- removeDentry(parentIno: number, name: string): Promise<void>;
64
- listDir(parentIno: number): Promise<DentryInfo[]>;
65
- listDirWithStats(parentIno: number): Promise<DentryStatInfo[]>;
66
- renameDentry(srcParentIno: number, srcName: string, dstParentIno: number, dstName: string): Promise<void>;
67
- resolvePath(path: string): Promise<number>;
68
- resolveParentPath(path: string): Promise<{
69
- parentIno: number;
70
- name: string;
71
- }>;
72
- private resolveComponents;
73
- readSymlink(ino: number): Promise<string>;
74
- getChunkKey(ino: number, chunkIndex: number): Promise<string | null>;
75
- setChunkKey(ino: number, chunkIndex: number, key: string): Promise<void>;
76
- getAllChunkKeys(ino: number): Promise<{
77
- chunkIndex: number;
78
- key: string;
79
- }[]>;
80
- deleteAllChunks(ino: number): Promise<string[]>;
81
- deleteChunksFrom(ino: number, startIndex: number): Promise<string[]>;
82
- createVersion(ino: number): Promise<number>;
83
- getVersion(ino: number, version: number): Promise<VersionMeta | null>;
84
- listVersions(ino: number): Promise<VersionMeta[]>;
85
- getVersionChunkMap(ino: number, version: number): Promise<{
86
- chunkIndex: number;
87
- key: string;
88
- }[]>;
89
- deleteVersions(ino: number, versions: number[]): Promise<string[]>;
90
- restoreVersion(ino: number, version: number): Promise<void>;
91
- }