@agentuity/core 0.0.33 → 0.0.35
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/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/json.js +23 -0
- package/dist/json.js.map +1 -0
- package/dist/services/_util.js +107 -0
- package/dist/services/_util.js.map +1 -0
- package/dist/services/adapter.js +2 -0
- package/dist/services/adapter.js.map +1 -0
- package/dist/services/exception.js +8 -0
- package/dist/services/exception.js.map +1 -0
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/keyvalue.js +85 -0
- package/dist/services/keyvalue.js.map +1 -0
- package/dist/services/objectstore.js +218 -0
- package/dist/services/objectstore.js.map +1 -0
- package/dist/services/stream.js +392 -0
- package/dist/services/stream.js.map +1 -0
- package/dist/services/vector.js +242 -0
- package/dist/services/vector.js.map +1 -0
- package/dist/standard_schema.js +2 -0
- package/dist/standard_schema.js.map +1 -0
- package/dist/typehelper.js +2 -0
- package/dist/typehelper.js.map +1 -0
- package/package.json +5 -4
- package/src/index.ts +4 -0
- package/src/json.ts +26 -0
- package/src/services/__test__/keyvalue.test.ts +402 -0
- package/src/services/__test__/mock-adapter.ts +114 -0
- package/src/services/__test__/objectstore.test.ts +431 -0
- package/src/services/__test__/stream.test.ts +554 -0
- package/src/services/__test__/vector.test.ts +813 -0
- package/src/services/_util.ts +117 -0
- package/src/services/adapter.ts +33 -0
- package/src/services/exception.ts +7 -0
- package/src/services/index.ts +7 -0
- package/src/services/keyvalue.ts +185 -0
- package/src/services/objectstore.ts +466 -0
- package/src/services/stream.ts +614 -0
- package/src/services/vector.ts +599 -0
- package/src/standard_schema.ts +69 -0
- package/src/typehelper.ts +5 -0
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import type { FetchAdapter, FetchRequest, Body } from './adapter';
|
|
2
|
+
import { buildUrl, toServiceException } from './_util';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parameters for putting an object into the object store
|
|
6
|
+
*/
|
|
7
|
+
export interface ObjectStorePutParams {
|
|
8
|
+
/**
|
|
9
|
+
* the content type of the object
|
|
10
|
+
*/
|
|
11
|
+
contentType?: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* the content encoding of the object
|
|
15
|
+
*/
|
|
16
|
+
contentEncoding?: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* the cache control header for the object
|
|
20
|
+
*/
|
|
21
|
+
cacheControl?: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* the content disposition header for the object
|
|
25
|
+
*/
|
|
26
|
+
contentDisposition?: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* the content language header for the object
|
|
30
|
+
*/
|
|
31
|
+
contentLanguage?: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* arbitrary metadata to attach to the object but not returned as part of the object when fetched via HTTP
|
|
35
|
+
*/
|
|
36
|
+
metadata?: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Result when an object is found in the object store
|
|
41
|
+
*/
|
|
42
|
+
export interface ObjectResultFound {
|
|
43
|
+
/**
|
|
44
|
+
* the object data
|
|
45
|
+
*/
|
|
46
|
+
data: Uint8Array;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* the content type of the object
|
|
50
|
+
*/
|
|
51
|
+
contentType: string;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* the object was found
|
|
55
|
+
*/
|
|
56
|
+
exists: true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Result when an object is not found in the object store
|
|
61
|
+
*/
|
|
62
|
+
export interface ObjectResultNotFound {
|
|
63
|
+
data: never;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* the object was not found
|
|
67
|
+
*/
|
|
68
|
+
exists: false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The result of an object store get operation
|
|
73
|
+
*/
|
|
74
|
+
export type ObjectResult = ObjectResultFound | ObjectResultNotFound;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Parameters for creating a public URL
|
|
78
|
+
*/
|
|
79
|
+
export interface CreatePublicURLParams {
|
|
80
|
+
/**
|
|
81
|
+
* the duration of the signed URL in milliseconds. If not provided, the default is 1 hour.
|
|
82
|
+
*/
|
|
83
|
+
expiresDuration?: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
interface ObjectStoreCreatePublicURLSuccessResponse {
|
|
87
|
+
success: true;
|
|
88
|
+
url: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface ObjectStoreCreatePublicURLErrorResponse {
|
|
92
|
+
success: false;
|
|
93
|
+
message: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
type ObjectStoreCreatePublicURLResponse =
|
|
97
|
+
| ObjectStoreCreatePublicURLSuccessResponse
|
|
98
|
+
| ObjectStoreCreatePublicURLErrorResponse;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Object store service for storing and retrieving binary data
|
|
102
|
+
*/
|
|
103
|
+
export interface ObjectStorage {
|
|
104
|
+
/**
|
|
105
|
+
* Get an object from the object store
|
|
106
|
+
*
|
|
107
|
+
* @param bucket - the bucket to get the object from
|
|
108
|
+
* @param key - the key of the object to get
|
|
109
|
+
* @returns a Promise that resolves to the object result
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const result = await objectStore.get('my-bucket', 'my-key');
|
|
114
|
+
* if (result.exists) {
|
|
115
|
+
* console.log('Content type:', result.contentType);
|
|
116
|
+
* console.log('Data:', result.data);
|
|
117
|
+
* }
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
get(bucket: string, key: string): Promise<ObjectResult>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Put an object into the object store
|
|
124
|
+
*
|
|
125
|
+
* @param bucket - the bucket to put the object into
|
|
126
|
+
* @param key - the key of the object to put
|
|
127
|
+
* @param data - the data to put (Uint8Array, ArrayBuffer, or ReadableStream)
|
|
128
|
+
* @param params - optional parameters for the put operation
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const data = new TextEncoder().encode('Hello, world!');
|
|
133
|
+
* await objectStore.put('my-bucket', 'greeting.txt', data, {
|
|
134
|
+
* contentType: 'text/plain',
|
|
135
|
+
* metadata: { author: 'user123' }
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
put(
|
|
140
|
+
bucket: string,
|
|
141
|
+
key: string,
|
|
142
|
+
data: Uint8Array | ArrayBuffer | ReadableStream,
|
|
143
|
+
params?: ObjectStorePutParams
|
|
144
|
+
): Promise<void>;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Delete an object from the object store
|
|
148
|
+
*
|
|
149
|
+
* @param bucket - the bucket to delete the object from
|
|
150
|
+
* @param key - the key of the object to delete
|
|
151
|
+
* @returns true if the object was deleted, false if the object did not exist
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const deleted = await objectStore.delete('my-bucket', 'my-key');
|
|
156
|
+
* if (deleted) {
|
|
157
|
+
* console.log('Object was deleted');
|
|
158
|
+
* } else {
|
|
159
|
+
* console.log('Object did not exist');
|
|
160
|
+
* }
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
delete(bucket: string, key: string): Promise<boolean>;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Create a public URL for an object. This URL can be used to access the object without authentication.
|
|
167
|
+
*
|
|
168
|
+
* @param bucket - the bucket to create the signed URL for
|
|
169
|
+
* @param key - the key of the object to create the signed URL for
|
|
170
|
+
* @param params - optional parameters including expiration duration
|
|
171
|
+
* @returns the public URL
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const url = await objectStore.createPublicURL('my-bucket', 'my-key', {
|
|
176
|
+
* expiresDuration: 3600000 // 1 hour in milliseconds
|
|
177
|
+
* });
|
|
178
|
+
* console.log('Public URL:', url);
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
createPublicURL(bucket: string, key: string, params?: CreatePublicURLParams): Promise<string>;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Implementation of the ObjectStorage interface
|
|
186
|
+
*/
|
|
187
|
+
export class ObjectStorageService implements ObjectStorage {
|
|
188
|
+
#adapter: FetchAdapter;
|
|
189
|
+
#baseUrl: string;
|
|
190
|
+
|
|
191
|
+
constructor(baseUrl: string, adapter: FetchAdapter) {
|
|
192
|
+
this.#baseUrl = baseUrl;
|
|
193
|
+
this.#adapter = adapter;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async get(bucket: string, key: string): Promise<ObjectResult> {
|
|
197
|
+
if (!bucket?.trim()) {
|
|
198
|
+
throw new Error('bucket is required and cannot be empty');
|
|
199
|
+
}
|
|
200
|
+
if (!key?.trim()) {
|
|
201
|
+
throw new Error('key is required and cannot be empty');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const url = buildUrl(
|
|
205
|
+
this.#baseUrl,
|
|
206
|
+
`/object/2025-03-17/${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const signal = AbortSignal.timeout(10_000);
|
|
210
|
+
const options: FetchRequest = {
|
|
211
|
+
method: 'GET',
|
|
212
|
+
signal,
|
|
213
|
+
telemetry: {
|
|
214
|
+
name: 'agentuity.objectstore.get',
|
|
215
|
+
attributes: {
|
|
216
|
+
'objectstore.bucket': bucket,
|
|
217
|
+
'objectstore.key': key,
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
const result = await this.#adapter.invoke<ArrayBuffer>(url, options);
|
|
224
|
+
|
|
225
|
+
if (result.response.status === 404) {
|
|
226
|
+
return { exists: false } as ObjectResultNotFound;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!result.ok) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`Failed to get object: ${result.response.statusText} (${result.response.status})`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const data = result.data;
|
|
236
|
+
if (!(data instanceof ArrayBuffer)) {
|
|
237
|
+
throw new Error('Expected ArrayBuffer response from object store');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const contentType =
|
|
241
|
+
result.response.headers.get('content-type') || 'application/octet-stream';
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
exists: true,
|
|
245
|
+
data: new Uint8Array(data),
|
|
246
|
+
contentType,
|
|
247
|
+
} as ObjectResultFound;
|
|
248
|
+
} catch (err) {
|
|
249
|
+
if (err instanceof Response) {
|
|
250
|
+
throw await toServiceException(err);
|
|
251
|
+
}
|
|
252
|
+
throw err;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async put(
|
|
257
|
+
bucket: string,
|
|
258
|
+
key: string,
|
|
259
|
+
data: Uint8Array | ArrayBuffer | ReadableStream,
|
|
260
|
+
params?: ObjectStorePutParams
|
|
261
|
+
): Promise<void> {
|
|
262
|
+
if (!bucket?.trim()) {
|
|
263
|
+
throw new Error('bucket is required and cannot be empty');
|
|
264
|
+
}
|
|
265
|
+
if (!key?.trim()) {
|
|
266
|
+
throw new Error('key is required and cannot be empty');
|
|
267
|
+
}
|
|
268
|
+
if (!data) {
|
|
269
|
+
throw new Error('data is required');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const url = buildUrl(
|
|
273
|
+
this.#baseUrl,
|
|
274
|
+
`/object/2025-03-17/${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const headers: Record<string, string> = {
|
|
278
|
+
'Content-Type': params?.contentType || 'application/octet-stream',
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
if (params?.contentEncoding) {
|
|
282
|
+
headers['Content-Encoding'] = params.contentEncoding;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (params?.cacheControl) {
|
|
286
|
+
headers['Cache-Control'] = params.cacheControl;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (params?.contentDisposition) {
|
|
290
|
+
headers['Content-Disposition'] = params.contentDisposition;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (params?.contentLanguage) {
|
|
294
|
+
headers['Content-Language'] = params.contentLanguage;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (params?.metadata) {
|
|
298
|
+
for (const [metaKey, metaValue] of Object.entries(params.metadata)) {
|
|
299
|
+
headers[`x-metadata-${metaKey}`] = metaValue;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
let body: Body;
|
|
304
|
+
if (data instanceof ArrayBuffer) {
|
|
305
|
+
body = data;
|
|
306
|
+
} else if (data instanceof Uint8Array) {
|
|
307
|
+
if (data.byteOffset !== 0 || data.byteLength !== data.buffer.byteLength) {
|
|
308
|
+
body = data.buffer.slice(
|
|
309
|
+
data.byteOffset,
|
|
310
|
+
data.byteOffset + data.byteLength
|
|
311
|
+
) as ArrayBuffer;
|
|
312
|
+
} else {
|
|
313
|
+
body = data.buffer as ArrayBuffer;
|
|
314
|
+
}
|
|
315
|
+
} else {
|
|
316
|
+
body = data;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const signal = AbortSignal.timeout(30_000);
|
|
320
|
+
const options: FetchRequest = {
|
|
321
|
+
method: 'PUT',
|
|
322
|
+
headers,
|
|
323
|
+
body,
|
|
324
|
+
signal,
|
|
325
|
+
telemetry: {
|
|
326
|
+
name: 'agentuity.objectstore.put',
|
|
327
|
+
attributes: {
|
|
328
|
+
'objectstore.bucket': bucket,
|
|
329
|
+
'objectstore.key': key,
|
|
330
|
+
'objectstore.contentType': params?.contentType || 'application/octet-stream',
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
try {
|
|
336
|
+
const result = await this.#adapter.invoke(url, options);
|
|
337
|
+
|
|
338
|
+
if (!result.ok || (result.response.status !== 200 && result.response.status !== 201)) {
|
|
339
|
+
throw new Error(
|
|
340
|
+
`Failed to put object: ${result.response.statusText} (${result.response.status})`
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
} catch (err) {
|
|
344
|
+
if (err instanceof Response) {
|
|
345
|
+
throw await toServiceException(err);
|
|
346
|
+
}
|
|
347
|
+
throw err;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async delete(bucket: string, key: string): Promise<boolean> {
|
|
352
|
+
if (!bucket?.trim()) {
|
|
353
|
+
throw new Error('bucket is required and cannot be empty');
|
|
354
|
+
}
|
|
355
|
+
if (!key?.trim()) {
|
|
356
|
+
throw new Error('key is required and cannot be empty');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const url = buildUrl(
|
|
360
|
+
this.#baseUrl,
|
|
361
|
+
`/object/2025-03-17/${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
const signal = AbortSignal.timeout(10_000);
|
|
365
|
+
const options: FetchRequest = {
|
|
366
|
+
method: 'DELETE',
|
|
367
|
+
signal,
|
|
368
|
+
telemetry: {
|
|
369
|
+
name: 'agentuity.objectstore.delete',
|
|
370
|
+
attributes: {
|
|
371
|
+
'objectstore.bucket': bucket,
|
|
372
|
+
'objectstore.key': key,
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
try {
|
|
378
|
+
const result = await this.#adapter.invoke(url, options);
|
|
379
|
+
|
|
380
|
+
if (result.response.status === 404) {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (result.response.status === 200) {
|
|
385
|
+
return true;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
throw new Error(
|
|
389
|
+
`Failed to delete object: ${result.response.statusText} (${result.response.status})`
|
|
390
|
+
);
|
|
391
|
+
} catch (err) {
|
|
392
|
+
if (err instanceof Response) {
|
|
393
|
+
throw await toServiceException(err);
|
|
394
|
+
}
|
|
395
|
+
throw err;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async createPublicURL(
|
|
400
|
+
bucket: string,
|
|
401
|
+
key: string,
|
|
402
|
+
params?: CreatePublicURLParams
|
|
403
|
+
): Promise<string> {
|
|
404
|
+
if (!bucket?.trim()) {
|
|
405
|
+
throw new Error('bucket is required and cannot be empty');
|
|
406
|
+
}
|
|
407
|
+
if (!key?.trim()) {
|
|
408
|
+
throw new Error('key is required and cannot be empty');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const url = buildUrl(
|
|
412
|
+
this.#baseUrl,
|
|
413
|
+
`/object/2025-03-17/presigned/${encodeURIComponent(bucket)}/${encodeURIComponent(key)}`
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
const requestBody: { expires?: number } = {};
|
|
417
|
+
if (params?.expiresDuration) {
|
|
418
|
+
requestBody.expires = params.expiresDuration;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const signal = AbortSignal.timeout(10_000);
|
|
422
|
+
const options: FetchRequest = {
|
|
423
|
+
method: 'POST',
|
|
424
|
+
contentType: 'application/json',
|
|
425
|
+
body: JSON.stringify(requestBody),
|
|
426
|
+
signal,
|
|
427
|
+
telemetry: {
|
|
428
|
+
name: 'agentuity.objectstore.createPublicURL',
|
|
429
|
+
attributes: {
|
|
430
|
+
'objectstore.bucket': bucket,
|
|
431
|
+
'objectstore.key': key,
|
|
432
|
+
'objectstore.expiresDuration': params?.expiresDuration?.toString() || '',
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
try {
|
|
438
|
+
const result = await this.#adapter.invoke<ObjectStoreCreatePublicURLResponse>(
|
|
439
|
+
url,
|
|
440
|
+
options
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
if (!result.ok) {
|
|
444
|
+
throw new Error(
|
|
445
|
+
`Failed to create public URL: ${result.response.statusText} (${result.response.status})`
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const data = result.data;
|
|
450
|
+
|
|
451
|
+
if (!data.success) {
|
|
452
|
+
throw new Error(data.message || 'Failed to create public URL');
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return data.url;
|
|
456
|
+
} catch (err) {
|
|
457
|
+
if (err instanceof Error && err.message.includes('Object not found')) {
|
|
458
|
+
throw err;
|
|
459
|
+
}
|
|
460
|
+
if (err instanceof Response) {
|
|
461
|
+
throw await toServiceException(err);
|
|
462
|
+
}
|
|
463
|
+
throw err;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|