@procedures/snapshot 0.0.0-stage → 0.2.0

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 (75) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +737 -2
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/index.d.ts +16 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +17 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/module.d.ts +21 -0
  10. package/dist/module.d.ts.map +1 -0
  11. package/dist/module.js +117 -0
  12. package/dist/module.js.map +1 -0
  13. package/dist/procedures/snapshot/archive-io.d.ts +12 -0
  14. package/dist/procedures/snapshot/archive-io.d.ts.map +1 -0
  15. package/dist/procedures/snapshot/archive-io.js +29 -0
  16. package/dist/procedures/snapshot/archive-io.js.map +1 -0
  17. package/dist/procedures/snapshot/commands.d.ts +15 -0
  18. package/dist/procedures/snapshot/commands.d.ts.map +1 -0
  19. package/dist/procedures/snapshot/commands.js +32 -0
  20. package/dist/procedures/snapshot/commands.js.map +1 -0
  21. package/dist/procedures/snapshot/create.d.ts +12 -0
  22. package/dist/procedures/snapshot/create.d.ts.map +1 -0
  23. package/dist/procedures/snapshot/create.js +279 -0
  24. package/dist/procedures/snapshot/create.js.map +1 -0
  25. package/dist/procedures/snapshot/delete.d.ts +12 -0
  26. package/dist/procedures/snapshot/delete.d.ts.map +1 -0
  27. package/dist/procedures/snapshot/delete.js +31 -0
  28. package/dist/procedures/snapshot/delete.js.map +1 -0
  29. package/dist/procedures/snapshot/diff.d.ts +12 -0
  30. package/dist/procedures/snapshot/diff.d.ts.map +1 -0
  31. package/dist/procedures/snapshot/diff.js +113 -0
  32. package/dist/procedures/snapshot/diff.js.map +1 -0
  33. package/dist/procedures/snapshot/index.d.ts +9 -0
  34. package/dist/procedures/snapshot/index.d.ts.map +1 -0
  35. package/dist/procedures/snapshot/index.js +9 -0
  36. package/dist/procedures/snapshot/index.js.map +1 -0
  37. package/dist/procedures/snapshot/list.d.ts +12 -0
  38. package/dist/procedures/snapshot/list.d.ts.map +1 -0
  39. package/dist/procedures/snapshot/list.js +57 -0
  40. package/dist/procedures/snapshot/list.js.map +1 -0
  41. package/dist/procedures/snapshot/names.d.ts +10 -0
  42. package/dist/procedures/snapshot/names.d.ts.map +1 -0
  43. package/dist/procedures/snapshot/names.js +20 -0
  44. package/dist/procedures/snapshot/names.js.map +1 -0
  45. package/dist/procedures/snapshot/restore.d.ts +12 -0
  46. package/dist/procedures/snapshot/restore.d.ts.map +1 -0
  47. package/dist/procedures/snapshot/restore.js +131 -0
  48. package/dist/procedures/snapshot/restore.js.map +1 -0
  49. package/dist/procedures/snapshot/s3-lookup.d.ts +39 -0
  50. package/dist/procedures/snapshot/s3-lookup.d.ts.map +1 -0
  51. package/dist/procedures/snapshot/s3-lookup.js +57 -0
  52. package/dist/procedures/snapshot/s3-lookup.js.map +1 -0
  53. package/dist/register.d.ts +7 -0
  54. package/dist/register.d.ts.map +1 -0
  55. package/dist/register.js +9 -0
  56. package/dist/register.js.map +1 -0
  57. package/dist/types.d.ts +193 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +168 -0
  60. package/dist/types.js.map +1 -0
  61. package/package.json +87 -3
  62. package/src/index.ts +51 -0
  63. package/src/module.ts +155 -0
  64. package/src/procedures/snapshot/archive-io.ts +31 -0
  65. package/src/procedures/snapshot/commands.ts +34 -0
  66. package/src/procedures/snapshot/create.ts +354 -0
  67. package/src/procedures/snapshot/delete.ts +40 -0
  68. package/src/procedures/snapshot/diff.ts +147 -0
  69. package/src/procedures/snapshot/index.ts +9 -0
  70. package/src/procedures/snapshot/list.ts +80 -0
  71. package/src/procedures/snapshot/names.ts +24 -0
  72. package/src/procedures/snapshot/restore.ts +166 -0
  73. package/src/procedures/snapshot/s3-lookup.ts +88 -0
  74. package/src/register.ts +11 -0
  75. package/src/types.ts +381 -0
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Snapshot Procedures Index
3
+ */
4
+ export { snapshotCreate } from "./create.js";
5
+ export { snapshotList } from "./list.js";
6
+ export { snapshotRestore } from "./restore.js";
7
+ export { snapshotDiff } from "./diff.js";
8
+ export { snapshotDelete } from "./delete.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/procedures/snapshot/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * snapshot.list procedure
3
+ *
4
+ * List available snapshots in S3 bucket.
5
+ */
6
+ import type { ProcedureContext } from "@procedures/client";
7
+ import type { SnapshotListInput, SnapshotListOutput } from "../../types.js";
8
+ /**
9
+ * List snapshots in S3 bucket
10
+ */
11
+ export declare function snapshotList(input: SnapshotListInput, ctx: ProcedureContext): Promise<SnapshotListOutput>;
12
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/procedures/snapshot/list.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAGnB,MAAM,gBAAgB,CAAC;AAGxB;;GAEG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,kBAAkB,CAAC,CAoD7B"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * snapshot.list procedure
3
+ *
4
+ * List available snapshots in S3 bucket.
5
+ */
6
+ import { listAllObjects } from "./s3-lookup.js";
7
+ /**
8
+ * List snapshots in S3 bucket
9
+ */
10
+ export async function snapshotList(input, ctx) {
11
+ const prefix = input.prefix
12
+ ? `snapshots/${input.prefix}`
13
+ : "snapshots/";
14
+ // List the metadata files of all pages. Sort them by the time of the write (newest first),
15
+ // then cut. Before, the procedure read one page (S3 lists by key, not by time) and cut it
16
+ // before the sort, so it returned the oldest snapshots (deep dive DATA-16).
17
+ const objects = await listAllObjects(ctx, input.bucket, prefix);
18
+ const metadataKeys = objects
19
+ .filter((obj) => obj.key.endsWith(".metadata.json"))
20
+ .sort((a, b) => timeOf(b.lastModified) - timeOf(a.lastModified))
21
+ .slice(0, input.maxResults);
22
+ // Fetch metadata for each snapshot
23
+ const snapshots = [];
24
+ for (const obj of metadataKeys) {
25
+ try {
26
+ const downloadResult = await ctx.client.call(["s3", "download"], {
27
+ bucket: input.bucket,
28
+ key: obj.key,
29
+ encoding: "utf8",
30
+ });
31
+ const metadata = JSON.parse(downloadResult.body);
32
+ snapshots.push({
33
+ id: metadata.id,
34
+ name: metadata.name,
35
+ preset: metadata.preset,
36
+ createdAt: metadata.createdAt,
37
+ size: metadata.archiveSize,
38
+ os: metadata.environment.os,
39
+ });
40
+ }
41
+ catch {
42
+ // Skip invalid metadata
43
+ }
44
+ }
45
+ // Sort by creation date (newest first)
46
+ snapshots.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
47
+ return {
48
+ snapshots,
49
+ count: snapshots.length,
50
+ };
51
+ }
52
+ /** A time in milliseconds. A missing or invalid time is 0, so it sorts last. */
53
+ function timeOf(iso) {
54
+ const time = iso ? Date.parse(iso) : NaN;
55
+ return Number.isNaN(time) ? 0 : time;
56
+ }
57
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/procedures/snapshot/list.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAwB,EACxB,GAAqB;IAErB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;QACzB,CAAC,CAAC,aAAa,KAAK,CAAC,MAAM,EAAE;QAC7B,CAAC,CAAC,YAAY,CAAC;IAEjB,2FAA2F;IAC3F,0FAA0F;IAC1F,4EAA4E;IAC5E,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChE,MAAM,YAAY,GAAG,OAAO;SACzB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;SACnD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;SAC/D,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAE9B,mCAAmC;IACnC,MAAM,SAAS,GAAwB,EAAE,CAAC;IAE1C,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,cAAc,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAG1C,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE;gBACpB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,QAAQ,EAAE,MAAM;aACjB,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAqB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YAEnE,SAAS,CAAC,IAAI,CAAC;gBACb,EAAE,EAAE,QAAQ,CAAC,EAAE;gBACf,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,IAAI,EAAE,QAAQ,CAAC,WAAW;gBAC1B,EAAE,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE;aAC5B,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACtB,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAClE,CAAC;IAEF,OAAO;QACL,SAAS;QACT,KAAK,EAAE,SAAS,CAAC,MAAM;KACxB,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,SAAS,MAAM,CAAC,GAAuB;IACrC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACzC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Names and exclusion rules of snapshots.
3
+ */
4
+ export declare function assertSnapshotName(field: string, value: string): void;
5
+ /**
6
+ * True when an archive entry is excluded: a pattern matches a whole path segment ("dist"
7
+ * excludes `dist/` but not `src/distance.ts`), or, for "*.ext", the end of the file name.
8
+ */
9
+ export declare function isExcluded(entryPath: string, patterns: readonly string[]): boolean;
10
+ //# sourceMappingURL=names.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../../src/procedures/snapshot/names.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAIrE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAMlF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Names and exclusion rules of snapshots.
3
+ */
4
+ /** A snapshot name or id: letters, digits, ".", "_" and "-", and not ".." (it goes into paths and S3 keys). */
5
+ const SNAPSHOT_NAME = /^[A-Za-z0-9._-]+$/;
6
+ export function assertSnapshotName(field, value) {
7
+ if (!SNAPSHOT_NAME.test(value) || value.includes("..")) {
8
+ throw new Error(`Invalid snapshot ${field}: ${JSON.stringify(value)} (use letters, digits, ".", "_" and "-")`);
9
+ }
10
+ }
11
+ /**
12
+ * True when an archive entry is excluded: a pattern matches a whole path segment ("dist"
13
+ * excludes `dist/` but not `src/distance.ts`), or, for "*.ext", the end of the file name.
14
+ */
15
+ export function isExcluded(entryPath, patterns) {
16
+ const segments = entryPath.split(/[\\/]/).filter((segment) => segment.length > 0);
17
+ const last = segments[segments.length - 1] ?? "";
18
+ return patterns.some((pattern) => pattern.startsWith("*.") ? last.endsWith(pattern.slice(1)) : segments.includes(pattern));
19
+ }
20
+ //# sourceMappingURL=names.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"names.js","sourceRoot":"","sources":["../../../src/procedures/snapshot/names.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,+GAA+G;AAC/G,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAE1C,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,KAAa;IAC7D,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,oBAAoB,KAAK,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACjH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,SAAiB,EAAE,QAA2B;IACvE,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClF,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAC/B,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CACxF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * snapshot.restore procedure
3
+ *
4
+ * Restore an environment snapshot from S3.
5
+ */
6
+ import type { ProcedureContext } from "@procedures/client";
7
+ import type { SnapshotRestoreInput, SnapshotRestoreOutput } from "../../types.js";
8
+ /**
9
+ * Restore a snapshot from S3
10
+ */
11
+ export declare function snapshotRestore(input: SnapshotRestoreInput, ctx: ProcedureContext): Promise<SnapshotRestoreOutput>;
12
+ //# sourceMappingURL=restore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../../../src/procedures/snapshot/restore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EAEtB,MAAM,gBAAgB,CAAC;AAKxB;;GAEG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,oBAAoB,EAC3B,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,qBAAqB,CAAC,CA2IhC"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * snapshot.restore procedure
3
+ *
4
+ * Restore an environment snapshot from S3.
5
+ */
6
+ import { existsSync, mkdirSync, mkdtempSync, readdirSync, renameSync, rmSync } from "node:fs";
7
+ import { basename, join } from "node:path";
8
+ import { tmpdir } from "node:os";
9
+ import * as tar from "tar";
10
+ import { listAllObjects, findSnapshotKey } from "./s3-lookup.js";
11
+ import { assertSnapshotName } from "./names.js";
12
+ import { sha256File } from "./archive-io.js";
13
+ /**
14
+ * Restore a snapshot from S3
15
+ */
16
+ export async function snapshotRestore(input, ctx) {
17
+ // Scratch directory used solely to hold the downloaded archive; it is always
18
+ // safe to delete. The extraction target is `input.targetPath` (required) and
19
+ // is never removed — that is the fix for the self-deleting-restore bug where
20
+ // targetPath defaulted to workDir and the `finally` then wiped it.
21
+ //
22
+ // The id must be a plain name, and the scratch folder is a new unique folder: before, the id
23
+ // went into the path, so `x/../../<dir>` made the `finally` delete <dir>, even when the S3
24
+ // lookup failed (deep dive DATA-1).
25
+ assertSnapshotName("id", input.id);
26
+ const workDir = mkdtempSync(join(tmpdir(), "restore-"));
27
+ try {
28
+ // First, download metadata to get archive location
29
+ const downloadStart = Date.now();
30
+ // Find the snapshot by ID (paginated listing, exact basename match).
31
+ const objects = await listAllObjects(ctx, input.bucket, "snapshots/");
32
+ const metadataKey = findSnapshotKey(objects, input.id, ".metadata.json");
33
+ if (!metadataKey) {
34
+ throw new Error(`Snapshot not found: ${input.id}`);
35
+ }
36
+ // Download metadata
37
+ const metadataResult = await ctx.client.call(["s3", "download"], {
38
+ bucket: input.bucket,
39
+ key: metadataKey,
40
+ encoding: "utf8",
41
+ });
42
+ const metadata = JSON.parse(metadataResult.body);
43
+ // Download archive
44
+ const archiveKey = metadataKey.replace(".metadata.json", ".tar.gz");
45
+ const archivePath = join(workDir, `${input.id}.tar.gz`);
46
+ // Stream the archive to disk: an archive can be large, and loading it into memory as
47
+ // base64 was a third larger again (BUGS-2026-07 M22)
48
+ await ctx.client.call(["s3", "download"], {
49
+ bucket: input.bucket,
50
+ key: archiveKey,
51
+ destPath: archivePath,
52
+ });
53
+ // Verify the downloaded archive against the checksum recorded at snapshot
54
+ // creation time. Do this before extracting so a corrupted or tampered
55
+ // archive never reaches the target directory.
56
+ if (metadata.checksum) {
57
+ const actualChecksum = await sha256File(archivePath);
58
+ if (actualChecksum !== metadata.checksum) {
59
+ throw new Error(`Checksum mismatch for snapshot ${input.id}: expected ${metadata.checksum}, got ${actualChecksum}`);
60
+ }
61
+ }
62
+ const downloadDuration = Date.now() - downloadStart;
63
+ // Extract archive into the caller-provided target directory.
64
+ const extractStart = Date.now();
65
+ const targetPath = input.targetPath;
66
+ if (!existsSync(targetPath)) {
67
+ mkdirSync(targetPath, { recursive: true });
68
+ }
69
+ // Check for existing files if not overwriting
70
+ if (!input.overwrite) {
71
+ // The archive stores each repository under the base name of its path (createArchive), not
72
+ // under its package name: before, the guard checked the package name, so an existing working
73
+ // copy was overwritten with overwrite: false (deep dive DATA-2)
74
+ for (const repo of metadata.repositories) {
75
+ const repoPath = join(targetPath, basename(repo.path));
76
+ if (existsSync(repoPath)) {
77
+ throw new Error(`Target path already exists: ${repoPath}. Use overwrite: true to replace.`);
78
+ }
79
+ }
80
+ }
81
+ // Extract into a staging folder in the target, then move each top-level folder into place.
82
+ // With overwrite: true, a restored folder replaces the existing one: before, the archive
83
+ // was extracted over it, and files that the snapshot does not hold stayed. A failed
84
+ // extraction leaves the target as it was.
85
+ const staging = mkdtempSync(join(targetPath, ".snapshot-restore-"));
86
+ try {
87
+ await tar.extract({
88
+ file: archivePath,
89
+ cwd: staging,
90
+ });
91
+ for (const entry of readdirSync(staging)) {
92
+ const destination = join(targetPath, entry);
93
+ if (existsSync(destination)) {
94
+ if (!input.overwrite) {
95
+ throw new Error(`Target path already exists: ${destination}. Use overwrite: true to replace.`);
96
+ }
97
+ rmSync(destination, { recursive: true, force: true });
98
+ }
99
+ renameSync(join(staging, entry), destination);
100
+ }
101
+ }
102
+ finally {
103
+ rmSync(staging, { recursive: true, force: true });
104
+ }
105
+ const extractDuration = Date.now() - extractStart;
106
+ // Restore stashes if available
107
+ const restoredPaths = [];
108
+ for (const repo of metadata.repositories) {
109
+ const repoPath = join(targetPath, basename(repo.path));
110
+ if (existsSync(repoPath)) {
111
+ restoredPaths.push(repoPath);
112
+ }
113
+ }
114
+ return {
115
+ success: true,
116
+ metadata,
117
+ restoredPaths,
118
+ downloadDuration,
119
+ extractDuration,
120
+ };
121
+ }
122
+ finally {
123
+ // Only ever remove the scratch download directory — never the extraction
124
+ // target. The `workDir !== input.targetPath` guard is belt-and-suspenders:
125
+ // targetPath is required and distinct from the temp scratch dir.
126
+ if (existsSync(workDir) && workDir !== input.targetPath) {
127
+ rmSync(workDir, { recursive: true, force: true });
128
+ }
129
+ }
130
+ }
131
+ //# sourceMappingURL=restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore.js","sourceRoot":"","sources":["../../../src/procedures/snapshot/restore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared S3 lookup helpers for snapshot procedures.
3
+ *
4
+ * Snapshot objects are stored under keys of the form
5
+ * snapshots/<name>/<id>.tar.gz
6
+ * snapshots/<name>/<id>.metadata.json
7
+ * where <id> already embeds <name>, a timestamp and a random suffix, so the
8
+ * final path segment (basename) of a key uniquely identifies a snapshot file.
9
+ *
10
+ * These helpers replace the previous "single s3.list + key.includes(id)"
11
+ * approach, which (a) missed snapshots once a bucket held more than 1000
12
+ * objects (S3 truncates and requires continuation), and (b) matched by
13
+ * substring, so an id that is a substring of a different snapshot's id could
14
+ * resolve to — and, for delete, remove — the wrong files.
15
+ */
16
+ import type { ProcedureContext } from "@procedures/client";
17
+ export interface S3ListedObject {
18
+ key: string;
19
+ /** The time of the last write (ISO 8601), as s3.list gives it */
20
+ lastModified?: string;
21
+ }
22
+ /**
23
+ * List every object under `prefix`, following S3 pagination via
24
+ * continuationToken until the listing is no longer truncated.
25
+ */
26
+ export declare function listAllObjects(ctx: ProcedureContext, bucket: string, prefix: string): Promise<S3ListedObject[]>;
27
+ /**
28
+ * Find the single object whose basename is exactly `${id}${suffix}`.
29
+ *
30
+ * Matching is by exact basename equality, never substring, so an id that is a
31
+ * substring of a different snapshot's id can never resolve to the wrong file.
32
+ */
33
+ export declare function findSnapshotKey(objects: S3ListedObject[], id: string, suffix: string): string | undefined;
34
+ /**
35
+ * All object keys belonging to snapshot `id` (archive + metadata), matched by
36
+ * exact basename so delete can never remove a different snapshot's files.
37
+ */
38
+ export declare function findSnapshotKeys(objects: S3ListedObject[], id: string): string[];
39
+ //# sourceMappingURL=s3-lookup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-lookup.d.ts","sourceRoot":"","sources":["../../../src/procedures/snapshot/s3-lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAQD;;;GAGG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,gBAAgB,EACrB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,EAAE,CAAC,CAmB3B;AAQD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,cAAc,EAAE,EACzB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,SAAS,CAGpB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAGhF"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Shared S3 lookup helpers for snapshot procedures.
3
+ *
4
+ * Snapshot objects are stored under keys of the form
5
+ * snapshots/<name>/<id>.tar.gz
6
+ * snapshots/<name>/<id>.metadata.json
7
+ * where <id> already embeds <name>, a timestamp and a random suffix, so the
8
+ * final path segment (basename) of a key uniquely identifies a snapshot file.
9
+ *
10
+ * These helpers replace the previous "single s3.list + key.includes(id)"
11
+ * approach, which (a) missed snapshots once a bucket held more than 1000
12
+ * objects (S3 truncates and requires continuation), and (b) matched by
13
+ * substring, so an id that is a substring of a different snapshot's id could
14
+ * resolve to — and, for delete, remove — the wrong files.
15
+ */
16
+ /**
17
+ * List every object under `prefix`, following S3 pagination via
18
+ * continuationToken until the listing is no longer truncated.
19
+ */
20
+ export async function listAllObjects(ctx, bucket, prefix) {
21
+ const all = [];
22
+ let continuationToken;
23
+ do {
24
+ const result = await ctx.client.call(["s3", "list"], {
25
+ bucket,
26
+ prefix,
27
+ ...(continuationToken ? { continuationToken } : {}),
28
+ });
29
+ all.push(...result.contents);
30
+ continuationToken = result.isTruncated ? result.nextContinuationToken : undefined;
31
+ } while (continuationToken);
32
+ return all;
33
+ }
34
+ /** Final path segment of an S3 key. */
35
+ function basenameOf(key) {
36
+ const idx = key.lastIndexOf("/");
37
+ return idx === -1 ? key : key.slice(idx + 1);
38
+ }
39
+ /**
40
+ * Find the single object whose basename is exactly `${id}${suffix}`.
41
+ *
42
+ * Matching is by exact basename equality, never substring, so an id that is a
43
+ * substring of a different snapshot's id can never resolve to the wrong file.
44
+ */
45
+ export function findSnapshotKey(objects, id, suffix) {
46
+ const target = `${id}${suffix}`;
47
+ return objects.find((obj) => basenameOf(obj.key) === target)?.key;
48
+ }
49
+ /**
50
+ * All object keys belonging to snapshot `id` (archive + metadata), matched by
51
+ * exact basename so delete can never remove a different snapshot's files.
52
+ */
53
+ export function findSnapshotKeys(objects, id) {
54
+ const targets = new Set([`${id}.tar.gz`, `${id}.metadata.json`]);
55
+ return objects.filter((obj) => targets.has(basenameOf(obj.key))).map((obj) => obj.key);
56
+ }
57
+ //# sourceMappingURL=s3-lookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-lookup.js","sourceRoot":"","sources":["../../../src/procedures/snapshot/s3-lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAqB,EACrB,MAAc,EACd,MAAc;IAEd,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,IAAI,iBAAqC,CAAC;IAE1C,GAAG,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAGlC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;YAChB,MAAM;YACN,MAAM;YACN,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC7B,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC;IACpF,CAAC,QAAQ,iBAAiB,EAAE;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,uCAAuC;AACvC,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACjC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAyB,EACzB,EAAU,EACV,MAAc;IAEd,MAAM,MAAM,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;IAChC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,EAAE,GAAG,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAyB,EAAE,EAAU;IACpE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACjE,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACzF,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Importing this file registers the procedures of @procedures/snapshot, and of the modules that it
3
+ * requires, in the global registry: `import "@procedures/snapshot/register"`. The package root and the
4
+ * `./module` entry register nothing (ARCHITECTURE-PROPOSALS-2026-10, P9).
5
+ */
6
+ export * from "./module.js";
7
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,aAAa,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Importing this file registers the procedures of @procedures/snapshot, and of the modules that it
3
+ * requires, in the global registry: `import "@procedures/snapshot/register"`. The package root and the
4
+ * `./module` entry register nothing (ARCHITECTURE-PROPOSALS-2026-10, P9).
5
+ */
6
+ import { registerSnapshotProcedures } from "./module.js";
7
+ export * from "./module.js";
8
+ registerSnapshotProcedures();
9
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAEzD,cAAc,aAAa,CAAC;AAE5B,0BAA0B,EAAE,CAAC"}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Type definitions for client-snapshot procedures
3
+ *
4
+ * Environment snapshot/restore for testing and recovery.
5
+ * Supports light/medium/heavy presets for different capture levels.
6
+ */
7
+ import { z } from "zod";
8
+ export type SnapshotPreset = "light" | "medium" | "heavy";
9
+ export declare const SnapshotPresetSchema: z.ZodEnum<{
10
+ light: "light";
11
+ medium: "medium";
12
+ heavy: "heavy";
13
+ }>;
14
+ /**
15
+ * Preset descriptions:
16
+ * - light: Git repos only (.git, working tree, branches, stashes) ~500MB
17
+ * - medium: + node_modules + pnpm lockfiles ~2GB
18
+ * - heavy: + pnpm store + global installs + configs ~10GB+
19
+ */
20
+ export interface RepositoryInfo {
21
+ /** Repository path relative to snapshot root */
22
+ path: string;
23
+ /** Package name from package.json */
24
+ name: string;
25
+ /** Current branch */
26
+ branch: string;
27
+ /** HEAD commit hash */
28
+ commit: string;
29
+ /** Whether working tree is dirty */
30
+ dirty: boolean;
31
+ /** Number of stashes */
32
+ stashCount: number;
33
+ /** Remote URL */
34
+ remoteUrl?: string | undefined;
35
+ /** Commits ahead of remote */
36
+ ahead: number;
37
+ /** Commits behind remote */
38
+ behind: number;
39
+ }
40
+ export interface SnapshotMetadata {
41
+ /** Unique snapshot ID */
42
+ id: string;
43
+ /** Human-readable name */
44
+ name: string;
45
+ /** Snapshot preset used */
46
+ preset: SnapshotPreset;
47
+ /** Creation timestamp (ISO string) */
48
+ createdAt: string;
49
+ /** Environment info */
50
+ environment: {
51
+ /** Operating system (win32, darwin, linux) */
52
+ os: string;
53
+ /** Node.js version */
54
+ nodeVersion: string;
55
+ /** pnpm version */
56
+ pnpmVersion: string;
57
+ /** Username who created snapshot */
58
+ username: string;
59
+ /** Hostname */
60
+ hostname: string;
61
+ };
62
+ /** List of repositories in snapshot */
63
+ repositories: RepositoryInfo[];
64
+ /** Archive checksum (SHA-256) */
65
+ checksum: string;
66
+ /** Compressed archive size in bytes */
67
+ archiveSize: number;
68
+ /** Optional description */
69
+ description?: string | undefined;
70
+ }
71
+ export declare const SnapshotCreateInputSchema: z.ZodObject<{
72
+ name: z.ZodString;
73
+ preset: z.ZodDefault<z.ZodEnum<{
74
+ light: "light";
75
+ medium: "medium";
76
+ heavy: "heavy";
77
+ }>>;
78
+ bucket: z.ZodString;
79
+ paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
80
+ description: z.ZodOptional<z.ZodString>;
81
+ }>;
82
+ export type SnapshotCreateInput = z.infer<typeof SnapshotCreateInputSchema>;
83
+ export interface SnapshotCreateOutput {
84
+ /** Snapshot ID */
85
+ id: string;
86
+ /** S3 location */
87
+ location: string;
88
+ /** Metadata */
89
+ metadata: SnapshotMetadata;
90
+ /** Upload duration in ms */
91
+ uploadDuration: number;
92
+ }
93
+ export declare const SnapshotRestoreInputSchema: z.ZodObject<{
94
+ id: z.ZodString;
95
+ bucket: z.ZodString;
96
+ targetPath: z.ZodString;
97
+ overwrite: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
98
+ }>;
99
+ export type SnapshotRestoreInput = z.infer<typeof SnapshotRestoreInputSchema>;
100
+ export interface SnapshotRestoreOutput {
101
+ /** Whether restore succeeded */
102
+ success: boolean;
103
+ /** Restored snapshot metadata */
104
+ metadata: SnapshotMetadata;
105
+ /** Paths that were restored */
106
+ restoredPaths: string[];
107
+ /** Download duration in ms */
108
+ downloadDuration: number;
109
+ /** Extract duration in ms */
110
+ extractDuration: number;
111
+ }
112
+ export declare const SnapshotListInputSchema: z.ZodObject<{
113
+ bucket: z.ZodString;
114
+ prefix: z.ZodOptional<z.ZodString>;
115
+ maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
116
+ }>;
117
+ export type SnapshotListInput = z.infer<typeof SnapshotListInputSchema>;
118
+ export interface SnapshotListEntry {
119
+ /** Snapshot ID */
120
+ id: string;
121
+ /** Snapshot name */
122
+ name: string;
123
+ /** Preset used */
124
+ preset: SnapshotPreset;
125
+ /** Creation date */
126
+ createdAt: string;
127
+ /** Archive size in bytes */
128
+ size: number;
129
+ /** OS it was created on */
130
+ os: string;
131
+ }
132
+ export interface SnapshotListOutput {
133
+ /** List of snapshots */
134
+ snapshots: SnapshotListEntry[];
135
+ /** Total count */
136
+ count: number;
137
+ }
138
+ export declare const SnapshotDiffInputSchema: z.ZodObject<{
139
+ id: z.ZodString;
140
+ bucket: z.ZodString;
141
+ paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
142
+ }>;
143
+ export type SnapshotDiffInput = z.infer<typeof SnapshotDiffInputSchema>;
144
+ export interface SnapshotDiffRepository {
145
+ /** Repository path */
146
+ path: string;
147
+ /** Branch difference (current vs snapshot) */
148
+ branchDiff?: {
149
+ current: string;
150
+ snapshot: string;
151
+ } | undefined;
152
+ /** Commit difference */
153
+ commitDiff?: {
154
+ current: string;
155
+ snapshot: string;
156
+ } | undefined;
157
+ /** Files changed since snapshot */
158
+ filesChanged: number;
159
+ /** New stashes since snapshot */
160
+ newStashes: number;
161
+ }
162
+ export interface SnapshotDiffOutput {
163
+ /** Snapshot metadata for comparison */
164
+ snapshotMetadata: SnapshotMetadata;
165
+ /** Per-repository differences */
166
+ repositories: SnapshotDiffRepository[];
167
+ /** Overall summary */
168
+ summary: {
169
+ /** Total repos with differences */
170
+ reposChanged: number;
171
+ /** Total files changed */
172
+ totalFilesChanged: number;
173
+ /** Whether current state matches snapshot */
174
+ isMatch: boolean;
175
+ };
176
+ }
177
+ export declare const SnapshotDeleteInputSchema: z.ZodObject<{
178
+ id: z.ZodString;
179
+ bucket: z.ZodString;
180
+ }>;
181
+ export type SnapshotDeleteInput = z.infer<typeof SnapshotDeleteInputSchema>;
182
+ export interface SnapshotDeleteOutput {
183
+ /** Whether deletion succeeded */
184
+ deleted: boolean;
185
+ /** Deleted snapshot ID */
186
+ id: string;
187
+ }
188
+ export declare const SnapshotCreateOutputSchema: z.ZodType<SnapshotCreateOutput>;
189
+ export declare const SnapshotRestoreOutputSchema: z.ZodType<SnapshotRestoreOutput>;
190
+ export declare const SnapshotListOutputSchema: z.ZodType<SnapshotListOutput>;
191
+ export declare const SnapshotDiffOutputSchema: z.ZodType<SnapshotDiffOutput>;
192
+ export declare const SnapshotDeleteOutputSchema: z.ZodType<SnapshotDeleteOutput>;
193
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}