@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.
- package/CHANGELOG.md +30 -0
- package/LICENSE +21 -0
- package/README.md +737 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +21 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +117 -0
- package/dist/module.js.map +1 -0
- package/dist/procedures/snapshot/archive-io.d.ts +12 -0
- package/dist/procedures/snapshot/archive-io.d.ts.map +1 -0
- package/dist/procedures/snapshot/archive-io.js +29 -0
- package/dist/procedures/snapshot/archive-io.js.map +1 -0
- package/dist/procedures/snapshot/commands.d.ts +15 -0
- package/dist/procedures/snapshot/commands.d.ts.map +1 -0
- package/dist/procedures/snapshot/commands.js +32 -0
- package/dist/procedures/snapshot/commands.js.map +1 -0
- package/dist/procedures/snapshot/create.d.ts +12 -0
- package/dist/procedures/snapshot/create.d.ts.map +1 -0
- package/dist/procedures/snapshot/create.js +279 -0
- package/dist/procedures/snapshot/create.js.map +1 -0
- package/dist/procedures/snapshot/delete.d.ts +12 -0
- package/dist/procedures/snapshot/delete.d.ts.map +1 -0
- package/dist/procedures/snapshot/delete.js +31 -0
- package/dist/procedures/snapshot/delete.js.map +1 -0
- package/dist/procedures/snapshot/diff.d.ts +12 -0
- package/dist/procedures/snapshot/diff.d.ts.map +1 -0
- package/dist/procedures/snapshot/diff.js +113 -0
- package/dist/procedures/snapshot/diff.js.map +1 -0
- package/dist/procedures/snapshot/index.d.ts +9 -0
- package/dist/procedures/snapshot/index.d.ts.map +1 -0
- package/dist/procedures/snapshot/index.js +9 -0
- package/dist/procedures/snapshot/index.js.map +1 -0
- package/dist/procedures/snapshot/list.d.ts +12 -0
- package/dist/procedures/snapshot/list.d.ts.map +1 -0
- package/dist/procedures/snapshot/list.js +57 -0
- package/dist/procedures/snapshot/list.js.map +1 -0
- package/dist/procedures/snapshot/names.d.ts +10 -0
- package/dist/procedures/snapshot/names.d.ts.map +1 -0
- package/dist/procedures/snapshot/names.js +20 -0
- package/dist/procedures/snapshot/names.js.map +1 -0
- package/dist/procedures/snapshot/restore.d.ts +12 -0
- package/dist/procedures/snapshot/restore.d.ts.map +1 -0
- package/dist/procedures/snapshot/restore.js +131 -0
- package/dist/procedures/snapshot/restore.js.map +1 -0
- package/dist/procedures/snapshot/s3-lookup.d.ts +39 -0
- package/dist/procedures/snapshot/s3-lookup.d.ts.map +1 -0
- package/dist/procedures/snapshot/s3-lookup.js +57 -0
- package/dist/procedures/snapshot/s3-lookup.js.map +1 -0
- package/dist/register.d.ts +7 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +9 -0
- package/dist/register.js.map +1 -0
- package/dist/types.d.ts +193 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +168 -0
- package/dist/types.js.map +1 -0
- package/package.json +87 -3
- package/src/index.ts +51 -0
- package/src/module.ts +155 -0
- package/src/procedures/snapshot/archive-io.ts +31 -0
- package/src/procedures/snapshot/commands.ts +34 -0
- package/src/procedures/snapshot/create.ts +354 -0
- package/src/procedures/snapshot/delete.ts +40 -0
- package/src/procedures/snapshot/diff.ts +147 -0
- package/src/procedures/snapshot/index.ts +9 -0
- package/src/procedures/snapshot/list.ts +80 -0
- package/src/procedures/snapshot/names.ts +24 -0
- package/src/procedures/snapshot/restore.ts +166 -0
- package/src/procedures/snapshot/s3-lookup.ts +88 -0
- package/src/register.ts +11 -0
- package/src/types.ts +381 -0
package/dist/types.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
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 const SnapshotPresetSchema = z.enum(["light", "medium", "heavy"]);
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// snapshot.create Types
|
|
11
|
+
// =============================================================================
|
|
12
|
+
export const SnapshotCreateInputSchema = z.object({
|
|
13
|
+
/** Snapshot name (used in S3 key and metadata) */
|
|
14
|
+
name: z.string().describe("Snapshot name (used in S3 key and metadata)"),
|
|
15
|
+
/** Capture preset (default: medium) */
|
|
16
|
+
preset: SnapshotPresetSchema.default("medium").describe("Capture preset (default: medium)"),
|
|
17
|
+
/** S3 bucket for storage */
|
|
18
|
+
bucket: z.string().describe("S3 bucket for storage"),
|
|
19
|
+
/** Specific paths to include (default: all repos in ecosystem) */
|
|
20
|
+
paths: z.array(z.string()).optional().describe("Specific paths to include (default: all repos in ecosystem)"),
|
|
21
|
+
/** Optional description */
|
|
22
|
+
description: z.string().optional().describe("Optional description"),
|
|
23
|
+
});
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// snapshot.restore Types
|
|
26
|
+
// =============================================================================
|
|
27
|
+
export const SnapshotRestoreInputSchema = z.object({
|
|
28
|
+
/** Snapshot ID to restore */
|
|
29
|
+
id: z.string().describe("Snapshot ID to restore"),
|
|
30
|
+
/** S3 bucket containing snapshot */
|
|
31
|
+
bucket: z.string().describe("S3 bucket containing snapshot"),
|
|
32
|
+
/**
|
|
33
|
+
* Destination directory the snapshot is extracted into. Required: restore
|
|
34
|
+
* must never fall back to a temporary scratch directory, because that
|
|
35
|
+
* scratch directory is deleted on cleanup and would wipe the restored files.
|
|
36
|
+
*/
|
|
37
|
+
targetPath: z.string().describe("Destination directory the snapshot is extracted into. Required: restore must never fall back to a temporary scratch directory, because that scratch directory is deleted on cleanup and would wipe the restored files."),
|
|
38
|
+
/** Overwrite existing files (default: false) */
|
|
39
|
+
overwrite: z.boolean().optional().default(false).describe("Overwrite existing files (default: false)"),
|
|
40
|
+
});
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// snapshot.list Types
|
|
43
|
+
// =============================================================================
|
|
44
|
+
export const SnapshotListInputSchema = z.object({
|
|
45
|
+
/** S3 bucket to list */
|
|
46
|
+
bucket: z.string().describe("S3 bucket to list"),
|
|
47
|
+
/** Filter by name prefix */
|
|
48
|
+
prefix: z.string().optional().describe("Filter by name prefix"),
|
|
49
|
+
/** Maximum results (default: 100) */
|
|
50
|
+
maxResults: z.number().optional().default(100).describe("Maximum results (default: 100)"),
|
|
51
|
+
});
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// snapshot.diff Types
|
|
54
|
+
// =============================================================================
|
|
55
|
+
export const SnapshotDiffInputSchema = z.object({
|
|
56
|
+
/** Snapshot ID to compare against */
|
|
57
|
+
id: z.string().describe("Snapshot ID to compare against"),
|
|
58
|
+
/** S3 bucket containing snapshot */
|
|
59
|
+
bucket: z.string().describe("S3 bucket containing snapshot"),
|
|
60
|
+
/** Specific paths to compare (default: all) */
|
|
61
|
+
paths: z.array(z.string()).optional().describe("Specific paths to compare (default: all)"),
|
|
62
|
+
});
|
|
63
|
+
// =============================================================================
|
|
64
|
+
// snapshot.delete Types
|
|
65
|
+
// =============================================================================
|
|
66
|
+
export const SnapshotDeleteInputSchema = z.object({
|
|
67
|
+
/** Snapshot ID to delete */
|
|
68
|
+
id: z.string().describe("Snapshot ID to delete"),
|
|
69
|
+
/** S3 bucket containing snapshot */
|
|
70
|
+
bucket: z.string().describe("S3 bucket containing snapshot"),
|
|
71
|
+
});
|
|
72
|
+
// =============================================================================
|
|
73
|
+
// Output schemas (roadmap 2.1)
|
|
74
|
+
// =============================================================================
|
|
75
|
+
// Loose objects: a field that a schema does not name stays in the result (a strict schema would
|
|
76
|
+
// remove it when the output is validated).
|
|
77
|
+
//
|
|
78
|
+
// The metadata of a snapshot comes back from S3, where an older version of this package can have
|
|
79
|
+
// written it with fewer fields. A schema that required each field of today's type would turn a
|
|
80
|
+
// restore that worked into a validation error, so the metadata parts require only the id. The
|
|
81
|
+
// casts say that these schemas are more lenient than the types on purpose.
|
|
82
|
+
const repositoryInfo = z.looseObject({
|
|
83
|
+
path: z.string().optional().describe("The repository folder, relative to the snapshot root"),
|
|
84
|
+
name: z.string().optional().describe("The package name"),
|
|
85
|
+
branch: z.string().optional().describe("The branch at the time of the snapshot"),
|
|
86
|
+
commit: z.string().optional().describe("The HEAD commit at the time of the snapshot"),
|
|
87
|
+
dirty: z.boolean().optional().describe("True when the working tree had changes"),
|
|
88
|
+
stashCount: z.number().optional().describe("The number of stashes"),
|
|
89
|
+
remoteUrl: z.string().optional().describe("The remote URL"),
|
|
90
|
+
ahead: z.number().optional().describe("The commits that the remote did not have"),
|
|
91
|
+
behind: z.number().optional().describe("The commits of the remote that the branch did not have"),
|
|
92
|
+
});
|
|
93
|
+
const snapshotMetadata = z
|
|
94
|
+
.looseObject({
|
|
95
|
+
id: z.string().describe("The snapshot id"),
|
|
96
|
+
name: z.string().optional().describe("The name of the snapshot"),
|
|
97
|
+
preset: z.string().optional().describe("The preset: light, medium or heavy"),
|
|
98
|
+
createdAt: z.string().optional().describe("The time of the snapshot (ISO 8601)"),
|
|
99
|
+
environment: z
|
|
100
|
+
.looseObject({
|
|
101
|
+
os: z.string().optional().describe("The operating system"),
|
|
102
|
+
nodeVersion: z.string().optional().describe("The Node.js version"),
|
|
103
|
+
pnpmVersion: z.string().optional().describe("The pnpm version"),
|
|
104
|
+
username: z.string().optional().describe("The user who made the snapshot"),
|
|
105
|
+
hostname: z.string().optional().describe("The host name"),
|
|
106
|
+
})
|
|
107
|
+
.optional()
|
|
108
|
+
.describe("The environment of the snapshot"),
|
|
109
|
+
repositories: z.array(repositoryInfo).optional().describe("The repositories in the snapshot"),
|
|
110
|
+
checksum: z.string().optional().describe("The SHA-256 checksum of the archive"),
|
|
111
|
+
archiveSize: z.number().optional().describe("The size of the compressed archive, in bytes"),
|
|
112
|
+
description: z.string().optional().describe("The description"),
|
|
113
|
+
})
|
|
114
|
+
.describe("The metadata of the snapshot");
|
|
115
|
+
export const SnapshotCreateOutputSchema = z.looseObject({
|
|
116
|
+
id: z.string().describe("The snapshot id"),
|
|
117
|
+
location: z.string().describe("The S3 location of the archive"),
|
|
118
|
+
metadata: snapshotMetadata,
|
|
119
|
+
uploadDuration: z.number().describe("The time of the upload, in milliseconds"),
|
|
120
|
+
});
|
|
121
|
+
export const SnapshotRestoreOutputSchema = z.looseObject({
|
|
122
|
+
success: z.boolean().describe("True when the restore succeeded"),
|
|
123
|
+
metadata: snapshotMetadata,
|
|
124
|
+
restoredPaths: z.array(z.string()).describe("The folders that the restore wrote"),
|
|
125
|
+
downloadDuration: z.number().describe("The time of the download, in milliseconds"),
|
|
126
|
+
extractDuration: z.number().describe("The time of the extraction, in milliseconds"),
|
|
127
|
+
});
|
|
128
|
+
export const SnapshotListOutputSchema = z.looseObject({
|
|
129
|
+
snapshots: z
|
|
130
|
+
.array(z.looseObject({
|
|
131
|
+
id: z.string().describe("The snapshot id"),
|
|
132
|
+
name: z.string().optional().describe("The name of the snapshot"),
|
|
133
|
+
preset: z.string().optional().describe("The preset"),
|
|
134
|
+
createdAt: z.string().optional().describe("The time of the snapshot (ISO 8601)"),
|
|
135
|
+
size: z.number().optional().describe("The size of the archive, in bytes"),
|
|
136
|
+
os: z.string().optional().describe("The operating system of the snapshot"),
|
|
137
|
+
}))
|
|
138
|
+
.describe("The snapshots, newest first"),
|
|
139
|
+
count: z.number().describe("The number of snapshots"),
|
|
140
|
+
});
|
|
141
|
+
const pair = z.looseObject({
|
|
142
|
+
current: z.string().describe("The value now"),
|
|
143
|
+
snapshot: z.string().describe("The value in the snapshot"),
|
|
144
|
+
});
|
|
145
|
+
export const SnapshotDiffOutputSchema = z.looseObject({
|
|
146
|
+
snapshotMetadata,
|
|
147
|
+
repositories: z
|
|
148
|
+
.array(z.looseObject({
|
|
149
|
+
path: z.string().describe("The repository folder"),
|
|
150
|
+
branchDiff: pair.optional().describe("The branch now and in the snapshot, when they differ"),
|
|
151
|
+
commitDiff: pair.optional().describe("The commit now and in the snapshot, when they differ"),
|
|
152
|
+
filesChanged: z.number().describe("The files changed since the snapshot"),
|
|
153
|
+
newStashes: z.number().describe("The stashes made since the snapshot"),
|
|
154
|
+
}))
|
|
155
|
+
.describe("The differences of each repository"),
|
|
156
|
+
summary: z
|
|
157
|
+
.looseObject({
|
|
158
|
+
reposChanged: z.number().describe("The repositories with differences"),
|
|
159
|
+
totalFilesChanged: z.number().describe("The files changed in all repositories"),
|
|
160
|
+
isMatch: z.boolean().describe("True when the current state matches the snapshot"),
|
|
161
|
+
})
|
|
162
|
+
.describe("The summary"),
|
|
163
|
+
});
|
|
164
|
+
export const SnapshotDeleteOutputSchema = z.looseObject({
|
|
165
|
+
deleted: z.boolean().describe("True when the snapshot was deleted"),
|
|
166
|
+
id: z.string().describe("The snapshot id"),
|
|
167
|
+
});
|
|
168
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,90 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package",
|
|
2
3
|
"name": "@procedures/snapshot",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"description": "Snapshot and restore development environments with S3: git state, packages and files, with streamed archives and a safe restore.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"snapshot",
|
|
8
|
+
"backup",
|
|
9
|
+
"restore",
|
|
10
|
+
"s3",
|
|
11
|
+
"environment",
|
|
12
|
+
"procedures"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://mark1russell7.github.io/client/",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/mark1russell7/client/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/mark1russell7/client.git",
|
|
21
|
+
"directory": "packages/client-snapshot"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "Mark Russell (https://github.com/mark1russell7)",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./module": {
|
|
34
|
+
"types": "./dist/module.d.ts",
|
|
35
|
+
"import": "./dist/module.js"
|
|
36
|
+
},
|
|
37
|
+
"./register": {
|
|
38
|
+
"types": "./dist/register.d.ts",
|
|
39
|
+
"import": "./dist/register.js"
|
|
40
|
+
},
|
|
41
|
+
"./register.js": {
|
|
42
|
+
"import": "./dist/register.js"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist",
|
|
47
|
+
"src",
|
|
48
|
+
"!src/**/*.test.ts",
|
|
49
|
+
"!src/**/*.test.tsx",
|
|
50
|
+
"!src/**/__tests__",
|
|
51
|
+
"CHANGELOG.md"
|
|
52
|
+
],
|
|
53
|
+
"sideEffects": [
|
|
54
|
+
"./dist/register.js"
|
|
55
|
+
],
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=22"
|
|
58
|
+
},
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public",
|
|
61
|
+
"provenance": true
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@procedures/client": "0.2.0",
|
|
65
|
+
"@procedures/fs": "0.2.0",
|
|
66
|
+
"@procedures/git": "0.2.0",
|
|
67
|
+
"@procedures/pnpm": "0.2.0",
|
|
68
|
+
"@procedures/s3": "0.2.0",
|
|
69
|
+
"@procedures/shell": "0.2.0",
|
|
70
|
+
"tar": "^7.5.0",
|
|
71
|
+
"zod": "^4.6.5"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"typescript": "^7.0.2",
|
|
75
|
+
"@types/node": "^22.0.0",
|
|
76
|
+
"@mark1russell7/cue": "^1.0.0",
|
|
77
|
+
"vitest": "^5.0.3",
|
|
78
|
+
"@types/tar": "^6.1.11"
|
|
79
|
+
},
|
|
80
|
+
"client": {
|
|
81
|
+
"procedures": "./dist/register.js"
|
|
82
|
+
},
|
|
83
|
+
"scripts": {
|
|
84
|
+
"build": "tsc -b",
|
|
85
|
+
"typecheck": "tsc --noEmit",
|
|
86
|
+
"clean": "rm -rf dist .tsbuildinfo",
|
|
87
|
+
"test": "vitest run",
|
|
88
|
+
"test:watch": "vitest"
|
|
89
|
+
}
|
|
6
90
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* client-snapshot - Environment snapshot/restore procedures
|
|
3
|
+
*
|
|
4
|
+
* Provides procedures for capturing and restoring environment snapshots
|
|
5
|
+
* including git repositories, node_modules, and pnpm stores.
|
|
6
|
+
*
|
|
7
|
+
* Presets:
|
|
8
|
+
* - light: Git repos only (~500MB)
|
|
9
|
+
* - medium: + node_modules (~2GB)
|
|
10
|
+
* - heavy: + pnpm store (~10GB+)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export * from "./module.js";
|
|
14
|
+
|
|
15
|
+
// Re-export types
|
|
16
|
+
export type {
|
|
17
|
+
SnapshotPreset,
|
|
18
|
+
RepositoryInfo,
|
|
19
|
+
SnapshotMetadata,
|
|
20
|
+
SnapshotCreateInput,
|
|
21
|
+
SnapshotCreateOutput,
|
|
22
|
+
SnapshotRestoreInput,
|
|
23
|
+
SnapshotRestoreOutput,
|
|
24
|
+
SnapshotListInput,
|
|
25
|
+
SnapshotListOutput,
|
|
26
|
+
SnapshotListEntry,
|
|
27
|
+
SnapshotDiffInput,
|
|
28
|
+
SnapshotDiffOutput,
|
|
29
|
+
SnapshotDiffRepository,
|
|
30
|
+
SnapshotDeleteInput,
|
|
31
|
+
SnapshotDeleteOutput,
|
|
32
|
+
} from "./types.js";
|
|
33
|
+
|
|
34
|
+
// Re-export schemas
|
|
35
|
+
export {
|
|
36
|
+
SnapshotPresetSchema,
|
|
37
|
+
SnapshotCreateInputSchema,
|
|
38
|
+
SnapshotRestoreInputSchema,
|
|
39
|
+
SnapshotListInputSchema,
|
|
40
|
+
SnapshotDiffInputSchema,
|
|
41
|
+
SnapshotDeleteInputSchema,
|
|
42
|
+
} from "./types.js";
|
|
43
|
+
|
|
44
|
+
// Re-export procedure implementations
|
|
45
|
+
export {
|
|
46
|
+
snapshotCreate,
|
|
47
|
+
snapshotList,
|
|
48
|
+
snapshotRestore,
|
|
49
|
+
snapshotDiff,
|
|
50
|
+
snapshotDelete,
|
|
51
|
+
} from "./procedures/snapshot/index.js";
|
package/src/module.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module (no side effects): the procedures of this package as data, for `createRegistry()`.
|
|
3
|
+
*
|
|
4
|
+
* Procedure Registration for snapshot operations
|
|
5
|
+
*
|
|
6
|
+
* Provides snapshot.create, snapshot.list, snapshot.restore, snapshot.diff, snapshot.delete procedures.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createProcedure, zodAdapter, defineModule, type ProcedureModule, PROCEDURE_REGISTRY, registerModules, type ProcedureRegistry } from "@procedures/client";
|
|
10
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
11
|
+
import {
|
|
12
|
+
snapshotCreate,
|
|
13
|
+
snapshotList,
|
|
14
|
+
snapshotRestore,
|
|
15
|
+
snapshotDiff,
|
|
16
|
+
snapshotDelete,
|
|
17
|
+
} from "./procedures/snapshot/index.js";
|
|
18
|
+
import {
|
|
19
|
+
SnapshotCreateInputSchema,
|
|
20
|
+
SnapshotListInputSchema,
|
|
21
|
+
SnapshotRestoreInputSchema,
|
|
22
|
+
SnapshotDiffInputSchema,
|
|
23
|
+
SnapshotDeleteInputSchema,
|
|
24
|
+
type SnapshotCreateInput,
|
|
25
|
+
type SnapshotCreateOutput,
|
|
26
|
+
type SnapshotListInput,
|
|
27
|
+
type SnapshotListOutput,
|
|
28
|
+
type SnapshotRestoreInput,
|
|
29
|
+
type SnapshotRestoreOutput,
|
|
30
|
+
type SnapshotDiffInput,
|
|
31
|
+
type SnapshotDiffOutput,
|
|
32
|
+
type SnapshotDeleteInput,
|
|
33
|
+
type SnapshotDeleteOutput,
|
|
34
|
+
SnapshotCreateOutputSchema,
|
|
35
|
+
SnapshotRestoreOutputSchema,
|
|
36
|
+
SnapshotListOutputSchema,
|
|
37
|
+
SnapshotDiffOutputSchema,
|
|
38
|
+
SnapshotDeleteOutputSchema,
|
|
39
|
+
} from "./types.js";
|
|
40
|
+
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// Procedures
|
|
43
|
+
// =============================================================================
|
|
44
|
+
|
|
45
|
+
const snapshotCreateProcedure = createProcedure()
|
|
46
|
+
.path(["snapshot", "create"])
|
|
47
|
+
.input(zodAdapter<SnapshotCreateInput>(SnapshotCreateInputSchema))
|
|
48
|
+
.output(zodAdapter<SnapshotCreateOutput>(SnapshotCreateOutputSchema))
|
|
49
|
+
.meta({
|
|
50
|
+
description: "Create environment snapshot and upload to S3",
|
|
51
|
+
// It writes the archive to a new folder of the temporary directory and to new S3 keys with a
|
|
52
|
+
// unique id, so it replaces no data
|
|
53
|
+
effects: { reads: ["fs", "s3", "network"], writes: ["fs", "s3", "network"], destructive: false },
|
|
54
|
+
args: ["name"],
|
|
55
|
+
shorts: { bucket: "b", preset: "p", description: "d" },
|
|
56
|
+
output: "json",
|
|
57
|
+
})
|
|
58
|
+
.handler(async (input: SnapshotCreateInput, ctx: ProcedureContext): Promise<SnapshotCreateOutput> => {
|
|
59
|
+
return snapshotCreate(input, ctx);
|
|
60
|
+
})
|
|
61
|
+
.build();
|
|
62
|
+
|
|
63
|
+
const snapshotListProcedure = createProcedure()
|
|
64
|
+
.path(["snapshot", "list"])
|
|
65
|
+
.input(zodAdapter<SnapshotListInput>(SnapshotListInputSchema))
|
|
66
|
+
.output(zodAdapter<SnapshotListOutput>(SnapshotListOutputSchema))
|
|
67
|
+
.meta({
|
|
68
|
+
description: "List available snapshots in S3 bucket",
|
|
69
|
+
// It downloads the metadata files into memory, not to a file
|
|
70
|
+
effects: { reads: ["s3", "network"], writes: [] },
|
|
71
|
+
args: [],
|
|
72
|
+
shorts: { bucket: "b", prefix: "p", maxResults: "n" },
|
|
73
|
+
output: "json",
|
|
74
|
+
})
|
|
75
|
+
.handler(async (input: SnapshotListInput, ctx: ProcedureContext): Promise<SnapshotListOutput> => {
|
|
76
|
+
return snapshotList(input, ctx);
|
|
77
|
+
})
|
|
78
|
+
.build();
|
|
79
|
+
|
|
80
|
+
const snapshotRestoreProcedure = createProcedure()
|
|
81
|
+
.path(["snapshot", "restore"])
|
|
82
|
+
.input(zodAdapter<SnapshotRestoreInput>(SnapshotRestoreInputSchema))
|
|
83
|
+
.output(zodAdapter<SnapshotRestoreOutput>(SnapshotRestoreOutputSchema))
|
|
84
|
+
.meta({
|
|
85
|
+
description: "Restore environment from S3 snapshot",
|
|
86
|
+
// With overwrite: true, a restored folder replaces the existing folder
|
|
87
|
+
effects: { reads: ["fs", "s3", "network"], writes: ["fs"] },
|
|
88
|
+
args: ["id"],
|
|
89
|
+
shorts: { bucket: "b", targetPath: "t", overwrite: "f" },
|
|
90
|
+
output: "json",
|
|
91
|
+
})
|
|
92
|
+
.handler(async (input: SnapshotRestoreInput, ctx: ProcedureContext): Promise<SnapshotRestoreOutput> => {
|
|
93
|
+
return snapshotRestore(input, ctx);
|
|
94
|
+
})
|
|
95
|
+
.build();
|
|
96
|
+
|
|
97
|
+
const snapshotDiffProcedure = createProcedure()
|
|
98
|
+
.path(["snapshot", "diff"])
|
|
99
|
+
.input(zodAdapter<SnapshotDiffInput>(SnapshotDiffInputSchema))
|
|
100
|
+
.output(zodAdapter<SnapshotDiffOutput>(SnapshotDiffOutputSchema))
|
|
101
|
+
.meta({
|
|
102
|
+
description: "Compare current state against a snapshot",
|
|
103
|
+
// It reads the repositories with git queries that change nothing
|
|
104
|
+
effects: { reads: ["fs", "s3", "network"], writes: [] },
|
|
105
|
+
args: ["id"],
|
|
106
|
+
shorts: { bucket: "b" },
|
|
107
|
+
output: "json",
|
|
108
|
+
})
|
|
109
|
+
.handler(async (input: SnapshotDiffInput, ctx: ProcedureContext): Promise<SnapshotDiffOutput> => {
|
|
110
|
+
return snapshotDiff(input, ctx);
|
|
111
|
+
})
|
|
112
|
+
.build();
|
|
113
|
+
|
|
114
|
+
const snapshotDeleteProcedure = createProcedure()
|
|
115
|
+
.path(["snapshot", "delete"])
|
|
116
|
+
.input(zodAdapter<SnapshotDeleteInput>(SnapshotDeleteInputSchema))
|
|
117
|
+
.output(zodAdapter<SnapshotDeleteOutput>(SnapshotDeleteOutputSchema))
|
|
118
|
+
.meta({
|
|
119
|
+
description: "Delete a snapshot from S3",
|
|
120
|
+
effects: { reads: ["s3", "network"], writes: ["s3", "network"] },
|
|
121
|
+
args: ["id"],
|
|
122
|
+
shorts: { bucket: "b" },
|
|
123
|
+
output: "json",
|
|
124
|
+
})
|
|
125
|
+
.handler(async (input: SnapshotDeleteInput, ctx: ProcedureContext): Promise<SnapshotDeleteOutput> => {
|
|
126
|
+
return snapshotDelete(input, ctx);
|
|
127
|
+
})
|
|
128
|
+
.build();
|
|
129
|
+
|
|
130
|
+
// =============================================================================
|
|
131
|
+
// Registration
|
|
132
|
+
// =============================================================================
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The module of this package, for `createRegistry()`: its procedures as data. Importing this
|
|
136
|
+
* file registers nothing. (`register.ts` registers the same procedures in the global registry.)
|
|
137
|
+
*/
|
|
138
|
+
export const snapshotModule: ProcedureModule = defineModule("@procedures/snapshot", [
|
|
139
|
+
snapshotCreateProcedure,
|
|
140
|
+
snapshotListProcedure,
|
|
141
|
+
snapshotRestoreProcedure,
|
|
142
|
+
snapshotDiffProcedure,
|
|
143
|
+
snapshotDeleteProcedure,
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
export default snapshotModule;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* This function registers the procedures of @procedures/snapshot, and of the modules that it requires, in
|
|
150
|
+
* a registry. The default is the global registry. Importing this file registers nothing: the
|
|
151
|
+
* `./register` entry starts this function (ARCHITECTURE-PROPOSALS-2026-10, P9).
|
|
152
|
+
*/
|
|
153
|
+
export function registerSnapshotProcedures(registry: ProcedureRegistry = PROCEDURE_REGISTRY): void {
|
|
154
|
+
registerModules(registry, [snapshotModule]);
|
|
155
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File access for snapshot archives without the whole archive in memory.
|
|
3
|
+
*
|
|
4
|
+
* Before, create and restore read each archive into memory (for the checksum and the upload).
|
|
5
|
+
* An archive over 2 GiB failed, and the peak was about 2.3 times the archive (deep dive DATA-19).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { createReadStream } from "node:fs";
|
|
10
|
+
import type { FileHandle } from "node:fs/promises";
|
|
11
|
+
|
|
12
|
+
/** The SHA-256 of a file, read as a stream. */
|
|
13
|
+
export async function sha256File(path: string): Promise<string> {
|
|
14
|
+
const hash = createHash("sha256");
|
|
15
|
+
for await (const chunk of createReadStream(path)) {
|
|
16
|
+
hash.update(chunk as Buffer);
|
|
17
|
+
}
|
|
18
|
+
return hash.digest("hex");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The bytes of a file from `offset`, at most `size`. */
|
|
22
|
+
export async function readPart(file: FileHandle, offset: number, size: number): Promise<Buffer> {
|
|
23
|
+
const buffer = Buffer.alloc(size);
|
|
24
|
+
let filled = 0;
|
|
25
|
+
while (filled < size) {
|
|
26
|
+
const { bytesRead } = await file.read(buffer, filled, size - filled, offset + filled);
|
|
27
|
+
if (bytesRead === 0) break;
|
|
28
|
+
filled += bytesRead;
|
|
29
|
+
}
|
|
30
|
+
return buffer.subarray(0, filled);
|
|
31
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The programs that the snapshot procedures run: git and pnpm, through `runCommand`.
|
|
3
|
+
*
|
|
4
|
+
* `runCommand` is async, kills the process tree when the signal aborts, and runs no shell.
|
|
5
|
+
* Before, the procedures used `execSync`: it blocked the event loop of the host for each call,
|
|
6
|
+
* ignored the signal, and passed the command line to a shell.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { runCommand } from "@procedures/shell/command";
|
|
10
|
+
import { resolvePnpm } from "@procedures/pnpm";
|
|
11
|
+
|
|
12
|
+
/** The longest time of one git or pnpm query, in milliseconds. */
|
|
13
|
+
const QUERY_TIMEOUT_MS = 30_000;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* This function runs `git <args>` in `cwd` and gives its trimmed output. It gives `undefined`
|
|
17
|
+
* when git fails, when it cannot start, or when the signal aborts.
|
|
18
|
+
*/
|
|
19
|
+
export async function gitText(args: readonly string[], cwd: string, signal?: AbortSignal): Promise<string | undefined> {
|
|
20
|
+
const result = await runCommand("git", { args, cwd, signal, timeout: QUERY_TIMEOUT_MS });
|
|
21
|
+
return result.success ? result.stdout.trim() : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** This function gives the version of pnpm, or "unknown" when pnpm cannot run. */
|
|
25
|
+
export async function pnpmVersion(signal?: AbortSignal): Promise<string> {
|
|
26
|
+
let pnpm: { command: string; prefix: string[] };
|
|
27
|
+
try {
|
|
28
|
+
pnpm = resolvePnpm();
|
|
29
|
+
} catch {
|
|
30
|
+
return "unknown";
|
|
31
|
+
}
|
|
32
|
+
const result = await runCommand(pnpm.command, { args: [...pnpm.prefix, "--version"], signal, timeout: QUERY_TIMEOUT_MS });
|
|
33
|
+
return result.success ? result.stdout.trim() : "unknown";
|
|
34
|
+
}
|