@agentuity/core 1.0.29 → 1.0.31
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.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/email.d.ts +507 -8
- package/dist/services/email.d.ts.map +1 -1
- package/dist/services/email.js +325 -1
- package/dist/services/email.js.map +1 -1
- package/dist/services/keyvalue.d.ts +5 -2
- package/dist/services/keyvalue.d.ts.map +1 -1
- package/dist/services/keyvalue.js +44 -1
- package/dist/services/keyvalue.js.map +1 -1
- package/dist/services/queue.d.ts +98 -0
- package/dist/services/queue.d.ts.map +1 -1
- package/dist/services/queue.js +100 -0
- package/dist/services/queue.js.map +1 -1
- package/dist/services/schedule.d.ts +413 -0
- package/dist/services/schedule.d.ts.map +1 -1
- package/dist/services/schedule.js +221 -0
- package/dist/services/schedule.js.map +1 -1
- package/dist/services/task.d.ts +1103 -11
- package/dist/services/task.d.ts.map +1 -1
- package/dist/services/task.js +589 -1
- package/dist/services/task.js.map +1 -1
- package/dist/services/webhook.d.ts +352 -0
- package/dist/services/webhook.d.ts.map +1 -1
- package/dist/services/webhook.js +254 -0
- package/dist/services/webhook.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +8 -0
- package/src/services/email.ts +560 -9
- package/src/services/keyvalue.ts +51 -3
- package/src/services/queue.ts +215 -0
- package/src/services/schedule.ts +442 -0
- package/src/services/task.ts +1329 -23
- package/src/services/webhook.ts +412 -0
package/src/services/keyvalue.ts
CHANGED
|
@@ -110,9 +110,12 @@ export interface KeyValueStats {
|
|
|
110
110
|
export interface KeyValueItemWithMetadata<T = unknown> {
|
|
111
111
|
value: T;
|
|
112
112
|
contentType: string;
|
|
113
|
+
contentEncoding?: string | null;
|
|
113
114
|
size: number;
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
expiresAt?: string | null;
|
|
116
|
+
firstUsed?: number | null;
|
|
117
|
+
lastUsed?: number | null;
|
|
118
|
+
count?: number | null;
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
export type KVSortField = 'name' | 'size' | 'records' | 'created' | 'lastUsed';
|
|
@@ -284,6 +287,51 @@ export interface KeyValueStorage {
|
|
|
284
287
|
createNamespace(name: string, params?: CreateNamespaceParams): Promise<void>;
|
|
285
288
|
}
|
|
286
289
|
|
|
290
|
+
/**
|
|
291
|
+
* Decodes a base64 string to a Uint8Array.
|
|
292
|
+
*/
|
|
293
|
+
function base64ToBytes(base64: string): Uint8Array {
|
|
294
|
+
const binaryString = atob(base64);
|
|
295
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
296
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
297
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
298
|
+
}
|
|
299
|
+
return bytes;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Deserializes search result values from the server's wire format.
|
|
304
|
+
*
|
|
305
|
+
* The Go server stores values as []byte, which Go's json.Marshal
|
|
306
|
+
* base64-encodes when embedding in a JSON response. This function
|
|
307
|
+
* decodes each item's value from base64 and parses it according
|
|
308
|
+
* to its contentType, aligning search() behavior with get().
|
|
309
|
+
*/
|
|
310
|
+
function deserializeSearchResults<T>(
|
|
311
|
+
data: Record<string, KeyValueItemWithMetadata<T>>
|
|
312
|
+
): Record<string, KeyValueItemWithMetadata<T>> {
|
|
313
|
+
for (const item of Object.values(data)) {
|
|
314
|
+
if (typeof item.value === 'string') {
|
|
315
|
+
try {
|
|
316
|
+
const bytes = base64ToBytes(item.value);
|
|
317
|
+
const ct = (item.contentType ?? '').toLowerCase();
|
|
318
|
+
|
|
319
|
+
if (ct.includes('json')) {
|
|
320
|
+
const text = new TextDecoder().decode(bytes);
|
|
321
|
+
item.value = JSON.parse(text) as T;
|
|
322
|
+
} else if (ct.startsWith('text/')) {
|
|
323
|
+
item.value = new TextDecoder().decode(bytes) as T;
|
|
324
|
+
} else {
|
|
325
|
+
item.value = bytes.buffer as T;
|
|
326
|
+
}
|
|
327
|
+
} catch {
|
|
328
|
+
// If base64 decoding or parsing fails, leave value as-is
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return data;
|
|
333
|
+
}
|
|
334
|
+
|
|
287
335
|
export class KeyValueStorageService implements KeyValueStorage {
|
|
288
336
|
#adapter: FetchAdapter;
|
|
289
337
|
#baseUrl: string;
|
|
@@ -510,7 +558,7 @@ export class KeyValueStorageService implements KeyValueStorage {
|
|
|
510
558
|
},
|
|
511
559
|
});
|
|
512
560
|
if (res.ok) {
|
|
513
|
-
return res.data;
|
|
561
|
+
return deserializeSearchResults<T>(res.data);
|
|
514
562
|
}
|
|
515
563
|
throw await toServiceException('GET', url, res.response);
|
|
516
564
|
}
|
package/src/services/queue.ts
CHANGED
|
@@ -108,6 +108,59 @@ export interface QueuePublishResult {
|
|
|
108
108
|
publishedAt: string;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Parameters for creating a queue.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const result = await ctx.queue.createQueue('my-queue', {
|
|
117
|
+
* queueType: 'pubsub',
|
|
118
|
+
* settings: { defaultTtlSeconds: 86400 },
|
|
119
|
+
* });
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export interface QueueCreateParams {
|
|
123
|
+
/**
|
|
124
|
+
* Type of queue to create.
|
|
125
|
+
* - `worker`: Messages are consumed by exactly one consumer with acknowledgment.
|
|
126
|
+
* - `pubsub`: Messages are broadcast to all subscribers.
|
|
127
|
+
* @default 'worker'
|
|
128
|
+
*/
|
|
129
|
+
queueType?: 'worker' | 'pubsub';
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Optional description of the queue's purpose.
|
|
133
|
+
*/
|
|
134
|
+
description?: string;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Optional settings to customize queue behavior.
|
|
138
|
+
* Only provided fields are applied; others use server defaults.
|
|
139
|
+
*/
|
|
140
|
+
settings?: {
|
|
141
|
+
/** Default time-to-live for messages in seconds. Null means no expiration. */
|
|
142
|
+
defaultTtlSeconds?: number | null;
|
|
143
|
+
/** Time in seconds a message is invisible after being received. */
|
|
144
|
+
defaultVisibilityTimeoutSeconds?: number;
|
|
145
|
+
/** Maximum number of delivery attempts before moving to DLQ. */
|
|
146
|
+
defaultMaxRetries?: number;
|
|
147
|
+
/** Maximum number of messages a single client can process concurrently. */
|
|
148
|
+
maxInFlightPerClient?: number;
|
|
149
|
+
/** Retention period for acknowledged messages in seconds. */
|
|
150
|
+
retentionSeconds?: number;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Result of creating a queue.
|
|
156
|
+
*/
|
|
157
|
+
export interface QueueCreateResult {
|
|
158
|
+
/** The queue name. */
|
|
159
|
+
name: string;
|
|
160
|
+
/** The queue type ('worker' or 'pubsub'). */
|
|
161
|
+
queueType: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
111
164
|
/**
|
|
112
165
|
* Queue service interface for publishing messages.
|
|
113
166
|
*
|
|
@@ -167,6 +220,49 @@ export interface QueueService {
|
|
|
167
220
|
payload: string | object,
|
|
168
221
|
params?: QueuePublishParams
|
|
169
222
|
): Promise<QueuePublishResult>;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Create a queue with idempotent semantics.
|
|
226
|
+
*
|
|
227
|
+
* If the queue already exists, this returns successfully without error.
|
|
228
|
+
* Safe to call multiple times — uses an internal cache to avoid redundant API calls.
|
|
229
|
+
*
|
|
230
|
+
* @param queueName - The name of the queue to create
|
|
231
|
+
* @param params - Optional creation parameters (queue type, settings, etc.)
|
|
232
|
+
* @returns The create result with queue name and type
|
|
233
|
+
* @throws {QueueValidationError} If the queue name is invalid
|
|
234
|
+
*
|
|
235
|
+
* @example Creating a worker queue
|
|
236
|
+
* ```typescript
|
|
237
|
+
* const result = await ctx.queue.createQueue('task-queue');
|
|
238
|
+
* ```
|
|
239
|
+
*
|
|
240
|
+
* @example Creating a pubsub queue with settings
|
|
241
|
+
* ```typescript
|
|
242
|
+
* const result = await ctx.queue.createQueue('events', {
|
|
243
|
+
* queueType: 'pubsub',
|
|
244
|
+
* settings: { defaultTtlSeconds: 86400 },
|
|
245
|
+
* });
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
createQueue(queueName: string, params?: QueueCreateParams): Promise<QueueCreateResult>;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Delete a queue.
|
|
252
|
+
*
|
|
253
|
+
* Permanently deletes a queue and all its messages. This action cannot be undone.
|
|
254
|
+
* If the queue has already been deleted or does not exist, a {@link QueueNotFoundError} is thrown.
|
|
255
|
+
*
|
|
256
|
+
* @param queueName - The name of the queue to delete
|
|
257
|
+
* @throws {QueueNotFoundError} If the queue does not exist
|
|
258
|
+
* @throws {QueueValidationError} If the queue name is invalid
|
|
259
|
+
*
|
|
260
|
+
* @example Deleting a queue
|
|
261
|
+
* ```typescript
|
|
262
|
+
* await ctx.queue.deleteQueue('old-queue');
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
deleteQueue(queueName: string): Promise<void>;
|
|
170
266
|
}
|
|
171
267
|
|
|
172
268
|
// ============================================================================
|
|
@@ -277,6 +373,7 @@ function validatePayloadInternal(payload: string): void {
|
|
|
277
373
|
export class QueueStorageService implements QueueService {
|
|
278
374
|
#adapter: FetchAdapter;
|
|
279
375
|
#baseUrl: string;
|
|
376
|
+
#knownQueues = new Set<string>();
|
|
280
377
|
|
|
281
378
|
/**
|
|
282
379
|
* Creates a new QueueStorageService.
|
|
@@ -388,4 +485,122 @@ export class QueueStorageService implements QueueService {
|
|
|
388
485
|
|
|
389
486
|
throw await toServiceException('POST', url, res.response);
|
|
390
487
|
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* @inheritdoc
|
|
491
|
+
*/
|
|
492
|
+
async createQueue(queueName: string, params?: QueueCreateParams): Promise<QueueCreateResult> {
|
|
493
|
+
validateQueueNameInternal(queueName);
|
|
494
|
+
|
|
495
|
+
if (this.#knownQueues.has(queueName)) {
|
|
496
|
+
return {
|
|
497
|
+
name: queueName,
|
|
498
|
+
queueType: params?.queueType ?? 'worker',
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const url = buildUrl(this.#baseUrl, '/queue/create/2026-01-15');
|
|
503
|
+
|
|
504
|
+
const requestBody: Record<string, unknown> = {
|
|
505
|
+
name: queueName,
|
|
506
|
+
queue_type: params?.queueType ?? 'worker',
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
if (params?.description !== undefined) {
|
|
510
|
+
requestBody.description = params.description;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (params?.settings) {
|
|
514
|
+
const settings: Record<string, unknown> = {};
|
|
515
|
+
if (params.settings.defaultTtlSeconds !== undefined) {
|
|
516
|
+
settings.default_ttl_seconds = params.settings.defaultTtlSeconds;
|
|
517
|
+
}
|
|
518
|
+
if (params.settings.defaultVisibilityTimeoutSeconds !== undefined) {
|
|
519
|
+
settings.default_visibility_timeout_seconds =
|
|
520
|
+
params.settings.defaultVisibilityTimeoutSeconds;
|
|
521
|
+
}
|
|
522
|
+
if (params.settings.defaultMaxRetries !== undefined) {
|
|
523
|
+
settings.default_max_retries = params.settings.defaultMaxRetries;
|
|
524
|
+
}
|
|
525
|
+
if (params.settings.maxInFlightPerClient !== undefined) {
|
|
526
|
+
settings.max_in_flight_per_client = params.settings.maxInFlightPerClient;
|
|
527
|
+
}
|
|
528
|
+
if (params.settings.retentionSeconds !== undefined) {
|
|
529
|
+
settings.retention_seconds = params.settings.retentionSeconds;
|
|
530
|
+
}
|
|
531
|
+
if (Object.keys(settings).length > 0) {
|
|
532
|
+
requestBody.settings = settings;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const signal = AbortSignal.timeout(30_000);
|
|
537
|
+
const res = await this.#adapter.invoke<QueueCreateResult>(url, {
|
|
538
|
+
method: 'POST',
|
|
539
|
+
signal,
|
|
540
|
+
body: JSON.stringify(requestBody),
|
|
541
|
+
contentType: 'application/json',
|
|
542
|
+
telemetry: {
|
|
543
|
+
name: 'agentuity.queue.create',
|
|
544
|
+
attributes: {
|
|
545
|
+
queueName,
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
if (res.ok) {
|
|
551
|
+
const data = res.data as unknown as Record<string, unknown>;
|
|
552
|
+
this.#knownQueues.add(queueName);
|
|
553
|
+
return {
|
|
554
|
+
name: (data.name as string) ?? queueName,
|
|
555
|
+
queueType: (data.queue_type as string) ?? params?.queueType ?? 'worker',
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (res.response.status === 409) {
|
|
560
|
+
this.#knownQueues.add(queueName);
|
|
561
|
+
return {
|
|
562
|
+
name: queueName,
|
|
563
|
+
queueType: params?.queueType ?? 'worker',
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
throw await toServiceException('POST', url, res.response);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* @inheritdoc
|
|
572
|
+
*/
|
|
573
|
+
async deleteQueue(queueName: string): Promise<void> {
|
|
574
|
+
validateQueueNameInternal(queueName);
|
|
575
|
+
|
|
576
|
+
const url = buildUrl(
|
|
577
|
+
this.#baseUrl,
|
|
578
|
+
`/queue/delete/2026-01-15/${encodeURIComponent(queueName)}`
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
const signal = AbortSignal.timeout(30_000);
|
|
582
|
+
const res = await this.#adapter.invoke<void>(url, {
|
|
583
|
+
method: 'DELETE',
|
|
584
|
+
signal,
|
|
585
|
+
telemetry: {
|
|
586
|
+
name: 'agentuity.queue.delete',
|
|
587
|
+
attributes: {
|
|
588
|
+
queueName,
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
if (res.ok) {
|
|
594
|
+
this.#knownQueues.delete(queueName);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (res.response.status === 404) {
|
|
599
|
+
throw new QueueNotFoundError({
|
|
600
|
+
message: `Queue not found: ${queueName}`,
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
throw await toServiceException('DELETE', url, res.response);
|
|
605
|
+
}
|
|
391
606
|
}
|