@amigo-ai/platform-sdk 0.4.0 → 0.4.2

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 (57) hide show
  1. package/README.md +147 -55
  2. package/api.md +354 -0
  3. package/dist/core/errors.js +26 -4
  4. package/dist/core/errors.js.map +1 -1
  5. package/dist/core/openapi-client.js +108 -6
  6. package/dist/core/openapi-client.js.map +1 -1
  7. package/dist/core/retry.js +5 -2
  8. package/dist/core/retry.js.map +1 -1
  9. package/dist/core/utils.js +48 -2
  10. package/dist/core/utils.js.map +1 -1
  11. package/dist/core/webhooks.js +8 -2
  12. package/dist/core/webhooks.js.map +1 -1
  13. package/dist/index.cjs +268 -40
  14. package/dist/index.cjs.map +4 -4
  15. package/dist/index.js +50 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +268 -40
  18. package/dist/index.mjs.map +4 -4
  19. package/dist/types/core/errors.d.ts +6 -0
  20. package/dist/types/core/errors.d.ts.map +1 -1
  21. package/dist/types/core/openapi-client.d.ts +24 -1
  22. package/dist/types/core/openapi-client.d.ts.map +1 -1
  23. package/dist/types/core/retry.d.ts +1 -1
  24. package/dist/types/core/retry.d.ts.map +1 -1
  25. package/dist/types/core/utils.d.ts +27 -1
  26. package/dist/types/core/utils.d.ts.map +1 -1
  27. package/dist/types/core/webhooks.d.ts.map +1 -1
  28. package/dist/types/index.d.ts +40 -2
  29. package/dist/types/index.d.ts.map +1 -1
  30. package/dist/types/resources/actions.d.ts +5 -5
  31. package/dist/types/resources/agents.d.ts +7 -7
  32. package/dist/types/resources/analytics.d.ts +11 -11
  33. package/dist/types/resources/api-keys.d.ts +4 -4
  34. package/dist/types/resources/audit.d.ts +6 -6
  35. package/dist/types/resources/billing.d.ts +6 -6
  36. package/dist/types/resources/calls.d.ts +6 -6
  37. package/dist/types/resources/compliance.d.ts +3 -3
  38. package/dist/types/resources/context-graphs.d.ts +7 -7
  39. package/dist/types/resources/data-sources.d.ts +6 -6
  40. package/dist/types/resources/functions.d.ts +6 -6
  41. package/dist/types/resources/integrations.d.ts +6 -6
  42. package/dist/types/resources/memory.d.ts +3 -3
  43. package/dist/types/resources/operators.d.ts +18 -18
  44. package/dist/types/resources/personas.d.ts +4 -4
  45. package/dist/types/resources/phone-numbers.d.ts +5 -5
  46. package/dist/types/resources/recordings.d.ts +2 -2
  47. package/dist/types/resources/review-queue.d.ts +17 -17
  48. package/dist/types/resources/safety.d.ts +5 -5
  49. package/dist/types/resources/services.d.ts +4 -4
  50. package/dist/types/resources/settings.d.ts +14 -14
  51. package/dist/types/resources/simulations.d.ts +6 -6
  52. package/dist/types/resources/skills.d.ts +5 -5
  53. package/dist/types/resources/triggers.d.ts +8 -8
  54. package/dist/types/resources/webhook-destinations.d.ts +6 -6
  55. package/dist/types/resources/workspaces.d.ts +5 -5
  56. package/dist/types/resources/world.d.ts +18 -18
  57. package/package.json +10 -4
package/dist/index.cjs CHANGED
@@ -42,6 +42,7 @@ __export(index_exports, {
42
42
  ParseError: () => ParseError,
43
43
  PermissionError: () => PermissionError,
44
44
  RateLimitError: () => RateLimitError,
45
+ RequestTimeoutError: () => RequestTimeoutError,
45
46
  ServerError: () => ServerError,
46
47
  ServiceUnavailableError: () => ServiceUnavailableError,
47
48
  ValidationError: () => ValidationError,
@@ -49,17 +50,20 @@ __export(index_exports, {
49
50
  actionId: () => actionId,
50
51
  agentId: () => agentId,
51
52
  apiKeyId: () => apiKeyId,
53
+ buildLastResponse: () => buildLastResponse,
52
54
  callId: () => callId,
53
55
  contextGraphId: () => contextGraphId,
54
56
  dataSourceId: () => dataSourceId,
55
57
  entityId: () => entityId,
56
58
  eventId: () => eventId,
59
+ extractRequestId: () => extractRequestId,
57
60
  functionId: () => functionId,
58
61
  integrationId: () => integrationId,
59
62
  isAmigoError: () => isAmigoError,
60
63
  isAuthenticationError: () => isAuthenticationError,
61
64
  isNotFoundError: () => isNotFoundError,
62
65
  isRateLimitError: () => isRateLimitError,
66
+ isRequestTimeoutError: () => isRequestTimeoutError,
63
67
  paginate: () => paginate,
64
68
  parseRateLimitHeaders: () => parseRateLimitHeaders,
65
69
  parseWebhookEvent: () => parseWebhookEvent,
@@ -191,6 +195,13 @@ var NetworkError = class extends AmigoError {
191
195
  }
192
196
  }
193
197
  };
198
+ var RequestTimeoutError = class extends NetworkError {
199
+ timeoutMs;
200
+ constructor(message, timeoutMs, cause) {
201
+ super(message, cause);
202
+ this.timeoutMs = timeoutMs;
203
+ }
204
+ };
194
205
  var ParseError = class extends AmigoError {
195
206
  body;
196
207
  constructor(message, body) {
@@ -264,6 +275,9 @@ function isRateLimitError(err) {
264
275
  function isAuthenticationError(err) {
265
276
  return err instanceof AuthenticationError;
266
277
  }
278
+ function isRequestTimeoutError(err) {
279
+ return err instanceof RequestTimeoutError;
280
+ }
267
281
 
268
282
  // src/core/openapi-client.ts
269
283
  var import_openapi_fetch = __toESM(require("openapi-fetch"), 1);
@@ -286,6 +300,20 @@ function createAuthMiddleware(config) {
286
300
  };
287
301
  }
288
302
 
303
+ // src/core/rate-limit.ts
304
+ function parseRateLimitHeaders(headers) {
305
+ const limit = headers.get("x-ratelimit-limit");
306
+ const remaining = headers.get("x-ratelimit-remaining");
307
+ const reset = headers.get("x-ratelimit-reset");
308
+ const retryAfter = headers.get("retry-after");
309
+ return {
310
+ limit: limit ? parseInt(limit, 10) : null,
311
+ remaining: remaining ? parseInt(remaining, 10) : null,
312
+ reset: reset ? new Date(parseInt(reset, 10) * 1e3) : null,
313
+ retryAfter: retryAfter ? parseInt(retryAfter, 10) : null
314
+ };
315
+ }
316
+
289
317
  // src/core/retry.ts
290
318
  var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
291
319
  var POST_RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429]);
@@ -319,28 +347,106 @@ function parseRetryAfterHeader(header) {
319
347
  }
320
348
  return void 0;
321
349
  }
322
- function resolveRetryOptions(opts) {
350
+ function resolveRetryOptions(opts, maxRetries) {
351
+ const maxAttempts = typeof maxRetries === "number" && Number.isFinite(maxRetries) ? Math.max(1, Math.floor(maxRetries) + 1) : opts?.maxAttempts ?? 3;
323
352
  return {
324
- maxAttempts: opts?.maxAttempts ?? 3,
353
+ maxAttempts,
325
354
  baseDelayMs: opts?.baseDelayMs ?? 250,
326
355
  maxDelayMs: opts?.maxDelayMs ?? 3e4
327
356
  };
328
357
  }
329
358
 
359
+ // src/core/utils.ts
360
+ function extractRequestId(response) {
361
+ return response.headers.get("x-request-id");
362
+ }
363
+ function buildLastResponse(response) {
364
+ return {
365
+ requestId: extractRequestId(response),
366
+ statusCode: response.status,
367
+ headers: response.headers,
368
+ rateLimit: parseRateLimitHeaders(response.headers)
369
+ };
370
+ }
371
+ function extractData(result) {
372
+ if (result.data !== void 0) {
373
+ return attachResponseMetadata(result.data, result.response);
374
+ }
375
+ throw new ParseError(
376
+ "Unexpected empty response from API",
377
+ result.error !== void 0 ? JSON.stringify(result.error) : void 0
378
+ );
379
+ }
380
+ function withResponse(result) {
381
+ const data = extractData(result);
382
+ const lastResponse = buildLastResponse(result.response);
383
+ return {
384
+ data,
385
+ response: result.response,
386
+ requestId: lastResponse.requestId,
387
+ rateLimit: lastResponse.rateLimit
388
+ };
389
+ }
390
+ async function* paginate(fetcher) {
391
+ let token = void 0;
392
+ while (true) {
393
+ const page = await fetcher(token);
394
+ for (const item of page.items) {
395
+ yield item;
396
+ }
397
+ if (!page.has_more || page.continuation_token === null) break;
398
+ token = page.continuation_token;
399
+ }
400
+ }
401
+ function attachResponseMetadata(data, response) {
402
+ if (!response || typeof data !== "object" || data === null) {
403
+ return data;
404
+ }
405
+ const target = data;
406
+ const lastResponse = buildLastResponse(response);
407
+ defineHiddenMetadata(target, "_request_id", lastResponse.requestId);
408
+ defineHiddenMetadata(target, "lastResponse", lastResponse);
409
+ return target;
410
+ }
411
+ function defineHiddenMetadata(target, key, value) {
412
+ try {
413
+ Object.defineProperty(target, key, {
414
+ value,
415
+ enumerable: false,
416
+ configurable: true,
417
+ writable: false
418
+ });
419
+ } catch {
420
+ }
421
+ }
422
+
330
423
  // src/core/openapi-client.ts
331
424
  var createClient = typeof import_openapi_fetch.default === "function" ? import_openapi_fetch.default : import_openapi_fetch.default.default;
332
425
  function createPlatformClient(config) {
333
- const retryOpts = resolveRetryOptions(config.retry);
334
426
  const baseFetch = config.fetch ?? globalThis.fetch;
335
427
  const retryingFetch = async (input, init) => {
336
- const method = (init?.method ?? "GET").toUpperCase();
337
- const signal = init?.signal;
428
+ const baseRequest = input instanceof Request ? input : new Request(input, init);
429
+ const method = baseRequest.method.toUpperCase();
430
+ const requestRetry = getRequestOption(baseRequest, "retry");
431
+ const requestMaxRetries = getRequestOption(baseRequest, "maxRetries");
432
+ const retryOpts = resolveRetryOptions(
433
+ requestRetry ?? config.retry,
434
+ requestMaxRetries ?? config.maxRetries
435
+ );
436
+ const timeoutMs = getRequestOption(baseRequest, "timeout") ?? config.timeout;
338
437
  const isIdempotent = method === "GET" || method === "HEAD" || method === "OPTIONS";
339
438
  for (let attempt = 0; attempt < retryOpts.maxAttempts; attempt++) {
340
439
  let response;
341
440
  let error;
441
+ let timedOut = false;
342
442
  try {
343
- response = await baseFetch(input, init);
443
+ const prepared = prepareRequestForAttempt(baseRequest, timeoutMs);
444
+ try {
445
+ response = await baseFetch(prepared.request, init);
446
+ } finally {
447
+ timedOut = prepared.timedOut;
448
+ prepared.cleanup();
449
+ }
344
450
  } catch (err) {
345
451
  error = err;
346
452
  }
@@ -348,6 +454,9 @@ function createPlatformClient(config) {
348
454
  const ctx = { method, attempt, response, options: retryOpts };
349
455
  const attemptsRemain = attempt + 1 < retryOpts.maxAttempts;
350
456
  if (error) {
457
+ if (timedOut) {
458
+ throw new RequestTimeoutError(`Request timed out after ${timeoutMs}ms`, timeoutMs, error);
459
+ }
351
460
  if (isIdempotent && attemptsRemain) {
352
461
  await sleep(computeDelay(attempt, new Response(), retryOpts));
353
462
  continue;
@@ -359,7 +468,7 @@ function createPlatformClient(config) {
359
468
  }
360
469
  if (response && attemptsRemain && shouldRetry(ctx)) {
361
470
  const delay = computeDelay(attempt, response, retryOpts);
362
- if (signal?.aborted) return response;
471
+ if (baseRequest.signal.aborted) return response;
363
472
  await sleep(delay);
364
473
  continue;
365
474
  }
@@ -369,7 +478,8 @@ function createPlatformClient(config) {
369
478
  };
370
479
  const client = createClient({
371
480
  baseUrl: config.baseUrl,
372
- fetch: retryingFetch
481
+ fetch: retryingFetch,
482
+ headers: config.headers
373
483
  });
374
484
  const errorMiddleware = {
375
485
  async onResponse({ response }) {
@@ -380,32 +490,95 @@ function createPlatformClient(config) {
380
490
  }
381
491
  };
382
492
  const authMiddleware = createAuthMiddleware({ apiKey: config.apiKey });
493
+ const hookMiddleware = config.hooks ? {
494
+ async onRequest({ request, schemaPath, id }) {
495
+ await config.hooks?.onRequest?.({ request, schemaPath, id });
496
+ return request;
497
+ },
498
+ async onResponse({ request, response, schemaPath, id }) {
499
+ await config.hooks?.onResponse?.({
500
+ id,
501
+ request,
502
+ response,
503
+ schemaPath,
504
+ requestId: extractRequestId(response),
505
+ rateLimit: parseRateLimitHeaders(response.headers)
506
+ });
507
+ return response;
508
+ },
509
+ async onError({ request, error, schemaPath, id }) {
510
+ await config.hooks?.onError?.({ id, request, error, schemaPath });
511
+ }
512
+ } : void 0;
383
513
  client.use(authMiddleware);
384
514
  client.use(errorMiddleware);
515
+ if (hookMiddleware) {
516
+ client.use(hookMiddleware);
517
+ }
385
518
  return client;
386
519
  }
387
520
  function sleep(ms) {
388
521
  return new Promise((resolve) => setTimeout(resolve, ms));
389
522
  }
390
-
391
- // src/core/utils.ts
392
- function extractData(result) {
393
- if (result.data !== void 0) return result.data;
394
- throw new ParseError(
395
- "Unexpected empty response from API",
396
- result.error !== void 0 ? JSON.stringify(result.error) : void 0
397
- );
523
+ function getRequestOption(request, key) {
524
+ const value = request[key];
525
+ return value;
398
526
  }
399
- async function* paginate(fetcher) {
400
- let token = void 0;
401
- while (true) {
402
- const page = await fetcher(token);
403
- for (const item of page.items) {
404
- yield item;
527
+ function prepareRequestForAttempt(request, timeoutMs) {
528
+ const attemptRequest = request.clone();
529
+ const timeout = createTimeoutSignal(attemptRequest.signal, timeoutMs);
530
+ if (!timeout.signal) {
531
+ return {
532
+ request: attemptRequest,
533
+ timedOut: false,
534
+ cleanup: timeout.cleanup
535
+ };
536
+ }
537
+ return {
538
+ request: new Request(attemptRequest, { signal: timeout.signal }),
539
+ get timedOut() {
540
+ return timeout.didTimeout;
541
+ },
542
+ cleanup: timeout.cleanup
543
+ };
544
+ }
545
+ function createTimeoutSignal(upstream, timeoutMs) {
546
+ if (!timeoutMs || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
547
+ return {
548
+ signal: upstream ?? void 0,
549
+ didTimeout: false,
550
+ cleanup: () => {
551
+ }
552
+ };
553
+ }
554
+ const controller = new AbortController();
555
+ let didTimeout = false;
556
+ const cleanups = [];
557
+ const onAbort = () => controller.abort(upstream?.reason);
558
+ if (upstream) {
559
+ if (upstream.aborted) {
560
+ controller.abort(upstream.reason);
561
+ } else {
562
+ upstream.addEventListener("abort", onAbort, { once: true });
563
+ cleanups.push(() => upstream.removeEventListener("abort", onAbort));
405
564
  }
406
- if (!page.has_more || page.continuation_token === null) break;
407
- token = page.continuation_token;
408
565
  }
566
+ const timer = setTimeout(() => {
567
+ didTimeout = true;
568
+ controller.abort();
569
+ }, timeoutMs);
570
+ cleanups.push(() => clearTimeout(timer));
571
+ return {
572
+ signal: controller.signal,
573
+ get didTimeout() {
574
+ return didTimeout;
575
+ },
576
+ cleanup: () => {
577
+ for (const cleanup of cleanups) {
578
+ cleanup();
579
+ }
580
+ }
581
+ };
409
582
  }
410
583
 
411
584
  // src/resources/base.ts
@@ -2184,20 +2357,6 @@ var simulationSessionId = (id) => id;
2184
2357
  var functionId = (id) => id;
2185
2358
  var dataSourceId = (id) => id;
2186
2359
 
2187
- // src/core/rate-limit.ts
2188
- function parseRateLimitHeaders(headers) {
2189
- const limit = headers.get("x-ratelimit-limit");
2190
- const remaining = headers.get("x-ratelimit-remaining");
2191
- const reset = headers.get("x-ratelimit-reset");
2192
- const retryAfter = headers.get("retry-after");
2193
- return {
2194
- limit: limit ? parseInt(limit, 10) : null,
2195
- remaining: remaining ? parseInt(remaining, 10) : null,
2196
- reset: reset ? new Date(parseInt(reset, 10) * 1e3) : null,
2197
- retryAfter: retryAfter ? parseInt(retryAfter, 10) : null
2198
- };
2199
- }
2200
-
2201
2360
  // src/core/webhooks.ts
2202
2361
  var textEncoder = new TextEncoder();
2203
2362
  var MAX_TIMESTAMP_SKEW_MS = 5 * 60 * 1e3;
@@ -2211,7 +2370,11 @@ var WebhookVerificationError = class extends Error {
2211
2370
  async function verifyWebhookSignature(payloadOrOptions, signature, secret) {
2212
2371
  const options = normalizeVerificationOptions(payloadOrOptions, signature, secret);
2213
2372
  const payloadBytes = toUint8Array(options.payload);
2214
- const expectedSignature = await signWebhookPayload(payloadBytes, options.secret, options.timestamp);
2373
+ const expectedSignature = await signWebhookPayload(
2374
+ payloadBytes,
2375
+ options.secret,
2376
+ options.timestamp
2377
+ );
2215
2378
  const actualSignature = normalizeSignature(options.signature);
2216
2379
  if (!actualSignature || !constantTimeEqual(expectedSignature, actualSignature)) {
2217
2380
  return false;
@@ -2292,7 +2455,7 @@ async function signWebhookPayload(payload, secret, timestamp) {
2292
2455
  ["sign"]
2293
2456
  );
2294
2457
  const message = timestamp ? concatUint8Arrays(textEncoder.encode(`v1:${timestamp}:`), payload) : payload;
2295
- const mac = await crypto.subtle.sign("HMAC", key, message);
2458
+ const mac = await crypto.subtle.sign("HMAC", key, toCryptoBuffer(message));
2296
2459
  return new Uint8Array(mac);
2297
2460
  }
2298
2461
  function normalizeSignature(signature) {
@@ -2328,10 +2491,16 @@ function concatUint8Arrays(left, right) {
2328
2491
  combined.set(right, left.length);
2329
2492
  return combined;
2330
2493
  }
2494
+ function toCryptoBuffer(bytes) {
2495
+ const copy = Uint8Array.from(bytes);
2496
+ return copy.buffer;
2497
+ }
2331
2498
 
2332
2499
  // src/index.ts
2333
2500
  var DEFAULT_BASE_URL = "https://api.platform.amigo.ai";
2334
2501
  var AmigoClient = class {
2502
+ workspaceId;
2503
+ baseUrl;
2335
2504
  workspaces;
2336
2505
  apiKeys;
2337
2506
  agents;
@@ -2360,6 +2529,7 @@ var AmigoClient = class {
2360
2529
  safety;
2361
2530
  compliance;
2362
2531
  functions;
2532
+ api;
2363
2533
  constructor(config) {
2364
2534
  if (!config.apiKey || typeof config.apiKey !== "string") {
2365
2535
  throw new ConfigurationError("apiKey is required and must be a non-empty string");
@@ -2372,9 +2542,16 @@ var AmigoClient = class {
2372
2542
  apiKey: config.apiKey,
2373
2543
  baseUrl,
2374
2544
  retry: config.retry,
2545
+ maxRetries: config.maxRetries,
2546
+ timeout: config.timeout,
2547
+ headers: config.headers,
2548
+ hooks: config.hooks,
2375
2549
  fetch: config.fetch
2376
2550
  });
2377
2551
  const ws = config.workspaceId;
2552
+ this.workspaceId = ws;
2553
+ this.baseUrl = baseUrl;
2554
+ this.api = client;
2378
2555
  this.workspaces = new WorkspacesResource(client, ws);
2379
2556
  this.apiKeys = new ApiKeysResource(client, ws);
2380
2557
  this.agents = new AgentsResource(client, ws);
@@ -2403,5 +2580,56 @@ var AmigoClient = class {
2403
2580
  this.compliance = new ComplianceResource(client, ws);
2404
2581
  this.functions = new FunctionsResource(client, ws);
2405
2582
  }
2583
+ async GET(path, init) {
2584
+ return withResponse(
2585
+ await this.api.GET(path, withWorkspaceId(path, init, this.workspaceId))
2586
+ );
2587
+ }
2588
+ async POST(path, init) {
2589
+ return withResponse(
2590
+ await this.api.POST(path, withWorkspaceId(path, init, this.workspaceId))
2591
+ );
2592
+ }
2593
+ async PUT(path, init) {
2594
+ return withResponse(
2595
+ await this.api.PUT(path, withWorkspaceId(path, init, this.workspaceId))
2596
+ );
2597
+ }
2598
+ async PATCH(path, init) {
2599
+ return withResponse(
2600
+ await this.api.PATCH(path, withWorkspaceId(path, init, this.workspaceId))
2601
+ );
2602
+ }
2603
+ async DELETE(path, init) {
2604
+ return withResponse(
2605
+ await this.api.DELETE(path, withWorkspaceId(path, init, this.workspaceId))
2606
+ );
2607
+ }
2608
+ async HEAD(path, init) {
2609
+ return withResponse(
2610
+ await this.api.HEAD(path, withWorkspaceId(path, init, this.workspaceId))
2611
+ );
2612
+ }
2613
+ async OPTIONS(path, init) {
2614
+ return withResponse(
2615
+ await this.api.OPTIONS(path, withWorkspaceId(path, init, this.workspaceId))
2616
+ );
2617
+ }
2406
2618
  };
2619
+ function withWorkspaceId(path, init, workspaceId2) {
2620
+ if (!path.includes("{workspace_id}")) {
2621
+ return init ?? {};
2622
+ }
2623
+ const current = init ?? {};
2624
+ return {
2625
+ ...current,
2626
+ params: {
2627
+ ...current.params ?? {},
2628
+ path: {
2629
+ workspace_id: workspaceId2,
2630
+ ...current.params?.path ?? {}
2631
+ }
2632
+ }
2633
+ };
2634
+ }
2407
2635
  //# sourceMappingURL=index.cjs.map