@agentuity/core 0.0.69 → 0.0.70

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.
@@ -1,431 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { ObjectStorageService } from '../objectstore';
3
- import { createMockAdapter } from './mock-adapter';
4
-
5
- const baseUrl = 'https://test.agentuity.ai';
6
-
7
- describe('ObjectStorageService', () => {
8
- describe('get', () => {
9
- test('should get an object successfully', async () => {
10
- const testData = new TextEncoder().encode('Hello, world!');
11
- const { adapter, calls } = createMockAdapter([
12
- {
13
- ok: true,
14
- data: testData.buffer,
15
- headers: { 'content-type': 'text/plain' },
16
- },
17
- ]);
18
-
19
- const service = new ObjectStorageService(baseUrl, adapter);
20
- const result = await service.get('test-bucket', 'test-key');
21
-
22
- expect(calls).toHaveLength(1);
23
- expect(calls[0].url).toBe(`${baseUrl}/object/2025-03-17/test-bucket/test-key`);
24
- expect(calls[0].options.method).toBe('GET');
25
- expect(calls[0].options.telemetry?.name).toBe('agentuity.objectstore.get');
26
-
27
- expect(result.exists).toBe(true);
28
- if (result.exists) {
29
- expect(result.contentType).toBe('text/plain');
30
- expect(new TextDecoder().decode(result.data)).toBe('Hello, world!');
31
- }
32
- });
33
-
34
- test('should return not found for non-existent object', async () => {
35
- const { adapter, calls } = createMockAdapter([{ ok: false, status: 404 }]);
36
-
37
- const service = new ObjectStorageService(baseUrl, adapter);
38
- const result = await service.get('test-bucket', 'missing-key');
39
-
40
- expect(calls).toHaveLength(1);
41
- expect(result.exists).toBe(false);
42
- });
43
-
44
- test('should use default content type when not provided', async () => {
45
- const testData = new Uint8Array([1, 2, 3]);
46
- const { adapter } = createMockAdapter([
47
- {
48
- ok: true,
49
- data: testData.buffer,
50
- headers: {},
51
- },
52
- ]);
53
-
54
- const service = new ObjectStorageService(baseUrl, adapter);
55
- const result = await service.get('test-bucket', 'test-key');
56
-
57
- expect(result.exists).toBe(true);
58
- if (result.exists) {
59
- expect(result.contentType).toBe('application/octet-stream');
60
- }
61
- });
62
-
63
- test('should validate bucket parameter', async () => {
64
- const { adapter } = createMockAdapter([]);
65
- const service = new ObjectStorageService(baseUrl, adapter);
66
-
67
- await expect(service.get('', 'test-key')).rejects.toThrow(
68
- 'bucket is required and cannot be empty'
69
- );
70
- });
71
-
72
- test('should validate key parameter', async () => {
73
- const { adapter } = createMockAdapter([]);
74
- const service = new ObjectStorageService(baseUrl, adapter);
75
-
76
- await expect(service.get('test-bucket', '')).rejects.toThrow(
77
- 'key is required and cannot be empty'
78
- );
79
- });
80
-
81
- test('should handle URL encoding for bucket and key', async () => {
82
- const { adapter, calls } = createMockAdapter([
83
- {
84
- ok: true,
85
- data: new ArrayBuffer(0),
86
- headers: {},
87
- },
88
- ]);
89
-
90
- const service = new ObjectStorageService(baseUrl, adapter);
91
- await service.get('my bucket', 'my/key with spaces');
92
-
93
- expect(calls[0].url).toBe(
94
- `${baseUrl}/object/2025-03-17/my%20bucket/my%2Fkey%20with%20spaces`
95
- );
96
- });
97
-
98
- test('should handle binary data without transformation', async () => {
99
- // Create binary data that would be corrupted if treated as text
100
- const binaryData = new Uint8Array([0x00, 0x01, 0x02, 0xff, 0xfe, 0xfd, 0x80, 0x7f]);
101
- const { adapter } = createMockAdapter([
102
- {
103
- ok: true,
104
- data: binaryData.buffer,
105
- headers: { 'content-type': 'application/octet-stream' },
106
- },
107
- ]);
108
-
109
- const service = new ObjectStorageService(baseUrl, adapter);
110
- const result = await service.get('test-bucket', 'binary-file');
111
-
112
- expect(result.exists).toBe(true);
113
- if (result.exists) {
114
- expect(result.data).toBeInstanceOf(Uint8Array);
115
- expect(result.data.length).toBe(8);
116
- expect(Array.from(result.data)).toEqual([
117
- 0x00, 0x01, 0x02, 0xff, 0xfe, 0xfd, 0x80, 0x7f,
118
- ]);
119
- }
120
- });
121
-
122
- test('should throw error for server errors (5xx status codes)', async () => {
123
- const { adapter } = createMockAdapter([
124
- { ok: false, status: 500, statusText: 'Internal Server Error' },
125
- ]);
126
-
127
- const service = new ObjectStorageService(baseUrl, adapter);
128
-
129
- await expect(service.get('test-bucket', 'test-key')).rejects.toThrow(
130
- 'Failed to get object: Internal Server Error (500)'
131
- );
132
- });
133
- });
134
-
135
- describe('put', () => {
136
- test('should put an object with Uint8Array data', async () => {
137
- const { adapter, calls } = createMockAdapter([{ ok: true, data: {} }]);
138
-
139
- const service = new ObjectStorageService(baseUrl, adapter);
140
- const data = new TextEncoder().encode('Test content');
141
-
142
- await service.put('test-bucket', 'test-key', data, {
143
- contentType: 'text/plain',
144
- });
145
-
146
- expect(calls).toHaveLength(1);
147
- expect(calls[0].url).toBe(`${baseUrl}/object/2025-03-17/test-bucket/test-key`);
148
- expect(calls[0].options.method).toBe('PUT');
149
- expect(calls[0].options.headers?.['Content-Type']).toBe('text/plain');
150
- expect(calls[0].options.telemetry?.name).toBe('agentuity.objectstore.put');
151
- });
152
-
153
- test('should put an object with ArrayBuffer data', async () => {
154
- const { adapter, calls } = createMockAdapter([{ ok: true, data: {} }]);
155
-
156
- const service = new ObjectStorageService(baseUrl, adapter);
157
- const data = new TextEncoder().encode('Test content').buffer;
158
-
159
- await service.put('test-bucket', 'test-key', data);
160
-
161
- expect(calls).toHaveLength(1);
162
- expect(calls[0].options.method).toBe('PUT');
163
- });
164
-
165
- test('should use default content type when not provided', async () => {
166
- const { adapter, calls } = createMockAdapter([{ ok: true, data: {} }]);
167
-
168
- const service = new ObjectStorageService(baseUrl, adapter);
169
- const data = new Uint8Array([1, 2, 3]);
170
-
171
- await service.put('test-bucket', 'test-key', data);
172
-
173
- expect(calls[0].options.headers?.['Content-Type']).toBe('application/octet-stream');
174
- });
175
-
176
- test('should include optional headers', async () => {
177
- const { adapter, calls } = createMockAdapter([{ ok: true, data: {} }]);
178
-
179
- const service = new ObjectStorageService(baseUrl, adapter);
180
- const data = new Uint8Array([1, 2, 3]);
181
-
182
- await service.put('test-bucket', 'test-key', data, {
183
- contentType: 'image/png',
184
- contentEncoding: 'gzip',
185
- cacheControl: 'max-age=3600',
186
- contentDisposition: 'attachment; filename="test.png"',
187
- contentLanguage: 'en-US',
188
- });
189
-
190
- expect(calls[0].options.headers?.['Content-Type']).toBe('image/png');
191
- expect(calls[0].options.headers?.['Content-Encoding']).toBe('gzip');
192
- expect(calls[0].options.headers?.['Cache-Control']).toBe('max-age=3600');
193
- expect(calls[0].options.headers?.['Content-Disposition']).toBe(
194
- 'attachment; filename="test.png"'
195
- );
196
- expect(calls[0].options.headers?.['Content-Language']).toBe('en-US');
197
- });
198
-
199
- test('should include metadata headers', async () => {
200
- const { adapter, calls } = createMockAdapter([{ ok: true, data: {} }]);
201
-
202
- const service = new ObjectStorageService(baseUrl, adapter);
203
- const data = new Uint8Array([1, 2, 3]);
204
-
205
- await service.put('test-bucket', 'test-key', data, {
206
- metadata: {
207
- author: 'user123',
208
- version: '1.0',
209
- },
210
- });
211
-
212
- expect(calls[0].options.headers?.['x-metadata-author']).toBe('user123');
213
- expect(calls[0].options.headers?.['x-metadata-version']).toBe('1.0');
214
- });
215
-
216
- test('should validate bucket parameter', async () => {
217
- const { adapter } = createMockAdapter([]);
218
- const service = new ObjectStorageService(baseUrl, adapter);
219
- const data = new Uint8Array([1, 2, 3]);
220
-
221
- await expect(service.put('', 'test-key', data)).rejects.toThrow(
222
- 'bucket is required and cannot be empty'
223
- );
224
- });
225
-
226
- test('should validate key parameter', async () => {
227
- const { adapter } = createMockAdapter([]);
228
- const service = new ObjectStorageService(baseUrl, adapter);
229
- const data = new Uint8Array([1, 2, 3]);
230
-
231
- await expect(service.put('test-bucket', '', data)).rejects.toThrow(
232
- 'key is required and cannot be empty'
233
- );
234
- });
235
-
236
- test('should validate data parameter', async () => {
237
- const { adapter } = createMockAdapter([]);
238
- const service = new ObjectStorageService(baseUrl, adapter);
239
-
240
- await expect(
241
- service.put('test-bucket', 'test-key', null as unknown as Uint8Array)
242
- ).rejects.toThrow('data is required');
243
- });
244
-
245
- test('should handle binary data in put operations', async () => {
246
- const { adapter, calls } = createMockAdapter([{ ok: true, data: {} }]);
247
-
248
- const service = new ObjectStorageService(baseUrl, adapter);
249
- // Binary data with null bytes and high bytes that would be corrupted if treated as UTF-8
250
- const binaryData = new Uint8Array([0x00, 0x01, 0x02, 0xff, 0xfe, 0xfd, 0x80, 0x7f]);
251
-
252
- await service.put('test-bucket', 'binary-file', binaryData, {
253
- contentType: 'application/octet-stream',
254
- });
255
-
256
- expect(calls).toHaveLength(1);
257
- expect(calls[0].options.method).toBe('PUT');
258
- expect(calls[0].options.headers?.['Content-Type']).toBe('application/octet-stream');
259
- // Verify the body is an ArrayBuffer (converted from Uint8Array)
260
- expect(calls[0].options.body).toBeInstanceOf(ArrayBuffer);
261
- });
262
-
263
- test('should throw error for client errors (4xx status codes)', async () => {
264
- const { adapter } = createMockAdapter([
265
- { ok: false, status: 400, statusText: 'Bad Request' },
266
- ]);
267
-
268
- const service = new ObjectStorageService(baseUrl, adapter);
269
- const data = new Uint8Array([1, 2, 3]);
270
-
271
- await expect(service.put('test-bucket', 'test-key', data)).rejects.toThrow(
272
- 'Failed to put object: Bad Request (400)'
273
- );
274
- });
275
- });
276
-
277
- describe('delete', () => {
278
- test('should delete an object successfully', async () => {
279
- const { adapter, calls } = createMockAdapter([{ ok: true, status: 200 }]);
280
-
281
- const service = new ObjectStorageService(baseUrl, adapter);
282
- const result = await service.delete('test-bucket', 'test-key');
283
-
284
- expect(calls).toHaveLength(1);
285
- expect(calls[0].url).toBe(`${baseUrl}/object/2025-03-17/test-bucket/test-key`);
286
- expect(calls[0].options.method).toBe('DELETE');
287
- expect(calls[0].options.telemetry?.name).toBe('agentuity.objectstore.delete');
288
- expect(result).toBe(true);
289
- });
290
-
291
- test('should return false for non-existent object', async () => {
292
- const { adapter, calls } = createMockAdapter([{ ok: false, status: 404 }]);
293
-
294
- const service = new ObjectStorageService(baseUrl, adapter);
295
- const result = await service.delete('test-bucket', 'missing-key');
296
-
297
- expect(calls).toHaveLength(1);
298
- expect(result).toBe(false);
299
- });
300
-
301
- test('should validate bucket parameter', async () => {
302
- const { adapter } = createMockAdapter([]);
303
- const service = new ObjectStorageService(baseUrl, adapter);
304
-
305
- await expect(service.delete('', 'test-key')).rejects.toThrow(
306
- 'bucket is required and cannot be empty'
307
- );
308
- });
309
-
310
- test('should validate key parameter', async () => {
311
- const { adapter } = createMockAdapter([]);
312
- const service = new ObjectStorageService(baseUrl, adapter);
313
-
314
- await expect(service.delete('test-bucket', '')).rejects.toThrow(
315
- 'key is required and cannot be empty'
316
- );
317
- });
318
-
319
- test('should throw error for access denied (403 status code)', async () => {
320
- const { adapter } = createMockAdapter([
321
- { ok: false, status: 403, statusText: 'Forbidden' },
322
- ]);
323
-
324
- const service = new ObjectStorageService(baseUrl, adapter);
325
-
326
- await expect(service.delete('test-bucket', 'test-key')).rejects.toThrow(
327
- 'Failed to delete object: Forbidden (403)'
328
- );
329
- });
330
- });
331
-
332
- describe('createPublicURL', () => {
333
- test('should create a public URL successfully', async () => {
334
- const { adapter, calls } = createMockAdapter([
335
- {
336
- ok: true,
337
- data: {
338
- success: true,
339
- url: 'https://cdn.example.com/signed-url',
340
- },
341
- },
342
- ]);
343
-
344
- const service = new ObjectStorageService(baseUrl, adapter);
345
- const url = await service.createPublicURL('test-bucket', 'test-key');
346
-
347
- expect(calls).toHaveLength(1);
348
- expect(calls[0].url).toBe(`${baseUrl}/object/2025-03-17/presigned/test-bucket/test-key`);
349
- expect(calls[0].options.method).toBe('POST');
350
- expect(calls[0].options.contentType).toBe('application/json');
351
- expect(calls[0].options.telemetry?.name).toBe('agentuity.objectstore.createPublicURL');
352
- expect(url).toBe('https://cdn.example.com/signed-url');
353
- });
354
-
355
- test('should create a public URL with expiration', async () => {
356
- const { adapter, calls } = createMockAdapter([
357
- {
358
- ok: true,
359
- data: {
360
- success: true,
361
- url: 'https://cdn.example.com/signed-url',
362
- },
363
- },
364
- ]);
365
-
366
- const service = new ObjectStorageService(baseUrl, adapter);
367
- const url = await service.createPublicURL('test-bucket', 'test-key', {
368
- expiresDuration: 3600000,
369
- });
370
-
371
- expect(calls).toHaveLength(1);
372
- expect(JSON.parse(calls[0].options.body as string)).toEqual({ expires: 3600000 });
373
- expect(url).toBe('https://cdn.example.com/signed-url');
374
- });
375
-
376
- test('should handle error response with message', async () => {
377
- const { adapter } = createMockAdapter([
378
- {
379
- ok: true,
380
- data: {
381
- success: false,
382
- message: 'Object not found',
383
- },
384
- },
385
- ]);
386
-
387
- const service = new ObjectStorageService(baseUrl, adapter);
388
-
389
- await expect(service.createPublicURL('test-bucket', 'test-key')).rejects.toThrow(
390
- 'Object not found'
391
- );
392
- });
393
-
394
- test('should validate bucket parameter', async () => {
395
- const { adapter } = createMockAdapter([]);
396
- const service = new ObjectStorageService(baseUrl, adapter);
397
-
398
- await expect(service.createPublicURL('', 'test-key')).rejects.toThrow(
399
- 'bucket is required and cannot be empty'
400
- );
401
- });
402
-
403
- test('should validate key parameter', async () => {
404
- const { adapter } = createMockAdapter([]);
405
- const service = new ObjectStorageService(baseUrl, adapter);
406
-
407
- await expect(service.createPublicURL('test-bucket', '')).rejects.toThrow(
408
- 'key is required and cannot be empty'
409
- );
410
- });
411
-
412
- test('should send empty JSON body when no expires duration provided', async () => {
413
- const { adapter, calls } = createMockAdapter([
414
- {
415
- ok: true,
416
- data: {
417
- success: true,
418
- url: 'https://cdn.example.com/signed-url',
419
- },
420
- },
421
- ]);
422
-
423
- const service = new ObjectStorageService(baseUrl, adapter);
424
- const url = await service.createPublicURL('test-bucket', 'test-key');
425
-
426
- expect(calls).toHaveLength(1);
427
- expect(calls[0].options.body).toBe('{}');
428
- expect(url).toBe('https://cdn.example.com/signed-url');
429
- });
430
- });
431
- });