@indigoai-us/hq-cloud 5.46.0 → 5.47.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 (49) hide show
  1. package/dist/bin/sync-runner.d.ts +12 -0
  2. package/dist/bin/sync-runner.d.ts.map +1 -1
  3. package/dist/bin/sync-runner.js +39 -0
  4. package/dist/bin/sync-runner.js.map +1 -1
  5. package/dist/bin/sync-runner.test.js +27 -1
  6. package/dist/bin/sync-runner.test.js.map +1 -1
  7. package/dist/cli/share.d.ts.map +1 -1
  8. package/dist/cli/share.js +17 -2
  9. package/dist/cli/share.js.map +1 -1
  10. package/dist/cli/share.test.js +2 -0
  11. package/dist/cli/share.test.js.map +1 -1
  12. package/dist/cli/sync-scope.test.js +1 -0
  13. package/dist/cli/sync-scope.test.js.map +1 -1
  14. package/dist/cli/sync.d.ts.map +1 -1
  15. package/dist/cli/sync.js +11 -1
  16. package/dist/cli/sync.js.map +1 -1
  17. package/dist/cli/sync.test.js +1 -0
  18. package/dist/cli/sync.test.js.map +1 -1
  19. package/dist/object-io.d.ts +218 -0
  20. package/dist/object-io.d.ts.map +1 -0
  21. package/dist/object-io.js +588 -0
  22. package/dist/object-io.js.map +1 -0
  23. package/dist/object-io.test.d.ts +11 -0
  24. package/dist/object-io.test.d.ts.map +1 -0
  25. package/dist/object-io.test.js +568 -0
  26. package/dist/object-io.test.js.map +1 -0
  27. package/dist/s3.d.ts +37 -0
  28. package/dist/s3.d.ts.map +1 -1
  29. package/dist/s3.js +207 -198
  30. package/dist/s3.js.map +1 -1
  31. package/dist/vault-client.d.ts +68 -0
  32. package/dist/vault-client.d.ts.map +1 -1
  33. package/dist/vault-client.js +35 -0
  34. package/dist/vault-client.js.map +1 -1
  35. package/package.json +1 -1
  36. package/scripts/presign-transport-e2e.mjs +203 -0
  37. package/scripts/vault-rebaseline.sh +275 -0
  38. package/scripts/vault-rescue.sh +8 -0
  39. package/src/bin/sync-runner.test.ts +41 -0
  40. package/src/bin/sync-runner.ts +52 -0
  41. package/src/cli/share.test.ts +2 -0
  42. package/src/cli/share.ts +29 -2
  43. package/src/cli/sync-scope.test.ts +1 -0
  44. package/src/cli/sync.test.ts +1 -0
  45. package/src/cli/sync.ts +22 -1
  46. package/src/object-io.test.ts +663 -0
  47. package/src/object-io.ts +782 -0
  48. package/src/s3.ts +259 -233
  49. package/src/vault-client.ts +101 -0
@@ -0,0 +1,568 @@
1
+ /**
2
+ * Unit tests for the ObjectIO transport seam.
3
+ *
4
+ * Focus is the PresignObjectIO path (the new transport): it talks to a
5
+ * VaultClient-shaped stub for URL minting and a mocked global `fetch` for the
6
+ * byte movement. The S3SdkObjectIO path is already covered transitively by
7
+ * s3.test.ts (which exercises s3.ts through the default factory), plus a couple
8
+ * of factory-selection tests here.
9
+ */
10
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
11
+ import { PresignObjectIO, S3SdkObjectIO, setObjectIOFactory, resolveObjectIO, presignObjectIOFactory, } from "./object-io.js";
12
+ const COMPANY = "cmp_test";
13
+ function ctx() {
14
+ return {
15
+ uid: COMPANY,
16
+ slug: "test",
17
+ bucketName: "bucket-test",
18
+ region: "us-east-1",
19
+ credentials: {
20
+ accessKeyId: "AKIA",
21
+ secretAccessKey: "secret",
22
+ sessionToken: "token",
23
+ },
24
+ expiresAt: "2099-01-01T00:00:00.000Z",
25
+ };
26
+ }
27
+ /**
28
+ * Minimal VaultClient stub. Each method returns whatever the per-test config
29
+ * sets; presign records the inputs it was called with so tests can assert the
30
+ * op/metadata/key shape the seam sends.
31
+ */
32
+ function makeVault() {
33
+ const presignCalls = [];
34
+ let nextPresign = [];
35
+ let nextList = { objects: [], cursor: null, truncated: false };
36
+ const vault = {
37
+ presign: async (input) => {
38
+ presignCalls.push({
39
+ companyUid: input.companyUid,
40
+ op: input.op,
41
+ keys: input.keys,
42
+ });
43
+ return { results: nextPresign, expiresAt: "2099-01-01T00:00:00.000Z" };
44
+ },
45
+ listFiles: async () => nextList,
46
+ };
47
+ return {
48
+ vault,
49
+ presignCalls,
50
+ setPresign: (rows) => {
51
+ nextPresign = rows;
52
+ },
53
+ setList: (v) => {
54
+ nextList = v;
55
+ },
56
+ };
57
+ }
58
+ describe("factory selection", () => {
59
+ afterEach(() => setObjectIOFactory(null));
60
+ it("defaults to the S3 SDK transport", () => {
61
+ const io = resolveObjectIO(ctx());
62
+ expect(io).toBeInstanceOf(S3SdkObjectIO);
63
+ });
64
+ it("setObjectIOFactory(null) resets to the default", () => {
65
+ const { vault } = makeVault();
66
+ setObjectIOFactory(presignObjectIOFactory(vault));
67
+ expect(resolveObjectIO(ctx())).toBeInstanceOf(PresignObjectIO);
68
+ setObjectIOFactory(null);
69
+ expect(resolveObjectIO(ctx())).toBeInstanceOf(S3SdkObjectIO);
70
+ });
71
+ it("presign factory derives companyUid from ctx.uid", async () => {
72
+ const { vault, presignCalls, setPresign } = makeVault();
73
+ setPresign([{ key: "k", op: "get", url: "https://x/get" }]);
74
+ vi.stubGlobal("fetch", vi.fn(async () => new Response(Buffer.from("body"), { status: 200 })));
75
+ const io = presignObjectIOFactory(vault)(ctx());
76
+ await io.getObject("k");
77
+ expect(presignCalls[0].companyUid).toBe(COMPANY);
78
+ vi.unstubAllGlobals();
79
+ });
80
+ });
81
+ describe("PresignObjectIO.putObject", () => {
82
+ let fetchMock;
83
+ beforeEach(() => {
84
+ fetchMock = vi.fn();
85
+ vi.stubGlobal("fetch", fetchMock);
86
+ });
87
+ afterEach(() => vi.unstubAllGlobals());
88
+ it("sends op:put with metadata and replays the signed headers verbatim", async () => {
89
+ const { vault, presignCalls, setPresign } = makeVault();
90
+ setPresign([
91
+ {
92
+ key: "shared/a.md",
93
+ op: "put",
94
+ url: "https://s3/put-url",
95
+ headers: {
96
+ "content-type": "text/markdown",
97
+ "x-amz-server-side-encryption": "aws:kms",
98
+ "x-amz-meta-created-by": "me@getindigo.ai",
99
+ },
100
+ },
101
+ ]);
102
+ fetchMock.mockResolvedValue(new Response(null, { status: 200, headers: { etag: '"abc123"' } }));
103
+ const io = new PresignObjectIO(vault, COMPANY);
104
+ const res = await io.putObject({
105
+ key: "shared/a.md",
106
+ body: Buffer.from("hello"),
107
+ contentType: "text/markdown",
108
+ metadata: { "created-by": "me@getindigo.ai" },
109
+ });
110
+ // Presign request carried op + per-key metadata.
111
+ expect(presignCalls[0].op).toBe("put");
112
+ expect(presignCalls[0].keys[0]).toMatchObject({
113
+ key: "shared/a.md",
114
+ op: "put",
115
+ contentType: "text/markdown",
116
+ metadata: { "created-by": "me@getindigo.ai" },
117
+ });
118
+ // PUT replays the exact signed headers.
119
+ const [url, init] = fetchMock.mock.calls[0];
120
+ expect(url).toBe("https://s3/put-url");
121
+ expect(init.method).toBe("PUT");
122
+ expect(init.headers).toEqual({
123
+ "content-type": "text/markdown",
124
+ "x-amz-server-side-encryption": "aws:kms",
125
+ "x-amz-meta-created-by": "me@getindigo.ai",
126
+ });
127
+ // ETag returned with quotes stripped.
128
+ expect(res.etag).toBe("abc123");
129
+ });
130
+ it("throws on a per-key denial (error row)", async () => {
131
+ const { vault, setPresign } = makeVault();
132
+ setPresign([
133
+ { key: "secret/x", op: "put", error: "forbidden", code: "ACL_DENY" },
134
+ ]);
135
+ const io = new PresignObjectIO(vault, COMPANY);
136
+ await expect(io.putObject({
137
+ key: "secret/x",
138
+ body: Buffer.from("z"),
139
+ contentType: "text/plain",
140
+ })).rejects.toThrow(/denied for secret\/x.*forbidden.*ACL_DENY/);
141
+ expect(fetchMock).not.toHaveBeenCalled();
142
+ });
143
+ it("throws when the PUT itself fails", async () => {
144
+ const { vault, setPresign } = makeVault();
145
+ setPresign([{ key: "k", op: "put", url: "https://s3/put" }]);
146
+ fetchMock.mockResolvedValue(new Response("AccessDenied", { status: 403 }));
147
+ const io = new PresignObjectIO(vault, COMPANY);
148
+ await expect(io.putObject({ key: "k", body: Buffer.from("z"), contentType: "x" })).rejects.toThrow(/presigned PUT failed for k: 403/);
149
+ });
150
+ });
151
+ describe("PresignObjectIO.getObject", () => {
152
+ let fetchMock;
153
+ beforeEach(() => {
154
+ fetchMock = vi.fn();
155
+ vi.stubGlobal("fetch", fetchMock);
156
+ });
157
+ afterEach(() => vi.unstubAllGlobals());
158
+ it("returns body bytes + x-amz-meta-* metadata", async () => {
159
+ const { vault, presignCalls, setPresign } = makeVault();
160
+ setPresign([{ key: "shared/a.md", op: "get", url: "https://s3/get" }]);
161
+ fetchMock.mockResolvedValue(new Response(Buffer.from("file-bytes"), {
162
+ status: 200,
163
+ headers: {
164
+ "x-amz-meta-created-by": "me@getindigo.ai",
165
+ "x-amz-meta-hq-mode": "640",
166
+ "content-type": "text/markdown",
167
+ },
168
+ }));
169
+ const io = new PresignObjectIO(vault, COMPANY);
170
+ const res = await io.getObject("shared/a.md");
171
+ expect(presignCalls[0].op).toBe("get");
172
+ expect(res.body.toString("utf-8")).toBe("file-bytes");
173
+ expect(res.metadata).toEqual({
174
+ "created-by": "me@getindigo.ai",
175
+ "hq-mode": "640",
176
+ });
177
+ });
178
+ it("throws a NotFound-named error on 404 (so s3.ts catch sites match)", async () => {
179
+ const { vault, setPresign } = makeVault();
180
+ setPresign([{ key: "gone", op: "get", url: "https://s3/get" }]);
181
+ fetchMock.mockResolvedValue(new Response("", { status: 404 }));
182
+ const io = new PresignObjectIO(vault, COMPANY);
183
+ await expect(io.getObject("gone")).rejects.toMatchObject({
184
+ name: "NotFound",
185
+ });
186
+ });
187
+ });
188
+ describe("PresignObjectIO.listObjects", () => {
189
+ it("maps listFiles rows into the RemoteObject shape (etag, Date)", async () => {
190
+ const { vault, setList } = makeVault();
191
+ setList({
192
+ objects: [
193
+ {
194
+ key: "shared/a.md",
195
+ size: 12,
196
+ lastModified: "2026-01-01T00:00:00.000Z",
197
+ etag: "deadbeef",
198
+ permission: "read",
199
+ },
200
+ {
201
+ key: "shared/b.md",
202
+ size: 0,
203
+ lastModified: null,
204
+ etag: null,
205
+ permission: "write",
206
+ },
207
+ ],
208
+ cursor: "next-token",
209
+ truncated: true,
210
+ });
211
+ const io = new PresignObjectIO(vault, COMPANY);
212
+ const res = await io.listObjects({ prefix: "shared/" });
213
+ expect(res.nextContinuationToken).toBe("next-token");
214
+ expect(res.objects[0]).toEqual({
215
+ key: "shared/a.md",
216
+ size: 12,
217
+ lastModified: new Date("2026-01-01T00:00:00.000Z"),
218
+ etag: "deadbeef",
219
+ });
220
+ // null etag → "" ; null lastModified → a Date (not crash).
221
+ expect(res.objects[1].etag).toBe("");
222
+ expect(res.objects[1].lastModified).toBeInstanceOf(Date);
223
+ });
224
+ it("exhausted listing yields undefined nextContinuationToken", async () => {
225
+ const { vault, setList } = makeVault();
226
+ setList({ objects: [], cursor: null, truncated: false });
227
+ const io = new PresignObjectIO(vault, COMPANY);
228
+ const res = await io.listObjects({});
229
+ expect(res.nextContinuationToken).toBeUndefined();
230
+ });
231
+ });
232
+ describe("PresignObjectIO.deleteObject", () => {
233
+ let fetchMock;
234
+ beforeEach(() => {
235
+ fetchMock = vi.fn();
236
+ vi.stubGlobal("fetch", fetchMock);
237
+ });
238
+ afterEach(() => vi.unstubAllGlobals());
239
+ it("sends op:delete and DELETEs the signed URL", async () => {
240
+ const { vault, presignCalls, setPresign } = makeVault();
241
+ setPresign([{ key: "shared/a.md", op: "delete", url: "https://s3/del" }]);
242
+ fetchMock.mockResolvedValue(new Response(null, { status: 204 }));
243
+ const io = new PresignObjectIO(vault, COMPANY);
244
+ await io.deleteObject("shared/a.md");
245
+ expect(presignCalls[0].op).toBe("delete");
246
+ expect(fetchMock.mock.calls[0][1].method).toBe("DELETE");
247
+ });
248
+ it("treats a 404 DELETE as success (idempotent)", async () => {
249
+ const { vault, setPresign } = makeVault();
250
+ setPresign([{ key: "gone", op: "delete", url: "https://s3/del" }]);
251
+ fetchMock.mockResolvedValue(new Response("", { status: 404 }));
252
+ const io = new PresignObjectIO(vault, COMPANY);
253
+ await expect(io.deleteObject("gone")).resolves.toBeUndefined();
254
+ });
255
+ });
256
+ describe("PresignObjectIO.headObject", () => {
257
+ let fetchMock;
258
+ beforeEach(() => {
259
+ fetchMock = vi.fn();
260
+ vi.stubGlobal("fetch", fetchMock);
261
+ });
262
+ afterEach(() => vi.unstubAllGlobals());
263
+ it("reads headers (etag/size/lastModified/metadata) via a presigned GET", async () => {
264
+ const { vault, setPresign } = makeVault();
265
+ setPresign([{ key: "shared/a.md", op: "get", url: "https://s3/get" }]);
266
+ fetchMock.mockResolvedValue(new Response(Buffer.from("ignored-body"), {
267
+ status: 200,
268
+ headers: {
269
+ etag: '"feedface"',
270
+ "content-length": "123",
271
+ "last-modified": "Wed, 01 Jan 2026 00:00:00 GMT",
272
+ "x-amz-meta-created-at": "2026-01-01T00:00:00.000Z",
273
+ },
274
+ }));
275
+ const io = new PresignObjectIO(vault, COMPANY);
276
+ const head = await io.headObject("shared/a.md");
277
+ expect(head).not.toBeNull();
278
+ expect(head.etag).toBe("feedface");
279
+ expect(head.size).toBe(123);
280
+ expect(head.metadata).toEqual({
281
+ "created-at": "2026-01-01T00:00:00.000Z",
282
+ });
283
+ expect(head.lastModified.getTime()).toBe(Date.parse("Wed, 01 Jan 2026 00:00:00 GMT"));
284
+ });
285
+ it("returns null on 404", async () => {
286
+ const { vault, setPresign } = makeVault();
287
+ setPresign([{ key: "gone", op: "get", url: "https://s3/get" }]);
288
+ fetchMock.mockResolvedValue(new Response("", { status: 404 }));
289
+ const io = new PresignObjectIO(vault, COMPANY);
290
+ expect(await io.headObject("gone")).toBeNull();
291
+ });
292
+ it("returns null when presign denies the key (no usable head)", async () => {
293
+ const { vault, setPresign } = makeVault();
294
+ setPresign([{ key: "secret/x", op: "get", error: "forbidden" }]);
295
+ const io = new PresignObjectIO(vault, COMPANY);
296
+ expect(await io.headObject("secret/x")).toBeNull();
297
+ expect(fetchMock).not.toHaveBeenCalled();
298
+ });
299
+ });
300
+ /**
301
+ * Echo vault: presign returns one signed row per requested key (url derived
302
+ * from op+key) and records call count + total keys, so prime/cache tests can
303
+ * assert "N files → ceil(N/100) presign calls, then zero".
304
+ */
305
+ function makeEchoVault() {
306
+ let calls = 0;
307
+ let totalKeys = 0;
308
+ const vault = {
309
+ presign: async (input) => {
310
+ calls++;
311
+ totalKeys += input.keys.length;
312
+ return {
313
+ results: input.keys.map((k) => ({
314
+ key: k.key,
315
+ op: k.op ?? input.op ?? "get",
316
+ url: `https://signed/${k.op ?? input.op}/${encodeURIComponent(k.key)}`,
317
+ ...(k.op === "put" || input.op === "put"
318
+ ? { headers: { "content-type": "text/plain" } }
319
+ : {}),
320
+ expiresIn: input.expiresIn ?? 900,
321
+ })),
322
+ expiresAt: "2099-01-01T00:00:00.000Z",
323
+ };
324
+ },
325
+ listFiles: async () => ({ objects: [], cursor: null, truncated: false }),
326
+ };
327
+ return {
328
+ vault,
329
+ calls: () => calls,
330
+ totalKeys: () => totalKeys,
331
+ };
332
+ }
333
+ describe("PresignObjectIO.prime — batch URL cache", () => {
334
+ let fetchMock;
335
+ beforeEach(() => {
336
+ fetchMock = vi.fn(async () => new Response(Buffer.from("x"), { status: 200 }));
337
+ vi.stubGlobal("fetch", fetchMock);
338
+ });
339
+ afterEach(() => vi.unstubAllGlobals());
340
+ it("chunks at 1000 keys per presign call (the server batch cap)", async () => {
341
+ const { vault, calls, totalKeys } = makeEchoVault();
342
+ const io = new PresignObjectIO(vault, COMPANY);
343
+ const keys = Array.from({ length: 2500 }, (_, i) => ({ key: `k${i}` }));
344
+ await io.prime("get", keys);
345
+ expect(calls()).toBe(3); // 1000 + 1000 + 500
346
+ expect(totalKeys()).toBe(2500);
347
+ });
348
+ it("primed getObject reuses the cache — zero extra presign calls", async () => {
349
+ const { vault, calls } = makeEchoVault();
350
+ const io = new PresignObjectIO(vault, COMPANY);
351
+ const keys = Array.from({ length: 5 }, (_, i) => ({ key: `f${i}` }));
352
+ await io.prime("get", keys);
353
+ const afterPrime = calls(); // 1 chunk
354
+ for (const k of keys)
355
+ await io.getObject(k.key);
356
+ expect(calls()).toBe(afterPrime); // no new presign calls
357
+ expect(fetchMock).toHaveBeenCalledTimes(5); // but the bytes were fetched
358
+ // The fetched URL is the primed (cached) one.
359
+ expect(fetchMock.mock.calls[0][0]).toBe("https://signed/get/f0");
360
+ });
361
+ it("primed GET cache also serves headObject (HEAD reuses GET URLs)", async () => {
362
+ const { vault, calls } = makeEchoVault();
363
+ fetchMock.mockResolvedValue(new Response(Buffer.from(""), {
364
+ status: 200,
365
+ headers: { etag: '"e"', "content-length": "0" },
366
+ }));
367
+ const io = new PresignObjectIO(vault, COMPANY);
368
+ await io.prime("get", [{ key: "doc.md" }]);
369
+ const afterPrime = calls();
370
+ const head = await io.headObject("doc.md");
371
+ expect(head).not.toBeNull();
372
+ expect(calls()).toBe(afterPrime); // head used the cached GET url, no presign
373
+ });
374
+ it("a key NOT primed falls back to a single presign", async () => {
375
+ const { vault, calls } = makeEchoVault();
376
+ const io = new PresignObjectIO(vault, COMPANY);
377
+ await io.prime("get", [{ key: "primed" }]);
378
+ const afterPrime = calls();
379
+ await io.getObject("not-primed");
380
+ expect(calls()).toBe(afterPrime + 1);
381
+ });
382
+ it("empty prime is a no-op (no presign call)", async () => {
383
+ const { vault, calls } = makeEchoVault();
384
+ const io = new PresignObjectIO(vault, COMPANY);
385
+ await io.prime("get", []);
386
+ expect(calls()).toBe(0);
387
+ });
388
+ it("a chunk that throws doesn't fail prime; those keys fall back per-file", async () => {
389
+ let calls = 0;
390
+ const vault = {
391
+ presign: async (input) => {
392
+ calls++;
393
+ if (calls === 1)
394
+ throw new Error("transient");
395
+ return {
396
+ results: input.keys.map((k) => ({
397
+ key: k.key,
398
+ op: "get",
399
+ url: `https://signed/get/${k.key}`,
400
+ expiresIn: 900,
401
+ })),
402
+ expiresAt: "2099-01-01T00:00:00.000Z",
403
+ };
404
+ },
405
+ listFiles: async () => ({ objects: [], cursor: null, truncated: false }),
406
+ };
407
+ const io = new PresignObjectIO(vault, COMPANY);
408
+ // Single chunk that throws — prime resolves anyway, key stays uncached.
409
+ await expect(io.prime("get", [{ key: "k" }])).resolves.toBeUndefined();
410
+ // getObject then single-presigns (call #2 succeeds).
411
+ await io.getObject("k");
412
+ expect(calls).toBe(2);
413
+ });
414
+ });
415
+ describe("presignObjectIOFactory — memoization", () => {
416
+ afterEach(() => setObjectIOFactory(null));
417
+ it("returns the SAME instance per companyUid so prime + transfer share a cache", () => {
418
+ const { vault } = makeEchoVault();
419
+ const factory = presignObjectIOFactory(vault);
420
+ const a1 = factory(ctx());
421
+ const a2 = factory(ctx());
422
+ expect(a1).toBe(a2); // same company → same instance
423
+ const other = factory({ ...ctx(), uid: "cmp_other" });
424
+ expect(other).not.toBe(a1); // different company → different instance
425
+ });
426
+ });
427
+ describe("PresignObjectIO — transient-failure retry (SDK parity)", () => {
428
+ afterEach(() => {
429
+ vi.useRealTimers();
430
+ vi.unstubAllGlobals();
431
+ });
432
+ it("retries a transient 503 then succeeds", async () => {
433
+ vi.useFakeTimers();
434
+ const { vault, setPresign } = makeVault();
435
+ setPresign([{ key: "k", op: "get", url: "https://s3/get" }]);
436
+ const fetchMock = vi
437
+ .fn()
438
+ .mockResolvedValueOnce(new Response("SlowDown", { status: 503 }))
439
+ .mockResolvedValueOnce(new Response(Buffer.from("ok"), { status: 200 }));
440
+ vi.stubGlobal("fetch", fetchMock);
441
+ const io = new PresignObjectIO(vault, COMPANY);
442
+ const pr = io.getObject("k");
443
+ await vi.runAllTimersAsync();
444
+ const res = await pr;
445
+ expect(res.body.toString("utf-8")).toBe("ok");
446
+ expect(fetchMock).toHaveBeenCalledTimes(2);
447
+ });
448
+ it("retries a network error (fetch throws) then succeeds", async () => {
449
+ vi.useFakeTimers();
450
+ const { vault, setPresign } = makeVault();
451
+ setPresign([{ key: "k", op: "get", url: "https://s3/get" }]);
452
+ const fetchMock = vi
453
+ .fn()
454
+ .mockRejectedValueOnce(new Error("socket hang up"))
455
+ .mockResolvedValueOnce(new Response(Buffer.from("ok"), { status: 200 }));
456
+ vi.stubGlobal("fetch", fetchMock);
457
+ const io = new PresignObjectIO(vault, COMPANY);
458
+ const pr = io.getObject("k");
459
+ await vi.runAllTimersAsync();
460
+ const res = await pr;
461
+ expect(res.body.toString("utf-8")).toBe("ok");
462
+ expect(fetchMock).toHaveBeenCalledTimes(2);
463
+ });
464
+ it("throws after exhausting retries on persistent 503 (initial + 3 retries = 4)", async () => {
465
+ vi.useFakeTimers();
466
+ const { vault, setPresign } = makeVault();
467
+ setPresign([{ key: "k", op: "get", url: "https://s3/get" }]);
468
+ const fetchMock = vi.fn().mockResolvedValue(new Response("err", { status: 503 }));
469
+ vi.stubGlobal("fetch", fetchMock);
470
+ const io = new PresignObjectIO(vault, COMPANY);
471
+ const pr = io.getObject("k").catch((e) => e);
472
+ await vi.runAllTimersAsync();
473
+ const err = await pr;
474
+ expect(String(err)).toMatch(/503/);
475
+ expect(fetchMock).toHaveBeenCalledTimes(4);
476
+ });
477
+ it("does NOT retry a definitive 404", async () => {
478
+ const { vault, setPresign } = makeVault();
479
+ setPresign([{ key: "gone", op: "get", url: "https://s3/get" }]);
480
+ const fetchMock = vi.fn().mockResolvedValue(new Response("", { status: 404 }));
481
+ vi.stubGlobal("fetch", fetchMock);
482
+ const io = new PresignObjectIO(vault, COMPANY);
483
+ await expect(io.getObject("gone")).rejects.toMatchObject({ name: "NotFound" });
484
+ expect(fetchMock).toHaveBeenCalledTimes(1);
485
+ });
486
+ });
487
+ import { VaultClientError } from "./vault-client.js";
488
+ describe("PresignObjectIO — 429 circuit breaker", () => {
489
+ afterEach(() => vi.unstubAllGlobals());
490
+ it("trips on a 429: uncached keys fail fast (no further presign), primed keys still work", async () => {
491
+ let presignCalls = 0;
492
+ const vault = {
493
+ presign: async (input) => {
494
+ presignCalls++;
495
+ if (input.keys.some((k) => k.key === "primed")) {
496
+ return {
497
+ results: input.keys.map((k) => ({
498
+ key: k.key,
499
+ op: k.op ?? "get",
500
+ url: `https://s/${k.key}`,
501
+ expiresIn: 900,
502
+ })),
503
+ expiresAt: "2099-01-01T00:00:00.000Z",
504
+ };
505
+ }
506
+ throw new VaultClientError("Rate limit exceeded: 100 requests per hour", 429);
507
+ },
508
+ listFiles: async () => ({ objects: [], cursor: null, truncated: false }),
509
+ };
510
+ vi.stubGlobal("fetch", vi.fn(async () => new Response(Buffer.from("x"), { status: 200 })));
511
+ const io = new PresignObjectIO(vault, COMPANY);
512
+ await io.prime("get", [{ key: "primed" }]); // caches "primed"
513
+ await expect(io.getObject("uncached1")).rejects.toMatchObject({
514
+ name: "RateLimited",
515
+ });
516
+ const afterTrip = presignCalls;
517
+ // Second uncached key fails fast — NO new presign call.
518
+ await expect(io.getObject("uncached2")).rejects.toMatchObject({
519
+ name: "RateLimited",
520
+ });
521
+ expect(presignCalls).toBe(afterTrip);
522
+ // The primed key still resolves from cache (no presign needed).
523
+ const r = await io.getObject("primed");
524
+ expect(r.body.toString("utf-8")).toBe("x");
525
+ });
526
+ it("prime stops minting once a chunk 429s (breaker trips, remaining chunks skipped)", async () => {
527
+ let calls = 0;
528
+ const vault = {
529
+ presign: async () => {
530
+ calls++;
531
+ throw new VaultClientError("rate", 429);
532
+ },
533
+ listFiles: async () => ({ objects: [], cursor: null, truncated: false }),
534
+ };
535
+ const io = new PresignObjectIO(vault, COMPANY);
536
+ // 10 chunks (10k keys @ 1000); concurrency is 4, so at most the first
537
+ // concurrent batch fires before the breaker trips — far fewer than 10.
538
+ await io.prime("get", Array.from({ length: 10_000 }, (_, i) => ({ key: `k${i}` })));
539
+ expect(calls).toBeLessThanOrEqual(4);
540
+ expect(calls).toBeLessThan(10);
541
+ });
542
+ });
543
+ describe("PresignObjectIO.hasPrimedPut", () => {
544
+ it("reflects a put prime", async () => {
545
+ const { vault } = makeEchoVault();
546
+ const io = new PresignObjectIO(vault, COMPANY);
547
+ expect(io.hasPrimedPut("k")).toBe(false);
548
+ await io.prime("put", [
549
+ { key: "k", op: "put", contentType: "text/plain", metadata: { "hq-mode": "644" } },
550
+ ]);
551
+ expect(io.hasPrimedPut("k")).toBe(true);
552
+ // A different, unprimed key stays false.
553
+ expect(io.hasPrimedPut("other")).toBe(false);
554
+ });
555
+ });
556
+ describe("presignObjectIOFactory — personal vaults route to S3 SDK", () => {
557
+ it("routes a person entity (prs_*) to S3SdkObjectIO, a company (cmp_*) to presign", () => {
558
+ const { vault } = makeEchoVault();
559
+ const factory = presignObjectIOFactory(vault);
560
+ const company = factory({ ...ctx(), uid: "cmp_real" });
561
+ const personal = factory({ ...ctx(), uid: "prs_real" });
562
+ expect(company).toBeInstanceOf(PresignObjectIO);
563
+ // Personal vaults use the membership-less vend-self model; the
564
+ // membership-gated presign endpoints 403 for them, so they stay on STS.
565
+ expect(personal).toBeInstanceOf(S3SdkObjectIO);
566
+ });
567
+ });
568
+ //# sourceMappingURL=object-io.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object-io.test.js","sourceRoot":"","sources":["../src/object-io.test.ts"],"names":[],"mappings":"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"}
package/dist/s3.d.ts CHANGED
@@ -168,6 +168,43 @@ export declare const FILE_BTIME_META_KEY = "hq-btime";
168
168
  * duplicating the prefix string.
169
169
  */
170
170
  export declare function encodeSymlinkBody(target: string): Buffer;
171
+ /**
172
+ * Batch pre-mint transport URLs for `keys` under `op` so the subsequent
173
+ * per-file transfer calls (downloadFile/headRemoteFile/…) reuse them instead
174
+ * of presigning one key at a time. On the presigned-URL transport this turns
175
+ * an N-file leg from N presign requests into ceil(N/100) — the difference
176
+ * between completing a bulk pull and 429ing past the 100-req/hr limit. No-op
177
+ * on the S3 SDK transport (which has no presign step) and harmless if called
178
+ * with an empty list. Best-effort: a prime failure never propagates — the
179
+ * per-file path falls back to a single presign.
180
+ *
181
+ * Call it once, right before a transfer loop, with the full key set the loop
182
+ * will touch. The presigned transport memoizes one IO instance per company for
183
+ * the run, so the warmed cache is the same one the loop drains.
184
+ */
185
+ export declare function primeObjectTransport(ctx: EntityContext, op: "get" | "put" | "delete", keys: string[]): Promise<void>;
186
+ /**
187
+ * One upload's identity for {@link primeUploads}: the vault key, the local
188
+ * path (to lstat for mode/mtime), whether it's a symlink, and the author.
189
+ */
190
+ export interface UploadPrimeItem {
191
+ key: string;
192
+ localPath: string;
193
+ isSymlink: boolean;
194
+ author?: UploadAuthor;
195
+ }
196
+ /**
197
+ * Batch pre-mint PUT URLs (+ the created-at HEADs they depend on) for a set of
198
+ * uploads, signing the SAME metadata uploadFile/uploadSymlink would compute so
199
+ * the transfer loop can replay the cached headers. Turns an N-file push from
200
+ * ~N presign calls (1 per PUT, sometimes 2-3 with HEADs) into ceil(N/1000) GET
201
+ * + ceil(N/1000) PUT — the difference between completing a bulk push and 429ing
202
+ * past the 100/hr limit. No-op on the S3 SDK transport; best-effort.
203
+ *
204
+ * The per-item created-at HEADs run over the GET cache primed first, so they
205
+ * cost S3 round-trips but NO extra presign calls (not counted against 100/hr).
206
+ */
207
+ export declare function primeUploads(ctx: EntityContext, items: UploadPrimeItem[]): Promise<void>;
171
208
  export declare function uploadFile(ctx: EntityContext, localPath: string, key: string, author?: UploadAuthor): Promise<{
172
209
  etag: string;
173
210
  }>;