zyrk 0.3.8 → 0.3.9

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 (189) hide show
  1. package/VERSION +1 -1
  2. package/bin/zyrk.js +1 -1
  3. package/dist/cli/main.d.ts +54 -0
  4. package/dist/cli/main.d.ts.map +1 -0
  5. package/dist/cli/main.js +473 -0
  6. package/dist/cli/npm-delegate.d.ts +38 -0
  7. package/dist/cli/npm-delegate.d.ts.map +1 -0
  8. package/{src/cli/npm-delegate.ts → dist/cli/npm-delegate.js} +26 -55
  9. package/dist/cli/parse.d.ts +40 -0
  10. package/dist/cli/parse.d.ts.map +1 -0
  11. package/dist/cli/parse.js +78 -0
  12. package/dist/commands/dependencies.d.ts +12 -0
  13. package/dist/commands/dependencies.d.ts.map +1 -0
  14. package/dist/commands/dependencies.js +118 -0
  15. package/dist/commands/deploy.d.ts +15 -0
  16. package/dist/commands/deploy.d.ts.map +1 -0
  17. package/dist/commands/deploy.js +506 -0
  18. package/dist/commands/maintenance.d.ts +27 -0
  19. package/dist/commands/maintenance.d.ts.map +1 -0
  20. package/dist/commands/maintenance.js +198 -0
  21. package/dist/commands/patch.d.ts +38 -0
  22. package/dist/commands/patch.d.ts.map +1 -0
  23. package/dist/commands/patch.js +336 -0
  24. package/dist/commands/project.d.ts +15 -0
  25. package/dist/commands/project.d.ts.map +1 -0
  26. package/dist/commands/project.js +396 -0
  27. package/dist/commands/store.d.ts +10 -0
  28. package/dist/commands/store.d.ts.map +1 -0
  29. package/dist/commands/store.js +551 -0
  30. package/dist/config/paths.d.ts +37 -0
  31. package/dist/config/paths.d.ts.map +1 -0
  32. package/dist/config/paths.js +66 -0
  33. package/dist/dlx/create.d.ts +23 -0
  34. package/dist/dlx/create.d.ts.map +1 -0
  35. package/dist/dlx/create.js +59 -0
  36. package/dist/dlx/run.d.ts +54 -0
  37. package/dist/dlx/run.d.ts.map +1 -0
  38. package/dist/dlx/run.js +274 -0
  39. package/dist/errors.d.ts +68 -0
  40. package/dist/errors.d.ts.map +1 -0
  41. package/dist/errors.js +111 -0
  42. package/dist/extract/tarball.d.ts +82 -0
  43. package/dist/extract/tarball.d.ts.map +1 -0
  44. package/dist/extract/tarball.js +645 -0
  45. package/dist/fetch/all.d.ts +48 -0
  46. package/dist/fetch/all.d.ts.map +1 -0
  47. package/dist/fetch/all.js +127 -0
  48. package/dist/fetch/package.d.ts +45 -0
  49. package/dist/fetch/package.d.ts.map +1 -0
  50. package/dist/fetch/package.js +124 -0
  51. package/dist/fetch/registry.d.ts +109 -0
  52. package/dist/fetch/registry.d.ts.map +1 -0
  53. package/dist/fetch/registry.js +418 -0
  54. package/dist/install/import-npm.d.ts +4 -0
  55. package/dist/install/import-npm.d.ts.map +1 -0
  56. package/dist/install/import-npm.js +147 -0
  57. package/dist/install/lock.d.ts +8 -0
  58. package/dist/install/lock.d.ts.map +1 -0
  59. package/dist/install/lock.js +146 -0
  60. package/dist/install/metadata.d.ts +19 -0
  61. package/dist/install/metadata.d.ts.map +1 -0
  62. package/dist/install/metadata.js +79 -0
  63. package/dist/install/registry.d.ts +8 -0
  64. package/dist/install/registry.d.ts.map +1 -0
  65. package/dist/install/registry.js +59 -0
  66. package/dist/install/run.d.ts +32 -0
  67. package/dist/install/run.d.ts.map +1 -0
  68. package/dist/install/run.js +545 -0
  69. package/dist/lockfile/fingerprints.d.ts +35 -0
  70. package/dist/lockfile/fingerprints.d.ts.map +1 -0
  71. package/dist/lockfile/fingerprints.js +56 -0
  72. package/dist/lockfile/read.d.ts +27 -0
  73. package/dist/lockfile/read.d.ts.map +1 -0
  74. package/dist/lockfile/read.js +126 -0
  75. package/dist/lockfile/types.d.ts +74 -0
  76. package/dist/lockfile/types.d.ts.map +1 -0
  77. package/dist/lockfile/types.js +17 -0
  78. package/dist/lockfile/write.d.ts +39 -0
  79. package/dist/lockfile/write.d.ts.map +1 -0
  80. package/dist/lockfile/write.js +180 -0
  81. package/dist/log.d.ts +21 -0
  82. package/dist/log.d.ts.map +1 -0
  83. package/dist/log.js +79 -0
  84. package/dist/project/projection.d.ts +50 -0
  85. package/dist/project/projection.d.ts.map +1 -0
  86. package/dist/project/projection.js +276 -0
  87. package/dist/resolve/resolver.d.ts +75 -0
  88. package/dist/resolve/resolver.d.ts.map +1 -0
  89. package/dist/resolve/resolver.js +533 -0
  90. package/dist/resolve/spec.d.ts +26 -0
  91. package/dist/resolve/spec.d.ts.map +1 -0
  92. package/dist/resolve/spec.js +87 -0
  93. package/dist/store/db.d.ts +49 -0
  94. package/dist/store/db.d.ts.map +1 -0
  95. package/{src/store/db.ts → dist/store/db.js} +106 -206
  96. package/dist/store/graph.d.ts +60 -0
  97. package/dist/store/graph.d.ts.map +1 -0
  98. package/dist/store/graph.js +115 -0
  99. package/dist/store/layout.d.ts +71 -0
  100. package/dist/store/layout.d.ts.map +1 -0
  101. package/dist/store/layout.js +282 -0
  102. package/dist/store/manifests.d.ts +78 -0
  103. package/dist/store/manifests.d.ts.map +1 -0
  104. package/dist/store/manifests.js +238 -0
  105. package/dist/store/objects.d.ts +56 -0
  106. package/dist/store/objects.d.ts.map +1 -0
  107. package/dist/store/objects.js +157 -0
  108. package/dist/store/realize.d.ts +38 -0
  109. package/dist/store/realize.d.ts.map +1 -0
  110. package/dist/store/realize.js +227 -0
  111. package/dist/store/source.d.ts +42 -0
  112. package/dist/store/source.d.ts.map +1 -0
  113. package/dist/store/source.js +169 -0
  114. package/dist/store/txn.d.ts +37 -0
  115. package/dist/store/txn.d.ts.map +1 -0
  116. package/dist/store/txn.js +97 -0
  117. package/dist/store/verify.d.ts +40 -0
  118. package/dist/store/verify.d.ts.map +1 -0
  119. package/dist/store/verify.js +396 -0
  120. package/dist/util/fsx.d.ts +54 -0
  121. package/dist/util/fsx.d.ts.map +1 -0
  122. package/dist/util/fsx.js +259 -0
  123. package/dist/util/hash.d.ts +48 -0
  124. package/dist/util/hash.d.ts.map +1 -0
  125. package/dist/util/hash.js +80 -0
  126. package/dist/util/ids.d.ts +19 -0
  127. package/dist/util/ids.d.ts.map +1 -0
  128. package/dist/util/ids.js +38 -0
  129. package/dist/util/integrity.d.ts +97 -0
  130. package/dist/util/integrity.d.ts.map +1 -0
  131. package/dist/util/integrity.js +192 -0
  132. package/dist/util/json.d.ts +14 -0
  133. package/dist/util/json.d.ts.map +1 -0
  134. package/dist/util/json.js +78 -0
  135. package/dist/util/locks.d.ts +40 -0
  136. package/dist/util/locks.d.ts.map +1 -0
  137. package/dist/util/locks.js +186 -0
  138. package/dist/util/proc.d.ts +32 -0
  139. package/dist/util/proc.d.ts.map +1 -0
  140. package/dist/util/proc.js +84 -0
  141. package/dist/version.d.ts +27 -0
  142. package/dist/version.d.ts.map +1 -0
  143. package/{src/version.ts → dist/version.js} +0 -8
  144. package/package.json +5 -3
  145. package/src/cli/main.ts +0 -602
  146. package/src/cli/parse.ts +0 -106
  147. package/src/commands/dependencies.ts +0 -154
  148. package/src/commands/deploy.ts +0 -777
  149. package/src/commands/maintenance.ts +0 -260
  150. package/src/commands/patch.ts +0 -408
  151. package/src/commands/project.ts +0 -598
  152. package/src/commands/store.ts +0 -689
  153. package/src/config/paths.ts +0 -119
  154. package/src/dlx/create.ts +0 -69
  155. package/src/dlx/run.ts +0 -389
  156. package/src/errors.ts +0 -142
  157. package/src/extract/tarball.ts +0 -868
  158. package/src/fetch/all.ts +0 -206
  159. package/src/fetch/package.ts +0 -181
  160. package/src/fetch/registry.ts +0 -615
  161. package/src/install/import-npm.ts +0 -177
  162. package/src/install/lock.ts +0 -176
  163. package/src/install/metadata.ts +0 -122
  164. package/src/install/registry.ts +0 -88
  165. package/src/install/run.ts +0 -760
  166. package/src/lockfile/fingerprints.ts +0 -74
  167. package/src/lockfile/read.ts +0 -198
  168. package/src/lockfile/types.ts +0 -75
  169. package/src/lockfile/write.ts +0 -257
  170. package/src/log.ts +0 -100
  171. package/src/project/projection.ts +0 -390
  172. package/src/resolve/resolver.ts +0 -757
  173. package/src/resolve/spec.ts +0 -131
  174. package/src/store/graph.ts +0 -175
  175. package/src/store/layout.ts +0 -431
  176. package/src/store/manifests.ts +0 -347
  177. package/src/store/objects.ts +0 -229
  178. package/src/store/realize.ts +0 -322
  179. package/src/store/source.ts +0 -249
  180. package/src/store/txn.ts +0 -118
  181. package/src/store/verify.ts +0 -433
  182. package/src/types/vendor.d.ts +0 -120
  183. package/src/util/fsx.ts +0 -289
  184. package/src/util/hash.ts +0 -117
  185. package/src/util/ids.ts +0 -42
  186. package/src/util/integrity.ts +0 -269
  187. package/src/util/json.ts +0 -89
  188. package/src/util/locks.ts +0 -266
  189. package/src/util/proc.ts +0 -108
@@ -1,431 +0,0 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
- import { ZyrkError } from "../errors.ts";
4
- import { resolveStoreRoot } from "../config/paths.ts";
5
- import {
6
- ensureDirWithMode,
7
- isErrno,
8
- pathExists,
9
- readJsonFile,
10
- writeFileAtomic,
11
- } from "../util/fsx.ts";
12
- import {
13
- CLI_VERSION,
14
- CONTEXT_CANONICALIZATION_VERSION,
15
- EXTRACTION_POLICY_VERSION,
16
- OBJECT_KEY_SCHEME,
17
- SOURCE_MANIFEST_SCHEMA_VERSION,
18
- STORE_FORMAT_FILE,
19
- STORE_FORMAT_VERSION,
20
- } from "../version.ts";
21
-
22
- /**
23
- * The managed store: one verified package store per OS user (SPEC 7).
24
- *
25
- * Layout follows SPEC 7.3. Path length is bounded because every
26
- * content-derived directory name is a fixed-length digest-based identifier
27
- * and package names never become path components.
28
- */
29
-
30
- export type StorePaths = {
31
- root: string;
32
- formatFile: string;
33
- objectsDir: string;
34
- sourcesDir: string;
35
- realizationsDir: string;
36
- graphsDir: string;
37
- metadataDir: string;
38
- journalDir: string;
39
- locksDir: string;
40
- stagingDir: string;
41
- quarantineDir: string;
42
- trashDir: string;
43
- pinsDir: string;
44
- dbFile: string;
45
- };
46
-
47
- export function storePaths(root: string): StorePaths {
48
- const metadataDir = path.join(root, "metadata");
49
- return {
50
- root,
51
- formatFile: path.join(root, STORE_FORMAT_FILE),
52
- objectsDir: path.join(root, "objects"),
53
- sourcesDir: path.join(root, "sources"),
54
- realizationsDir: path.join(root, "realizations"),
55
- graphsDir: path.join(root, "graphs"),
56
- metadataDir,
57
- journalDir: path.join(metadataDir, "journal"),
58
- locksDir: path.join(root, "locks"),
59
- stagingDir: path.join(root, "staging"),
60
- quarantineDir: path.join(root, "quarantine"),
61
- trashDir: path.join(root, "trash"),
62
- pinsDir: path.join(root, "pins"),
63
- dbFile: path.join(metadataDir, "state.sqlite"),
64
- };
65
- }
66
-
67
- export type StoreFormatMarker = {
68
- storeFormatVersion: number;
69
- objectKeyScheme: string;
70
- sourceManifestSchemaVersion: number;
71
- extractionPolicyVersion: number;
72
- contextCanonicalizationVersion: number;
73
- createdAt: string;
74
- tool: { name: string; version: string };
75
- };
76
-
77
- export type OpenStoreOptions = {
78
- /** Explicit root; defaults to the platform location or ZYRK_STORE_DIR. */
79
- root?: string;
80
- /** Create and initialize the store if it does not exist. */
81
- create?: boolean;
82
- /**
83
- * Test-only escape hatch for permission checks. Normal operation must never
84
- * pass this: a group/world-writable store is a blocking diagnostic
85
- * (SPEC 7.2).
86
- */
87
- allowUnsafePermissions?: boolean;
88
- };
89
-
90
- export class Store {
91
- readonly root: string;
92
- readonly paths: StorePaths;
93
- /** undefined when the store has not been initialized yet. */
94
- readonly format: StoreFormatMarker | undefined;
95
-
96
- private constructor(root: string, format: StoreFormatMarker | undefined) {
97
- this.root = root;
98
- this.paths = storePaths(root);
99
- this.format = format;
100
- }
101
-
102
- get initialized(): boolean {
103
- return this.format !== undefined;
104
- }
105
-
106
- static async find(options: { root?: string } = {}): Promise<string> {
107
- return options.root ?? resolveStoreRoot().root;
108
- }
109
-
110
- static async open(options: OpenStoreOptions = {}): Promise<Store> {
111
- const root = await canonicalizeRoot(
112
- path.resolve(options.root ?? resolveStoreRoot().root),
113
- );
114
- const exists = await pathExists(root);
115
- if (!exists) {
116
- if (options.create !== true) {
117
- return new Store(root, undefined);
118
- }
119
- await Store.initialize(root, options.allowUnsafePermissions === true);
120
- } else {
121
- await Store.checkSafety(root, options.allowUnsafePermissions === true);
122
- }
123
-
124
- const paths = storePaths(root);
125
- const markerPath = paths.formatFile;
126
- if (!(await pathExists(markerPath))) {
127
- if (options.create === true) {
128
- await Store.initialize(root, options.allowUnsafePermissions === true);
129
- } else {
130
- return new Store(root, undefined);
131
- }
132
- }
133
-
134
- const marker = await readStoreFormatMarker(markerPath);
135
- validateStoreFormatMarker(marker, markerPath);
136
- return new Store(root, marker);
137
- }
138
-
139
- /** Throw unless the store is initialized and usable. */
140
- requireInitialized(): StoreFormatMarker {
141
- if (this.format === undefined) {
142
- throw new ZyrkError(
143
- "ZYRK_STORE_UNSAFE",
144
- `the zyrk store at ${this.root} is not initialized`,
145
- {
146
- detail: { storeRoot: this.root },
147
- remedy:
148
- "run an install or fetch command to initialize the store, or set ZYRK_STORE_DIR to an existing initialized store",
149
- },
150
- );
151
- }
152
- return this.format;
153
- }
154
-
155
- private static async initialize(
156
- root: string,
157
- allowUnsafePermissions: boolean,
158
- ): Promise<void> {
159
- if (!(await pathExists(root))) {
160
- await ensureDirWithMode(root, 0o700);
161
- }
162
- // An existing directory is checked, never silently chmodded: quietly
163
- // changing the permissions of a directory the user pointed at (a home
164
- // directory, a shared mount) is worse than refusing with a diagnostic
165
- // (SPEC 7.2).
166
- await Store.checkSafety(root, allowUnsafePermissions);
167
-
168
- const paths = storePaths(root);
169
- for (const dir of [
170
- paths.objectsDir,
171
- paths.sourcesDir,
172
- paths.realizationsDir,
173
- paths.graphsDir,
174
- paths.metadataDir,
175
- paths.journalDir,
176
- paths.locksDir,
177
- paths.stagingDir,
178
- paths.quarantineDir,
179
- paths.trashDir,
180
- paths.pinsDir,
181
- ]) {
182
- await ensureDirWithMode(dir, 0o700);
183
- }
184
-
185
- if (!(await pathExists(paths.formatFile))) {
186
- const marker: StoreFormatMarker = {
187
- storeFormatVersion: STORE_FORMAT_VERSION,
188
- objectKeyScheme: OBJECT_KEY_SCHEME,
189
- sourceManifestSchemaVersion: SOURCE_MANIFEST_SCHEMA_VERSION,
190
- extractionPolicyVersion: EXTRACTION_POLICY_VERSION,
191
- contextCanonicalizationVersion: CONTEXT_CANONICALIZATION_VERSION,
192
- createdAt: new Date().toISOString(),
193
- tool: { name: "zyrk", version: CLI_VERSION },
194
- };
195
- await writeFileAtomic(
196
- paths.formatFile,
197
- `${JSON.stringify(marker, null, 2)}\n`,
198
- { mode: 0o644 },
199
- );
200
- }
201
- }
202
-
203
- /**
204
- * Blocking diagnostics for account isolation (SPEC 7.2): the store must be
205
- * user-owned and not group/world writable. Never fixes ownership
206
- * automatically; a root-owned store gets a repair explanation instead.
207
- */
208
- private static async checkSafety(
209
- root: string,
210
- allowUnsafePermissions: boolean,
211
- ): Promise<void> {
212
- const resolved = await fs.realpath(root);
213
- const stat = await fs.stat(resolved);
214
- if (!stat.isDirectory()) {
215
- throw new ZyrkError(
216
- "ZYRK_STORE_UNSAFE",
217
- `store path is not a directory: ${root}`,
218
- {
219
- detail: { storeRoot: root },
220
- remedy:
221
- "choose a directory for the store, or remove the conflicting file",
222
- },
223
- );
224
- }
225
-
226
- if (process.platform === "win32") {
227
- // Windows ACL verification arrives with Windows platform support
228
- // (SPEC 27); until then the store is not advertised as supported there.
229
- throw new ZyrkError(
230
- "ZYRK_PLATFORM_UNSUPPORTED",
231
- "Windows store permission checks are not implemented yet",
232
- {
233
- detail: { storeRoot: root, platform: process.platform },
234
- remedy:
235
- "run on Linux for now; Windows support is gated on its platform fixtures",
236
- },
237
- );
238
- }
239
-
240
- if (allowUnsafePermissions) return;
241
-
242
- const uid = process.getuid?.();
243
- if (uid !== undefined && stat.uid !== uid) {
244
- throw new ZyrkError(
245
- "ZYRK_STORE_UNSAFE",
246
- `store is owned by another user (uid ${stat.uid}, running as ${uid}): ${root}`,
247
- {
248
- detail: { storeRoot: root, ownerUid: stat.uid, runningUid: uid },
249
- remedy:
250
- "if this store was created by root, move it under your own account or point ZYRK_STORE_DIR at a user-owned location; zyrk never rewrites ownership recursively",
251
- },
252
- );
253
- }
254
- if (uid !== undefined && stat.uid === 0 && uid !== 0) {
255
- throw new ZyrkError("ZYRK_STORE_UNSAFE", `store is root-owned: ${root}`, {
256
- detail: { storeRoot: root, ownerUid: stat.uid },
257
- remedy:
258
- "create a fresh store under your account instead of reusing a root-owned one",
259
- });
260
- }
261
-
262
- const mode = stat.mode & 0o777;
263
- if ((mode & 0o022) !== 0) {
264
- throw new ZyrkError(
265
- "ZYRK_STORE_UNSAFE",
266
- `store is group- or world-writable (mode ${mode.toString(8)}): ${root}`,
267
- {
268
- detail: { storeRoot: root, mode: mode.toString(8) },
269
- remedy: `chmod go-w '${root}' (and its subdirectories) so other accounts cannot modify shared package content`,
270
- },
271
- );
272
- }
273
-
274
- // Every managed boundary zyrk writes or reuses through gets the same
275
- // ownership, type, and mode checks as the root, evaluated with lstat so
276
- // a substituted symlink is rejected instead of followed (S02). Missing
277
- // directories are created on demand with 0700; existing ones are never
278
- // silently repaired.
279
- const paths = storePaths(resolved);
280
- for (const dir of [
281
- paths.objectsDir,
282
- paths.sourcesDir,
283
- paths.realizationsDir,
284
- paths.graphsDir,
285
- paths.metadataDir,
286
- paths.journalDir,
287
- paths.locksDir,
288
- paths.stagingDir,
289
- paths.quarantineDir,
290
- paths.trashDir,
291
- paths.pinsDir,
292
- ]) {
293
- await Store.checkManagedDir(dir, uid, allowUnsafePermissions);
294
- }
295
- }
296
-
297
- private static async checkManagedDir(
298
- dir: string,
299
- uid: number | undefined,
300
- allowUnsafePermissions: boolean,
301
- ): Promise<void> {
302
- let stat;
303
- try {
304
- stat = await fs.lstat(dir);
305
- } catch (error) {
306
- if (isErrno(error, "ENOENT")) return;
307
- throw error;
308
- }
309
- if (!stat.isDirectory() || stat.isSymbolicLink()) {
310
- throw new ZyrkError(
311
- "ZYRK_STORE_UNSAFE",
312
- `store directory is not a real directory: ${dir}`,
313
- {
314
- detail: { storeDir: dir },
315
- remedy:
316
- "remove the unexpected file or link and let zyrk recreate the managed directory",
317
- },
318
- );
319
- }
320
- if (allowUnsafePermissions) return;
321
- if (uid !== undefined && stat.uid !== uid) {
322
- throw new ZyrkError(
323
- "ZYRK_STORE_UNSAFE",
324
- `store directory is owned by another user (uid ${stat.uid}, running as ${uid}): ${dir}`,
325
- {
326
- detail: { storeDir: dir, ownerUid: stat.uid, runningUid: uid },
327
- remedy:
328
- "zyrk never rewrites ownership recursively; use a store your account owns",
329
- },
330
- );
331
- }
332
- if ((stat.mode & 0o777 & 0o022) !== 0) {
333
- throw new ZyrkError(
334
- "ZYRK_STORE_UNSAFE",
335
- `store directory is group- or world-writable (mode ${(stat.mode & 0o777).toString(8)}): ${dir}`,
336
- {
337
- detail: { storeDir: dir, mode: (stat.mode & 0o777).toString(8) },
338
- remedy: `chmod go-w '${dir}' so other accounts cannot modify shared package content`,
339
- },
340
- );
341
- }
342
- }
343
- }
344
-
345
- /**
346
- * Resolve symlinks deliberately so the store has one canonical identity
347
- * for safety checks, paths, and records. A symlinked ZYRK_STORE_DIR is
348
- * allowed; it always means its target. Missing leaves resolve through
349
- * their nearest existing ancestor.
350
- */
351
- async function canonicalizeRoot(root: string): Promise<string> {
352
- try {
353
- return await fs.realpath(root);
354
- } catch (error) {
355
- if (!isErrno(error, "ENOENT")) throw error;
356
- // A dangling root symlink exists according to lstat but not realpath.
357
- // Resolve its target before initialization so writes and safety checks
358
- // use the same canonical directory as an already-existing root.
359
- try {
360
- if ((await fs.lstat(root)).isSymbolicLink()) {
361
- return await canonicalizeRoot(
362
- path.resolve(path.dirname(root), await fs.readlink(root)),
363
- );
364
- }
365
- } catch (linkError) {
366
- if (!isErrno(linkError, "ENOENT")) throw linkError;
367
- }
368
- const parent = path.dirname(root);
369
- if (parent === root) throw error;
370
- return path.join(await canonicalizeRoot(parent), path.basename(root));
371
- }
372
- }
373
-
374
- async function readStoreFormatMarker(
375
- markerPath: string,
376
- ): Promise<StoreFormatMarker> {
377
- try {
378
- return await readJsonFile<StoreFormatMarker>(markerPath);
379
- } catch (error) {
380
- throw new ZyrkError(
381
- "ZYRK_STORE_CORRUPT",
382
- `store format marker is unreadable: ${markerPath}`,
383
- {
384
- detail: { formatFile: markerPath },
385
- remedy:
386
- "inspect the marker file; if it is damaged, remove it and re-run an install to reinitialize format metadata",
387
- cause: error,
388
- },
389
- );
390
- }
391
- }
392
-
393
- function validateStoreFormatMarker(
394
- marker: StoreFormatMarker,
395
- markerPath: string,
396
- ): void {
397
- if (marker.storeFormatVersion !== STORE_FORMAT_VERSION) {
398
- throw new ZyrkError(
399
- "ZYRK_STORE_FORMAT_UNSUPPORTED",
400
- `store format ${marker.storeFormatVersion} is not supported by this zyrk (expects ${STORE_FORMAT_VERSION})`,
401
- {
402
- detail: {
403
- formatFile: markerPath,
404
- storeFormatVersion: marker.storeFormatVersion,
405
- supported: STORE_FORMAT_VERSION,
406
- },
407
- remedy:
408
- "use a CLI matching this store format, or initialize a fresh store at a new location; if this store is newer, upgrade zyrk first",
409
- },
410
- );
411
- }
412
- if (marker.objectKeyScheme !== OBJECT_KEY_SCHEME) {
413
- throw new ZyrkError(
414
- "ZYRK_STORE_FORMAT_UNSUPPORTED",
415
- `object key scheme ${marker.objectKeyScheme} is not supported`,
416
- {
417
- detail: {
418
- formatFile: markerPath,
419
- objectKeyScheme: marker.objectKeyScheme,
420
- },
421
- remedy:
422
- "use a CLI that understands this store, or initialize a fresh store",
423
- },
424
- );
425
- }
426
- if (marker.extractionPolicyVersion !== EXTRACTION_POLICY_VERSION) {
427
- // Extraction-rule changes are part of source identity (SPEC 8.1/13.4):
428
- // existing manifests stay readable, but new fetches mint new identities.
429
- // This is an informational condition, not an error.
430
- }
431
- }