@qnsp/storage-sdk 0.2.1 → 0.3.1

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/src/index.test.ts CHANGED
@@ -1,9 +1,34 @@
1
+ import { clearActivationCache } from "@qnsp/sdk-activation";
1
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
3
  import { StorageClient, StorageEventsClient } from "./index.js";
3
4
 
4
- const mockTenantId = "tenant-123";
5
+ const mockTenantId = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
5
6
  const baseUrl = "https://storage.qnsp.example/";
6
7
 
8
+ // Valid UUID test constants
9
+ const mockUploadId = "11111111-1111-4111-a111-111111111111";
10
+ const mockUploadId2 = "22222222-2222-4222-a222-222222222222";
11
+ const mockUploadIdErr = "33333333-3333-4333-a333-333333333333";
12
+ const mockDocumentId = "44444444-4444-4444-a444-444444444444";
13
+
14
+ const MOCK_ACTIVATION_RESPONSE = {
15
+ activated: true,
16
+ tenantId: "a1b2c3d4-e5f6-4789-8abc-def012345678",
17
+ tier: "dev-pro",
18
+ activationToken: "tok_test",
19
+ expiresInSeconds: 3600,
20
+ activatedAt: new Date().toISOString(),
21
+ limits: {
22
+ storageGB: 50,
23
+ apiCalls: 100_000,
24
+ enclavesEnabled: false,
25
+ aiTrainingEnabled: false,
26
+ aiInferenceEnabled: true,
27
+ sseEnabled: true,
28
+ vaultEnabled: true,
29
+ },
30
+ };
31
+
7
32
  function jsonResponse(payload: unknown, init?: ResponseInit): Response {
8
33
  return new Response(JSON.stringify(payload), {
9
34
  status: 200,
@@ -43,6 +68,7 @@ async function collectStream(stream: ReadableStream<Uint8Array>): Promise<Uint8A
43
68
 
44
69
  describe("StorageClient", () => {
45
70
  beforeEach(() => {
71
+ clearActivationCache();
46
72
  vi.stubGlobal("fetch", vi.fn());
47
73
  });
48
74
 
@@ -60,8 +86,8 @@ describe("StorageClient", () => {
60
86
  });
61
87
 
62
88
  const expectedResponse = {
63
- uploadId: "upload-1",
64
- documentId: "document-1",
89
+ uploadId: mockUploadId,
90
+ documentId: mockDocumentId,
65
91
  tenantId: mockTenantId,
66
92
  chunkSizeBytes: 16_777_216,
67
93
  totalSizeBytes: 42_000_000,
@@ -76,9 +102,9 @@ describe("StorageClient", () => {
76
102
  },
77
103
  };
78
104
 
79
- (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(
80
- jsonResponse(expectedResponse),
81
- );
105
+ (globalThis.fetch as unknown as ReturnType<typeof vi.fn>)
106
+ .mockResolvedValueOnce(jsonResponse(MOCK_ACTIVATION_RESPONSE))
107
+ .mockResolvedValueOnce(jsonResponse(expectedResponse));
82
108
 
83
109
  const result = await client.initiateUpload({
84
110
  name: "contract.pdf",
@@ -88,8 +114,8 @@ describe("StorageClient", () => {
88
114
  });
89
115
 
90
116
  expect(result).toEqual(expectedResponse);
91
- expect(globalThis.fetch).toHaveBeenCalledTimes(1);
92
- const call = (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mock.calls.at(0);
117
+ expect(globalThis.fetch).toHaveBeenCalledTimes(2);
118
+ const call = (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mock.calls.at(1);
93
119
  expect(call).toBeDefined();
94
120
  if (!call) throw new Error("fetch not invoked");
95
121
  const [url, init] = call;
@@ -118,7 +144,7 @@ describe("StorageClient", () => {
118
144
  });
119
145
 
120
146
  const expectedPayload = {
121
- uploadId: "upload-1",
147
+ uploadId: mockUploadId,
122
148
  partId: 1,
123
149
  status: "uploaded",
124
150
  sizeBytes: 3,
@@ -131,16 +157,16 @@ describe("StorageClient", () => {
131
157
  resumeToken: null,
132
158
  };
133
159
 
134
- (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(
135
- jsonResponse(expectedPayload),
136
- );
160
+ (globalThis.fetch as unknown as ReturnType<typeof vi.fn>)
161
+ .mockResolvedValueOnce(jsonResponse(MOCK_ACTIVATION_RESPONSE))
162
+ .mockResolvedValueOnce(jsonResponse(expectedPayload));
137
163
 
138
164
  const source = Buffer.from([0xde, 0xad, 0xbe]);
139
165
 
140
- const result = await client.uploadPart("upload-1", 1, source);
166
+ const result = await client.uploadPart(mockUploadId, 1, source);
141
167
  expect(result).toEqual(expectedPayload);
142
- expect(globalThis.fetch).toHaveBeenCalledTimes(1);
143
- const uploadCall = (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mock.calls.at(0);
168
+ expect(globalThis.fetch).toHaveBeenCalledTimes(2);
169
+ const uploadCall = (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mock.calls.at(1);
144
170
  expect(uploadCall).toBeDefined();
145
171
  if (!uploadCall) throw new Error("fetch not invoked");
146
172
  const [, init] = uploadCall;
@@ -158,6 +184,7 @@ describe("StorageClient", () => {
158
184
  it("parses ranged download responses and surfaces stream metadata", async () => {
159
185
  const client = new StorageClient({
160
186
  baseUrl,
187
+ apiKey: "test-api-key",
161
188
  tenantId: mockTenantId,
162
189
  });
163
190
 
@@ -177,14 +204,16 @@ describe("StorageClient", () => {
177
204
  },
178
205
  });
179
206
 
180
- (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(response);
207
+ (globalThis.fetch as unknown as ReturnType<typeof vi.fn>)
208
+ .mockResolvedValueOnce(jsonResponse(MOCK_ACTIVATION_RESPONSE))
209
+ .mockResolvedValueOnce(response);
181
210
 
182
- const result = await client.downloadStream("document-1", 2, {
211
+ const result = await client.downloadStream(mockDocumentId, 2, {
183
212
  range: "bytes=0-2",
184
213
  });
185
214
 
186
215
  expect(globalThis.fetch).toHaveBeenCalledWith(
187
- "https://storage.qnsp.example/storage/v1/documents/document-1/versions/2/content?tenantId=tenant-123&range=bytes%3D0-2",
216
+ `https://storage.qnsp.example/storage/v1/documents/${mockDocumentId}/versions/2/content?tenantId=${mockTenantId}&range=bytes%3D0-2`,
188
217
  expect.objectContaining({
189
218
  method: "GET",
190
219
  headers: expect.objectContaining({
@@ -207,13 +236,14 @@ describe("StorageClient", () => {
207
236
  const telemetry = { record: vi.fn() };
208
237
  const client = new StorageClient({
209
238
  baseUrl,
239
+ apiKey: "test-api-key",
210
240
  tenantId: mockTenantId,
211
241
  telemetry,
212
242
  });
213
243
 
214
244
  const statusResponse = {
215
- uploadId: "upload-123",
216
- documentId: "doc-1",
245
+ uploadId: mockUploadId2,
246
+ documentId: mockDocumentId,
217
247
  tenantId: mockTenantId,
218
248
  status: "pending",
219
249
  chunkSizeBytes: 4,
@@ -228,11 +258,11 @@ describe("StorageClient", () => {
228
258
  lastPartNumber: 1,
229
259
  };
230
260
 
231
- (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(
232
- jsonResponse(statusResponse),
233
- );
261
+ (globalThis.fetch as unknown as ReturnType<typeof vi.fn>)
262
+ .mockResolvedValueOnce(jsonResponse(MOCK_ACTIVATION_RESPONSE))
263
+ .mockResolvedValueOnce(jsonResponse(statusResponse));
234
264
 
235
- await client.getUploadStatus("upload-123");
265
+ await client.getUploadStatus(mockUploadId2);
236
266
 
237
267
  expect(telemetry.record).toHaveBeenCalled();
238
268
  const event = (telemetry.record as ReturnType<typeof vi.fn>).mock.calls.at(-1)?.[0];
@@ -248,15 +278,16 @@ describe("StorageClient", () => {
248
278
  const telemetry = { record: vi.fn() };
249
279
  const client = new StorageClient({
250
280
  baseUrl,
281
+ apiKey: "test-api-key",
251
282
  tenantId: mockTenantId,
252
283
  telemetry,
253
284
  });
254
285
 
255
- (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(
256
- new Response("boom", { status: 500, statusText: "error" }),
257
- );
286
+ (globalThis.fetch as unknown as ReturnType<typeof vi.fn>)
287
+ .mockResolvedValueOnce(jsonResponse(MOCK_ACTIVATION_RESPONSE))
288
+ .mockResolvedValueOnce(new Response("boom", { status: 500, statusText: "error" }));
258
289
 
259
- await expect(client.completeUpload("upload-err")).rejects.toThrow(/Storage API error/);
290
+ await expect(client.completeUpload(mockUploadIdErr)).rejects.toThrow(/Storage API error/);
260
291
 
261
292
  const event = (telemetry.record as ReturnType<typeof vi.fn>).mock.calls.at(-1)?.[0];
262
293
  expect(event).toBeDefined();
@@ -271,12 +302,13 @@ describe("StorageClient", () => {
271
302
  const telemetry = { record: vi.fn() };
272
303
  const client = new StorageClient({
273
304
  baseUrl,
305
+ apiKey: "test-api-key",
274
306
  tenantId: mockTenantId,
275
307
  telemetry,
276
308
  });
277
309
 
278
310
  const expectedPayload = {
279
- uploadId: "upload-1",
311
+ uploadId: mockUploadId,
280
312
  partId: 1,
281
313
  status: "uploaded",
282
314
  sizeBytes: 3,
@@ -289,11 +321,11 @@ describe("StorageClient", () => {
289
321
  resumeToken: null,
290
322
  };
291
323
 
292
- (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(
293
- jsonResponse(expectedPayload),
294
- );
324
+ (globalThis.fetch as unknown as ReturnType<typeof vi.fn>)
325
+ .mockResolvedValueOnce(jsonResponse(MOCK_ACTIVATION_RESPONSE))
326
+ .mockResolvedValueOnce(jsonResponse(expectedPayload));
295
327
 
296
- await client.uploadPart("upload-1", 1, Buffer.from([1, 2, 3]));
328
+ await client.uploadPart(mockUploadId, 1, Buffer.from([1, 2, 3]));
297
329
 
298
330
  const event = (telemetry.record as ReturnType<typeof vi.fn>).mock.calls.at(-1)?.[0];
299
331
  expect(event).toBeDefined();
@@ -312,10 +344,12 @@ describe("StorageClient", () => {
312
344
  });
313
345
 
314
346
  (globalThis.fetch as unknown as ReturnType<typeof vi.fn>)
347
+ // activation
348
+ .mockResolvedValueOnce(jsonResponse(MOCK_ACTIVATION_RESPONSE))
315
349
  // PATCH response
316
350
  .mockResolvedValueOnce(
317
351
  jsonResponse({
318
- documentId: "doc-1",
352
+ documentId: mockDocumentId,
319
353
  tenantId: mockTenantId,
320
354
  compliance: {
321
355
  retentionMode: "compliance",
@@ -328,7 +362,7 @@ describe("StorageClient", () => {
328
362
  // GET response
329
363
  .mockResolvedValueOnce(
330
364
  jsonResponse({
331
- documentId: "doc-1",
365
+ documentId: mockDocumentId,
332
366
  tenantId: mockTenantId,
333
367
  compliance: {
334
368
  retentionMode: "compliance",
@@ -344,26 +378,30 @@ describe("StorageClient", () => {
344
378
  }),
345
379
  );
346
380
 
347
- const updated = await client.updateDocumentPolicies("doc-1", {
381
+ const updated = await client.updateDocumentPolicies(mockDocumentId, {
348
382
  retentionMode: "compliance",
349
383
  retainUntil: "2026-01-01T00:00:00Z",
350
384
  legalHolds: ["hold-1"],
351
385
  });
352
- expect(updated.documentId).toBe("doc-1");
386
+ expect(updated.documentId).toBe(mockDocumentId);
353
387
  const patchCall = (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mock
354
- .calls[0] as unknown as [string, RequestInit];
355
- expect(patchCall[0]).toBe("https://storage.qnsp.example/storage/v1/documents/doc-1/policies");
388
+ .calls[1] as unknown as [string, RequestInit];
389
+ expect(patchCall[0]).toBe(
390
+ `https://storage.qnsp.example/storage/v1/documents/${mockDocumentId}/policies`,
391
+ );
356
392
  expect(patchCall[1]?.headers).toMatchObject({
357
393
  "Content-Type": "application/json",
358
394
  Authorization: "Bearer key",
359
395
  "x-tenant-id": mockTenantId,
360
396
  });
361
397
 
362
- const policies = await client.getDocumentPolicies("doc-1");
398
+ const policies = await client.getDocumentPolicies(mockDocumentId);
363
399
  expect(policies.tenantId).toBe(mockTenantId);
364
400
  const getCall = (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mock
365
- .calls[1] as unknown as [string, RequestInit];
366
- expect(getCall[0]).toBe("https://storage.qnsp.example/storage/v1/documents/doc-1/policies");
401
+ .calls[2] as unknown as [string, RequestInit];
402
+ expect(getCall[0]).toBe(
403
+ `https://storage.qnsp.example/storage/v1/documents/${mockDocumentId}/policies`,
404
+ );
367
405
  expect(getCall[1]?.headers).toMatchObject({
368
406
  "Content-Type": "application/json",
369
407
  Authorization: "Bearer key",
@@ -379,10 +417,12 @@ describe("StorageClient", () => {
379
417
  });
380
418
 
381
419
  (globalThis.fetch as unknown as ReturnType<typeof vi.fn>)
420
+ // activation
421
+ .mockResolvedValueOnce(jsonResponse(MOCK_ACTIVATION_RESPONSE))
382
422
  // apply
383
423
  .mockResolvedValueOnce(
384
424
  jsonResponse({
385
- documentId: "doc-1",
425
+ documentId: mockDocumentId,
386
426
  tenantId: mockTenantId,
387
427
  legalHolds: ["hold-9"],
388
428
  }),
@@ -390,21 +430,23 @@ describe("StorageClient", () => {
390
430
  // release (204)
391
431
  .mockResolvedValueOnce(new Response(null, { status: 204 }));
392
432
 
393
- const applied = await client.applyLegalHold("doc-1", { holdId: "hold-9" });
433
+ const applied = await client.applyLegalHold(mockDocumentId, { holdId: "hold-9" });
394
434
  expect(applied.legalHolds).toContain("hold-9");
395
435
  const postCall = (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mock
396
- .calls[0] as unknown as [string, RequestInit];
397
- expect(postCall[0]).toBe("https://storage.qnsp.example/storage/v1/documents/doc-1/legal-holds");
436
+ .calls[1] as unknown as [string, RequestInit];
437
+ expect(postCall[0]).toBe(
438
+ `https://storage.qnsp.example/storage/v1/documents/${mockDocumentId}/legal-holds`,
439
+ );
398
440
  expect(postCall[1]?.method).toBe("POST");
399
441
  expect(postCall[1]?.headers).toMatchObject({
400
442
  "x-tenant-id": mockTenantId,
401
443
  });
402
444
 
403
- await client.releaseLegalHold("doc-1", "hold-9");
445
+ await client.releaseLegalHold(mockDocumentId, "hold-9");
404
446
  const delCall = (globalThis.fetch as unknown as ReturnType<typeof vi.fn>).mock
405
- .calls[1] as unknown as [string, RequestInit];
447
+ .calls[2] as unknown as [string, RequestInit];
406
448
  expect(delCall[0]).toBe(
407
- "https://storage.qnsp.example/storage/v1/documents/doc-1/legal-holds/hold-9",
449
+ `https://storage.qnsp.example/storage/v1/documents/${mockDocumentId}/legal-holds/hold-9`,
408
450
  );
409
451
  expect(delCall[1]?.method).toBe("DELETE");
410
452
  expect(delCall[1]?.headers).toMatchObject({
@@ -427,6 +469,7 @@ describe("StorageEventsClient", () => {
427
469
  const telemetry = { record: vi.fn() };
428
470
  const client = new StorageEventsClient({
429
471
  baseUrl,
472
+ apiKey: "test-api-key",
430
473
  telemetry,
431
474
  });
432
475