@superblocksteam/sdk 2.0.117 → 2.0.118-next.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/.turbo/turbo-build.log +1 -1
- package/dist/cli-replacement/dev.d.mts +6 -0
- package/dist/cli-replacement/dev.d.mts.map +1 -1
- package/dist/cli-replacement/dev.mjs +1 -0
- package/dist/cli-replacement/dev.mjs.map +1 -1
- package/dist/client.d.ts +67 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +94 -0
- package/dist/client.js.map +1 -1
- package/dist/dev-utils/dedupe-async.d.ts +16 -0
- package/dist/dev-utils/dedupe-async.d.ts.map +1 -0
- package/dist/dev-utils/dedupe-async.js +27 -0
- package/dist/dev-utils/dedupe-async.js.map +1 -0
- package/dist/dev-utils/dedupe-async.test.d.ts +2 -0
- package/dist/dev-utils/dedupe-async.test.d.ts.map +1 -0
- package/dist/dev-utils/dedupe-async.test.js +120 -0
- package/dist/dev-utils/dedupe-async.test.js.map +1 -0
- package/dist/dev-utils/dev-server-metrics.d.mts +95 -0
- package/dist/dev-utils/dev-server-metrics.d.mts.map +1 -0
- package/dist/dev-utils/dev-server-metrics.mjs +193 -0
- package/dist/dev-utils/dev-server-metrics.mjs.map +1 -0
- package/dist/dev-utils/dev-server-persist.test.mjs +117 -17
- package/dist/dev-utils/dev-server-persist.test.mjs.map +1 -1
- package/dist/dev-utils/dev-server.d.mts +19 -1
- package/dist/dev-utils/dev-server.d.mts.map +1 -1
- package/dist/dev-utils/dev-server.mjs +296 -28
- package/dist/dev-utils/dev-server.mjs.map +1 -1
- package/dist/flag.d.ts +1 -1
- package/dist/flag.d.ts.map +1 -1
- package/dist/flag.js +3 -3
- package/dist/flag.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/sdk.d.ts +8 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +24 -1
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.test.js +102 -1
- package/dist/sdk.test.js.map +1 -1
- package/dist/telemetry/index.d.ts +2 -1
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +8 -1
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/logging.d.ts +1 -2
- package/dist/telemetry/logging.d.ts.map +1 -1
- package/dist/telemetry/logging.js +1 -1
- package/dist/telemetry/logging.js.map +1 -1
- package/dist/telemetry/memory-metrics.d.ts +3 -0
- package/dist/telemetry/memory-metrics.d.ts.map +1 -0
- package/dist/telemetry/memory-metrics.js +59 -0
- package/dist/telemetry/memory-metrics.js.map +1 -0
- package/dist/types/common.d.ts +1 -1
- package/dist/types/common.d.ts.map +1 -1
- package/dist/version-control.d.mts.map +1 -1
- package/dist/version-control.mjs +14 -19
- package/dist/version-control.mjs.map +1 -1
- package/eslint.config.js +6 -0
- package/package.json +8 -8
- package/src/cli-replacement/dev.mts +8 -0
- package/src/client.ts +189 -6
- package/src/dev-utils/dedupe-async.test.ts +151 -0
- package/src/dev-utils/dedupe-async.ts +45 -0
- package/src/dev-utils/dev-server-metrics.mts +252 -0
- package/src/dev-utils/dev-server-persist.test.mts +170 -19
- package/src/dev-utils/dev-server.mts +366 -32
- package/src/flag.ts +4 -4
- package/src/index.ts +19 -1
- package/src/sdk.test.ts +145 -6
- package/src/sdk.ts +36 -0
- package/src/telemetry/index.ts +9 -1
- package/src/telemetry/logging.ts +2 -2
- package/src/telemetry/memory-metrics.ts +90 -0
- package/src/types/common.ts +1 -1
- package/src/version-control.mts +11 -30
- package/test/version-control.test.mts +0 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/turbo.json +1 -0
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type * as NodeChildProcess from "node:child_process";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
|
+
import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
3
6
|
import { PassThrough } from "node:stream";
|
|
4
7
|
|
|
5
|
-
import { describe, expect, it, vi } from "vitest";
|
|
8
|
+
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
|
6
9
|
|
|
7
10
|
const { spawnMock } = vi.hoisted(() => ({
|
|
8
11
|
spawnMock: vi.fn(),
|
|
@@ -22,6 +25,14 @@ vi.mock("node:child_process", async () => {
|
|
|
22
25
|
};
|
|
23
26
|
});
|
|
24
27
|
|
|
28
|
+
// Use a static import so the slow `dev-server.mjs` module graph (vite, react
|
|
29
|
+
// plugin, workspace deps) loads during file evaluation rather than inside each
|
|
30
|
+
// test, where the cold-import cost easily exceeds the default 5s test timeout.
|
|
31
|
+
import {
|
|
32
|
+
createWorkspacePersistArchive,
|
|
33
|
+
getSuperblocksTarExcludes,
|
|
34
|
+
} from "./dev-server.mjs";
|
|
35
|
+
|
|
25
36
|
function createMockProcess() {
|
|
26
37
|
return Object.assign(new EventEmitter(), {
|
|
27
38
|
stdin: new PassThrough(),
|
|
@@ -30,8 +41,53 @@ function createMockProcess() {
|
|
|
30
41
|
});
|
|
31
42
|
}
|
|
32
43
|
|
|
44
|
+
describe("getSuperblocksTarExcludes", () => {
|
|
45
|
+
let tempRoot: string;
|
|
46
|
+
|
|
47
|
+
beforeAll(() => {
|
|
48
|
+
tempRoot = mkdtempSync(join(tmpdir(), "persist-test-"));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterAll(() => {
|
|
52
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("excludes .superblocks entirely when the directory does not exist", () => {
|
|
56
|
+
const result = getSuperblocksTarExcludes(tempRoot);
|
|
57
|
+
expect(result).toEqual(["--exclude", ".superblocks"]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("excludes subdirs not in the safelist and keeps context/drafts", () => {
|
|
61
|
+
const sb = join(tempRoot, ".superblocks");
|
|
62
|
+
mkdirSync(sb);
|
|
63
|
+
mkdirSync(join(sb, "context"));
|
|
64
|
+
mkdirSync(join(sb, "drafts"));
|
|
65
|
+
mkdirSync(join(sb, "recordings"));
|
|
66
|
+
mkdirSync(join(sb, "scratch"));
|
|
67
|
+
mkdirSync(join(sb, "system-skills"));
|
|
68
|
+
|
|
69
|
+
const result = getSuperblocksTarExcludes(tempRoot);
|
|
70
|
+
|
|
71
|
+
// Safelisted dirs must NOT appear
|
|
72
|
+
expect(result).not.toContain(".superblocks/context");
|
|
73
|
+
expect(result).not.toContain(".superblocks/drafts");
|
|
74
|
+
|
|
75
|
+
// Non-safelisted dirs must be excluded
|
|
76
|
+
expect(result).toContain(".superblocks/recordings");
|
|
77
|
+
expect(result).toContain(".superblocks/scratch");
|
|
78
|
+
expect(result).toContain(".superblocks/system-skills");
|
|
79
|
+
|
|
80
|
+
// Each excluded dir has a preceding --exclude flag
|
|
81
|
+
for (const name of ["recordings", "scratch", "system-skills"]) {
|
|
82
|
+
const idx = result.indexOf(`.superblocks/${name}`);
|
|
83
|
+
expect(idx).toBeGreaterThan(0);
|
|
84
|
+
expect(result[idx - 1]).toBe("--exclude");
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
33
89
|
describe("createWorkspacePersistArchive", () => {
|
|
34
|
-
it("
|
|
90
|
+
it("archive respects excludes", async () => {
|
|
35
91
|
const tarProc = createMockProcess();
|
|
36
92
|
const zstdProc = createMockProcess();
|
|
37
93
|
spawnMock.mockImplementation((command: string) => {
|
|
@@ -47,27 +103,17 @@ describe("createWorkspacePersistArchive", () => {
|
|
|
47
103
|
return zstdProc;
|
|
48
104
|
});
|
|
49
105
|
|
|
50
|
-
const { createWorkspacePersistArchive } = await import("./dev-server.mjs");
|
|
51
|
-
|
|
52
106
|
await expect(createWorkspacePersistArchive("/workspace")).resolves.toEqual(
|
|
53
107
|
Buffer.from("archive"),
|
|
54
108
|
);
|
|
55
109
|
|
|
56
110
|
const tarCall = spawnMock.mock.calls.find(([command]) => command === "tar");
|
|
57
111
|
expect(tarCall).toBeDefined();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"--exclude",
|
|
64
|
-
"node_modules",
|
|
65
|
-
"--exclude",
|
|
66
|
-
".superblocks",
|
|
67
|
-
"-C",
|
|
68
|
-
"/workspace",
|
|
69
|
-
".",
|
|
70
|
-
]);
|
|
112
|
+
const args: string[] = tarCall?.[1];
|
|
113
|
+
|
|
114
|
+
// Standard excludes are always present
|
|
115
|
+
expect(args).toContain(".git");
|
|
116
|
+
expect(args).toContain("node_modules");
|
|
71
117
|
});
|
|
72
118
|
|
|
73
119
|
it("rejects if tar fails after zstd closes successfully", async () => {
|
|
@@ -87,10 +133,115 @@ describe("createWorkspacePersistArchive", () => {
|
|
|
87
133
|
return zstdProc;
|
|
88
134
|
});
|
|
89
135
|
|
|
90
|
-
const { createWorkspacePersistArchive } = await import("./dev-server.mjs");
|
|
91
|
-
|
|
92
136
|
await expect(
|
|
93
137
|
createWorkspacePersistArchive("/workspace"),
|
|
94
138
|
).rejects.toThrowError(/^tar archival failed \(code 2\): tar failed$/);
|
|
95
139
|
});
|
|
96
140
|
});
|
|
141
|
+
|
|
142
|
+
describe("createWorkspacePersistUploadHeaders", () => {
|
|
143
|
+
it("forwards presigned upload headers and adds the archive content length", async () => {
|
|
144
|
+
const { createWorkspacePersistUploadHeaders } =
|
|
145
|
+
await import("./dev-server.mjs");
|
|
146
|
+
|
|
147
|
+
expect(
|
|
148
|
+
createWorkspacePersistUploadHeaders(123, {
|
|
149
|
+
"Content-Type": "application/custom-zstd",
|
|
150
|
+
"x-amz-server-side-encryption": "AES256",
|
|
151
|
+
}),
|
|
152
|
+
).toEqual({
|
|
153
|
+
"content-length": "123",
|
|
154
|
+
"content-type": "application/custom-zstd",
|
|
155
|
+
"x-amz-server-side-encryption": "AES256",
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("normalizes presigned upload header names case-insensitively", async () => {
|
|
160
|
+
const { createWorkspacePersistUploadHeaders } =
|
|
161
|
+
await import("./dev-server.mjs");
|
|
162
|
+
|
|
163
|
+
expect(
|
|
164
|
+
createWorkspacePersistUploadHeaders(789, {
|
|
165
|
+
"content-type": "application/custom-zstd",
|
|
166
|
+
"content-length": "1",
|
|
167
|
+
"x-amz-server-side-encryption": "AES256",
|
|
168
|
+
}),
|
|
169
|
+
).toEqual({
|
|
170
|
+
"content-length": "789",
|
|
171
|
+
"content-type": "application/custom-zstd",
|
|
172
|
+
"x-amz-server-side-encryption": "AES256",
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("keeps the legacy content headers when SABS sends only a URL", async () => {
|
|
177
|
+
const { createWorkspacePersistUploadHeaders } =
|
|
178
|
+
await import("./dev-server.mjs");
|
|
179
|
+
|
|
180
|
+
expect(createWorkspacePersistUploadHeaders(456)).toEqual({
|
|
181
|
+
"content-length": "456",
|
|
182
|
+
"content-type": "application/zstd",
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe("isWorkspacePersistUploadHeaders", () => {
|
|
188
|
+
it("accepts undefined (legacy SABS payloads with no uploadHeaders)", async () => {
|
|
189
|
+
const { isWorkspacePersistUploadHeaders } =
|
|
190
|
+
await import("./dev-server.mjs");
|
|
191
|
+
|
|
192
|
+
expect(isWorkspacePersistUploadHeaders(undefined)).toBe(true);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("accepts a valid string map", async () => {
|
|
196
|
+
const { isWorkspacePersistUploadHeaders } =
|
|
197
|
+
await import("./dev-server.mjs");
|
|
198
|
+
|
|
199
|
+
expect(
|
|
200
|
+
isWorkspacePersistUploadHeaders({
|
|
201
|
+
"content-type": "application/zstd",
|
|
202
|
+
"x-amz-server-side-encryption": "AES256",
|
|
203
|
+
}),
|
|
204
|
+
).toBe(true);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("rejects null, arrays, and non-string values", async () => {
|
|
208
|
+
const { isWorkspacePersistUploadHeaders } =
|
|
209
|
+
await import("./dev-server.mjs");
|
|
210
|
+
|
|
211
|
+
expect(isWorkspacePersistUploadHeaders(null)).toBe(false);
|
|
212
|
+
expect(isWorkspacePersistUploadHeaders([])).toBe(false);
|
|
213
|
+
expect(isWorkspacePersistUploadHeaders({ "x-foo": 1 })).toBe(false);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("rejects case-insensitive duplicate keys", async () => {
|
|
217
|
+
const { isWorkspacePersistUploadHeaders } =
|
|
218
|
+
await import("./dev-server.mjs");
|
|
219
|
+
|
|
220
|
+
expect(
|
|
221
|
+
isWorkspacePersistUploadHeaders({
|
|
222
|
+
"Content-Type": "application/zstd",
|
|
223
|
+
"content-type": "application/custom-zstd",
|
|
224
|
+
}),
|
|
225
|
+
).toBe(false);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("rejects header names with illegal characters", async () => {
|
|
229
|
+
const { isWorkspacePersistUploadHeaders } =
|
|
230
|
+
await import("./dev-server.mjs");
|
|
231
|
+
|
|
232
|
+
// Spaces are not allowed in HTTP token names.
|
|
233
|
+
expect(isWorkspacePersistUploadHeaders({ "bad header": "value" })).toBe(
|
|
234
|
+
false,
|
|
235
|
+
);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("rejects header values with illegal characters", async () => {
|
|
239
|
+
const { isWorkspacePersistUploadHeaders } =
|
|
240
|
+
await import("./dev-server.mjs");
|
|
241
|
+
|
|
242
|
+
// CR/LF in header values is not allowed (header injection guard).
|
|
243
|
+
expect(isWorkspacePersistUploadHeaders({ "x-foo": "bad\r\nvalue" })).toBe(
|
|
244
|
+
false,
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
});
|