@superblocksteam/sdk 2.0.115-next.1 → 2.0.115
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/.turbo/turbo-build.log +1 -1
- package/dist/cli-replacement/dev-s3-restore.test.d.mts +2 -0
- package/dist/cli-replacement/dev-s3-restore.test.d.mts.map +1 -0
- package/dist/cli-replacement/dev-s3-restore.test.mjs +457 -0
- package/dist/cli-replacement/dev-s3-restore.test.mjs.map +1 -0
- package/dist/cli-replacement/dev.d.mts +7 -0
- package/dist/cli-replacement/dev.d.mts.map +1 -1
- package/dist/cli-replacement/dev.mjs +49 -2
- package/dist/cli-replacement/dev.mjs.map +1 -1
- package/dist/cli-replacement/package-json-snapshot.d.mts +26 -0
- package/dist/cli-replacement/package-json-snapshot.d.mts.map +1 -0
- package/dist/cli-replacement/package-json-snapshot.mjs +222 -0
- package/dist/cli-replacement/package-json-snapshot.mjs.map +1 -0
- package/dist/cli-replacement/package-json-snapshot.test.d.mts +2 -0
- package/dist/cli-replacement/package-json-snapshot.test.d.mts.map +1 -0
- package/dist/cli-replacement/package-json-snapshot.test.mjs +207 -0
- package/dist/cli-replacement/package-json-snapshot.test.mjs.map +1 -0
- package/dist/dev-utils/dev-server-persist.test.d.mts +2 -0
- package/dist/dev-utils/dev-server-persist.test.d.mts.map +1 -0
- package/dist/dev-utils/dev-server-persist.test.mjs +77 -0
- package/dist/dev-utils/dev-server-persist.test.mjs.map +1 -0
- package/dist/dev-utils/dev-server.d.mts +1 -0
- package/dist/dev-utils/dev-server.d.mts.map +1 -1
- package/dist/dev-utils/dev-server.mjs +75 -53
- package/dist/dev-utils/dev-server.mjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/cli-replacement/dev-s3-restore.test.mts +599 -0
- package/src/cli-replacement/dev.mts +91 -2
- package/src/cli-replacement/package-json-snapshot.mts +328 -0
- package/src/cli-replacement/package-json-snapshot.test.mts +250 -0
- package/src/dev-utils/dev-server-persist.test.mts +96 -0
- package/src/dev-utils/dev-server.mts +91 -73
- package/src/index.ts +15 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type * as NodeChildProcess from "node:child_process";
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
import { PassThrough } from "node:stream";
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it, vi } from "vitest";
|
|
6
|
+
|
|
7
|
+
const { spawnMock } = vi.hoisted(() => ({
|
|
8
|
+
spawnMock: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
vi.mock("node:child_process", async () => {
|
|
12
|
+
const actual =
|
|
13
|
+
await vi.importActual<typeof NodeChildProcess>("node:child_process");
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
...actual,
|
|
17
|
+
default: {
|
|
18
|
+
...actual,
|
|
19
|
+
spawn: spawnMock,
|
|
20
|
+
},
|
|
21
|
+
spawn: spawnMock,
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function createMockProcess() {
|
|
26
|
+
return Object.assign(new EventEmitter(), {
|
|
27
|
+
stdin: new PassThrough(),
|
|
28
|
+
stdout: new PassThrough(),
|
|
29
|
+
stderr: new PassThrough(),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe("createWorkspacePersistArchive", () => {
|
|
34
|
+
it("excludes node_modules from the tar archive", async () => {
|
|
35
|
+
const tarProc = createMockProcess();
|
|
36
|
+
const zstdProc = createMockProcess();
|
|
37
|
+
spawnMock.mockImplementation((command: string) => {
|
|
38
|
+
if (command === "tar") {
|
|
39
|
+
queueMicrotask(() => tarProc.emit("close", 0));
|
|
40
|
+
return tarProc;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
queueMicrotask(() => {
|
|
44
|
+
zstdProc.stdout.emit("data", Buffer.from("archive"));
|
|
45
|
+
zstdProc.emit("close", 0);
|
|
46
|
+
});
|
|
47
|
+
return zstdProc;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const { createWorkspacePersistArchive } = await import("./dev-server.mjs");
|
|
51
|
+
|
|
52
|
+
await expect(createWorkspacePersistArchive("/workspace")).resolves.toEqual(
|
|
53
|
+
Buffer.from("archive"),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const tarCall = spawnMock.mock.calls.find(([command]) => command === "tar");
|
|
57
|
+
expect(tarCall).toBeDefined();
|
|
58
|
+
expect(tarCall?.[1]).toEqual([
|
|
59
|
+
"cf",
|
|
60
|
+
"-",
|
|
61
|
+
"--exclude",
|
|
62
|
+
".git",
|
|
63
|
+
"--exclude",
|
|
64
|
+
"node_modules",
|
|
65
|
+
"--exclude",
|
|
66
|
+
".superblocks",
|
|
67
|
+
"-C",
|
|
68
|
+
"/workspace",
|
|
69
|
+
".",
|
|
70
|
+
]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("rejects if tar fails after zstd closes successfully", async () => {
|
|
74
|
+
const tarProc = createMockProcess();
|
|
75
|
+
const zstdProc = createMockProcess();
|
|
76
|
+
spawnMock.mockImplementation((command: string) => {
|
|
77
|
+
if (command === "tar") {
|
|
78
|
+
return tarProc;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
queueMicrotask(() => {
|
|
82
|
+
zstdProc.emit("close", 0);
|
|
83
|
+
zstdProc.stderr.emit("data", Buffer.from("zstd diagnostic"));
|
|
84
|
+
tarProc.stderr.emit("data", Buffer.from("tar failed"));
|
|
85
|
+
tarProc.emit("close", 2);
|
|
86
|
+
});
|
|
87
|
+
return zstdProc;
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const { createWorkspacePersistArchive } = await import("./dev-server.mjs");
|
|
91
|
+
|
|
92
|
+
await expect(
|
|
93
|
+
createWorkspacePersistArchive("/workspace"),
|
|
94
|
+
).rejects.toThrowError(/^tar archival failed \(code 2\): tar failed$/);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -123,6 +123,96 @@ function vitePlugins(
|
|
|
123
123
|
];
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
export async function createWorkspacePersistArchive(root: string) {
|
|
127
|
+
// Warm pods already have template dependencies installed, so persist only
|
|
128
|
+
// user workspace files and let startup reconcile package drift if needed.
|
|
129
|
+
return new Promise<Buffer>((resolveArchive, rejectArchive) => {
|
|
130
|
+
const tarProc = child_process.spawn(
|
|
131
|
+
"tar",
|
|
132
|
+
[
|
|
133
|
+
"cf",
|
|
134
|
+
"-",
|
|
135
|
+
"--exclude",
|
|
136
|
+
".git",
|
|
137
|
+
"--exclude",
|
|
138
|
+
"node_modules",
|
|
139
|
+
"--exclude",
|
|
140
|
+
".superblocks",
|
|
141
|
+
"-C",
|
|
142
|
+
root,
|
|
143
|
+
".",
|
|
144
|
+
],
|
|
145
|
+
{ stdio: ["ignore", "pipe", "pipe"] },
|
|
146
|
+
);
|
|
147
|
+
const zstdProc = child_process.spawn("zstd", ["-1", "--no-progress"], {
|
|
148
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
149
|
+
});
|
|
150
|
+
let settled = false;
|
|
151
|
+
let tarExitCode: number | null | undefined;
|
|
152
|
+
let zstdExitCode: number | null | undefined;
|
|
153
|
+
const rejectOnce = (error: Error) => {
|
|
154
|
+
if (settled) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
settled = true;
|
|
158
|
+
rejectArchive(error);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
tarProc.stdout.pipe(zstdProc.stdin);
|
|
162
|
+
|
|
163
|
+
// Attach error handlers on the piped stdin. ChildProcess-level 'error'
|
|
164
|
+
// events don't catch stream errors like EPIPE from writing to a closed
|
|
165
|
+
// pipe if the downstream process crashes.
|
|
166
|
+
zstdProc.stdin.on("error", (err) => {
|
|
167
|
+
rejectOnce(new Error(`zstd stdin stream error: ${err.message}`));
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const chunks: Buffer[] = [];
|
|
171
|
+
zstdProc.stdout.on("data", (chunk: Buffer) => chunks.push(chunk));
|
|
172
|
+
|
|
173
|
+
let tarStderr = "";
|
|
174
|
+
let zstdStderr = "";
|
|
175
|
+
tarProc.stderr.on("data", (chunk: Buffer) => {
|
|
176
|
+
tarStderr += chunk.toString();
|
|
177
|
+
});
|
|
178
|
+
zstdProc.stderr.on("data", (chunk: Buffer) => {
|
|
179
|
+
zstdStderr += chunk.toString();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const finishIfClosed = () => {
|
|
183
|
+
if (settled || tarExitCode === undefined || zstdExitCode === undefined) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
settled = true;
|
|
187
|
+
if (zstdExitCode !== 0) {
|
|
188
|
+
rejectArchive(
|
|
189
|
+
new Error(
|
|
190
|
+
`zstd compression failed (code ${zstdExitCode}): ${zstdStderr}`,
|
|
191
|
+
),
|
|
192
|
+
);
|
|
193
|
+
} else if (tarExitCode !== 0) {
|
|
194
|
+
rejectArchive(
|
|
195
|
+
new Error(`tar archival failed (code ${tarExitCode}): ${tarStderr}`),
|
|
196
|
+
);
|
|
197
|
+
} else {
|
|
198
|
+
resolveArchive(Buffer.concat(chunks));
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
tarProc.on("close", (code) => {
|
|
203
|
+
tarExitCode = code;
|
|
204
|
+
finishIfClosed();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
zstdProc.on("close", (code) => {
|
|
208
|
+
zstdExitCode = code;
|
|
209
|
+
finishIfClosed();
|
|
210
|
+
});
|
|
211
|
+
tarProc.on("error", rejectOnce);
|
|
212
|
+
zstdProc.on("error", rejectOnce);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
126
216
|
export const RESTART_EXIT_CODE = 98;
|
|
127
217
|
|
|
128
218
|
function getJwksUriWithBaseUrl(superblocksBaseUrl?: string): string {
|
|
@@ -591,79 +681,7 @@ export async function createDevServer({
|
|
|
591
681
|
|
|
592
682
|
logger.info("/_sb_persist: archiving and uploading workspace to S3...");
|
|
593
683
|
|
|
594
|
-
|
|
595
|
-
// then stream directly to S3 via presigned PUT URL.
|
|
596
|
-
const archive = await new Promise<Buffer>(
|
|
597
|
-
(resolveArchive, rejectArchive) => {
|
|
598
|
-
const tarProc = child_process.spawn(
|
|
599
|
-
"tar",
|
|
600
|
-
[
|
|
601
|
-
"cf",
|
|
602
|
-
"-",
|
|
603
|
-
"--exclude",
|
|
604
|
-
".git",
|
|
605
|
-
"--exclude",
|
|
606
|
-
"node_modules/.cache",
|
|
607
|
-
"--exclude",
|
|
608
|
-
".superblocks",
|
|
609
|
-
"-C",
|
|
610
|
-
process.cwd(),
|
|
611
|
-
".",
|
|
612
|
-
],
|
|
613
|
-
{ stdio: ["ignore", "pipe", "pipe"] },
|
|
614
|
-
);
|
|
615
|
-
const zstdProc = child_process.spawn(
|
|
616
|
-
"zstd",
|
|
617
|
-
["-1", "--no-progress"],
|
|
618
|
-
{
|
|
619
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
620
|
-
},
|
|
621
|
-
);
|
|
622
|
-
|
|
623
|
-
tarProc.stdout.pipe(zstdProc.stdin);
|
|
624
|
-
|
|
625
|
-
// Attach error handlers on the piped stdin. ChildProcess-level 'error'
|
|
626
|
-
// events don't catch stream errors like EPIPE from writing to a closed
|
|
627
|
-
// pipe if the downstream process crashes.
|
|
628
|
-
zstdProc.stdin.on("error", (err) => {
|
|
629
|
-
rejectArchive(new Error(`zstd stdin stream error: ${err.message}`));
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
const chunks: Buffer[] = [];
|
|
633
|
-
zstdProc.stdout.on("data", (chunk: Buffer) => chunks.push(chunk));
|
|
634
|
-
|
|
635
|
-
let stderr = "";
|
|
636
|
-
tarProc.stderr.on("data", (chunk: Buffer) => {
|
|
637
|
-
stderr += chunk.toString();
|
|
638
|
-
});
|
|
639
|
-
zstdProc.stderr.on("data", (chunk: Buffer) => {
|
|
640
|
-
stderr += chunk.toString();
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
let tarExitCode: number | null = null;
|
|
644
|
-
tarProc.on("close", (code) => {
|
|
645
|
-
tarExitCode = code;
|
|
646
|
-
});
|
|
647
|
-
|
|
648
|
-
zstdProc.on("close", (code) => {
|
|
649
|
-
if (code !== 0) {
|
|
650
|
-
rejectArchive(
|
|
651
|
-
new Error(`zstd compression failed (code ${code}): ${stderr}`),
|
|
652
|
-
);
|
|
653
|
-
} else if (tarExitCode !== null && tarExitCode !== 0) {
|
|
654
|
-
rejectArchive(
|
|
655
|
-
new Error(
|
|
656
|
-
`tar archival failed (code ${tarExitCode}): ${stderr}`,
|
|
657
|
-
),
|
|
658
|
-
);
|
|
659
|
-
} else {
|
|
660
|
-
resolveArchive(Buffer.concat(chunks));
|
|
661
|
-
}
|
|
662
|
-
});
|
|
663
|
-
tarProc.on("error", rejectArchive);
|
|
664
|
-
zstdProc.on("error", rejectArchive);
|
|
665
|
-
},
|
|
666
|
-
);
|
|
684
|
+
const archive = await createWorkspacePersistArchive(process.cwd());
|
|
667
685
|
|
|
668
686
|
logger.info(
|
|
669
687
|
`/_sb_persist: archive created (${(archive.length / 1024 / 1024).toFixed(1)}MB) in ${Date.now() - persistStart}ms, uploading...`,
|
package/src/index.ts
CHANGED
|
@@ -86,6 +86,21 @@ export {
|
|
|
86
86
|
|
|
87
87
|
export { dev, DevServerAutoUpgradeMode } from "./cli-replacement/dev.mjs";
|
|
88
88
|
|
|
89
|
+
export {
|
|
90
|
+
didPackageJsonSnapshotChange,
|
|
91
|
+
packageJsonSnapshot,
|
|
92
|
+
packageJsonSnapshotDiagnostic,
|
|
93
|
+
readPackageJsonSnapshot,
|
|
94
|
+
readPackageJsonSnapshotWithSource,
|
|
95
|
+
PACKAGE_DEPENDENCY_FIELDS,
|
|
96
|
+
restoreManagedPackageDependencies,
|
|
97
|
+
MANAGED_PACKAGE_DEPENDENCIES,
|
|
98
|
+
SUPERBLOCKS_SDK_API_PACKAGE,
|
|
99
|
+
SUPERBLOCKS_LIBRARY_PACKAGE,
|
|
100
|
+
type PackageJsonSnapshot,
|
|
101
|
+
type PackageJsonSnapshotReadResult,
|
|
102
|
+
} from "./cli-replacement/package-json-snapshot.mjs";
|
|
103
|
+
|
|
89
104
|
export { getLogger } from "./telemetry/logging.js";
|
|
90
105
|
|
|
91
106
|
export {
|