@slates/provider 1.0.0-rc.28 → 1.0.0-rc.29

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.cjs CHANGED
@@ -30,6 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ API_ERROR_MAX_DETAILS: () => API_ERROR_MAX_DETAILS,
34
+ API_ERROR_MAX_MESSAGE_LENGTH: () => API_ERROR_MAX_MESSAGE_LENGTH,
35
+ API_ERROR_TRUNCATED_PLACEHOLDER: () => API_ERROR_TRUNCATED_PLACEHOLDER,
33
36
  AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX: () => AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX,
34
37
  AuthConfigSecretRedactor: () => AuthConfigSecretRedactor,
35
38
  GET_FILE_URL_TOOL_ID: () => GET_FILE_URL_TOOL_ID,
@@ -68,8 +71,10 @@ __export(index_exports, {
68
71
  createSlateError: () => createSlateError,
69
72
  createTextAttachment: () => createTextAttachment,
70
73
  createUrlAttachment: () => createUrlAttachment,
74
+ decodeApiErrorBody: () => decodeApiErrorBody,
71
75
  extractApiErrorMessage: () => extractApiErrorMessage,
72
76
  getApiErrorResponse: () => getApiErrorResponse,
77
+ getApiErrorResponseWithBody: () => getApiErrorResponseWithBody,
73
78
  getApiErrorStatus: () => getApiErrorStatus,
74
79
  getBase64ByteLength: () => getBase64ByteLength,
75
80
  getCurrentContext: () => getCurrentContext,
@@ -87,6 +92,7 @@ __export(index_exports, {
87
92
  isAxiosErrorLike: () => isAxiosErrorLike,
88
93
  isServiceErrorData: () => isServiceErrorData,
89
94
  isUrlEmbeddedCredential: () => isUrlEmbeddedCredential,
95
+ looksLikeHtmlErrorBody: () => looksLikeHtmlErrorBody,
90
96
  mapServiceErrorCode: () => mapServiceErrorCode,
91
97
  mapServiceErrorToSlateErrorInput: () => mapServiceErrorToSlateErrorInput,
92
98
  mergeScopes: () => mergeScopes,
@@ -94,6 +100,8 @@ __export(index_exports, {
94
100
  normalizeOAuthTokenResponse: () => normalizeOAuthTokenResponse,
95
101
  pickDefined: () => pickDefined,
96
102
  publicTool: () => publicTool,
103
+ pushBoundedApiErrorDetail: () => pushBoundedApiErrorDetail,
104
+ readApiErrorText: () => readApiErrorText,
97
105
  redactUrlAttachmentSecrets: () => redactUrlAttachmentSecrets,
98
106
  requestAxios: () => requestAxios,
99
107
  requestAxiosData: () => requestAxiosData,
@@ -106,6 +114,7 @@ __export(index_exports, {
106
114
  tool: () => tool,
107
115
  trigger: () => trigger,
108
116
  triggerGroup: () => triggerGroup,
117
+ truncateApiErrorMessage: () => truncateApiErrorMessage,
109
118
  uploadAttachmentDirect: () => uploadAttachmentDirect,
110
119
  validateScopes: () => validateScopes,
111
120
  verifyHmacSignature: () => verifyHmacSignature
@@ -178,2152 +187,2537 @@ var SlateAction = class {
178
187
 
179
188
  // src/error/api.ts
180
189
  var import_error = require("@lowerdeck/error");
181
- var DEFAULT_DETAIL_KEYS = ["message", "detail", "error", "error_description", "code"];
182
- var DEFAULT_NESTED_KEYS = ["errors"];
183
- var isApiErrorRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
184
- var pushDetail = (details, value, options = {}) => {
185
- if (typeof value !== "string" && (options.includeNumbers === false || typeof value !== "number")) {
186
- return;
187
- }
188
- let detail = String(value).trim();
189
- if (detail && !details.includes(detail)) {
190
- details.push(detail);
191
- }
192
- };
193
- var collectApiErrorDetails = (value, details, options = {}) => {
194
- if (Array.isArray(value)) {
195
- for (let item of value) {
196
- collectApiErrorDetails(item, details, options);
197
- }
198
- return;
199
- }
200
- if (!isApiErrorRecord(value)) {
201
- pushDetail(details, value, options);
202
- return;
203
- }
204
- for (let key of options.detailKeys ?? DEFAULT_DETAIL_KEYS) {
205
- pushDetail(details, value[key], options);
190
+
191
+ // src/auth/redact.ts
192
+ var AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX = "$$MT$secret$authConfig$";
193
+ var ALWAYS = () => true;
194
+ var AuthConfigSecretRedactor = class {
195
+ // A value shared by several fields keeps every path, so a filter that rejects one
196
+ // field (e.g. `username`) can still match another (e.g. `token`) with the same value.
197
+ secretToPaths = /* @__PURE__ */ new Map();
198
+ constructor(authConfig) {
199
+ if (authConfig) this.buildSecretMap(authConfig);
206
200
  }
207
- for (let key of options.nestedKeys ?? DEFAULT_NESTED_KEYS) {
208
- collectApiErrorDetails(value[key], details, options);
201
+ redact(value, wholeValue = ALWAYS) {
202
+ return this.transform(value, (stringValue) => {
203
+ return this.placeholderFor(stringValue, wholeValue) ?? stringValue;
204
+ });
209
205
  }
210
- };
211
- var getSlateErrorResponse = (error) => {
212
- if (error.name !== "SlateError" || !isApiErrorRecord(error.data)) {
213
- return void 0;
206
+ /**
207
+ * `embeddable` limits which secrets are also replaced inside longer strings;
208
+ * `wholeValue` limits which secrets replace a string that equals them exactly.
209
+ */
210
+ redactEmbedded(value, embeddable = ALWAYS, wholeValue = ALWAYS) {
211
+ let embeddedPlaceholders = /* @__PURE__ */ new Map();
212
+ for (let secret of this.secretToPaths.keys()) {
213
+ let placeholder = this.placeholderFor(secret, embeddable);
214
+ if (placeholder) embeddedPlaceholders.set(secret, placeholder);
215
+ }
216
+ if (embeddedPlaceholders.size === 0) return this.redact(value, wholeValue);
217
+ let pattern = new RegExp(
218
+ [...embeddedPlaceholders.keys()].sort((a, b) => b.length - a.length).map((secret) => secret.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"),
219
+ "g"
220
+ );
221
+ return this.transform(value, (stringValue) => {
222
+ let exactPlaceholder = this.placeholderFor(stringValue, wholeValue);
223
+ if (exactPlaceholder) return exactPlaceholder;
224
+ return stringValue.replace(pattern, (secret) => `${embeddedPlaceholders.get(secret)}$$`);
225
+ });
214
226
  }
215
- let data = error.data;
216
- let upstream = isApiErrorRecord(data.upstream) ? data.upstream : void 0;
217
- let status = upstream?.status ?? data.status;
218
- return typeof status === "number" || typeof status === "string" ? { status } : void 0;
219
- };
220
- var getApiErrorResponse = (error) => {
221
- if (!isApiErrorRecord(error)) {
227
+ // The last registered path that passes the filter wins, matching the historical
228
+ // last-write-wins behavior when no filter is given.
229
+ placeholderFor(value, filter) {
230
+ let paths = this.secretToPaths.get(value);
231
+ if (!paths) return void 0;
232
+ for (let index = paths.length - 1; index >= 0; index--) {
233
+ let path = paths[index];
234
+ if (path !== void 0 && filter(value, path))
235
+ return `${AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX}${path}`;
236
+ }
222
237
  return void 0;
223
238
  }
224
- if (!isApiErrorRecord(error.response)) {
225
- return getSlateErrorResponse(error);
226
- }
227
- let response = error.response;
228
- return {
229
- status: typeof response.status === "number" || typeof response.status === "string" ? response.status : void 0,
230
- statusText: typeof response.statusText === "string" ? response.statusText : void 0,
231
- data: response.data
232
- };
233
- };
234
- var getApiErrorStatus = (error) => getApiErrorResponse(error)?.status;
235
- var statusLabelForApiError = (status, statusText) => status !== void 0 ? `HTTP ${status}${statusText ? ` ${statusText}` : ""}: ` : "";
236
- var extractApiErrorMessage = (error, options = {}) => {
237
- let details = [];
238
- let response = options.response ?? getApiErrorResponse(error);
239
- collectApiErrorDetails(response?.data, details, options);
240
- if (details.length > 0) {
241
- return details.join(options.separator ?? " - ");
242
- }
243
- if (error instanceof Error && error.message) {
244
- return error.message;
245
- }
246
- return options.fallbackMessage ?? "Unknown error";
247
- };
248
- var createApiServiceError = (message, options = {}) => {
249
- let error = new import_error.ServiceError((0, import_error.badRequestError)({ message }));
250
- if (options.reason !== void 0) {
251
- error.data.reason = options.reason;
252
- }
253
- if ("upstreamStatus" in options) {
254
- error.data.upstreamStatus = options.upstreamStatus;
239
+ buildSecretMap(value, path = []) {
240
+ if (typeof value === "string") {
241
+ if (value.length === 0) return;
242
+ let paths = this.secretToPaths.get(value);
243
+ if (paths) paths.push(path.join("."));
244
+ else this.secretToPaths.set(value, [path.join(".")]);
245
+ return;
246
+ }
247
+ if (Array.isArray(value)) {
248
+ value.forEach((item, index) => {
249
+ this.buildSecretMap(item, [...path, String(index)]);
250
+ });
251
+ return;
252
+ }
253
+ if (this.isPlainObject(value)) {
254
+ Object.entries(value).forEach(([key, nestedValue]) => {
255
+ this.buildSecretMap(nestedValue, [...path, key]);
256
+ });
257
+ }
255
258
  }
256
- if ("upstreamCode" in options) {
257
- error.data.upstreamCode = options.upstreamCode;
259
+ transform(value, transformString) {
260
+ if (typeof value === "string") {
261
+ return transformString(value);
262
+ }
263
+ if (Array.isArray(value)) {
264
+ return value.map((item) => this.transform(item, transformString));
265
+ }
266
+ if (this.isPlainObject(value)) {
267
+ let result = {};
268
+ Object.entries(value).forEach(([key, nestedValue]) => {
269
+ result[key] = this.transform(nestedValue, transformString);
270
+ });
271
+ return result;
272
+ }
273
+ return value;
258
274
  }
259
- if (options.parent instanceof Error) {
260
- error.setParent(options.parent);
275
+ isPlainObject(value) {
276
+ return typeof value === "object" && value !== null && !Array.isArray(value);
261
277
  }
262
- return error;
263
- };
264
- var helpers = {
265
- collectDetails: collectApiErrorDetails,
266
- extractMessage: extractApiErrorMessage,
267
- getResponse: getApiErrorResponse,
268
- getStatus: getApiErrorStatus,
269
- isRecord: isApiErrorRecord,
270
- statusLabelFor: statusLabelForApiError
271
278
  };
272
- var buildApiServiceError = (error, options) => {
273
- if (error instanceof import_error.ServiceError) {
274
- return error;
275
- }
276
- let operation = options.operation ?? "request";
277
- let response = options.extractResponse?.(error, helpers) ?? getApiErrorResponse(error);
278
- let status = options.extractStatus?.(error, response, helpers) ?? response?.status;
279
- let message = options.extractMessage?.(error, helpers) ?? extractApiErrorMessage(error, { ...options, response });
280
- let statusLabel = statusLabelForApiError(status, response?.statusText);
281
- let fullMessage = options.formatMessage?.({
282
- providerLabel: options.providerLabel,
283
- operation,
284
- statusLabel,
285
- message,
286
- response,
287
- status
288
- }) ?? `${options.providerLabel} API ${operation} failed: ${statusLabel}${message}`;
289
- return createApiServiceError(fullMessage, {
290
- reason: options.reason,
291
- upstreamStatus: status,
292
- upstreamCode: options.extractUpstreamCode?.(error, response, helpers),
293
- parent: options.parent ?? error
279
+ var URL_CREDENTIAL_KEY = /^(?:.*[-_])?(?:token|secret|password|api[-_]?key)$/i;
280
+ var isUrlEmbeddedCredential = (secret, path) => secret.length >= 8 && URL_CREDENTIAL_KEY.test(path.split(".").pop() ?? "");
281
+ var redactUrlAttachmentSecrets = (attachments, authConfig) => {
282
+ if (!authConfig || !attachments) return attachments;
283
+ let redactor = new AuthConfigSecretRedactor(authConfig);
284
+ return attachments.map((attachment) => {
285
+ if (attachment.content.type !== "url") return attachment;
286
+ let { url, headers, query } = attachment.content;
287
+ return {
288
+ ...attachment,
289
+ content: {
290
+ ...attachment.content,
291
+ url: redactor.redactEmbedded(url, isUrlEmbeddedCredential),
292
+ ...headers ? { headers: redactor.redactEmbedded(headers) } : {},
293
+ ...query ? { query: redactor.redactEmbedded(query) } : {}
294
+ }
295
+ };
294
296
  });
295
297
  };
296
298
 
297
- // src/error/axios.ts
298
- var import_axios = require("axios");
299
-
300
- // src/context/hook.ts
301
- var import_async_hooks = require("async_hooks");
302
- var slateContextStorageKey = /* @__PURE__ */ Symbol.for("slates.provider.context.asyncLocalStorage");
303
- var globalWithSlateContext = globalThis;
304
- var asyncLocalStorage = globalWithSlateContext[slateContextStorageKey] ?? new import_async_hooks.AsyncLocalStorage();
305
- globalWithSlateContext[slateContextStorageKey] = asyncLocalStorage;
306
- var runWithContext = (context, fn) => {
307
- return asyncLocalStorage.run(context, fn);
308
- };
309
- var getCurrentContext = () => {
310
- let context = asyncLocalStorage.getStore();
311
- if (!context) {
312
- throw new Error("No Slate context is available");
313
- }
314
- return context;
315
- };
316
-
317
- // src/error/defaults.ts
318
- var DEFAULT_CODE = "internal.unexpected";
319
- var DEFAULT_MESSAGES = {
320
- "declaration.invalid_definition": "The slate definition is invalid.",
321
- "context.missing": "No Slate context is available.",
322
- "input.invalid": "The provided input is invalid.",
323
- "request.bad": "The request is invalid.",
324
- "request.invalid_version": "The requested version is invalid.",
325
- "request.precondition_failed": "The request precondition failed.",
326
- "request.not_acceptable": "The request is not acceptable.",
327
- "request.rate_limited": "Too many requests were made in a short period of time.",
328
- "config.invalid": "The provided configuration is invalid.",
329
- "auth.required": "Authentication is required.",
330
- "auth.invalid": "Authentication failed.",
331
- "auth.expired": "Authentication has expired.",
332
- "permission.denied": "Permission was denied.",
333
- "resource.not_found": "The requested resource was not found.",
334
- "resource.conflict": "The requested resource is in conflict.",
335
- "resource.gone": "The requested resource is no longer available.",
336
- "payment.required": "Payment is required to continue.",
337
- "operation.not_implemented": "The requested operation is not implemented.",
338
- "upstream.invalid_request": "The upstream service rejected the request.",
339
- "upstream.rate_limited": "The upstream service rate limited the request.",
340
- "upstream.timeout": "The upstream service timed out.",
341
- "upstream.network_error": "A network error occurred while contacting the upstream service.",
342
- "upstream.unavailable": "The upstream service is unavailable.",
343
- "upstream.invalid_response": "The upstream service returned an invalid response.",
344
- "upstream.error": "The upstream service returned an error.",
345
- "transport.invoke_failed": "The provider transport failed.",
346
- "internal.timeout": "The operation timed out.",
347
- "internal.unexpected": "An unexpected internal error occurred."
348
- };
349
- var SERVICE_ERROR_CODE_MAP = {
350
- invalid_data: "input.invalid",
351
- bad_request: "request.bad",
352
- not_found: "resource.not_found",
353
- unauthorized: "auth.required",
354
- forbidden: "permission.denied",
355
- invalid_version: "request.invalid_version",
356
- conflict: "resource.conflict",
357
- gone: "resource.gone",
358
- payment_required: "payment.required",
359
- precondition_failed: "request.precondition_failed",
360
- not_acceptable: "request.not_acceptable",
361
- not_implemented: "operation.not_implemented",
362
- too_many_requests: "request.rate_limited",
363
- timeout: "internal.timeout",
364
- internal_server_error: "internal.unexpected"
365
- };
366
-
367
- // src/error/utils.ts
368
- var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
369
- var normalizeKind = (code, kind) => {
370
- if (kind) return kind;
371
- if (code.startsWith("declaration.")) return "declaration";
372
- if (code.startsWith("input.")) return "validation";
373
- if (code.startsWith("request.")) return "request";
374
- if (code.startsWith("config.")) return "config";
375
- if (code.startsWith("auth.") || code.startsWith("permission.")) return "auth";
376
- if (code.startsWith("resource.")) return "resource";
377
- if (code.startsWith("payment.")) return "payment";
378
- if (code.startsWith("transport.")) return "transport";
379
- if (code.startsWith("upstream.")) return "upstream";
380
- return "internal";
381
- };
382
- var normalizeStatus = (code, status) => {
383
- if (status) return status;
384
- if (code === "input.invalid" || code === "request.bad" || code === "config.invalid")
385
- return 400;
386
- if (code === "request.invalid_version") return 400;
387
- if (code === "auth.required" || code === "auth.invalid" || code === "auth.expired")
388
- return 401;
389
- if (code === "payment.required") return 402;
390
- if (code === "permission.denied") return 403;
391
- if (code === "resource.not_found") return 404;
392
- if (code === "resource.conflict") return 409;
393
- if (code === "resource.gone") return 410;
394
- if (code === "request.not_acceptable") return 406;
395
- if (code === "request.precondition_failed") return 412;
396
- if (code === "request.rate_limited" || code === "upstream.rate_limited") return 429;
397
- if (code === "operation.not_implemented") return 501;
398
- if (code === "upstream.invalid_request") return 400;
399
- if (code === "upstream.timeout" || code === "internal.timeout") return 504;
400
- if (code === "upstream.unavailable") return 503;
401
- if (code === "upstream.error") return 502;
402
- return void 0;
403
- };
404
- var normalizeRetryable = (code, retryable) => {
405
- if (typeof retryable === "boolean") return retryable;
406
- return code === "request.rate_limited" || code === "upstream.rate_limited" || code === "upstream.timeout" || code === "upstream.network_error" || code === "upstream.unavailable" || code === "upstream.error" || code === "transport.invoke_failed" || code === "internal.timeout";
407
- };
408
- var getDefaultMessage = (code, message) => {
409
- if (message?.trim()) return message;
410
- return DEFAULT_MESSAGES[code] ?? DEFAULT_MESSAGES[DEFAULT_CODE] ?? "An unexpected internal error occurred.";
411
- };
412
- var cleanRecord = (value) => {
413
- if (!value) return void 0;
414
- let entries = Object.entries(value).filter(([, entry]) => entry !== void 0);
415
- if (entries.length === 0) return void 0;
416
- return Object.fromEntries(entries);
417
- };
418
- var mergeRecords = (left, right) => {
419
- if (!left && !right) return void 0;
420
- return cleanRecord({
421
- ...left ?? {},
422
- ...right ?? {}
423
- });
424
- };
425
- var mergeSlateErrorData = (base, override) => {
426
- if (!override) return base;
427
- return {
428
- ...base,
429
- ...override,
430
- provider: cleanRecord({
431
- ...base.provider ?? {},
432
- ...override.provider ?? {}
433
- }),
434
- upstream: cleanRecord({
435
- ...base.upstream ?? {},
436
- ...override.upstream ?? {}
437
- }),
438
- baggage: mergeRecords(base.baggage, override.baggage),
439
- issues: override.issues ?? base.issues,
440
- requestTraces: override.requestTraces ?? base.requestTraces
441
- };
442
- };
443
- var sanitizeForBaggage = (value, depth = 0) => {
444
- if (value == null) return value;
445
- if (depth >= 4) return "[truncated]";
446
- if (typeof value === "string") {
447
- return value.length > 2e3 ? `${value.slice(0, 2e3)}...[truncated]` : value;
448
- }
449
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
450
- return value;
451
- }
452
- if (Array.isArray(value)) {
453
- return value.slice(0, 20).map((item) => sanitizeForBaggage(item, depth + 1));
454
- }
455
- if (isRecord(value)) {
456
- return Object.fromEntries(
457
- Object.entries(value).slice(0, 30).map(([key, entry]) => [key, sanitizeForBaggage(entry, depth + 1)])
458
- );
459
- }
460
- return String(value);
461
- };
462
- var normalizeSlateErrorInput = (input) => {
463
- let code = input.code || DEFAULT_CODE;
464
- return {
465
- code,
466
- message: getDefaultMessage(code, input.message),
467
- kind: normalizeKind(code, input.kind),
468
- retryable: normalizeRetryable(code, input.retryable),
469
- status: normalizeStatus(code, input.status ?? input.upstream?.status),
470
- issues: input.issues,
471
- provider: cleanRecord(input.provider),
472
- upstream: cleanRecord({
473
- ...input.upstream,
474
- status: input.upstream?.status ?? input.status
475
- }),
476
- baggage: cleanRecord(input.baggage),
477
- requestTraces: input.requestTraces
478
- };
479
- };
480
- var isSlateErrorResponse = (error) => {
481
- if (!isRecord(error)) return false;
482
- return typeof error.code === "string" && typeof error.message === "string";
483
- };
484
-
485
- // src/error/axios.ts
486
- var getResponseField = (value, key) => {
487
- if (!isRecord(value)) return void 0;
488
- return value[key];
489
- };
490
- var getNestedMessage = (value) => {
491
- if (typeof value === "string") return value;
492
- if (!isRecord(value)) return void 0;
493
- let message = getResponseField(value, "message");
494
- if (typeof message === "string" && message.trim()) return message;
495
- let description = getResponseField(value, "description");
496
- if (typeof description === "string" && description.trim()) return description;
497
- let error = getResponseField(value, "error");
498
- if (typeof error === "string" && error.trim()) return error;
499
- if (isRecord(error)) {
500
- let nested = getNestedMessage(error);
501
- if (nested) return nested;
502
- }
503
- let errorDescription = getResponseField(value, "error_description");
504
- if (typeof errorDescription === "string" && errorDescription.trim()) {
505
- return errorDescription;
506
- }
507
- return void 0;
508
- };
509
- var getNestedCode = (value) => {
510
- if (!isRecord(value)) return void 0;
511
- let directCode = getResponseField(value, "code");
512
- if (typeof directCode === "string" && directCode.trim()) return directCode;
513
- let errorCode = getResponseField(value, "error_code");
514
- if (typeof errorCode === "string" && errorCode.trim()) return errorCode;
515
- let type = getResponseField(value, "type");
516
- if (typeof type === "string" && type.trim()) return type;
517
- let error = getResponseField(value, "error");
518
- if (typeof error === "string" && error.trim()) return error;
519
- if (isRecord(error)) return getNestedCode(error);
520
- return void 0;
521
- };
522
- var getNestedType = (value) => {
523
- if (!isRecord(value)) return void 0;
524
- let type = getResponseField(value, "type");
525
- if (typeof type === "string" && type.trim()) return type;
526
- let error = getResponseField(value, "error");
527
- if (isRecord(error)) {
528
- let nestedType = getNestedType(error);
529
- if (nestedType) return nestedType;
530
- }
531
- return void 0;
532
- };
533
- var getHeaderValue = (headers, key) => {
534
- if (!headers) return void 0;
535
- if (typeof headers.get === "function") {
536
- let value = headers.get(key);
537
- if (typeof value === "string" && value.trim()) return value;
538
- }
539
- if (isRecord(headers)) {
540
- for (let [headerKey, headerValue] of Object.entries(headers)) {
541
- if (headerKey.toLowerCase() !== key.toLowerCase()) continue;
542
- if (typeof headerValue === "string" && headerValue.trim()) return headerValue;
543
- if (Array.isArray(headerValue)) {
544
- let first = headerValue.find((item) => typeof item === "string" && item.trim());
545
- if (typeof first === "string") return first;
546
- }
547
- }
548
- }
549
- return void 0;
550
- };
551
- var buildRequestUrl = (error) => {
552
- let baseURL = error.config?.baseURL;
553
- let url = error.config?.url;
554
- if (!url) return void 0;
555
- if (!baseURL) return url;
556
- try {
557
- return new URL(url, baseURL).toString();
558
- } catch {
559
- return url;
560
- }
561
- };
562
- var getProviderDefaults = () => {
563
- try {
564
- let ctx = getCurrentContext();
565
- return {
566
- provider: {
567
- key: ctx.specification.key
568
- },
569
- ...ctx.getHttpTraces().length > 0 ? { requestTraces: ctx.getHttpTraces() } : {}
570
- };
571
- } catch {
572
- return {};
573
- }
574
- };
575
- var inferAxiosCode = (error, data) => {
576
- let status = error.response?.status;
577
- let axiosCode = error.code?.toUpperCase();
578
- let remoteCode = getNestedCode(data)?.toLowerCase();
579
- if (axiosCode === "ECONNABORTED" || axiosCode === "ETIMEDOUT" || status === 408 || remoteCode?.includes("timeout")) {
580
- return "upstream.timeout";
581
- }
582
- if (!error.response) {
583
- return "upstream.network_error";
584
- }
585
- if (status === 401) return "auth.invalid";
586
- if (status === 403) {
587
- return remoteCode?.includes("rate") ? "upstream.rate_limited" : "permission.denied";
588
- }
589
- if (status === 404) return "resource.not_found";
590
- if (status === 409) return "resource.conflict";
591
- if (status === 422 || status === 400) return "upstream.invalid_request";
592
- if (status === 429) return "upstream.rate_limited";
593
- if (status === 502 || status === 503 || status === 504) return "upstream.unavailable";
594
- if (status && status >= 500) return "upstream.error";
595
- return "upstream.error";
596
- };
597
- var inferAxiosMessage = (error, data, code) => {
598
- return getNestedMessage(data) ?? error.response?.statusText ?? error.message ?? getDefaultMessage(code);
599
- };
600
- var inferAxiosRetryable = (error, code) => {
601
- let headerValue = getHeaderValue(error.response?.headers, "retry-after");
602
- if (headerValue) return true;
603
- return normalizeRetryable(code, void 0);
604
- };
605
- var isAxiosErrorLike = (error) => (0, import_axios.isAxiosError)(error);
606
- var inferSlateErrorFromAxios = (error, options = {}) => {
607
- let responseData = error.response ? options.extractResponseData?.(error.response) ?? error.response.data : void 0;
608
- let code = inferAxiosCode(error, responseData);
609
- return normalizeSlateErrorInput({
610
- ...getProviderDefaults(),
611
- ...options.defaults,
612
- code: options.defaults?.code ?? code,
613
- message: options.defaults?.message ?? inferAxiosMessage(error, responseData, code),
614
- kind: options.defaults?.kind ?? normalizeKind(options.defaults?.code ?? code),
615
- retryable: options.defaults?.retryable ?? inferAxiosRetryable(error, options.defaults?.code ?? code),
616
- status: options.defaults?.status ?? error.response?.status,
617
- provider: {
618
- ...getProviderDefaults().provider,
619
- ...options.defaults?.provider ?? {}
620
- },
621
- upstream: {
622
- ...options.defaults?.upstream ?? {},
623
- status: error.response?.status ?? options.defaults?.upstream?.status,
624
- code: getNestedCode(responseData) ?? options.defaults?.upstream?.code,
625
- type: getNestedType(responseData) ?? options.defaults?.upstream?.type,
626
- requestId: getHeaderValue(error.response?.headers, "x-request-id") ?? getHeaderValue(error.response?.headers, "request-id") ?? getHeaderValue(error.response?.headers, "x-correlation-id") ?? options.defaults?.upstream?.requestId,
627
- method: error.config?.method?.toUpperCase() ?? options.defaults?.upstream?.method,
628
- url: buildRequestUrl(error) ?? options.defaults?.upstream?.url
629
- },
630
- baggage: mergeRecords(options.defaults?.baggage, {
631
- axiosCode: error.code,
632
- response: sanitizeForBaggage(responseData)
633
- })
634
- });
635
- };
636
-
637
- // src/error/service.ts
638
- var import_error2 = require("@lowerdeck/error");
639
- var SERVICE_ERROR_DATA_RESERVED_KEYS = /* @__PURE__ */ new Set([
640
- "status",
641
- "code",
642
- "message",
643
- "hint",
644
- "description",
645
- "reason",
646
- "errors",
647
- "object",
648
- "ok"
299
+ // src/axios/trace.ts
300
+ var traceDraftsByConfig = /* @__PURE__ */ new WeakMap();
301
+ var traceDraftsByHeaders = /* @__PURE__ */ new WeakMap();
302
+ var TRACE_TEXT_LIMIT = 10 * 1024;
303
+ var REDACTED_VALUE = "[redacted]";
304
+ var STRUCTURED_DEPTH_LIMIT = 6;
305
+ var STRUCTURED_ENTRY_LIMIT = 50;
306
+ var CORE_SECRET_KEY_ATOMS = [
307
+ // HTTP authentication
308
+ "authorization",
309
+ "proxy[-_.]?authorization",
310
+ "www[-_.]?authenticate",
311
+ "bearer",
312
+ // Generic tokens
313
+ "token",
314
+ "tokens",
315
+ "access[-_.]?token",
316
+ "refresh[-_.]?token",
317
+ "id[-_.]?token",
318
+ "auth[-_.]?token",
319
+ "bearer[-_.]?token",
320
+ "session[-_.]?token",
321
+ "api[-_.]?token",
322
+ "app[-_.]?token",
323
+ "user[-_.]?token",
324
+ "oauth[-_.]?token",
325
+ "personal[-_.]?access[-_.]?token",
326
+ "x[-_.]?auth[-_.]?token",
327
+ "x[-_.]?access[-_.]?token",
328
+ "x[-_.]?refresh[-_.]?token",
329
+ // API keys
330
+ "apikey",
331
+ "api[-_.]?key",
332
+ "app[-_.]?key",
333
+ "x[-_.]?api[-_.]?key",
334
+ "x[-_.]?app[-_.]?key",
335
+ // HubSpot legacy API key query param
336
+ "hapikey",
337
+ "access[-_.]?key",
338
+ // OAuth client credentials
339
+ "client[-_.]?secret",
340
+ "client[-_.]?key",
341
+ "consumer[-_.]?secret",
342
+ "consumer[-_.]?key",
343
+ // Cryptographic keys
344
+ "private[-_.]?key",
345
+ "privatekey",
346
+ "secret[-_.]?key",
347
+ "secretkey",
348
+ "secret[-_.]?access[-_.]?key",
349
+ "encryption[-_.]?key",
350
+ "decryption[-_.]?key",
351
+ "signing[-_.]?key",
352
+ "signing[-_.]?secret",
353
+ "master[-_.]?key",
354
+ "master[-_.]?secret",
355
+ "master[-_.]?password",
356
+ "shared[-_.]?secret",
357
+ "webhook[-_.]?secret",
358
+ "webhook[-_.]?signing[-_.]?secret",
359
+ // OAuth codes & PKCE
360
+ "auth[-_.]?code",
361
+ "authcode",
362
+ "authorization[-_.]?code",
363
+ "code[-_.]?verifier",
364
+ "code[-_.]?challenge",
365
+ // Passwords & passcodes
366
+ "password",
367
+ "passwd",
368
+ "pwd",
369
+ "passphrase",
370
+ "pass[-_.]?phrase",
371
+ "pin",
372
+ "passcode",
373
+ // Generic secret markers
374
+ "secret",
375
+ "secrets",
376
+ "credential",
377
+ "credentials",
378
+ "creds",
379
+ "auth",
380
+ "x[-_.]?auth",
381
+ "x[-_.]?auth[-_.]?key",
382
+ // CSRF / XSRF
383
+ "csrf",
384
+ "xsrf",
385
+ "csrf[-_.]?token",
386
+ "xsrf[-_.]?token",
387
+ "x[-_.]?csrf[-_.]?token",
388
+ "x[-_.]?xsrf[-_.]?token",
389
+ // JWT
390
+ "jwt",
391
+ // Sessions & cookies
392
+ "session[-_.]?id",
393
+ "sessionid",
394
+ "sid",
395
+ "sessid",
396
+ "jsessionid",
397
+ "phpsessid",
398
+ "cookie",
399
+ "cookies",
400
+ "set[-_.]?cookie",
401
+ // Signatures / MAC
402
+ "signature",
403
+ "x[-_.]?hub[-_.]?signature",
404
+ "x[-_.]?signature",
405
+ "sig",
406
+ "hmac",
407
+ "mac",
408
+ // Crypto artifacts
409
+ "salt",
410
+ "nonce",
411
+ // Multi-factor / verification
412
+ "otp",
413
+ "totp",
414
+ "mfa",
415
+ "mfa[-_.]?code",
416
+ "2fa",
417
+ "two[-_.]?factor",
418
+ "twofactor",
419
+ "verification[-_.]?code",
420
+ "verify[-_.]?code",
421
+ "confirm(?:ation)?[-_.]?code",
422
+ "sms[-_.]?code",
423
+ "email[-_.]?code",
424
+ // Recovery & seed phrases
425
+ "seed[-_.]?phrase",
426
+ "mnemonic",
427
+ "recovery[-_.]?key",
428
+ "recovery[-_.]?code",
429
+ "recovery[-_.]?phrase",
430
+ // PII / financial
431
+ "card[-_.]?number",
432
+ "card[-_.]?code",
433
+ "cvv",
434
+ "cvc",
435
+ "ccv",
436
+ "cc[-_.]?num(?:ber)?",
437
+ "pan",
438
+ "ssn",
439
+ "social[-_.]?security",
440
+ "license[-_.]?key"
441
+ ];
442
+ var URL_FORM_SECRET_KEY_ATOMS = [...CORE_SECRET_KEY_ATOMS, "code"];
443
+ var buildKeyBoundaryPattern = (atoms, flags) => new RegExp(`(?:^|[^A-Za-z0-9])(?:${atoms.join("|")})(?=[^A-Za-z0-9]|$)`, flags);
444
+ var SECRET_KEY_PATTERN = buildKeyBoundaryPattern(CORE_SECRET_KEY_ATOMS, "i");
445
+ var URL_FORM_SECRET_KEY_PATTERN = buildKeyBoundaryPattern(URL_FORM_SECRET_KEY_ATOMS, "i");
446
+ var NON_SECRET_KEY_EXACT = /* @__PURE__ */ new Set([
447
+ "token_type",
448
+ "token-type",
449
+ "tokentype",
450
+ "token_kind",
451
+ "token-kind",
452
+ "tokenkind",
453
+ "token_ttl",
454
+ "token-ttl",
455
+ "token_expires_in",
456
+ "token-expires-in",
457
+ "token_expiry",
458
+ "signature_method",
459
+ "signature-method",
460
+ "signature_type",
461
+ "signature-type",
462
+ "signature_version",
463
+ "signature-version",
464
+ "auth_type",
465
+ "auth-type",
466
+ "auth_method",
467
+ "auth-method",
468
+ "authentication_type",
469
+ "authentication-type",
470
+ "authentication_method",
471
+ "authentication-method",
472
+ "grant_type",
473
+ "grant-type",
474
+ "password_strength",
475
+ "password-strength",
476
+ "password_policy",
477
+ "password-policy",
478
+ "key_type",
479
+ "key-type",
480
+ "key_name",
481
+ "key-name",
482
+ "key_id",
483
+ "key-id",
484
+ "kid"
649
485
  ]);
650
- var isStructuredValue = (value) => (typeof value === "object" || typeof value === "function") && value !== null;
651
- var mapServiceErrorCodeByStatus = (status) => {
652
- if (status === 400) return "request.bad";
653
- if (status === 401) return "auth.required";
654
- if (status === 402) return "payment.required";
655
- if (status === 403) return "permission.denied";
656
- if (status === 404) return "resource.not_found";
657
- if (status === 406) return "request.not_acceptable";
658
- if (status === 409) return "resource.conflict";
659
- if (status === 410) return "resource.gone";
660
- if (status === 412) return "request.precondition_failed";
661
- if (status === 429) return "request.rate_limited";
662
- if (status === 501) return "operation.not_implemented";
663
- if (status === 504) return "internal.timeout";
664
- if (status && status >= 500) return "internal.unexpected";
665
- return DEFAULT_CODE;
666
- };
667
- var normalizeServiceErrorIssues = (errors) => {
668
- if (!Array.isArray(errors)) return void 0;
669
- let issues = errors.map((error) => {
670
- if (!isRecord(error)) {
671
- return {
672
- message: String(error)
673
- };
674
- }
675
- let path = Array.isArray(error.path) ? error.path.map((entry) => String(entry)) : void 0;
676
- return {
677
- ...error,
678
- path,
679
- code: typeof error.code === "string" ? error.code : void 0,
680
- message: typeof error.message === "string" ? error.message : typeof error.hint === "string" ? error.hint : "Validation issue"
681
- };
682
- });
683
- return issues.length > 0 ? issues : void 0;
684
- };
685
- var getServiceErrorBaggage = (data) => {
686
- let extraEntries = Object.entries(data).filter(
687
- ([key]) => !SERVICE_ERROR_DATA_RESERVED_KEYS.has(key)
688
- );
689
- return cleanRecord({
690
- serviceError: {
691
- code: data.code,
692
- status: data.status,
693
- hint: data.hint,
694
- description: data.description,
695
- reason: data.reason
696
- },
697
- ...extraEntries.length > 0 ? {
698
- serviceErrorData: sanitizeForBaggage(Object.fromEntries(extraEntries))
699
- } : {}
700
- });
486
+ var isSecretKeyName = (name) => {
487
+ let normalized = name.toLowerCase();
488
+ if (NON_SECRET_KEY_EXACT.has(normalized)) return false;
489
+ return SECRET_KEY_PATTERN.test(normalized);
701
490
  };
702
- var mapServiceErrorCode = (code, status) => SERVICE_ERROR_CODE_MAP[code] ?? mapServiceErrorCodeByStatus(status);
703
- var isServiceErrorData = (value) => isRecord(value) && typeof value.status === "number" && typeof value.code === "string" && typeof value.message === "string" && !("config" in value) && !("request" in value) && !("response" in value) && !("isAxiosError" in value);
704
- var getServiceErrorData = (error) => {
705
- if ((0, import_error2.isServiceError)(error)) {
706
- return isServiceErrorData(error.data) ? error.data : null;
707
- }
708
- if (isServiceErrorData(error)) {
709
- return error;
710
- }
711
- if (isStructuredValue(error) && "data" in error && isServiceErrorData(error.data)) {
712
- return error.data;
713
- }
714
- if (isStructuredValue(error) && "toResponse" in error && typeof error.toResponse === "function") {
715
- let response = error.toResponse();
716
- return isServiceErrorData(response) ? response : null;
491
+ var URL_FORM_EXACT_SECRET_KEYS = /* @__PURE__ */ new Set(["key"]);
492
+ var isUrlFormSecretKeyName = (name) => {
493
+ let normalized = name.toLowerCase();
494
+ if (NON_SECRET_KEY_EXACT.has(normalized)) return false;
495
+ if (URL_FORM_EXACT_SECRET_KEYS.has(normalized)) return true;
496
+ return URL_FORM_SECRET_KEY_PATTERN.test(normalized);
497
+ };
498
+ var splitCamelCase = (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
499
+ var splitKeyParts = (key) => splitCamelCase(key).toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
500
+ var NON_SECRET_KEY_SUFFIXES = /* @__PURE__ */ new Set([
501
+ "count",
502
+ "limit",
503
+ "timeout",
504
+ "expired",
505
+ "expires",
506
+ "expiry",
507
+ "at",
508
+ "valid",
509
+ "url",
510
+ "uri",
511
+ "error",
512
+ "type",
513
+ "id",
514
+ "ids",
515
+ "name"
516
+ ]);
517
+ var NON_SECRET_FIELD_KEYS = /* @__PURE__ */ new Set([
518
+ "page_token",
519
+ "next_page_token",
520
+ "prev_page_token",
521
+ "previous_page_token",
522
+ "next_token",
523
+ "continuation_token"
524
+ ]);
525
+ var SECRET_ID_QUALIFIERS = /* @__PURE__ */ new Set(["session", "sess", "secret"]);
526
+ var isSecretFieldName = (key) => {
527
+ let parts = splitKeyParts(key);
528
+ if (parts.length === 0) return false;
529
+ let normalized = parts.join("_");
530
+ if (NON_SECRET_FIELD_KEYS.has(normalized)) return false;
531
+ let last = parts[parts.length - 1] ?? "";
532
+ if (parts.length > 1 && NON_SECRET_KEY_SUFFIXES.has(last)) {
533
+ return (last === "id" || last === "ids") && SECRET_ID_QUALIFIERS.has(parts[parts.length - 2] ?? "");
534
+ }
535
+ return isSecretKeyName(key) || isSecretKeyName(normalized) || parts.includes("session");
536
+ };
537
+ var AUTH_CONFIG_CREDENTIAL_SUFFIXES = /* @__PURE__ */ new Set(["key", "keys", "hash"]);
538
+ var HEADER_NAME_VALUE_PATTERN = /^[A-Za-z]+(?:-[A-Za-z]+)*$/;
539
+ var isAuthConfigSecretValue = (secret, path) => {
540
+ let segment = path.split(".").reverse().find((part) => !/^\d+$/.test(part));
541
+ if (!segment) return false;
542
+ let parts = splitKeyParts(segment);
543
+ let last = parts[parts.length - 1] ?? "";
544
+ if (last === "header" && HEADER_NAME_VALUE_PATTERN.test(secret)) return false;
545
+ return isSecretFieldName(segment) || AUTH_CONFIG_CREDENTIAL_SUFFIXES.has(last);
546
+ };
547
+ var KNOWN_SECRET_VALUE_PATTERNS = [
548
+ // JSON Web Tokens (header.payload.signature)
549
+ /\beyJ[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\b/g,
550
+ // AWS access key IDs
551
+ /\b(?:AKIA|ASIA|AGPA|AIDA|ANPA|ANVA|AROA|APKA|ASCA)[A-Z0-9]{16}\b/g,
552
+ // GitHub tokens (PAT / OAuth / server-to-server / user-to-server / refresh)
553
+ /\bgh[pousr]_[A-Za-z0-9]{30,}\b/g,
554
+ // Slack tokens
555
+ /\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g,
556
+ // Stripe secret / public / restricted keys
557
+ /\b(?:sk|rk|pk)_(?:test|live)_[A-Za-z0-9]{16,}\b/g,
558
+ // OpenAI API keys
559
+ /\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b/g,
560
+ // Anthropic API keys
561
+ /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g,
562
+ // Google API keys
563
+ /\bAIza[A-Za-z0-9_-]{35}\b/g,
564
+ // SendGrid API keys
565
+ /\bSG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\b/g,
566
+ // Twilio API keys
567
+ /\bSK[0-9a-fA-F]{32}\b/g,
568
+ // PEM-encoded private keys (multi-line)
569
+ /-----BEGIN[A-Z ]*PRIVATE KEY-----[\s\S]*?-----END[A-Z ]*PRIVATE KEY-----/g,
570
+ // SSH private keys (OpenSSH format)
571
+ /-----BEGIN OPENSSH PRIVATE KEY-----[\s\S]*?-----END OPENSSH PRIVATE KEY-----/g
572
+ ];
573
+ var HTTP_AUTH_SCHEME_PATTERN = /\b(bearer|basic|digest|token|negotiate|apikey)\s+([A-Za-z0-9_\-.~+/=]{4,})/gi;
574
+ var GENERIC_KEY_VALUE_PATTERN = /(?<![A-Za-z0-9])([A-Za-z0-9][A-Za-z0-9_\-.]*)(\s*=\s*)([^&#\s;]+)/g;
575
+ var GENERIC_JSON_KEY_VALUE_PATTERN = /"([^"\\]*(?:\\.[^"\\]*)*)"(\s*:\s*)"([^"\\]*(?:\\.[^"\\]*)*)"/g;
576
+ var SAFE_HEADER_NAMES = /* @__PURE__ */ new Set([
577
+ "accept",
578
+ "accept-encoding",
579
+ "accept-language",
580
+ "cache-control",
581
+ "connection",
582
+ "content-encoding",
583
+ "content-language",
584
+ "content-length",
585
+ "content-type",
586
+ "date",
587
+ "etag",
588
+ "expires",
589
+ "if-modified-since",
590
+ "if-none-match",
591
+ "keep-alive",
592
+ "last-modified",
593
+ "location",
594
+ "origin",
595
+ "pragma",
596
+ "referer",
597
+ "referrer-policy",
598
+ "request-id",
599
+ "retry-after",
600
+ "server",
601
+ "transfer-encoding",
602
+ "user-agent",
603
+ "vary",
604
+ "via",
605
+ "x-correlation-id",
606
+ "x-powered-by",
607
+ "x-request-id",
608
+ "x-slates-provider",
609
+ "x-trace-id"
610
+ ]);
611
+ var SAFE_HEADER_PREFIXES = ["ratelimit-", "x-ratelimit-"];
612
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
613
+ var isObjectLike = (value) => typeof value === "object" && value !== null;
614
+ var normalizeContentType = (value) => value?.split(";")[0]?.trim().toLowerCase() || void 0;
615
+ var isTextContentType = (contentType) => !contentType || /(^text\/)|json|xml|html|javascript|graphql|x-www-form-urlencoded|svg/.test(contentType);
616
+ var redactKnownSecretValues = (text) => {
617
+ let result = text;
618
+ for (let pattern of KNOWN_SECRET_VALUE_PATTERNS) {
619
+ result = result.replace(pattern, REDACTED_VALUE);
717
620
  }
718
- return null;
621
+ return result;
719
622
  };
720
- var mapServiceErrorToSlateErrorInput = (error, defaults = {}) => {
721
- let data = getServiceErrorData(error);
722
- if (!data) {
723
- return {
724
- code: defaults.code ?? DEFAULT_CODE,
725
- message: defaults.message ?? "An unexpected internal error occurred.",
726
- kind: defaults.kind,
727
- retryable: defaults.retryable,
728
- status: defaults.status,
729
- provider: defaults.provider,
730
- upstream: defaults.upstream,
731
- baggage: defaults.baggage
732
- };
623
+ var isSafeHeaderName = (name) => {
624
+ let normalized = name.toLowerCase();
625
+ if (isSecretKeyName(normalized)) return false;
626
+ if (SAFE_HEADER_NAMES.has(normalized)) return true;
627
+ return SAFE_HEADER_PREFIXES.some((prefix) => normalized.startsWith(prefix));
628
+ };
629
+ var truncateText = (text) => {
630
+ if (text.length <= TRACE_TEXT_LIMIT) {
631
+ return { text, truncated: false };
733
632
  }
734
- let code = defaults.code ?? mapServiceErrorCode(data.code, data.status);
735
633
  return {
736
- code,
737
- message: defaults.message ?? data.message,
738
- kind: defaults.kind ?? normalizeKind(code),
739
- retryable: defaults.retryable ?? normalizeRetryable(code),
740
- status: defaults.status ?? data.status,
741
- issues: defaults.issues ?? normalizeServiceErrorIssues(data.errors),
742
- provider: defaults.provider,
743
- upstream: defaults.upstream,
744
- baggage: cleanRecord({
745
- ...defaults.baggage ?? {},
746
- ...getServiceErrorBaggage(data)
747
- })
634
+ text: `${text.slice(0, TRACE_TEXT_LIMIT)}...[truncated]`,
635
+ truncated: true
748
636
  };
749
637
  };
750
-
751
- // src/error/base.ts
752
- var SlateError = class _SlateError extends Error {
753
- cause;
754
- data;
755
- constructor(input) {
756
- let normalized = normalizeSlateErrorInput(input);
757
- super(normalized.message);
758
- this.name = "SlateError";
759
- this.data = normalized;
760
- this.cause = input.cause;
761
- }
762
- get code() {
763
- return this.data.code;
764
- }
765
- get kind() {
766
- return this.data.kind;
767
- }
768
- get status() {
769
- return this.data.status;
770
- }
771
- get retryable() {
772
- return this.data.retryable;
773
- }
774
- toResponse() {
775
- return {
776
- ...this.data
777
- };
778
- }
779
- toJSON() {
780
- return this.toResponse();
781
- }
782
- static is(error) {
783
- return error instanceof _SlateError;
784
- }
785
- static fromUnknown(error, defaults = {}) {
786
- if (_SlateError.is(error)) return error;
787
- if (isSlateErrorResponse(error)) return new _SlateError({ ...defaults, ...error });
788
- if (getServiceErrorData(error)) return _SlateError.fromServiceError(error, defaults);
789
- if (isAxiosErrorLike(error)) return _SlateError.fromAxios(error, { defaults });
790
- if (error instanceof Error) {
791
- return new _SlateError({
792
- code: defaults.code ?? DEFAULT_CODE,
793
- message: error.message,
794
- kind: defaults.kind,
795
- retryable: defaults.retryable,
796
- status: defaults.status,
797
- issues: defaults.issues,
798
- provider: defaults.provider,
799
- upstream: defaults.upstream,
800
- baggage: mergeRecords(defaults.baggage, {
801
- originalName: error.name
802
- }),
803
- cause: error
804
- });
638
+ var sanitizeFreeText = (text, redactor) => {
639
+ if (!text) return text;
640
+ let result = redactor ? redactor.redact(text, isAuthConfigSecretValue) : text;
641
+ result = result.replace(
642
+ HTTP_AUTH_SCHEME_PATTERN,
643
+ (_match, scheme) => `${scheme} ${REDACTED_VALUE}`
644
+ );
645
+ result = redactKnownSecretValues(result);
646
+ result = result.replace(
647
+ GENERIC_KEY_VALUE_PATTERN,
648
+ (match, key, equals, _value) => isUrlFormSecretKeyName(key) ? `${key}${equals}${REDACTED_VALUE}` : match
649
+ );
650
+ result = result.replace(
651
+ GENERIC_JSON_KEY_VALUE_PATTERN,
652
+ (match, key, colon, _value) => isSecretKeyName(key) ? `"${key}"${colon}"${REDACTED_VALUE}"` : match
653
+ );
654
+ return result;
655
+ };
656
+ var PROSE_SAFE_AUTH_SCHEME_PATTERN = /\b(bearer|basic|digest|token|negotiate|apikey)(\s+)([A-Za-z0-9_\-.~+/=]{8,})/gi;
657
+ var looksLikeCredential = (value) => {
658
+ if (/^[A-Za-z][A-Za-z0-9_\-.]*=/.test(value)) return false;
659
+ return /[0-9_\-.~+/=]/.test(value) || /[a-z]/.test(value) && /[A-Z]/.test(value.slice(1));
660
+ };
661
+ var CREDENTIAL_HEADER_VALUE_PATTERN = /\b(proxy-authorization|authorization|x-api-key|api[-_]?key|set-cookie|cookie)(\s*[:=]\s*)(?:(["'])((?:\\.|(?!\3)[^\\\r\n])*)|([^\r\n&]*))/gi;
662
+ var AUTH_SCHEME_WORD_PATTERN = /^(?:bearer|basic|digest|token|negotiate|apikey)$/i;
663
+ var COOKIE_HEADER_NAME_PATTERN = /^(?:set-)?cookie$/i;
664
+ var AUTHORIZATION_HEADER_NAME_PATTERN = /^(?:proxy-)?authorization$/i;
665
+ var COOKIE_PAIRS_PATTERN = /^[^\s;=&"',]+=[^\s;&"',]*(?:;\s*[^\s;=&"',]+=[^\s;&"',]*)*/;
666
+ var HEADER_TOKEN_PATTERN = /^[^\s&"',;]+/;
667
+ var HEADER_SCHEME_PATTERN = /^([A-Za-z][\w-]*)(\s+)([\s\S]*)$/;
668
+ var HEADER_AUTH_PARAMS_PATTERN = /^[A-Za-z][\w-]*\s*=/;
669
+ var redactCredentialHeaderValue = (name, value) => {
670
+ if (COOKIE_HEADER_NAME_PATTERN.test(name)) {
671
+ let pairs = COOKIE_PAIRS_PATTERN.exec(value)?.[0];
672
+ if (pairs) return `${REDACTED_VALUE}${value.slice(pairs.length)}`;
673
+ }
674
+ let scheme = HEADER_SCHEME_PATTERN.exec(value);
675
+ if (scheme) {
676
+ let [, word = "", space = "", rest = ""] = scheme;
677
+ let schemePrefix = `${word}${space}`;
678
+ if (AUTHORIZATION_HEADER_NAME_PATTERN.test(name) && HEADER_AUTH_PARAMS_PATTERN.test(rest)) {
679
+ return `${schemePrefix}${REDACTED_VALUE}`;
680
+ }
681
+ let credential = HEADER_TOKEN_PATTERN.exec(rest)?.[0];
682
+ if (credential === REDACTED_VALUE) return value;
683
+ if (credential && (AUTH_SCHEME_WORD_PATTERN.test(word) || looksLikeCredential(credential))) {
684
+ return `${schemePrefix}${REDACTED_VALUE}${rest.slice(credential.length)}`;
685
+ }
686
+ }
687
+ let token = HEADER_TOKEN_PATTERN.exec(value)?.[0];
688
+ if (token && token !== REDACTED_VALUE && looksLikeCredential(token)) {
689
+ return `${REDACTED_VALUE}${value.slice(token.length)}`;
690
+ }
691
+ return value;
692
+ };
693
+ var GENERIC_SINGLE_QUOTED_KEY_VALUE_PATTERN = /'([^'\\]*(?:\\.[^'\\]*)*)'(\s*:\s*)'([^'\\]*(?:\\.[^'\\]*)*)'/g;
694
+ var PROSE_KEY_VALUE_PATTERN = /(?<![A-Za-z0-9_\-.])([A-Za-z][A-Za-z0-9_\-.]*)([ \t]*:[ \t]*)(["'`]?)([^\s"'`,;&)\]}]+)/g;
695
+ var PROSE_STATE_WORD_PATTERN = /^(?:required|missing|invalid|expired|revoked|empty|blank|null|undefined|none|not|is|was|has|must|should|cannot|incorrect|wrong|malformed|provided|present|absent|unknown|denied|rejected|unauthorized|forbidden|true|false|too|the|a|an)$/i;
696
+ var PROSE_ERROR_CODE_PATTERN = /^[a-z]+(?:_[a-z]+)+$/;
697
+ var redactProseKeyValue = (match, key, separator, quote, value) => {
698
+ if (AUTHORIZATION_HEADER_NAME_PATTERN.test(key) || COOKIE_HEADER_NAME_PATTERN.test(key)) {
699
+ return match;
700
+ }
701
+ if (value.startsWith("[") || value.startsWith(AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX)) {
702
+ return match;
703
+ }
704
+ if (!isSecretFieldName(key)) return match;
705
+ let credential = value.replace(/[.!?:]+$/, "");
706
+ if (!credential || PROSE_ERROR_CODE_PATTERN.test(credential)) return match;
707
+ let compoundKey = splitKeyParts(key).length > 1;
708
+ if (looksLikeCredential(credential) || compoundKey && !PROSE_STATE_WORD_PATTERN.test(credential)) {
709
+ return `${key}${separator}${quote}${REDACTED_VALUE}${value.slice(credential.length)}`;
710
+ }
711
+ return match;
712
+ };
713
+ var sanitizeSecretValuesInText = (text) => {
714
+ if (!text) return text;
715
+ let result = text.replace(
716
+ PROSE_SAFE_AUTH_SCHEME_PATTERN,
717
+ (match, scheme, space, value) => looksLikeCredential(value) ? `${scheme}${space}${REDACTED_VALUE}` : match
718
+ );
719
+ result = result.replace(
720
+ CREDENTIAL_HEADER_VALUE_PATTERN,
721
+ (_match, name, separator, quote, quotedValue, plainValue) => `${name}${separator}${quote ?? ""}${redactCredentialHeaderValue(
722
+ name,
723
+ quote ? quotedValue ?? "" : plainValue ?? ""
724
+ )}`
725
+ );
726
+ result = redactKnownSecretValues(result);
727
+ result = result.replace(
728
+ GENERIC_KEY_VALUE_PATTERN,
729
+ (match, key, equals, value, offset, whole) => {
730
+ if (!isSecretKeyName(key)) return match;
731
+ let rest = whole.slice(offset + match.length);
732
+ if (AUTH_SCHEME_WORD_PATTERN.test(value) && /^\s+\[redacted\]/.test(rest)) return match;
733
+ return `${key}${equals}${REDACTED_VALUE}`;
805
734
  }
806
- return new _SlateError({
807
- code: defaults.code ?? DEFAULT_CODE,
808
- message: getDefaultMessage(defaults.code ?? DEFAULT_CODE, defaults.message),
809
- kind: defaults.kind,
810
- retryable: defaults.retryable,
811
- status: defaults.status,
812
- issues: defaults.issues,
813
- provider: defaults.provider,
814
- upstream: defaults.upstream,
815
- baggage: mergeRecords(defaults.baggage, {
816
- originalValue: sanitizeForBaggage(error)
817
- })
818
- });
735
+ );
736
+ result = result.replace(PROSE_KEY_VALUE_PATTERN, redactProseKeyValue);
737
+ result = result.replace(
738
+ GENERIC_SINGLE_QUOTED_KEY_VALUE_PATTERN,
739
+ (match, key, colon, _value) => isSecretKeyName(key) ? `'${key}'${colon}'${REDACTED_VALUE}'` : match
740
+ );
741
+ return result.replace(
742
+ GENERIC_JSON_KEY_VALUE_PATTERN,
743
+ (match, key, colon, _value) => isSecretKeyName(key) ? `"${key}"${colon}"${REDACTED_VALUE}"` : match
744
+ );
745
+ };
746
+ var sanitizeScalar = (value, redactor) => truncateText(sanitizeFreeText(value, redactor));
747
+ var redactStructuredValue = (value, depth = 0, redactor) => {
748
+ if (value == null) return value;
749
+ if (depth >= STRUCTURED_DEPTH_LIMIT) return "[truncated]";
750
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
751
+ return typeof value === "string" ? sanitizeFreeText(value, redactor) : value;
819
752
  }
820
- static fromServiceError(error, defaults = {}) {
821
- return new _SlateError(mapServiceErrorToSlateErrorInput(error, defaults));
753
+ if (Array.isArray(value)) {
754
+ return value.slice(0, STRUCTURED_ENTRY_LIMIT).map((entry) => redactStructuredValue(entry, depth + 1, redactor));
822
755
  }
823
- static fromAxios(error, options = {}) {
824
- if (_SlateError.is(error)) return error;
825
- if (getServiceErrorData(error))
826
- return _SlateError.fromServiceError(error, options.defaults);
827
- if (!isAxiosErrorLike(error)) return _SlateError.fromUnknown(error, options.defaults);
828
- let inferred = inferSlateErrorFromAxios(error, options);
829
- let mapped = options.mapAxiosError?.(error, inferred);
830
- if (_SlateError.is(mapped)) return mapped;
831
- return new _SlateError(mergeSlateErrorData(inferred, mapped ?? void 0));
756
+ if (isRecord(value)) {
757
+ return Object.fromEntries(
758
+ Object.entries(value).slice(0, STRUCTURED_ENTRY_LIMIT).map(([key, entry]) => [
759
+ key,
760
+ isSecretKeyName(key) ? REDACTED_VALUE : redactStructuredValue(entry, depth + 1, redactor)
761
+ ])
762
+ );
832
763
  }
764
+ return String(value);
833
765
  };
834
- var createSlateError = (input) => new SlateError(input);
835
-
836
- // src/error/declaration.ts
837
- var SlateDeclarationError = class _SlateDeclarationError extends SlateError {
838
- constructor(message, input = {}) {
839
- super({
840
- code: "declaration.invalid_definition",
841
- kind: "declaration",
842
- message,
843
- ...input
844
- });
845
- this.name = "SlateError.DeclarationError";
766
+ var maybeParseJson = (text, contentType) => {
767
+ let trimmed = text.trim();
768
+ if (!trimmed) return null;
769
+ if (!contentType?.includes("json") && !/^[[{]/.test(trimmed)) {
770
+ return null;
846
771
  }
847
- static is(error) {
848
- return error instanceof _SlateDeclarationError;
772
+ try {
773
+ return JSON.parse(trimmed);
774
+ } catch {
775
+ return null;
849
776
  }
850
777
  };
851
-
852
- // src/action/scopes.ts
853
- var scopeClause = (...scopes) => {
854
- assertScopeValues(scopes);
778
+ var sanitizeTextBody = (text, contentType, redactor) => {
779
+ if (!text) return void 0;
780
+ let normalizedContentType = normalizeContentType(contentType);
781
+ let parsedJson = maybeParseJson(text, normalizedContentType);
782
+ let normalizedText = parsedJson !== null ? JSON.stringify(redactStructuredValue(parsedJson, 0, redactor)) : sanitizeFreeText(text, redactor);
783
+ let { text: truncatedText, truncated } = truncateText(normalizedText);
855
784
  return {
856
- OR: [...scopes]
785
+ ...normalizedContentType ? { contentType: normalizedContentType } : {},
786
+ text: truncatedText,
787
+ ...truncated ? { truncated: true } : {}
857
788
  };
858
789
  };
859
- var anyOf = (...scopes) => ({
860
- AND: [scopeClause(...scopes)]
861
- });
862
- var allOf = (...inputs) => {
863
- let AND = inputs.flatMap((input) => normalizeScopes(input).AND);
864
- return validateScopes({ AND });
790
+ var isBinaryLike = (value) => {
791
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) return true;
792
+ if (value instanceof ArrayBuffer) return true;
793
+ if (ArrayBuffer.isView(value)) return true;
794
+ if (typeof Blob !== "undefined" && value instanceof Blob) return true;
795
+ if (typeof FormData !== "undefined" && value instanceof FormData) return true;
796
+ return false;
865
797
  };
866
- var mergeScopes = (...inputs) => {
867
- let AND = inputs.flatMap((input) => input ? input.AND : []);
868
- if (AND.length === 0) {
798
+ var serializeTextBody = (value, contentType, redactor) => {
799
+ let normalizedContentType = normalizeContentType(contentType);
800
+ if (value == null || isBinaryLike(value) || !isTextContentType(normalizedContentType)) {
869
801
  return void 0;
870
802
  }
871
- return validateScopes({ AND });
872
- };
873
- var validateScopes = (scopes) => {
874
- if (!Array.isArray(scopes.AND) || scopes.AND.length === 0) {
875
- throw new SlateDeclarationError("Action scopes must include at least one AND clause");
876
- }
877
- return {
878
- AND: scopes.AND.map((clause) => normalizeClause(clause))
879
- };
880
- };
881
- var normalizeScopes = (input) => {
882
- if (isScopes(input)) {
883
- return validateScopes(input);
803
+ if (typeof value === "string") {
804
+ return sanitizeTextBody(value, normalizedContentType, redactor);
884
805
  }
885
- return {
886
- AND: [normalizeClause(input)]
887
- };
888
- };
889
- var normalizeClause = (input) => {
890
- if (typeof input === "string") {
891
- return scopeClause(input);
806
+ if (value instanceof URLSearchParams) {
807
+ return sanitizeTextBody(value.toString(), normalizedContentType, redactor);
892
808
  }
893
- if (Array.isArray(input)) {
894
- return scopeClause(...input);
809
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
810
+ return sanitizeTextBody(String(value), normalizedContentType, redactor);
895
811
  }
896
- if (!isClause(input)) {
897
- throw new SlateDeclarationError("Action scope clauses must be strings or OR clauses");
812
+ if (Array.isArray(value) || isRecord(value)) {
813
+ return sanitizeTextBody(
814
+ JSON.stringify(redactStructuredValue(value, 0, redactor)),
815
+ "application/json",
816
+ redactor
817
+ );
898
818
  }
899
- assertScopeValues(input.OR);
900
- return {
901
- OR: [...input.OR]
902
- };
819
+ return void 0;
903
820
  };
904
- var assertScopeValues = (scopes) => {
905
- if (scopes.length === 0) {
906
- throw new SlateDeclarationError(
907
- "Each action scope clause must include at least one OR scope"
908
- );
821
+ var buildUrl = (baseURL, url) => {
822
+ if (!url) return "";
823
+ if (!baseURL) return url;
824
+ try {
825
+ return new URL(url, baseURL).toString();
826
+ } catch {
827
+ return url;
909
828
  }
910
- for (let scope of scopes) {
911
- if (typeof scope !== "string" || scope.trim().length === 0) {
912
- throw new SlateDeclarationError("Action scopes must be non-empty strings");
829
+ };
830
+ var REDACTED_ENCODED = encodeURIComponent(REDACTED_VALUE);
831
+ var decodeRedactedMarker = (value) => REDACTED_ENCODED === REDACTED_VALUE ? value : value.split(REDACTED_ENCODED).join(REDACTED_VALUE);
832
+ var redactQueryValue = (rawValue, redactor) => redactKnownSecretValues(
833
+ redactor ? redactor.redact(rawValue, isAuthConfigSecretValue) : rawValue
834
+ );
835
+ var redactHashFragment = (hash, redactor) => {
836
+ if (!hash?.includes("=")) return hash;
837
+ let withoutHash = hash.startsWith("#") ? hash.slice(1) : hash;
838
+ let redacted = withoutHash.replace(
839
+ /(?<![A-Za-z0-9])([A-Za-z0-9][A-Za-z0-9_\-.]*)=([^&]*)/g,
840
+ (match, key, rawValue) => {
841
+ if (isUrlFormSecretKeyName(key)) return `${key}=${REDACTED_VALUE}`;
842
+ let redactedValue = redactQueryValue(rawValue, redactor);
843
+ return redactedValue !== rawValue ? `${key}=${redactedValue}` : match;
913
844
  }
914
- }
845
+ );
846
+ return redacted ? `#${redacted}` : "";
915
847
  };
916
- var isClause = (value) => typeof value === "object" && value !== null && "OR" in value && Array.isArray(value.OR);
917
- var isScopes = (value) => typeof value === "object" && value !== null && "AND" in value && Array.isArray(value.AND);
918
-
919
- // src/action/builder.ts
920
- var SlateActionBuilder = class {
921
- constructor(type, spec2, params, factory, isPublicTool = false) {
922
- this.type = type;
923
- this.spec = spec2;
924
- this.params = params;
925
- this.factory = factory;
926
- this.isPublicTool = isPublicTool;
927
- this.#configSchema = spec2.configSchema;
928
- this.#authSchema = spec2.authSchema;
929
- }
930
- type;
931
- spec;
932
- params;
933
- factory;
934
- isPublicTool;
935
- #configSchema;
936
- #authSchema;
937
- #inputSchema = null;
938
- #outputSchema = null;
939
- #scopes;
940
- #authMethods;
941
- #toolParams = null;
942
- #triggerGroup = null;
943
- #triggerMatches = null;
944
- #triggerMap = null;
945
- #interfaceLocked = false;
946
- input(schema) {
947
- if (this.#interfaceLocked) {
948
- throw new SlateDeclarationError("Adapter contract input schema cannot be changed");
848
+ var isEmbeddedPathSecret = (secret, path) => secret.length >= 8 && isAuthConfigSecretValue(secret, path);
849
+ var redactAuthConfigSecretsInText = (text, redactor) => redactor.redactEmbedded(text, isEmbeddedPathSecret, isAuthConfigSecretValue);
850
+ var sanitizeUrl = (value, redactor) => {
851
+ if (!value) return value;
852
+ try {
853
+ let url = new URL(value);
854
+ if (url.username || url.password) {
855
+ url.username = "";
856
+ url.password = "";
949
857
  }
950
- this.#inputSchema = schema;
951
- return this;
952
- }
953
- output(schema) {
954
- if (this.#interfaceLocked) {
955
- throw new SlateDeclarationError("Adapter contract output schema cannot be changed");
858
+ if (redactor) url.pathname = redactAuthConfigSecretsInText(url.pathname, redactor);
859
+ for (let key of Array.from(url.searchParams.keys())) {
860
+ if (isUrlFormSecretKeyName(key)) {
861
+ url.searchParams.set(key, REDACTED_VALUE);
862
+ continue;
863
+ }
864
+ let rawValue = url.searchParams.get(key) ?? "";
865
+ let redactedValue = redactQueryValue(rawValue, redactor);
866
+ if (redactedValue !== rawValue) url.searchParams.set(key, redactedValue);
956
867
  }
957
- this.#outputSchema = schema;
958
- return this;
959
- }
960
- lockInterface() {
961
- this.#interfaceLocked = true;
962
- return this;
868
+ url.hash = redactHashFragment(url.hash, redactor);
869
+ return decodeRedactedMarker(url.toString());
870
+ } catch {
871
+ let text = redactor ? redactAuthConfigSecretsInText(value, redactor) : value;
872
+ return text.replace(
873
+ /([?&]([^=&#]+)=)([^&#]+)/g,
874
+ (_match, prefix, key, rawValue) => isUrlFormSecretKeyName(key) ? `${prefix}${REDACTED_VALUE}` : `${prefix}${redactKnownSecretValues(rawValue)}`
875
+ );
963
876
  }
964
- scopes(scopes) {
965
- validateScopes(scopes);
966
- this.#scopes = scopes;
967
- return this;
877
+ };
878
+ var flattenHeaderValue = (value) => {
879
+ if (typeof value === "string") return value;
880
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
881
+ if (Array.isArray(value)) {
882
+ let normalized = value.map((entry) => flattenHeaderValue(entry)).filter((entry) => typeof entry === "string" && entry.length > 0);
883
+ return normalized.length > 0 ? normalized.join(", ") : void 0;
968
884
  }
969
- authMethods(authMethods) {
970
- if (this.isPublicTool) {
971
- throw new SlateDeclarationError("Public tools cannot require authentication methods");
885
+ return void 0;
886
+ };
887
+ var headerEntries = (headers) => {
888
+ if (!headers) return [];
889
+ if (typeof headers.toJSON === "function") {
890
+ let json = headers.toJSON();
891
+ if (isRecord(json)) {
892
+ return Object.entries(json).map(([key, value]) => {
893
+ let flattened = flattenHeaderValue(value);
894
+ return flattened ? [key, flattened] : null;
895
+ }).filter((entry) => entry !== null);
972
896
  }
973
- this.#authMethods = this.validateAuthMethods(authMethods);
974
- return this;
975
897
  }
976
- validateAuthMethods(authMethods) {
977
- if (!authMethods) return void 0;
978
- let normalized = [...new Set(authMethods.map((authMethod) => authMethod.trim()))];
979
- if (normalized.some((authMethod) => !authMethod)) {
980
- throw new SlateDeclarationError("Auth method IDs must be non-empty strings");
981
- }
982
- return normalized;
898
+ if (typeof headers.entries === "function") {
899
+ return Array.from(
900
+ headers.entries()
901
+ ).map(([key, value]) => [key, value]);
902
+ }
903
+ if (isRecord(headers)) {
904
+ return Object.entries(headers).map(([key, value]) => {
905
+ let flattened = flattenHeaderValue(value);
906
+ return flattened ? [key, flattened] : null;
907
+ }).filter((entry) => entry !== null);
908
+ }
909
+ return [];
910
+ };
911
+ var sanitizeHeaders = (headers, redactor) => {
912
+ let entries = headerEntries(headers).map(
913
+ ([key, value]) => [key.toLowerCase(), sanitizeScalar(value, redactor).text]
914
+ ).filter(([key]) => isSafeHeaderName(key));
915
+ if (entries.length === 0) return void 0;
916
+ return Object.fromEntries(entries);
917
+ };
918
+ var getContentType = (headers) => headerEntries(headers).find(([key]) => key.toLowerCase() === "content-type")?.[1];
919
+ var takeTraceDraft = (config2) => {
920
+ if (!config2) return void 0;
921
+ let draft = config2.__slatesHttpTraceDraft ?? (isObjectLike(config2) ? traceDraftsByConfig.get(config2) : void 0) ?? (isObjectLike(config2.headers) ? traceDraftsByHeaders.get(config2.headers) : void 0);
922
+ if (!draft) return void 0;
923
+ return draft;
924
+ };
925
+ var clearTraceDraft = (config2, draft) => {
926
+ if (!config2) return;
927
+ if (config2.__slatesHttpTraceDraft === draft) {
928
+ config2.__slatesHttpTraceDraft = void 0;
983
929
  }
984
- handleInvocation(handler) {
985
- if (this.type !== "tool") {
986
- throw new SlateDeclarationError("handleInvocation can only be set for tool actions");
987
- }
988
- this.#toolParams = {
989
- type: "tool",
990
- handleInvocation: handler
991
- };
992
- return this;
930
+ if (isObjectLike(config2)) {
931
+ traceDraftsByConfig.delete(config2);
993
932
  }
994
- triggerGroup(group) {
995
- if (this.type !== "trigger") {
996
- throw new SlateDeclarationError("triggerGroup can only be set for trigger actions");
997
- }
998
- this.#triggerGroup = group;
999
- return this;
933
+ if (isObjectLike(config2.headers)) {
934
+ traceDraftsByHeaders.delete(config2.headers);
1000
935
  }
1001
- matches(handler) {
1002
- if (this.type !== "trigger") {
1003
- throw new SlateDeclarationError("matches can only be set for trigger actions");
936
+ };
937
+ var attachHttpTraceDraft = (config2, context) => {
938
+ let traceAwareConfig = config2;
939
+ let contentType = getContentType(config2.headers);
940
+ let redactor = new AuthConfigSecretRedactor(context._getAuthConfigForRedaction());
941
+ traceAwareConfig.__slatesHttpTraceDraft = {
942
+ context,
943
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
944
+ startedAtMs: Date.now(),
945
+ request: {
946
+ method: (config2.method ?? "GET").toUpperCase(),
947
+ url: sanitizeUrl(buildUrl(config2.baseURL, config2.url), redactor),
948
+ ...sanitizeHeaders(config2.headers, redactor) ? { headers: sanitizeHeaders(config2.headers, redactor) } : {},
949
+ ...serializeTextBody(config2.data, contentType, redactor) ? { body: serializeTextBody(config2.data, contentType, redactor) } : {}
1004
950
  }
1005
- this.#triggerMatches = handler;
1006
- return this;
951
+ };
952
+ if (isObjectLike(traceAwareConfig)) {
953
+ traceDraftsByConfig.set(traceAwareConfig, traceAwareConfig.__slatesHttpTraceDraft);
1007
954
  }
1008
- map(handler) {
1009
- if (this.type !== "trigger") {
1010
- throw new SlateDeclarationError("map can only be set for trigger actions");
1011
- }
1012
- this.#triggerMap = handler;
1013
- return this;
955
+ if (isObjectLike(traceAwareConfig.headers)) {
956
+ traceDraftsByHeaders.set(
957
+ traceAwareConfig.headers,
958
+ traceAwareConfig.__slatesHttpTraceDraft
959
+ );
1014
960
  }
1015
- build() {
1016
- let scopes = this.#scopes ?? this.params.scopes;
1017
- if (scopes) {
1018
- validateScopes(scopes);
1019
- }
1020
- let authMethods = this.validateAuthMethods(this.#authMethods ?? this.params.authMethods);
1021
- if (this.isPublicTool && authMethods) {
1022
- throw new SlateDeclarationError("Public tools cannot require authentication methods");
1023
- }
1024
- if (!this.#inputSchema) {
1025
- throw new SlateDeclarationError("Input schema is not defined");
1026
- }
1027
- if (!this.#outputSchema) {
1028
- throw new SlateDeclarationError("Output schema is not defined");
1029
- }
1030
- if (this.type === "tool" && !this.#toolParams) {
1031
- throw new SlateDeclarationError("Tool invocation handler is not defined");
1032
- }
1033
- if (this.type === "trigger" && !this.#triggerGroup) {
1034
- throw new SlateDeclarationError("Trigger group is not defined");
1035
- }
1036
- if (this.type === "trigger" && !this.#triggerMatches) {
1037
- throw new SlateDeclarationError("Trigger matches handler is not defined");
961
+ return config2;
962
+ };
963
+ var recordHttpTraceFromResponse = (response) => {
964
+ let config2 = response.config;
965
+ let draft = takeTraceDraft(config2);
966
+ if (!draft) return response;
967
+ clearTraceDraft(config2, draft);
968
+ let redactor = new AuthConfigSecretRedactor(draft.context._getAuthConfigForRedaction());
969
+ let contentType = getContentType(response.headers);
970
+ draft.context.recordHttpTrace({
971
+ startedAt: draft.startedAt,
972
+ durationMs: Math.max(Date.now() - draft.startedAtMs, 0),
973
+ request: draft.request,
974
+ response: {
975
+ status: response.status,
976
+ ...response.statusText ? { statusText: response.statusText } : {},
977
+ ...sanitizeHeaders(response.headers, redactor) ? { headers: sanitizeHeaders(response.headers, redactor) } : {},
978
+ ...serializeTextBody(response.data, contentType, redactor) ? { body: serializeTextBody(response.data, contentType, redactor) } : {}
1038
979
  }
1039
- if (this.type === "trigger" && !this.#triggerMap) {
1040
- throw new SlateDeclarationError("Trigger map handler is not defined");
980
+ });
981
+ return response;
982
+ };
983
+ var recordHttpTraceFromError = (error) => {
984
+ let config2 = error.config;
985
+ let draft = takeTraceDraft(config2);
986
+ if (!draft) return;
987
+ clearTraceDraft(config2, draft);
988
+ let redactor = new AuthConfigSecretRedactor(draft.context._getAuthConfigForRedaction());
989
+ let responseContentType = getContentType(error.response?.headers);
990
+ draft.context.recordHttpTrace({
991
+ startedAt: draft.startedAt,
992
+ durationMs: Math.max(Date.now() - draft.startedAtMs, 0),
993
+ request: draft.request,
994
+ ...error.response ? {
995
+ response: {
996
+ status: error.response.status,
997
+ ...error.response.statusText ? { statusText: error.response.statusText } : {},
998
+ ...sanitizeHeaders(error.response.headers, redactor) ? { headers: sanitizeHeaders(error.response.headers, redactor) } : {},
999
+ ...serializeTextBody(error.response.data, responseContentType, redactor) ? { body: serializeTextBody(error.response.data, responseContentType, redactor) } : {}
1000
+ }
1001
+ } : {},
1002
+ error: {
1003
+ ...error.code ? { code: error.code } : {},
1004
+ message: error.message
1041
1005
  }
1042
- let triggerParams = this.type === "trigger" ? {
1043
- type: "trigger",
1044
- triggerGroup: this.#triggerGroup,
1045
- matches: this.#triggerMatches,
1046
- map: this.#triggerMap
1047
- } : null;
1048
- return this.factory({
1049
- ...this.params,
1050
- scopes,
1051
- authMethods,
1052
- isPublic: this.isPublicTool === true,
1053
- configSchema: this.#configSchema,
1054
- authSchema: this.#authSchema,
1055
- inputSchema: this.#inputSchema,
1056
- outputSchema: this.#outputSchema,
1057
- ...this.#toolParams,
1058
- ...triggerParams
1059
- });
1006
+ });
1007
+ };
1008
+
1009
+ // src/context/hook.ts
1010
+ var import_async_hooks = require("async_hooks");
1011
+ var slateContextStorageKey = /* @__PURE__ */ Symbol.for("slates.provider.context.asyncLocalStorage");
1012
+ var globalWithSlateContext = globalThis;
1013
+ var asyncLocalStorage = globalWithSlateContext[slateContextStorageKey] ?? new import_async_hooks.AsyncLocalStorage();
1014
+ globalWithSlateContext[slateContextStorageKey] = asyncLocalStorage;
1015
+ var runWithContext = (context, fn) => {
1016
+ return asyncLocalStorage.run(context, fn);
1017
+ };
1018
+ var getCurrentContext = () => {
1019
+ let context = asyncLocalStorage.getStore();
1020
+ if (!context) {
1021
+ throw new Error("No Slate context is available");
1060
1022
  }
1023
+ return context;
1024
+ };
1025
+
1026
+ // src/error/defaults.ts
1027
+ var DEFAULT_CODE = "internal.unexpected";
1028
+ var DEFAULT_MESSAGES = {
1029
+ "declaration.invalid_definition": "The slate definition is invalid.",
1030
+ "context.missing": "No Slate context is available.",
1031
+ "input.invalid": "The provided input is invalid.",
1032
+ "request.bad": "The request is invalid.",
1033
+ "request.invalid_version": "The requested version is invalid.",
1034
+ "request.precondition_failed": "The request precondition failed.",
1035
+ "request.not_acceptable": "The request is not acceptable.",
1036
+ "request.rate_limited": "Too many requests were made in a short period of time.",
1037
+ "config.invalid": "The provided configuration is invalid.",
1038
+ "auth.required": "Authentication is required.",
1039
+ "auth.invalid": "Authentication failed.",
1040
+ "auth.expired": "Authentication has expired.",
1041
+ "permission.denied": "Permission was denied.",
1042
+ "resource.not_found": "The requested resource was not found.",
1043
+ "resource.conflict": "The requested resource is in conflict.",
1044
+ "resource.gone": "The requested resource is no longer available.",
1045
+ "payment.required": "Payment is required to continue.",
1046
+ "operation.not_implemented": "The requested operation is not implemented.",
1047
+ "upstream.invalid_request": "The upstream service rejected the request.",
1048
+ "upstream.rate_limited": "The upstream service rate limited the request.",
1049
+ "upstream.timeout": "The upstream service timed out.",
1050
+ "upstream.network_error": "A network error occurred while contacting the upstream service.",
1051
+ "upstream.unavailable": "The upstream service is unavailable.",
1052
+ "upstream.invalid_response": "The upstream service returned an invalid response.",
1053
+ "upstream.error": "The upstream service returned an error.",
1054
+ "transport.invoke_failed": "The provider transport failed.",
1055
+ "internal.timeout": "The operation timed out.",
1056
+ "internal.unexpected": "An unexpected internal error occurred."
1057
+ };
1058
+ var SERVICE_ERROR_CODE_MAP = {
1059
+ invalid_data: "input.invalid",
1060
+ bad_request: "request.bad",
1061
+ not_found: "resource.not_found",
1062
+ unauthorized: "auth.required",
1063
+ forbidden: "permission.denied",
1064
+ invalid_version: "request.invalid_version",
1065
+ conflict: "resource.conflict",
1066
+ gone: "resource.gone",
1067
+ payment_required: "payment.required",
1068
+ precondition_failed: "request.precondition_failed",
1069
+ not_acceptable: "request.not_acceptable",
1070
+ not_implemented: "operation.not_implemented",
1071
+ too_many_requests: "request.rate_limited",
1072
+ timeout: "internal.timeout",
1073
+ internal_server_error: "internal.unexpected"
1074
+ };
1075
+
1076
+ // src/error/utils.ts
1077
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1078
+ var normalizeKind = (code, kind) => {
1079
+ if (kind) return kind;
1080
+ if (code.startsWith("declaration.")) return "declaration";
1081
+ if (code.startsWith("input.")) return "validation";
1082
+ if (code.startsWith("request.")) return "request";
1083
+ if (code.startsWith("config.")) return "config";
1084
+ if (code.startsWith("auth.") || code.startsWith("permission.")) return "auth";
1085
+ if (code.startsWith("resource.")) return "resource";
1086
+ if (code.startsWith("payment.")) return "payment";
1087
+ if (code.startsWith("transport.")) return "transport";
1088
+ if (code.startsWith("upstream.")) return "upstream";
1089
+ return "internal";
1090
+ };
1091
+ var normalizeStatus = (code, status) => {
1092
+ if (status) return status;
1093
+ if (code === "input.invalid" || code === "request.bad" || code === "config.invalid")
1094
+ return 400;
1095
+ if (code === "request.invalid_version") return 400;
1096
+ if (code === "auth.required" || code === "auth.invalid" || code === "auth.expired")
1097
+ return 401;
1098
+ if (code === "payment.required") return 402;
1099
+ if (code === "permission.denied") return 403;
1100
+ if (code === "resource.not_found") return 404;
1101
+ if (code === "resource.conflict") return 409;
1102
+ if (code === "resource.gone") return 410;
1103
+ if (code === "request.not_acceptable") return 406;
1104
+ if (code === "request.precondition_failed") return 412;
1105
+ if (code === "request.rate_limited" || code === "upstream.rate_limited") return 429;
1106
+ if (code === "operation.not_implemented") return 501;
1107
+ if (code === "upstream.invalid_request") return 400;
1108
+ if (code === "upstream.timeout" || code === "internal.timeout") return 504;
1109
+ if (code === "upstream.unavailable") return 503;
1110
+ if (code === "upstream.error") return 502;
1111
+ return void 0;
1112
+ };
1113
+ var normalizeRetryable = (code, retryable) => {
1114
+ if (typeof retryable === "boolean") return retryable;
1115
+ return code === "request.rate_limited" || code === "upstream.rate_limited" || code === "upstream.timeout" || code === "upstream.network_error" || code === "upstream.unavailable" || code === "upstream.error" || code === "transport.invoke_failed" || code === "internal.timeout";
1116
+ };
1117
+ var getDefaultMessage = (code, message) => {
1118
+ if (message?.trim()) return message;
1119
+ return DEFAULT_MESSAGES[code] ?? DEFAULT_MESSAGES[DEFAULT_CODE] ?? "An unexpected internal error occurred.";
1120
+ };
1121
+ var cleanRecord = (value) => {
1122
+ if (!value) return void 0;
1123
+ let entries = Object.entries(value).filter(([, entry]) => entry !== void 0);
1124
+ if (entries.length === 0) return void 0;
1125
+ return Object.fromEntries(entries);
1061
1126
  };
1062
-
1063
- // src/action/getFileUrlTool.ts
1064
- var import_zod = require("zod");
1065
-
1066
- // src/auth/redact.ts
1067
- var AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX = "$$MT$secret$authConfig$";
1068
- var AuthConfigSecretRedactor = class {
1069
- secretToPlaceholder = /* @__PURE__ */ new Map();
1070
- constructor(authConfig) {
1071
- if (authConfig) this.buildSecretMap(authConfig);
1127
+ var mergeRecords = (left, right) => {
1128
+ if (!left && !right) return void 0;
1129
+ return cleanRecord({
1130
+ ...left ?? {},
1131
+ ...right ?? {}
1132
+ });
1133
+ };
1134
+ var mergeSlateErrorData = (base, override) => {
1135
+ if (!override) return base;
1136
+ return {
1137
+ ...base,
1138
+ ...override,
1139
+ provider: cleanRecord({
1140
+ ...base.provider ?? {},
1141
+ ...override.provider ?? {}
1142
+ }),
1143
+ upstream: cleanRecord({
1144
+ ...base.upstream ?? {},
1145
+ ...override.upstream ?? {}
1146
+ }),
1147
+ baggage: mergeRecords(base.baggage, override.baggage),
1148
+ issues: override.issues ?? base.issues,
1149
+ requestTraces: override.requestTraces ?? base.requestTraces
1150
+ };
1151
+ };
1152
+ var BAGGAGE_TRUNCATED_VALUE = "[truncated]";
1153
+ var BAGGAGE_REDACTED_VALUE = "[redacted]";
1154
+ var BAGGAGE_UNSERIALIZABLE_VALUE = "[unserializable]";
1155
+ var BAGGAGE_DEFAULT_MAX_DEPTH = 4;
1156
+ var BAGGAGE_RESPONSE_MAX_DEPTH = 8;
1157
+ var BAGGAGE_MAX_STRING_LENGTH = 2e3;
1158
+ var BAGGAGE_MAX_ARRAY_ITEMS = 20;
1159
+ var BAGGAGE_MAX_OBJECT_KEYS = 30;
1160
+ var BAGGAGE_MAX_SERIALIZED_SIZE = 16384;
1161
+ var BAGGAGE_STRING_TRUNCATION_SUFFIX = "...[truncated]";
1162
+ var BAGGAGE_MIN_STRING_SLICE = 32;
1163
+ var BAGGAGE_SCAN_LENGTH = BAGGAGE_MAX_STRING_LENGTH + 100;
1164
+ var BAGGAGE_REDACTOR_SCAN_LENGTH = BAGGAGE_MAX_STRING_LENGTH * 4;
1165
+ var BAGGAGE_MIN_ENTRY_COST = 6;
1166
+ var getCurrentAuthConfigRedactor = () => {
1167
+ try {
1168
+ let authConfig = getCurrentContext()._getAuthConfigForRedaction();
1169
+ return authConfig ? new AuthConfigSecretRedactor(authConfig) : void 0;
1170
+ } catch {
1171
+ return void 0;
1072
1172
  }
1073
- redact(value) {
1074
- return this.transform(value, (stringValue) => {
1075
- return this.secretToPlaceholder.get(stringValue) ?? stringValue;
1076
- });
1173
+ };
1174
+ var ERROR_TEXT_MAX_LENGTH = BAGGAGE_MAX_STRING_LENGTH * 4;
1175
+ var ERROR_TEXT_SCAN_MARGIN = 512;
1176
+ var sanitizeErrorText = (text, redactor) => {
1177
+ let activeRedactor = redactor === void 0 ? getCurrentAuthConfigRedactor() : redactor;
1178
+ let truncated = text.length > ERROR_TEXT_MAX_LENGTH;
1179
+ let scanned = truncated ? text.slice(0, ERROR_TEXT_MAX_LENGTH + ERROR_TEXT_SCAN_MARGIN) : text;
1180
+ let result = scanned;
1181
+ if (activeRedactor) {
1182
+ try {
1183
+ result = redactAuthConfigSecretsInText(result, activeRedactor);
1184
+ } catch {
1185
+ result = scanned;
1186
+ }
1187
+ }
1188
+ result = sanitizeSecretValuesInText(result);
1189
+ return truncated ? `${result.slice(0, ERROR_TEXT_MAX_LENGTH)}${BAGGAGE_STRING_TRUNCATION_SUFFIX}` : result;
1190
+ };
1191
+ var NUMERIC_SECRET_KEY_PATTERN = /(?:^|_)(?:pin|passcode|password|passwd|pwd|otp|totp|cvv|cvc|ccv|pan|ssn|card_number|card_code|cc_num(?:ber)?)(?:_|$)|(?:^|_)(?:code|secret|key)$/;
1192
+ var VALIDATION_VOCABULARY_PATTERN = /\b(?:required|invalid|must|blank|empty|missing|too (?:short|long|weak|common|simple)|characters?|(?:does not|doesn't|do not|don't) match|cannot be|can't be|not allowed|not valid|at least|at most|incorrect|already (?:taken|used|exists|in use)|has expired|is expired)\b/i;
1193
+ var isValidationProse = (value) => {
1194
+ let text = value.trim();
1195
+ if (text.length > 300) return false;
1196
+ let words = text.split(/\s+/);
1197
+ if (words.length < 3) return false;
1198
+ if (words.some((word) => word.length > 20 || /[a-z]/i.test(word) && /\d/.test(word))) {
1199
+ return false;
1200
+ }
1201
+ return VALIDATION_VOCABULARY_PATTERN.test(text);
1202
+ };
1203
+ var isKeptUnderSecretKey = (key, value) => {
1204
+ if (typeof value === "boolean") return true;
1205
+ if (typeof value === "number")
1206
+ return !NUMERIC_SECRET_KEY_PATTERN.test(splitKeyParts(key).join("_"));
1207
+ if (typeof value === "string") return isValidationProse(value);
1208
+ if (Array.isArray(value)) {
1209
+ return value.length > 0 && value.length <= BAGGAGE_MAX_ARRAY_ITEMS && value.every((item) => typeof item === "string" && isValidationProse(item));
1077
1210
  }
1078
- /** `embeddable` limits which secrets are also replaced inside longer strings. */
1079
- redactEmbedded(value, embeddable = () => true) {
1080
- let secrets = [...this.secretToPlaceholder.entries()].filter(
1081
- ([secret, placeholder]) => embeddable(secret, placeholder.slice(AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX.length))
1082
- ).map(([secret]) => secret);
1083
- if (secrets.length === 0) return this.redact(value);
1084
- let pattern = new RegExp(
1085
- secrets.sort((a, b) => b.length - a.length).map((secret) => secret.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"),
1086
- "g"
1211
+ return false;
1212
+ };
1213
+ var jsonLength = (value) => JSON.stringify(value).length;
1214
+ var redactLiteralSecrets = (value, redactor) => {
1215
+ if (!redactor) return value;
1216
+ try {
1217
+ return redactAuthConfigSecretsInText(
1218
+ value.slice(0, BAGGAGE_REDACTOR_SCAN_LENGTH),
1219
+ redactor
1087
1220
  );
1088
- return this.transform(value, (stringValue) => {
1089
- let exactPlaceholder = this.secretToPlaceholder.get(stringValue);
1090
- if (exactPlaceholder) return exactPlaceholder;
1091
- return stringValue.replace(
1092
- pattern,
1093
- (secret) => `${this.secretToPlaceholder.get(secret)}$$`
1094
- );
1095
- });
1221
+ } catch {
1222
+ return value;
1096
1223
  }
1097
- buildSecretMap(value, path = []) {
1098
- if (typeof value === "string") {
1099
- if (value.length === 0) return;
1100
- this.secretToPlaceholder.set(
1101
- value,
1102
- `${AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX}${path.join(".")}`
1103
- );
1104
- return;
1105
- }
1106
- if (Array.isArray(value)) {
1107
- value.forEach((item, index) => {
1108
- this.buildSecretMap(item, [...path, String(index)]);
1109
- });
1110
- return;
1111
- }
1112
- if (this.isPlainObject(value)) {
1113
- Object.entries(value).forEach(([key, nestedValue]) => {
1114
- this.buildSecretMap(nestedValue, [...path, key]);
1115
- });
1116
- }
1224
+ };
1225
+ var sanitizeBaggageString = (value, state) => {
1226
+ let literalRedacted = redactLiteralSecrets(value, state.redactor);
1227
+ let text = sanitizeSecretValuesInText(literalRedacted.slice(0, BAGGAGE_SCAN_LENGTH));
1228
+ if (value.length > BAGGAGE_MAX_STRING_LENGTH || literalRedacted.length > BAGGAGE_MAX_STRING_LENGTH || text.length > BAGGAGE_MAX_STRING_LENGTH) {
1229
+ text = `${text.slice(0, BAGGAGE_MAX_STRING_LENGTH)}${BAGGAGE_STRING_TRUNCATION_SUFFIX}`;
1117
1230
  }
1118
- transform(value, transformString) {
1119
- if (typeof value === "string") {
1120
- return transformString(value);
1121
- }
1122
- if (Array.isArray(value)) {
1123
- return value.map((item) => this.transform(item, transformString));
1124
- }
1125
- if (this.isPlainObject(value)) {
1126
- let result = {};
1127
- Object.entries(value).forEach(([key, nestedValue]) => {
1128
- result[key] = this.transform(nestedValue, transformString);
1129
- });
1130
- return result;
1231
+ let cost = jsonLength(text);
1232
+ if (cost > state.remaining) {
1233
+ let sliceLength = state.remaining - BAGGAGE_STRING_TRUNCATION_SUFFIX.length - 2 - (cost - text.length);
1234
+ text = sliceLength >= BAGGAGE_MIN_STRING_SLICE ? `${text.slice(0, sliceLength)}${BAGGAGE_STRING_TRUNCATION_SUFFIX}` : BAGGAGE_TRUNCATED_VALUE;
1235
+ cost = jsonLength(text);
1236
+ if (cost > state.remaining && text !== BAGGAGE_TRUNCATED_VALUE) {
1237
+ text = BAGGAGE_TRUNCATED_VALUE;
1238
+ cost = jsonLength(text);
1131
1239
  }
1240
+ }
1241
+ state.remaining -= cost;
1242
+ return text;
1243
+ };
1244
+ var sanitizeBaggageValue = (value, depth, maxDepth, state) => {
1245
+ if (value === void 0) return value;
1246
+ if (value === null) {
1247
+ state.remaining -= 4;
1132
1248
  return value;
1133
1249
  }
1134
- isPlainObject(value) {
1135
- return typeof value === "object" && value !== null && !Array.isArray(value);
1250
+ if (depth >= maxDepth) {
1251
+ state.remaining -= jsonLength(BAGGAGE_TRUNCATED_VALUE);
1252
+ return BAGGAGE_TRUNCATED_VALUE;
1136
1253
  }
1137
- };
1138
- var URL_CREDENTIAL_KEY = /^(?:.*[-_])?(?:token|secret|password|api[-_]?key)$/i;
1139
- var isUrlEmbeddedCredential = (secret, path) => secret.length >= 8 && URL_CREDENTIAL_KEY.test(path.split(".").pop() ?? "");
1140
- var redactUrlAttachmentSecrets = (attachments, authConfig) => {
1141
- if (!authConfig || !attachments) return attachments;
1142
- let redactor = new AuthConfigSecretRedactor(authConfig);
1143
- return attachments.map((attachment) => {
1144
- if (attachment.content.type !== "url") return attachment;
1145
- let { url, headers, query } = attachment.content;
1146
- return {
1147
- ...attachment,
1148
- content: {
1149
- ...attachment.content,
1150
- url: redactor.redactEmbedded(url, isUrlEmbeddedCredential),
1151
- ...headers ? { headers: redactor.redactEmbedded(headers) } : {},
1152
- ...query ? { query: redactor.redactEmbedded(query) } : {}
1153
- }
1154
- };
1155
- });
1156
- };
1157
-
1158
- // src/action/tool.ts
1159
- var SlateTool = class _SlateTool extends SlateAction {
1160
- #handleInvocation;
1161
- constructor(spec2, inputSchema, outputSchema, params) {
1162
- super("tool", spec2, inputSchema, outputSchema, params);
1163
- this.#handleInvocation = params.handleInvocation;
1254
+ if (typeof value === "string") return sanitizeBaggageString(value, state);
1255
+ if (typeof value === "number" || typeof value === "boolean") {
1256
+ state.remaining -= String(value).length;
1257
+ return value;
1164
1258
  }
1165
- static create(spec2, params) {
1166
- return new SlateActionBuilder("tool", spec2, params, (params2) => {
1167
- return _SlateTool.fromCreateParameters(spec2, params2);
1168
- });
1259
+ if (typeof value === "bigint") return sanitizeBaggageString(value.toString(), state);
1260
+ if (Array.isArray(value)) {
1261
+ state.remaining -= 2;
1262
+ let items = [];
1263
+ for (let item of value.slice(0, BAGGAGE_MAX_ARRAY_ITEMS)) {
1264
+ if (state.remaining <= 0) break;
1265
+ state.remaining -= 1;
1266
+ if (item === void 0) {
1267
+ state.remaining -= 4;
1268
+ items.push(null);
1269
+ continue;
1270
+ }
1271
+ items.push(sanitizeBaggageValue(item, depth + 1, maxDepth, state));
1272
+ }
1273
+ return items;
1169
1274
  }
1170
- static fromCreateParameters(spec2, params) {
1171
- if (params.type !== "tool") throw new Error("Invalid action type for tool");
1172
- return new _SlateTool(spec2, params.inputSchema, params.outputSchema, params);
1275
+ if (isRecord2(value)) {
1276
+ state.remaining -= 2;
1277
+ let entries = [];
1278
+ for (let key of Object.keys(value).slice(0, BAGGAGE_MAX_OBJECT_KEYS)) {
1279
+ if (state.remaining < BAGGAGE_MIN_ENTRY_COST) break;
1280
+ let keyCost = jsonLength(key) + 2;
1281
+ if (state.remaining - keyCost <= 0) continue;
1282
+ state.remaining -= keyCost;
1283
+ try {
1284
+ let entry = value[key];
1285
+ if (entry != null && isSecretFieldName(key) && !isKeptUnderSecretKey(key, entry)) {
1286
+ state.remaining -= jsonLength(BAGGAGE_REDACTED_VALUE);
1287
+ entries.push([key, BAGGAGE_REDACTED_VALUE]);
1288
+ continue;
1289
+ }
1290
+ entries.push([key, sanitizeBaggageValue(entry, depth + 1, maxDepth, state)]);
1291
+ } catch {
1292
+ state.remaining -= jsonLength(BAGGAGE_UNSERIALIZABLE_VALUE);
1293
+ entries.push([key, BAGGAGE_UNSERIALIZABLE_VALUE]);
1294
+ }
1295
+ }
1296
+ return Object.fromEntries(entries);
1173
1297
  }
1174
- get handleInvocation() {
1175
- return this.#handleInvocation;
1298
+ return sanitizeBaggageString(String(value), state);
1299
+ };
1300
+ var sanitizeForBaggage = (value, options = {}) => {
1301
+ try {
1302
+ return sanitizeBaggageValue(value, 0, options.maxDepth ?? BAGGAGE_DEFAULT_MAX_DEPTH, {
1303
+ remaining: options.maxSerializedSize ?? BAGGAGE_MAX_SERIALIZED_SIZE,
1304
+ redactor: options.redactor === null ? void 0 : options.redactor ?? getCurrentAuthConfigRedactor()
1305
+ });
1306
+ } catch {
1307
+ return BAGGAGE_UNSERIALIZABLE_VALUE;
1176
1308
  }
1177
1309
  };
1178
- var tool = (spec2, params) => SlateTool.create(spec2, params);
1179
-
1180
- // src/action/getFileUrlTool.ts
1181
- var GET_FILE_URL_TOOL_ID = "metorial$getFileUrl";
1182
- var getFileUrlToolInputSchema = import_zod.z.object({
1183
- url: import_zod.z.string(),
1184
- reference: import_zod.z.any().nullable()
1185
- });
1186
- var getFileUrlToolOutputSchema = import_zod.z.object({
1187
- url: import_zod.z.string(),
1188
- expiresAt: import_zod.z.string(),
1189
- headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
1190
- query: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional()
1191
- });
1192
- var getFileUrlTool = (spec2, handleGetFileUrl) => tool(spec2, {
1193
- key: GET_FILE_URL_TOOL_ID,
1194
- name: "Get File URL",
1195
- description: "Reserved: refreshes an expiring attachment download URL. Hub-internal only."
1196
- }).input(getFileUrlToolInputSchema).output(getFileUrlToolOutputSchema).handleInvocation(async (ctx) => {
1197
- let output = await handleGetFileUrl(ctx);
1198
- let redactor = new AuthConfigSecretRedactor(ctx._getAuthConfigForRedaction());
1310
+ var normalizeSlateErrorInput = (input) => {
1311
+ let code = input.code || DEFAULT_CODE;
1199
1312
  return {
1200
- output: {
1201
- ...output,
1202
- url: redactor.redactEmbedded(output.url, isUrlEmbeddedCredential),
1203
- ...output.headers ? { headers: redactor.redactEmbedded(output.headers) } : {},
1204
- ...output.query ? { query: redactor.redactEmbedded(output.query) } : {}
1205
- },
1206
- message: "ok"
1313
+ code,
1314
+ message: getDefaultMessage(code, input.message),
1315
+ kind: normalizeKind(code, input.kind),
1316
+ retryable: normalizeRetryable(code, input.retryable),
1317
+ status: normalizeStatus(code, input.status ?? input.upstream?.status),
1318
+ issues: input.issues,
1319
+ provider: cleanRecord(input.provider),
1320
+ upstream: cleanRecord({
1321
+ ...input.upstream,
1322
+ status: input.upstream?.status ?? input.status
1323
+ }),
1324
+ baggage: cleanRecord(input.baggage),
1325
+ requestTraces: input.requestTraces
1207
1326
  };
1208
- }).build();
1327
+ };
1328
+ var isSlateErrorResponse = (error) => {
1329
+ if (!isRecord2(error)) return false;
1330
+ return typeof error.code === "string" && typeof error.message === "string";
1331
+ };
1209
1332
 
1210
- // src/action/publicTool.ts
1211
- var SlatePublicTool = class {
1212
- constructor() {
1333
+ // src/error/api.ts
1334
+ var DEFAULT_DETAIL_KEYS = ["message", "detail", "error", "error_description", "code"];
1335
+ var DEFAULT_NESTED_KEYS = ["errors"];
1336
+ var isApiErrorRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1337
+ var pushDetail = (details, value, options = {}) => {
1338
+ if (typeof value !== "string" && (options.includeNumbers === false || typeof value !== "number")) {
1339
+ return;
1213
1340
  }
1214
- static create(spec2, params) {
1215
- return new SlateActionBuilder(
1216
- "tool",
1217
- spec2,
1218
- params,
1219
- (params2) => {
1220
- return SlateTool.fromCreateParameters(spec2, {
1221
- ...params2,
1222
- isPublic: true
1223
- });
1224
- },
1225
- true
1226
- );
1341
+ let detail = String(value).trim();
1342
+ if (detail && !details.includes(detail)) {
1343
+ details.push(detail);
1227
1344
  }
1228
1345
  };
1229
- var publicTool = (spec2, params) => SlatePublicTool.create(spec2, params);
1230
-
1231
- // src/action/trigger.ts
1232
- var SlateTrigger = class _SlateTrigger extends SlateAction {
1233
- #triggerGroup;
1234
- #matches;
1235
- #map;
1236
- constructor(spec2, inputSchema, outputSchema, params) {
1237
- super("trigger", spec2, inputSchema, outputSchema, params);
1238
- this.#triggerGroup = params.triggerGroup;
1239
- this.#matches = params.matches;
1240
- this.#map = params.map;
1346
+ var collectApiErrorDetails = (value, details, options = {}) => {
1347
+ if (Array.isArray(value)) {
1348
+ for (let item of value) {
1349
+ collectApiErrorDetails(item, details, options);
1350
+ }
1351
+ return;
1241
1352
  }
1242
- static create(spec2, params) {
1243
- return new SlateActionBuilder("trigger", spec2, params, (params2) => {
1244
- if (params2.type !== "trigger") throw new Error("Invalid action type for trigger");
1245
- return new _SlateTrigger(spec2, params2.inputSchema, params2.outputSchema, params2);
1246
- });
1353
+ if (!isApiErrorRecord(value)) {
1354
+ pushDetail(details, value, options);
1355
+ return;
1247
1356
  }
1248
- get triggerGroup() {
1249
- return this.#triggerGroup;
1357
+ for (let key of options.detailKeys ?? DEFAULT_DETAIL_KEYS) {
1358
+ pushDetail(details, value[key], options);
1250
1359
  }
1251
- get matches() {
1252
- return this.#matches;
1360
+ for (let key of options.nestedKeys ?? DEFAULT_NESTED_KEYS) {
1361
+ collectApiErrorDetails(value[key], details, options);
1253
1362
  }
1254
- get map() {
1255
- return this.#map;
1363
+ };
1364
+ var getSlateErrorResponse = (error) => {
1365
+ if (error.name !== "SlateError" || !isApiErrorRecord(error.data)) {
1366
+ return void 0;
1256
1367
  }
1368
+ let data = error.data;
1369
+ let upstream = isApiErrorRecord(data.upstream) ? data.upstream : void 0;
1370
+ let status = upstream?.status ?? data.status;
1371
+ return typeof status === "number" || typeof status === "string" ? { status } : void 0;
1257
1372
  };
1258
- var trigger = (spec2, params) => SlateTrigger.create(spec2, params);
1259
-
1260
- // src/action/triggerGroup.ts
1261
- var import_zod2 = require("zod");
1262
- var SlateDefaultPollingIntervalSeconds = 60 * 10;
1263
- var SlateTriggerGroup = class _SlateTriggerGroup {
1264
- constructor(_spec, _params) {
1265
- this._spec = _spec;
1266
- this._params = _params;
1373
+ var getApiErrorResponse = (error) => {
1374
+ if (!isApiErrorRecord(error)) {
1375
+ return void 0;
1267
1376
  }
1268
- _spec;
1269
- _params;
1270
- static create(spec2, params) {
1271
- return new SlateTriggerGroupBuilder(spec2, params, (p) => new _SlateTriggerGroup(spec2, p));
1377
+ if (!isApiErrorRecord(error.response)) {
1378
+ return getSlateErrorResponse(error);
1272
1379
  }
1273
- get spec() {
1274
- return this._spec;
1380
+ let response = error.response;
1381
+ return {
1382
+ status: typeof response.status === "number" || typeof response.status === "string" ? response.status : void 0,
1383
+ statusText: typeof response.statusText === "string" ? response.statusText : void 0,
1384
+ data: response.data
1385
+ };
1386
+ };
1387
+ var getApiErrorStatus = (error) => getApiErrorResponse(error)?.status;
1388
+ var getApiErrorResponseWithBody = (error) => {
1389
+ let response = getApiErrorResponse(error);
1390
+ if (response?.data !== void 0) return response;
1391
+ if (!isApiErrorRecord(error) || error.name !== "SlateError" || !isApiErrorRecord(error.data)) {
1392
+ return response;
1393
+ }
1394
+ let baggage = isApiErrorRecord(error.data.baggage) ? error.data.baggage : void 0;
1395
+ if (baggage?.response === void 0) return response;
1396
+ return { ...response, data: baggage.response };
1397
+ };
1398
+ var API_ERROR_MAX_DETAILS = 5;
1399
+ var API_ERROR_MAX_MESSAGE_LENGTH = 1e3;
1400
+ var API_ERROR_TRUNCATED_PLACEHOLDER = BAGGAGE_TRUNCATED_VALUE;
1401
+ var BAGGAGE_PLACEHOLDERS = /* @__PURE__ */ new Set([
1402
+ BAGGAGE_TRUNCATED_VALUE,
1403
+ BAGGAGE_REDACTED_VALUE,
1404
+ BAGGAGE_UNSERIALIZABLE_VALUE
1405
+ ]);
1406
+ var looksLikeHtmlErrorBody = (value) => /^\s*<!doctype\s+html\b/i.test(value) || /^\s*<(html|head)\b[^>]*>/i.test(value) || /<\/(html|head|body)\s*>/i.test(value) || /^\s*<(title|h[1-6]|p|div|pre|center)\b[^>]*>[\s\S]*<\/\1\s*>/i.test(value);
1407
+ var truncateApiErrorMessage = (value, maxLength = API_ERROR_MAX_MESSAGE_LENGTH) => value.length > maxLength ? `${value.slice(0, maxLength)}...` : value;
1408
+ var readApiErrorText = (value, options = {}) => {
1409
+ if (typeof value !== "string" && (options.includeNumbers === false || typeof value !== "number")) {
1410
+ return void 0;
1275
1411
  }
1276
- get key() {
1277
- return this._params.key;
1412
+ let text = String(value).trim();
1413
+ if (!text || BAGGAGE_PLACEHOLDERS.has(text) || looksLikeHtmlErrorBody(text)) {
1414
+ return void 0;
1278
1415
  }
1279
- get name() {
1280
- return this._params.name;
1416
+ return text;
1417
+ };
1418
+ var pushBoundedApiErrorDetail = (details, value, options = {}) => {
1419
+ if (details.length >= (options.maxDetails ?? API_ERROR_MAX_DETAILS)) return;
1420
+ let text = readApiErrorText(value, options);
1421
+ if (!text) return;
1422
+ let detail = options.field ? `${options.field}: ${text}` : text;
1423
+ if (!details.includes(detail)) {
1424
+ details.push(detail);
1281
1425
  }
1282
- get description() {
1283
- return this._params.description;
1426
+ };
1427
+ var decodeApiErrorBody = (data, options = {}) => {
1428
+ let text;
1429
+ if (typeof data === "string") {
1430
+ text = data;
1431
+ } else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
1432
+ let bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1433
+ if (options.maxBytes !== void 0 && bytes.byteLength > options.maxBytes) {
1434
+ bytes = bytes.subarray(0, options.maxBytes);
1435
+ }
1436
+ text = new TextDecoder("utf-8").decode(bytes);
1437
+ } else {
1438
+ return data;
1284
1439
  }
1285
- get metadata() {
1286
- return this._params.metadata;
1440
+ let trimmed = text.trim();
1441
+ if (/^[{[]/.test(trimmed)) {
1442
+ try {
1443
+ return JSON.parse(trimmed);
1444
+ } catch {
1445
+ }
1287
1446
  }
1288
- get eventSchema() {
1289
- return this._params.eventSchema ?? import_zod2.z.object({}).passthrough();
1447
+ return trimmed;
1448
+ };
1449
+ var statusLabelForApiError = (status, statusText) => status !== void 0 ? `HTTP ${status}${statusText ? ` ${statusText}` : ""}: ` : "";
1450
+ var extractApiErrorMessage = (error, options = {}) => {
1451
+ let details = [];
1452
+ let response = options.response ?? getApiErrorResponse(error);
1453
+ collectApiErrorDetails(response?.data, details, options);
1454
+ if (details.length > 0) {
1455
+ return details.join(options.separator ?? " - ");
1290
1456
  }
1291
- get source() {
1292
- return this._params.source;
1457
+ if (error instanceof Error && error.message) {
1458
+ return error.message;
1293
1459
  }
1294
- get polling() {
1295
- return this._params.polling;
1460
+ return options.fallbackMessage ?? "Unknown error";
1461
+ };
1462
+ var createApiServiceError = (message, options = {}) => {
1463
+ let error = new import_error.ServiceError((0, import_error.badRequestError)({ message }));
1464
+ if (options.reason !== void 0) {
1465
+ error.data.reason = options.reason;
1296
1466
  }
1297
- get webhook() {
1298
- return this._params.webhook;
1467
+ if ("upstreamStatus" in options) {
1468
+ error.data.upstreamStatus = options.upstreamStatus;
1299
1469
  }
1300
- get gateway() {
1301
- return this._params.gateway;
1470
+ if ("upstreamCode" in options) {
1471
+ error.data.upstreamCode = options.upstreamCode;
1302
1472
  }
1303
- get routingMatchers() {
1304
- return this._params.routingMatchers;
1473
+ if (options.parent instanceof Error) {
1474
+ error.setParent(options.parent);
1305
1475
  }
1476
+ return error;
1306
1477
  };
1307
- var SlateTriggerGroupBuilder = class {
1308
- constructor(spec2, params, factory) {
1309
- this.spec = spec2;
1310
- this.params = params;
1311
- this.factory = factory;
1478
+ var helpers = {
1479
+ collectDetails: collectApiErrorDetails,
1480
+ extractMessage: extractApiErrorMessage,
1481
+ getResponse: getApiErrorResponse,
1482
+ getResponseWithBody: getApiErrorResponseWithBody,
1483
+ getStatus: getApiErrorStatus,
1484
+ isRecord: isApiErrorRecord,
1485
+ statusLabelFor: statusLabelForApiError
1486
+ };
1487
+ var buildApiServiceError = (error, options) => {
1488
+ if (error instanceof import_error.ServiceError) {
1489
+ return error;
1312
1490
  }
1313
- spec;
1314
- params;
1315
- factory;
1316
- #source = null;
1317
- #polling = null;
1318
- #webhook = null;
1319
- #gateway = null;
1320
- #routingMatchers = null;
1321
- polling(props) {
1322
- if (this.#source) {
1323
- throw new SlateDeclarationError("Trigger group invocation is already defined");
1324
- }
1325
- this.#source = "polling";
1326
- this.#polling = {
1327
- intervalSeconds: props.intervalSeconds ?? SlateDefaultPollingIntervalSeconds,
1328
- pollEvents: props.pollEvents
1329
- };
1330
- return this;
1491
+ let operation = options.operation ?? "request";
1492
+ let response = options.extractResponse?.(error, helpers) ?? getApiErrorResponse(error);
1493
+ let status = options.extractStatus?.(error, response, helpers) ?? response?.status;
1494
+ let message = options.extractMessage?.(error, helpers) ?? extractApiErrorMessage(error, { ...options, response });
1495
+ let statusLabel = statusLabelForApiError(status, response?.statusText);
1496
+ let fullMessage = options.formatMessage?.({
1497
+ providerLabel: options.providerLabel,
1498
+ operation,
1499
+ statusLabel,
1500
+ message,
1501
+ response,
1502
+ status
1503
+ }) ?? `${options.providerLabel} API ${operation} failed: ${statusLabel}${message}`;
1504
+ return createApiServiceError(fullMessage, {
1505
+ reason: options.reason,
1506
+ upstreamStatus: status,
1507
+ upstreamCode: options.extractUpstreamCode?.(error, response, helpers),
1508
+ parent: options.parent ?? error
1509
+ });
1510
+ };
1511
+
1512
+ // src/error/axios.ts
1513
+ var import_axios = require("axios");
1514
+ var getResponseField = (value, key) => {
1515
+ if (!isRecord2(value)) return void 0;
1516
+ return value[key];
1517
+ };
1518
+ var getNestedMessage = (value) => {
1519
+ if (typeof value === "string") return value;
1520
+ if (!isRecord2(value)) return void 0;
1521
+ let message = getResponseField(value, "message");
1522
+ if (typeof message === "string" && message.trim()) return message;
1523
+ let description = getResponseField(value, "description");
1524
+ if (typeof description === "string" && description.trim()) return description;
1525
+ let error = getResponseField(value, "error");
1526
+ if (typeof error === "string" && error.trim()) return error;
1527
+ if (isRecord2(error)) {
1528
+ let nested = getNestedMessage(error);
1529
+ if (nested) return nested;
1331
1530
  }
1332
- webhook(props) {
1333
- if (this.#source) {
1334
- throw new SlateDeclarationError("Trigger group invocation is already defined");
1335
- }
1336
- if (!!props.autoRegistration === !!props.manualRegistration) {
1337
- throw new SlateDeclarationError(
1338
- "Webhook trigger groups require exactly one of autoRegistration or manualRegistration"
1339
- );
1340
- }
1341
- this.#source = "webhook";
1342
- this.#webhook = {
1343
- autoRegistration: props.autoRegistration,
1344
- manualRegistration: props.manualRegistration,
1345
- process: props.process
1346
- };
1347
- return this;
1531
+ let errorDescription = getResponseField(value, "error_description");
1532
+ if (typeof errorDescription === "string" && errorDescription.trim()) {
1533
+ return errorDescription;
1348
1534
  }
1349
- /** Receive events over a platform-managed persistent connection (e.g. a WebSocket gateway). */
1350
- gateway(props) {
1351
- if (this.#source) {
1352
- throw new SlateDeclarationError("Trigger group invocation is already defined");
1353
- }
1354
- this.#source = "gateway";
1355
- this.#gateway = { connect: props.connect, receive: props.receive };
1356
- return this;
1535
+ return void 0;
1536
+ };
1537
+ var getNestedCode = (value) => {
1538
+ if (!isRecord2(value)) return void 0;
1539
+ let directCode = getResponseField(value, "code");
1540
+ if (typeof directCode === "string" && directCode.trim()) return directCode;
1541
+ let errorCode = getResponseField(value, "error_code");
1542
+ if (typeof errorCode === "string" && errorCode.trim()) return errorCode;
1543
+ let type = getResponseField(value, "type");
1544
+ if (typeof type === "string" && type.trim()) return type;
1545
+ let error = getResponseField(value, "error");
1546
+ if (typeof error === "string" && error.trim()) return error;
1547
+ if (isRecord2(error)) return getNestedCode(error);
1548
+ return void 0;
1549
+ };
1550
+ var getNestedType = (value) => {
1551
+ if (!isRecord2(value)) return void 0;
1552
+ let type = getResponseField(value, "type");
1553
+ if (typeof type === "string" && type.trim()) return type;
1554
+ let error = getResponseField(value, "error");
1555
+ if (isRecord2(error)) {
1556
+ let nestedType = getNestedType(error);
1557
+ if (nestedType) return nestedType;
1357
1558
  }
1358
- routingMatchers(handler) {
1359
- this.#routingMatchers = handler;
1360
- return this;
1559
+ return void 0;
1560
+ };
1561
+ var getHeaderValue = (headers, key) => {
1562
+ if (!headers) return void 0;
1563
+ if (typeof headers.get === "function") {
1564
+ let value = headers.get(key);
1565
+ if (typeof value === "string" && value.trim()) return value;
1361
1566
  }
1362
- build() {
1363
- if (!this.#source) {
1364
- throw new SlateDeclarationError(
1365
- "Trigger group invocation (polling, webhook, or gateway) is not defined"
1366
- );
1367
- }
1368
- if (!this.#routingMatchers) {
1369
- throw new SlateDeclarationError("Trigger group routing matchers handler is not defined");
1567
+ if (isRecord2(headers)) {
1568
+ for (let [headerKey, headerValue] of Object.entries(headers)) {
1569
+ if (headerKey.toLowerCase() !== key.toLowerCase()) continue;
1570
+ if (typeof headerValue === "string" && headerValue.trim()) return headerValue;
1571
+ if (Array.isArray(headerValue)) {
1572
+ let first = headerValue.find((item) => typeof item === "string" && item.trim());
1573
+ if (typeof first === "string") return first;
1574
+ }
1370
1575
  }
1371
- return this.factory({
1372
- ...this.params,
1373
- source: this.#source,
1374
- polling: this.#polling ?? void 0,
1375
- webhook: this.#webhook ?? void 0,
1376
- gateway: this.#gateway ?? void 0,
1377
- routingMatchers: this.#routingMatchers
1378
- });
1379
1576
  }
1577
+ return void 0;
1380
1578
  };
1381
- var triggerGroup = (spec2, params) => SlateTriggerGroup.create(spec2, params);
1382
-
1383
- // src/action/attachment.ts
1384
- var createUrlAttachment = (url, opts = {}) => {
1385
- if (opts.refreshReference !== void 0 && !opts.refreshAt) {
1386
- throw new Error("createUrlAttachment: refreshAt is required when refreshReference is set");
1387
- }
1388
- return {
1389
- mimeType: opts.mimeType,
1390
- attachmentHash: opts.attachmentHash,
1391
- content: {
1392
- type: "url",
1393
- url,
1394
- ...opts.headers ? { headers: opts.headers } : {},
1395
- ...opts.query ? { query: opts.query } : {},
1396
- ...opts.refreshReference !== void 0 ? { refreshReference: opts.refreshReference } : {},
1397
- ...opts.refreshAt ? { refreshAt: opts.refreshAt } : {}
1398
- }
1399
- };
1579
+ var sanitizeRequestUrl = (url, redactor) => {
1580
+ try {
1581
+ return sanitizeUrl(url, redactor);
1582
+ } catch {
1583
+ return sanitizeUrl(url);
1584
+ }
1400
1585
  };
1401
- var createBase64Attachment = (content, mimeType, attachmentHash) => ({
1402
- mimeType,
1403
- attachmentHash,
1404
- content: {
1405
- type: "content",
1406
- encoding: "base64",
1407
- content
1586
+ var buildRequestUrl = (error, redactor) => {
1587
+ let baseURL = error.config?.baseURL;
1588
+ let url = error.config?.url;
1589
+ if (!url) return void 0;
1590
+ if (!baseURL) return sanitizeRequestUrl(url, redactor);
1591
+ let absoluteUrl = url;
1592
+ try {
1593
+ absoluteUrl = new URL(url, baseURL).toString();
1594
+ } catch {
1408
1595
  }
1409
- });
1410
- var createTextAttachment = (content, mimeType, attachmentHash) => ({
1411
- mimeType,
1412
- attachmentHash,
1413
- content: {
1414
- type: "content",
1415
- encoding: "utf-8",
1416
- content
1596
+ return sanitizeRequestUrl(absoluteUrl, redactor);
1597
+ };
1598
+ var getProviderDefaults = () => {
1599
+ try {
1600
+ let ctx = getCurrentContext();
1601
+ return {
1602
+ provider: {
1603
+ key: ctx.specification.key
1604
+ },
1605
+ ...ctx.getHttpTraces().length > 0 ? { requestTraces: ctx.getHttpTraces() } : {}
1606
+ };
1607
+ } catch {
1608
+ return {};
1417
1609
  }
1418
- });
1419
-
1420
- // src/action/directUpload.ts
1421
- var bufferAttachmentBody = async (body, maxSizeBytes) => {
1422
- if (body instanceof Uint8Array) {
1423
- if (body.byteLength > maxSizeBytes) {
1424
- throw new Error(`Attachment exceeds the maximum size of ${maxSizeBytes} bytes`);
1425
- }
1426
- let buffered2 = new ArrayBuffer(body.byteLength);
1427
- new Uint8Array(buffered2).set(body);
1428
- return buffered2;
1610
+ };
1611
+ var inferAxiosCode = (error, data) => {
1612
+ let status = error.response?.status;
1613
+ let axiosCode = error.code?.toUpperCase();
1614
+ let remoteCode = getNestedCode(data)?.toLowerCase();
1615
+ if (axiosCode === "ECONNABORTED" || axiosCode === "ETIMEDOUT" || status === 408 || remoteCode?.includes("timeout")) {
1616
+ return "upstream.timeout";
1429
1617
  }
1430
- let reader = body.getReader();
1431
- let chunks = [];
1432
- let sizeBytes = 0;
1433
- while (true) {
1434
- let { done, value } = await reader.read();
1435
- if (done) break;
1436
- if (!value) continue;
1437
- sizeBytes += value.byteLength;
1438
- if (sizeBytes > maxSizeBytes) {
1439
- await reader.cancel();
1440
- throw new Error(`Attachment exceeds the maximum size of ${maxSizeBytes} bytes`);
1441
- }
1442
- chunks.push(value);
1618
+ if (!error.response) {
1619
+ return "upstream.network_error";
1443
1620
  }
1444
- let buffered = new ArrayBuffer(sizeBytes);
1445
- let bufferedView = new Uint8Array(buffered);
1446
- let offset = 0;
1447
- for (let chunk of chunks) {
1448
- bufferedView.set(chunk, offset);
1449
- offset += chunk.byteLength;
1621
+ if (status === 401) return "auth.invalid";
1622
+ if (status === 403) {
1623
+ return remoteCode?.includes("rate") ? "upstream.rate_limited" : "permission.denied";
1450
1624
  }
1451
- return buffered;
1625
+ if (status === 404) return "resource.not_found";
1626
+ if (status === 409) return "resource.conflict";
1627
+ if (status === 422 || status === 400) return "upstream.invalid_request";
1628
+ if (status === 429) return "upstream.rate_limited";
1629
+ if (status === 502 || status === 503 || status === 504) return "upstream.unavailable";
1630
+ if (status && status >= 500) return "upstream.error";
1631
+ return "upstream.error";
1452
1632
  };
1453
- var uploadAttachmentDirect = async (d) => {
1454
- let baseUrl = d.live.baseUrl.replace(/\/$/, "");
1455
- let body = await bufferAttachmentBody(d.body, d.live.maxAttachmentSizeBytes);
1456
- let registerRes = await fetch(`${baseUrl}/slates-hub/live-invocation/attachments`, {
1457
- method: "POST",
1458
- headers: {
1459
- "content-type": "application/json",
1460
- authorization: `Bearer ${d.live.token}`
1633
+ var inferAxiosMessage = (error, data, code, redactor) => {
1634
+ let message = getNestedMessage(data) ?? error.response?.statusText ?? error.message ?? getDefaultMessage(code);
1635
+ let scrubbed = sanitizeErrorText(message, redactor ?? null);
1636
+ return scrubbed.length > BAGGAGE_MAX_STRING_LENGTH ? `${scrubbed.slice(0, BAGGAGE_MAX_STRING_LENGTH)}...` : scrubbed;
1637
+ };
1638
+ var inferAxiosRetryable = (error, code) => {
1639
+ let headerValue = getHeaderValue(error.response?.headers, "retry-after");
1640
+ if (headerValue) return true;
1641
+ return normalizeRetryable(code, void 0);
1642
+ };
1643
+ var isAxiosErrorLike = (error) => (0, import_axios.isAxiosError)(error);
1644
+ var inferSlateErrorFromAxios = (error, options = {}) => {
1645
+ let responseData = error.response ? options.extractResponseData?.(error.response) ?? error.response.data : void 0;
1646
+ let code = inferAxiosCode(error, responseData);
1647
+ let redactor = getCurrentAuthConfigRedactor();
1648
+ return normalizeSlateErrorInput({
1649
+ ...getProviderDefaults(),
1650
+ ...options.defaults,
1651
+ code: options.defaults?.code ?? code,
1652
+ message: options.defaults?.message ?? inferAxiosMessage(error, responseData, code, redactor),
1653
+ kind: options.defaults?.kind ?? normalizeKind(options.defaults?.code ?? code),
1654
+ retryable: options.defaults?.retryable ?? inferAxiosRetryable(error, options.defaults?.code ?? code),
1655
+ status: options.defaults?.status ?? error.response?.status,
1656
+ provider: {
1657
+ ...getProviderDefaults().provider,
1658
+ ...options.defaults?.provider ?? {}
1461
1659
  },
1462
- body: JSON.stringify({
1463
- attachments: [
1464
- {
1465
- mimeType: d.mimeType,
1466
- filename: d.filename,
1467
- sizeBytes: body.byteLength || void 0
1468
- }
1469
- ]
1660
+ upstream: {
1661
+ ...options.defaults?.upstream ?? {},
1662
+ status: error.response?.status ?? options.defaults?.upstream?.status,
1663
+ code: getNestedCode(responseData) ?? options.defaults?.upstream?.code,
1664
+ type: getNestedType(responseData) ?? options.defaults?.upstream?.type,
1665
+ requestId: getHeaderValue(error.response?.headers, "x-request-id") ?? getHeaderValue(error.response?.headers, "request-id") ?? getHeaderValue(error.response?.headers, "x-correlation-id") ?? options.defaults?.upstream?.requestId,
1666
+ method: error.config?.method?.toUpperCase() ?? options.defaults?.upstream?.method,
1667
+ url: buildRequestUrl(error, redactor) ?? options.defaults?.upstream?.url
1668
+ },
1669
+ baggage: mergeRecords(options.defaults?.baggage, {
1670
+ axiosCode: error.code,
1671
+ response: sanitizeForBaggage(responseData, {
1672
+ maxDepth: BAGGAGE_RESPONSE_MAX_DEPTH,
1673
+ redactor: redactor ?? null
1674
+ })
1470
1675
  })
1471
1676
  });
1472
- if (!registerRes.ok) {
1473
- throw new Error(
1474
- `Failed to register attachment for direct upload (status ${registerRes.status})`
1475
- );
1476
- }
1477
- let { attachments } = await registerRes.json();
1478
- let registration = attachments[0];
1479
- if (!registration) {
1480
- throw new Error("Live invocation API returned no attachment registrations");
1481
- }
1482
- let putRes = await fetch(registration.uploadUrl, {
1483
- method: "PUT",
1484
- headers: {
1485
- ...d.mimeType ? { "content-type": d.mimeType } : {},
1486
- "content-length": String(body.byteLength)
1677
+ };
1678
+
1679
+ // src/error/service.ts
1680
+ var import_error2 = require("@lowerdeck/error");
1681
+ var SERVICE_ERROR_DATA_RESERVED_KEYS = /* @__PURE__ */ new Set([
1682
+ "status",
1683
+ "code",
1684
+ "message",
1685
+ "hint",
1686
+ "description",
1687
+ "reason",
1688
+ "errors",
1689
+ "object",
1690
+ "ok"
1691
+ ]);
1692
+ var isStructuredValue = (value) => (typeof value === "object" || typeof value === "function") && value !== null;
1693
+ var mapServiceErrorCodeByStatus = (status) => {
1694
+ if (status === 400) return "request.bad";
1695
+ if (status === 401) return "auth.required";
1696
+ if (status === 402) return "payment.required";
1697
+ if (status === 403) return "permission.denied";
1698
+ if (status === 404) return "resource.not_found";
1699
+ if (status === 406) return "request.not_acceptable";
1700
+ if (status === 409) return "resource.conflict";
1701
+ if (status === 410) return "resource.gone";
1702
+ if (status === 412) return "request.precondition_failed";
1703
+ if (status === 429) return "request.rate_limited";
1704
+ if (status === 501) return "operation.not_implemented";
1705
+ if (status === 504) return "internal.timeout";
1706
+ if (status && status >= 500) return "internal.unexpected";
1707
+ return DEFAULT_CODE;
1708
+ };
1709
+ var normalizeServiceErrorIssues = (errors) => {
1710
+ if (!Array.isArray(errors)) return void 0;
1711
+ let issues = errors.map((error) => {
1712
+ if (!isRecord2(error)) {
1713
+ return {
1714
+ message: String(error)
1715
+ };
1716
+ }
1717
+ let path = Array.isArray(error.path) ? error.path.map((entry) => String(entry)) : void 0;
1718
+ return {
1719
+ ...error,
1720
+ path,
1721
+ code: typeof error.code === "string" ? error.code : void 0,
1722
+ message: typeof error.message === "string" ? error.message : typeof error.hint === "string" ? error.hint : "Validation issue"
1723
+ };
1724
+ });
1725
+ return issues.length > 0 ? issues : void 0;
1726
+ };
1727
+ var getServiceErrorBaggage = (data) => {
1728
+ let extraEntries = Object.entries(data).filter(
1729
+ ([key]) => !SERVICE_ERROR_DATA_RESERVED_KEYS.has(key)
1730
+ );
1731
+ return cleanRecord({
1732
+ serviceError: {
1733
+ code: data.code,
1734
+ status: data.status,
1735
+ hint: data.hint,
1736
+ description: data.description,
1737
+ reason: data.reason
1487
1738
  },
1488
- body
1739
+ ...extraEntries.length > 0 ? {
1740
+ serviceErrorData: sanitizeForBaggage(Object.fromEntries(extraEntries))
1741
+ } : {}
1489
1742
  });
1490
- if (!putRes.ok) {
1491
- throw new Error(`Failed to upload attachment content (status ${putRes.status})`);
1743
+ };
1744
+ var mapServiceErrorCode = (code, status) => SERVICE_ERROR_CODE_MAP[code] ?? mapServiceErrorCodeByStatus(status);
1745
+ var isServiceErrorData = (value) => isRecord2(value) && typeof value.status === "number" && typeof value.code === "string" && typeof value.message === "string" && !("config" in value) && !("request" in value) && !("response" in value) && !("isAxiosError" in value);
1746
+ var getServiceErrorData = (error) => {
1747
+ if ((0, import_error2.isServiceError)(error)) {
1748
+ return isServiceErrorData(error.data) ? error.data : null;
1749
+ }
1750
+ if (isServiceErrorData(error)) {
1751
+ return error;
1752
+ }
1753
+ if (isStructuredValue(error) && "data" in error && isServiceErrorData(error.data)) {
1754
+ return error.data;
1755
+ }
1756
+ if (isStructuredValue(error) && "toResponse" in error && typeof error.toResponse === "function") {
1757
+ let response = error.toResponse();
1758
+ return isServiceErrorData(response) ? response : null;
1759
+ }
1760
+ return null;
1761
+ };
1762
+ var mapServiceErrorToSlateErrorInput = (error, defaults = {}) => {
1763
+ let data = getServiceErrorData(error);
1764
+ if (!data) {
1765
+ return {
1766
+ code: defaults.code ?? DEFAULT_CODE,
1767
+ message: defaults.message ?? "An unexpected internal error occurred.",
1768
+ kind: defaults.kind,
1769
+ retryable: defaults.retryable,
1770
+ status: defaults.status,
1771
+ provider: defaults.provider,
1772
+ upstream: defaults.upstream,
1773
+ baggage: defaults.baggage
1774
+ };
1492
1775
  }
1776
+ let code = defaults.code ?? mapServiceErrorCode(data.code, data.status);
1493
1777
  return {
1494
- mimeType: d.mimeType,
1495
- content: { type: "upload_reference", referenceId: registration.referenceId }
1778
+ code,
1779
+ message: defaults.message ?? data.message,
1780
+ kind: defaults.kind ?? normalizeKind(code),
1781
+ retryable: defaults.retryable ?? normalizeRetryable(code),
1782
+ status: defaults.status ?? data.status,
1783
+ issues: defaults.issues ?? normalizeServiceErrorIssues(data.errors),
1784
+ provider: defaults.provider,
1785
+ upstream: defaults.upstream,
1786
+ baggage: cleanRecord({
1787
+ ...defaults.baggage ?? {},
1788
+ ...getServiceErrorBaggage(data)
1789
+ })
1496
1790
  };
1497
1791
  };
1498
1792
 
1499
- // src/adapter/adapter.ts
1500
- var SlateAdapter = class {
1501
- constructor(_spec, _tools, _triggers) {
1502
- this._spec = _spec;
1503
- this._tools = _tools;
1504
- this._triggers = _triggers;
1505
- }
1506
- _spec;
1507
- _tools;
1508
- _triggers;
1509
- get spec() {
1510
- return this._spec;
1793
+ // src/error/base.ts
1794
+ var SlateError = class _SlateError extends Error {
1795
+ cause;
1796
+ data;
1797
+ constructor(input) {
1798
+ let normalized = normalizeSlateErrorInput(input);
1799
+ super(normalized.message);
1800
+ this.name = "SlateError";
1801
+ this.data = normalized;
1802
+ this.cause = input.cause;
1511
1803
  }
1512
- get id() {
1513
- return this._spec.id;
1804
+ get code() {
1805
+ return this.data.code;
1514
1806
  }
1515
- get name() {
1516
- return this._spec.name;
1807
+ get kind() {
1808
+ return this.data.kind;
1517
1809
  }
1518
- get capabilities() {
1519
- return this._spec.capabilities;
1810
+ get status() {
1811
+ return this.data.status;
1520
1812
  }
1521
- get tools() {
1522
- return this._tools;
1813
+ get retryable() {
1814
+ return this.data.retryable;
1523
1815
  }
1524
- get triggers() {
1525
- return this._triggers;
1816
+ toResponse() {
1817
+ return {
1818
+ ...this.data
1819
+ };
1526
1820
  }
1527
- get actions() {
1528
- return [...this._triggers, ...this._tools];
1821
+ toJSON() {
1822
+ return this.toResponse();
1529
1823
  }
1530
- };
1531
-
1532
- // src/adapter/spec.ts
1533
- var SlateAdapterSpec = class _SlateAdapterSpec {
1534
- constructor(_params) {
1535
- this._params = _params;
1824
+ static is(error) {
1825
+ return error instanceof _SlateError;
1536
1826
  }
1537
- _params;
1538
- static create(params) {
1539
- let id = params.id?.trim();
1540
- let name = params.name?.trim();
1541
- if (!id) {
1542
- throw new SlateDeclarationError("Adapter id must be a non-empty string");
1543
- }
1544
- if (!name) {
1545
- throw new SlateDeclarationError("Adapter name must be a non-empty string");
1827
+ static fromUnknown(error, defaults = {}) {
1828
+ if (_SlateError.is(error)) return error;
1829
+ if (isSlateErrorResponse(error)) return new _SlateError({ ...defaults, ...error });
1830
+ if (getServiceErrorData(error)) return _SlateError.fromServiceError(error, defaults);
1831
+ if (isAxiosErrorLike(error)) return _SlateError.fromAxios(error, { defaults });
1832
+ if (error instanceof Error) {
1833
+ return new _SlateError({
1834
+ code: defaults.code ?? DEFAULT_CODE,
1835
+ message: error.message,
1836
+ kind: defaults.kind,
1837
+ retryable: defaults.retryable,
1838
+ status: defaults.status,
1839
+ issues: defaults.issues,
1840
+ provider: defaults.provider,
1841
+ upstream: defaults.upstream,
1842
+ baggage: mergeRecords(defaults.baggage, {
1843
+ originalName: error.name
1844
+ }),
1845
+ cause: error
1846
+ });
1546
1847
  }
1547
- return new _SlateAdapterSpec({
1548
- id,
1549
- name,
1550
- capabilities: validateCapabilities(params.capabilities ?? [])
1848
+ return new _SlateError({
1849
+ code: defaults.code ?? DEFAULT_CODE,
1850
+ message: getDefaultMessage(defaults.code ?? DEFAULT_CODE, defaults.message),
1851
+ kind: defaults.kind,
1852
+ retryable: defaults.retryable,
1853
+ status: defaults.status,
1854
+ issues: defaults.issues,
1855
+ provider: defaults.provider,
1856
+ upstream: defaults.upstream,
1857
+ baggage: mergeRecords(defaults.baggage, {
1858
+ originalValue: sanitizeForBaggage(error)
1859
+ })
1551
1860
  });
1552
1861
  }
1553
- get id() {
1554
- return this._params.id;
1862
+ static fromServiceError(error, defaults = {}) {
1863
+ return new _SlateError(mapServiceErrorToSlateErrorInput(error, defaults));
1555
1864
  }
1556
- get name() {
1557
- return this._params.name;
1865
+ static fromAxios(error, options = {}) {
1866
+ if (_SlateError.is(error)) return error;
1867
+ if (getServiceErrorData(error))
1868
+ return _SlateError.fromServiceError(error, options.defaults);
1869
+ if (!isAxiosErrorLike(error)) return _SlateError.fromUnknown(error, options.defaults);
1870
+ let inferred = inferSlateErrorFromAxios(error, options);
1871
+ let mapped = options.mapAxiosError?.(error, inferred);
1872
+ if (_SlateError.is(mapped)) return mapped;
1873
+ return new _SlateError(mergeSlateErrorData(inferred, mapped ?? void 0));
1558
1874
  }
1559
- get capabilities() {
1560
- return this._params.capabilities;
1875
+ };
1876
+ var createSlateError = (input) => new SlateError(input);
1877
+
1878
+ // src/error/declaration.ts
1879
+ var SlateDeclarationError = class _SlateDeclarationError extends SlateError {
1880
+ constructor(message, input = {}) {
1881
+ super({
1882
+ code: "declaration.invalid_definition",
1883
+ kind: "declaration",
1884
+ message,
1885
+ ...input
1886
+ });
1887
+ this.name = "SlateError.DeclarationError";
1561
1888
  }
1562
- get parameters() {
1563
- return this._params;
1889
+ static is(error) {
1890
+ return error instanceof _SlateDeclarationError;
1564
1891
  }
1565
- tool(spec2, params) {
1566
- return SlateTool.create(spec2, this.linkAction(params));
1892
+ };
1893
+
1894
+ // src/action/scopes.ts
1895
+ var scopeClause = (...scopes) => {
1896
+ assertScopeValues(scopes);
1897
+ return {
1898
+ OR: [...scopes]
1899
+ };
1900
+ };
1901
+ var anyOf = (...scopes) => ({
1902
+ AND: [scopeClause(...scopes)]
1903
+ });
1904
+ var allOf = (...inputs) => {
1905
+ let AND = inputs.flatMap((input) => normalizeScopes(input).AND);
1906
+ return validateScopes({ AND });
1907
+ };
1908
+ var mergeScopes = (...inputs) => {
1909
+ let AND = inputs.flatMap((input) => input ? input.AND : []);
1910
+ if (AND.length === 0) {
1911
+ return void 0;
1567
1912
  }
1568
- publicTool(spec2, params) {
1569
- return SlatePublicTool.create(spec2, this.linkAction(params));
1913
+ return validateScopes({ AND });
1914
+ };
1915
+ var validateScopes = (scopes) => {
1916
+ if (!Array.isArray(scopes.AND) || scopes.AND.length === 0) {
1917
+ throw new SlateDeclarationError("Action scopes must include at least one AND clause");
1570
1918
  }
1571
- trigger(spec2, params) {
1572
- return SlateTrigger.create(spec2, this.linkAction(params));
1919
+ return {
1920
+ AND: scopes.AND.map((clause) => normalizeClause(clause))
1921
+ };
1922
+ };
1923
+ var normalizeScopes = (input) => {
1924
+ if (isScopes(input)) {
1925
+ return validateScopes(input);
1573
1926
  }
1574
- register(params) {
1575
- let actions = [...params.tools, ...params.triggers];
1576
- let seenKeys = /* @__PURE__ */ new Set();
1577
- for (let action of actions) {
1578
- if (action.adapter && action.adapter !== this.id) {
1579
- throw new SlateDeclarationError(
1580
- `Action "${action.key}" is linked to adapter "${action.adapter}", not "${this.id}"`
1581
- );
1582
- }
1583
- if (!action.adapter) {
1584
- throw new SlateDeclarationError(
1585
- `Action "${action.key}" must be created with this adapter's tool(), publicTool(), or trigger() helpers`
1586
- );
1587
- }
1588
- if (seenKeys.has(action.key)) {
1589
- throw new SlateDeclarationError(
1590
- `Adapter "${this.id}" already has an action with key "${action.key}"`
1591
- );
1592
- }
1593
- seenKeys.add(action.key);
1594
- }
1595
- return new SlateAdapter(this, params.tools, params.triggers);
1927
+ return {
1928
+ AND: [normalizeClause(input)]
1929
+ };
1930
+ };
1931
+ var normalizeClause = (input) => {
1932
+ if (typeof input === "string") {
1933
+ return scopeClause(input);
1596
1934
  }
1597
- linkAction(params) {
1598
- if (params.adapter != null && params.adapter !== this.id) {
1599
- throw new SlateDeclarationError(
1600
- `Action "${params.key}" cannot be linked to adapter "${this.id}" because it is already linked to "${params.adapter}"`
1601
- );
1602
- }
1603
- return {
1604
- ...params,
1605
- adapter: this.id
1606
- };
1935
+ if (Array.isArray(input)) {
1936
+ return scopeClause(...input);
1937
+ }
1938
+ if (!isClause(input)) {
1939
+ throw new SlateDeclarationError("Action scope clauses must be strings or OR clauses");
1607
1940
  }
1941
+ assertScopeValues(input.OR);
1942
+ return {
1943
+ OR: [...input.OR]
1944
+ };
1608
1945
  };
1609
- var adapterSpec = (params) => SlateAdapterSpec.create(params);
1610
- var validateCapabilities = (capabilities) => {
1611
- let seenIds = /* @__PURE__ */ new Set();
1612
- return capabilities.map((capability) => {
1613
- let id = capability.id?.trim();
1614
- if (!id) {
1615
- throw new SlateDeclarationError("Adapter capability ids must be non-empty strings");
1616
- }
1617
- if (seenIds.has(id)) {
1618
- throw new SlateDeclarationError(`Adapter capability "${id}" is defined more than once`);
1946
+ var assertScopeValues = (scopes) => {
1947
+ if (scopes.length === 0) {
1948
+ throw new SlateDeclarationError(
1949
+ "Each action scope clause must include at least one OR scope"
1950
+ );
1951
+ }
1952
+ for (let scope of scopes) {
1953
+ if (typeof scope !== "string" || scope.trim().length === 0) {
1954
+ throw new SlateDeclarationError("Action scopes must be non-empty strings");
1619
1955
  }
1620
- seenIds.add(id);
1621
- return {
1622
- id,
1623
- value: capability.value
1624
- };
1625
- });
1956
+ }
1626
1957
  };
1958
+ var isClause = (value) => typeof value === "object" && value !== null && "OR" in value && Array.isArray(value.OR);
1959
+ var isScopes = (value) => typeof value === "object" && value !== null && "AND" in value && Array.isArray(value.AND);
1627
1960
 
1628
- // src/auth/auth.ts
1629
- var SlateAuth = class _SlateAuth {
1630
- #outputSchema = null;
1631
- #authStack = [];
1632
- constructor() {
1961
+ // src/action/builder.ts
1962
+ var SlateActionBuilder = class {
1963
+ constructor(type, spec2, params, factory, isPublicTool = false) {
1964
+ this.type = type;
1965
+ this.spec = spec2;
1966
+ this.params = params;
1967
+ this.factory = factory;
1968
+ this.isPublicTool = isPublicTool;
1969
+ this.#configSchema = spec2.configSchema;
1970
+ this.#authSchema = spec2.authSchema;
1633
1971
  }
1634
- static create() {
1635
- return new _SlateAuth();
1972
+ type;
1973
+ spec;
1974
+ params;
1975
+ factory;
1976
+ isPublicTool;
1977
+ #configSchema;
1978
+ #authSchema;
1979
+ #inputSchema = null;
1980
+ #outputSchema = null;
1981
+ #scopes;
1982
+ #authMethods;
1983
+ #toolParams = null;
1984
+ #triggerGroup = null;
1985
+ #triggerMatches = null;
1986
+ #triggerMap = null;
1987
+ #interfaceLocked = false;
1988
+ input(schema) {
1989
+ if (this.#interfaceLocked) {
1990
+ throw new SlateDeclarationError("Adapter contract input schema cannot be changed");
1991
+ }
1992
+ this.#inputSchema = schema;
1993
+ return this;
1636
1994
  }
1637
1995
  output(schema) {
1996
+ if (this.#interfaceLocked) {
1997
+ throw new SlateDeclarationError("Adapter contract output schema cannot be changed");
1998
+ }
1638
1999
  this.#outputSchema = schema;
1639
2000
  return this;
1640
2001
  }
1641
- addAuth(auth2) {
1642
- let existingKeys = this.#authStack.map((a) => a.key);
1643
- if (existingKeys.includes(auth2.key)) {
1644
- throw new Error(`Auth with key "${auth2.key}" already exists in the auth stack`);
1645
- }
1646
- this.#authStack.push(auth2);
2002
+ lockInterface() {
2003
+ this.#interfaceLocked = true;
1647
2004
  return this;
1648
2005
  }
1649
- addOauth(auth2) {
1650
- this.addAuth(auth2);
2006
+ scopes(scopes) {
2007
+ validateScopes(scopes);
2008
+ this.#scopes = scopes;
1651
2009
  return this;
1652
2010
  }
1653
- addTokenAuth(auth2) {
1654
- this.addAuth(auth2);
2011
+ authMethods(authMethods) {
2012
+ if (this.isPublicTool) {
2013
+ throw new SlateDeclarationError("Public tools cannot require authentication methods");
2014
+ }
2015
+ this.#authMethods = this.validateAuthMethods(authMethods);
1655
2016
  return this;
1656
2017
  }
1657
- addServiceAccountAuth(auth2) {
1658
- this.addAuth(auth2);
2018
+ validateAuthMethods(authMethods) {
2019
+ if (!authMethods) return void 0;
2020
+ let normalized = [...new Set(authMethods.map((authMethod) => authMethod.trim()))];
2021
+ if (normalized.some((authMethod) => !authMethod)) {
2022
+ throw new SlateDeclarationError("Auth method IDs must be non-empty strings");
2023
+ }
2024
+ return normalized;
2025
+ }
2026
+ handleInvocation(handler) {
2027
+ if (this.type !== "tool") {
2028
+ throw new SlateDeclarationError("handleInvocation can only be set for tool actions");
2029
+ }
2030
+ this.#toolParams = {
2031
+ type: "tool",
2032
+ handleInvocation: handler
2033
+ };
1659
2034
  return this;
1660
2035
  }
1661
- addCustomAuth(auth2) {
1662
- this.addAuth(auth2);
2036
+ triggerGroup(group) {
2037
+ if (this.type !== "trigger") {
2038
+ throw new SlateDeclarationError("triggerGroup can only be set for trigger actions");
2039
+ }
2040
+ this.#triggerGroup = group;
1663
2041
  return this;
1664
2042
  }
1665
- addNone() {
1666
- this.addAuth({
1667
- type: "auth.none",
1668
- name: "No Authentication",
1669
- key: "none"
1670
- });
2043
+ matches(handler) {
2044
+ if (this.type !== "trigger") {
2045
+ throw new SlateDeclarationError("matches can only be set for trigger actions");
2046
+ }
2047
+ this.#triggerMatches = handler;
1671
2048
  return this;
1672
2049
  }
1673
- get authStack() {
1674
- return this.#authStack.filter((a) => a.type !== "auth.none");
2050
+ map(handler) {
2051
+ if (this.type !== "trigger") {
2052
+ throw new SlateDeclarationError("map can only be set for trigger actions");
2053
+ }
2054
+ this.#triggerMap = handler;
2055
+ return this;
1675
2056
  }
1676
- get outputSchema() {
2057
+ build() {
2058
+ let scopes = this.#scopes ?? this.params.scopes;
2059
+ if (scopes) {
2060
+ validateScopes(scopes);
2061
+ }
2062
+ let authMethods = this.validateAuthMethods(this.#authMethods ?? this.params.authMethods);
2063
+ if (this.isPublicTool && authMethods) {
2064
+ throw new SlateDeclarationError("Public tools cannot require authentication methods");
2065
+ }
2066
+ if (!this.#inputSchema) {
2067
+ throw new SlateDeclarationError("Input schema is not defined");
2068
+ }
1677
2069
  if (!this.#outputSchema) {
1678
- throw new Error("Output schema is not defined for this auth");
2070
+ throw new SlateDeclarationError("Output schema is not defined");
1679
2071
  }
1680
- return this.#outputSchema;
2072
+ if (this.type === "tool" && !this.#toolParams) {
2073
+ throw new SlateDeclarationError("Tool invocation handler is not defined");
2074
+ }
2075
+ if (this.type === "trigger" && !this.#triggerGroup) {
2076
+ throw new SlateDeclarationError("Trigger group is not defined");
2077
+ }
2078
+ if (this.type === "trigger" && !this.#triggerMatches) {
2079
+ throw new SlateDeclarationError("Trigger matches handler is not defined");
2080
+ }
2081
+ if (this.type === "trigger" && !this.#triggerMap) {
2082
+ throw new SlateDeclarationError("Trigger map handler is not defined");
2083
+ }
2084
+ let triggerParams = this.type === "trigger" ? {
2085
+ type: "trigger",
2086
+ triggerGroup: this.#triggerGroup,
2087
+ matches: this.#triggerMatches,
2088
+ map: this.#triggerMap
2089
+ } : null;
2090
+ return this.factory({
2091
+ ...this.params,
2092
+ scopes,
2093
+ authMethods,
2094
+ isPublic: this.isPublicTool === true,
2095
+ configSchema: this.#configSchema,
2096
+ authSchema: this.#authSchema,
2097
+ inputSchema: this.#inputSchema,
2098
+ outputSchema: this.#outputSchema,
2099
+ ...this.#toolParams,
2100
+ ...triggerParams
2101
+ });
1681
2102
  }
1682
2103
  };
1683
- var auth = () => SlateAuth.create();
1684
2104
 
1685
- // src/auth/oauth.ts
1686
- var isOAuthTokenResponse = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1687
- var formatOAuthTokenResponseMessage = (fieldLabel, providerLabel = "OAuth provider", operation = "token response") => `${providerLabel} OAuth ${operation} did not return ${fieldLabel}.`;
1688
- var getOAuthExpiresAtFromExpiresIn = (expiresIn, options = {}) => {
1689
- let {
1690
- nowMs = Date.now(),
1691
- providerLabel,
1692
- operation,
1693
- required = false,
1694
- expiresInType = "numberLike",
1695
- message
1696
- } = options;
1697
- if (expiresIn === void 0 || expiresIn === null || expiresIn === "") {
1698
- if (required) {
1699
- throw createApiServiceError(
1700
- message ?? formatOAuthTokenResponseMessage(
1701
- "a valid expires_in value",
1702
- providerLabel,
1703
- operation
1704
- ),
1705
- { reason: "oauth_token_response" }
1706
- );
1707
- }
1708
- return void 0;
2105
+ // src/action/getFileUrlTool.ts
2106
+ var import_zod = require("zod");
2107
+
2108
+ // src/action/tool.ts
2109
+ var SlateTool = class _SlateTool extends SlateAction {
2110
+ #handleInvocation;
2111
+ constructor(spec2, inputSchema, outputSchema, params) {
2112
+ super("tool", spec2, inputSchema, outputSchema, params);
2113
+ this.#handleInvocation = params.handleInvocation;
1709
2114
  }
1710
- let seconds = typeof expiresIn === "number" ? expiresIn : expiresInType === "numberLike" && typeof expiresIn === "string" ? Number(expiresIn) : Number.NaN;
1711
- if (!Number.isFinite(seconds)) {
1712
- throw createApiServiceError(
1713
- message ?? formatOAuthTokenResponseMessage("a valid expires_in value", providerLabel, operation),
1714
- { reason: "oauth_token_response" }
2115
+ static create(spec2, params) {
2116
+ return new SlateActionBuilder("tool", spec2, params, (params2) => {
2117
+ return _SlateTool.fromCreateParameters(spec2, params2);
2118
+ });
2119
+ }
2120
+ static fromCreateParameters(spec2, params) {
2121
+ if (params.type !== "tool") throw new Error("Invalid action type for tool");
2122
+ return new _SlateTool(spec2, params.inputSchema, params.outputSchema, params);
2123
+ }
2124
+ get handleInvocation() {
2125
+ return this.#handleInvocation;
2126
+ }
2127
+ };
2128
+ var tool = (spec2, params) => SlateTool.create(spec2, params);
2129
+
2130
+ // src/action/getFileUrlTool.ts
2131
+ var GET_FILE_URL_TOOL_ID = "metorial$getFileUrl";
2132
+ var getFileUrlToolInputSchema = import_zod.z.object({
2133
+ url: import_zod.z.string(),
2134
+ reference: import_zod.z.any().nullable()
2135
+ });
2136
+ var getFileUrlToolOutputSchema = import_zod.z.object({
2137
+ url: import_zod.z.string(),
2138
+ expiresAt: import_zod.z.string(),
2139
+ headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
2140
+ query: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional()
2141
+ });
2142
+ var getFileUrlTool = (spec2, handleGetFileUrl) => tool(spec2, {
2143
+ key: GET_FILE_URL_TOOL_ID,
2144
+ name: "Get File URL",
2145
+ description: "Reserved: refreshes an expiring attachment download URL. Hub-internal only."
2146
+ }).input(getFileUrlToolInputSchema).output(getFileUrlToolOutputSchema).handleInvocation(async (ctx) => {
2147
+ let output = await handleGetFileUrl(ctx);
2148
+ let redactor = new AuthConfigSecretRedactor(ctx._getAuthConfigForRedaction());
2149
+ return {
2150
+ output: {
2151
+ ...output,
2152
+ url: redactor.redactEmbedded(output.url, isUrlEmbeddedCredential),
2153
+ ...output.headers ? { headers: redactor.redactEmbedded(output.headers) } : {},
2154
+ ...output.query ? { query: redactor.redactEmbedded(output.query) } : {}
2155
+ },
2156
+ message: "ok"
2157
+ };
2158
+ }).build();
2159
+
2160
+ // src/action/publicTool.ts
2161
+ var SlatePublicTool = class {
2162
+ constructor() {
2163
+ }
2164
+ static create(spec2, params) {
2165
+ return new SlateActionBuilder(
2166
+ "tool",
2167
+ spec2,
2168
+ params,
2169
+ (params2) => {
2170
+ return SlateTool.fromCreateParameters(spec2, {
2171
+ ...params2,
2172
+ isPublic: true
2173
+ });
2174
+ },
2175
+ true
1715
2176
  );
1716
2177
  }
1717
- return new Date(nowMs + seconds * 1e3).toISOString();
1718
- };
1719
- var getRefreshToken = (refreshToken, previousRefreshToken, fallbackMode) => {
1720
- if (typeof refreshToken === "string") {
1721
- if (fallbackMode === "falsy" && !refreshToken) {
1722
- return previousRefreshToken;
1723
- }
1724
- return refreshToken;
2178
+ };
2179
+ var publicTool = (spec2, params) => SlatePublicTool.create(spec2, params);
2180
+
2181
+ // src/action/trigger.ts
2182
+ var SlateTrigger = class _SlateTrigger extends SlateAction {
2183
+ #triggerGroup;
2184
+ #matches;
2185
+ #map;
2186
+ constructor(spec2, inputSchema, outputSchema, params) {
2187
+ super("trigger", spec2, inputSchema, outputSchema, params);
2188
+ this.#triggerGroup = params.triggerGroup;
2189
+ this.#matches = params.matches;
2190
+ this.#map = params.map;
2191
+ }
2192
+ static create(spec2, params) {
2193
+ return new SlateActionBuilder("trigger", spec2, params, (params2) => {
2194
+ if (params2.type !== "trigger") throw new Error("Invalid action type for trigger");
2195
+ return new _SlateTrigger(spec2, params2.inputSchema, params2.outputSchema, params2);
2196
+ });
1725
2197
  }
1726
- if (fallbackMode === "falsy" && !refreshToken) {
1727
- return previousRefreshToken;
2198
+ get triggerGroup() {
2199
+ return this.#triggerGroup;
1728
2200
  }
1729
- return refreshToken === void 0 || refreshToken === null ? previousRefreshToken : void 0;
1730
- };
1731
- var normalizeOAuthTokenResponse = (data, options = {}) => {
1732
- let {
1733
- providerLabel,
1734
- operation,
1735
- previousRefreshToken,
1736
- refreshTokenFallbackMode = "nullish",
1737
- accessTokenMessage,
1738
- expiresInMessage,
1739
- ...expiresAtOptions
1740
- } = options;
1741
- if (!isOAuthTokenResponse(data)) {
1742
- throw createApiServiceError(
1743
- accessTokenMessage ?? formatOAuthTokenResponseMessage("a token response object", providerLabel, operation),
1744
- { reason: "oauth_token_response" }
1745
- );
2201
+ get matches() {
2202
+ return this.#matches;
1746
2203
  }
1747
- if (typeof data.access_token !== "string" || !data.access_token) {
1748
- throw createApiServiceError(
1749
- accessTokenMessage ?? formatOAuthTokenResponseMessage("an access token", providerLabel, operation),
1750
- { reason: "oauth_token_response" }
1751
- );
2204
+ get map() {
2205
+ return this.#map;
1752
2206
  }
1753
- return {
1754
- token: data.access_token,
1755
- refreshToken: getRefreshToken(
1756
- data.refresh_token,
1757
- previousRefreshToken,
1758
- refreshTokenFallbackMode
1759
- ),
1760
- expiresAt: getOAuthExpiresAtFromExpiresIn(data.expires_in, {
1761
- ...expiresAtOptions,
1762
- providerLabel,
1763
- operation,
1764
- message: expiresInMessage
1765
- })
1766
- };
1767
2207
  };
2208
+ var trigger = (spec2, params) => SlateTrigger.create(spec2, params);
1768
2209
 
1769
- // src/axios/index.ts
1770
- var import_axios3 = __toESM(require("axios"), 1);
1771
-
1772
- // src/axios/trace.ts
1773
- var traceDraftsByConfig = /* @__PURE__ */ new WeakMap();
1774
- var traceDraftsByHeaders = /* @__PURE__ */ new WeakMap();
1775
- var TRACE_TEXT_LIMIT = 10 * 1024;
1776
- var REDACTED_VALUE = "[redacted]";
1777
- var STRUCTURED_DEPTH_LIMIT = 6;
1778
- var STRUCTURED_ENTRY_LIMIT = 50;
1779
- var CORE_SECRET_KEY_ATOMS = [
1780
- // HTTP authentication
1781
- "authorization",
1782
- "proxy[-_.]?authorization",
1783
- "www[-_.]?authenticate",
1784
- "bearer",
1785
- // Generic tokens
1786
- "token",
1787
- "tokens",
1788
- "access[-_.]?token",
1789
- "refresh[-_.]?token",
1790
- "id[-_.]?token",
1791
- "auth[-_.]?token",
1792
- "bearer[-_.]?token",
1793
- "session[-_.]?token",
1794
- "api[-_.]?token",
1795
- "app[-_.]?token",
1796
- "user[-_.]?token",
1797
- "oauth[-_.]?token",
1798
- "personal[-_.]?access[-_.]?token",
1799
- "x[-_.]?auth[-_.]?token",
1800
- "x[-_.]?access[-_.]?token",
1801
- "x[-_.]?refresh[-_.]?token",
1802
- // API keys
1803
- "apikey",
1804
- "api[-_.]?key",
1805
- "app[-_.]?key",
1806
- "x[-_.]?api[-_.]?key",
1807
- "x[-_.]?app[-_.]?key",
1808
- // OAuth client credentials
1809
- "client[-_.]?secret",
1810
- "client[-_.]?key",
1811
- "consumer[-_.]?secret",
1812
- "consumer[-_.]?key",
1813
- // Cryptographic keys
1814
- "private[-_.]?key",
1815
- "privatekey",
1816
- "secret[-_.]?key",
1817
- "secretkey",
1818
- "secret[-_.]?access[-_.]?key",
1819
- "encryption[-_.]?key",
1820
- "decryption[-_.]?key",
1821
- "signing[-_.]?key",
1822
- "signing[-_.]?secret",
1823
- "master[-_.]?key",
1824
- "master[-_.]?secret",
1825
- "master[-_.]?password",
1826
- "shared[-_.]?secret",
1827
- "webhook[-_.]?secret",
1828
- "webhook[-_.]?signing[-_.]?secret",
1829
- // OAuth codes & PKCE
1830
- "auth[-_.]?code",
1831
- "authcode",
1832
- "authorization[-_.]?code",
1833
- "code[-_.]?verifier",
1834
- "code[-_.]?challenge",
1835
- // Passwords & passcodes
1836
- "password",
1837
- "passwd",
1838
- "pwd",
1839
- "passphrase",
1840
- "pass[-_.]?phrase",
1841
- "pin",
1842
- "passcode",
1843
- // Generic secret markers
1844
- "secret",
1845
- "secrets",
1846
- "credential",
1847
- "credentials",
1848
- "creds",
1849
- "auth",
1850
- "x[-_.]?auth",
1851
- "x[-_.]?auth[-_.]?key",
1852
- // CSRF / XSRF
1853
- "csrf",
1854
- "xsrf",
1855
- "csrf[-_.]?token",
1856
- "xsrf[-_.]?token",
1857
- "x[-_.]?csrf[-_.]?token",
1858
- "x[-_.]?xsrf[-_.]?token",
1859
- // JWT
1860
- "jwt",
1861
- // Sessions & cookies
1862
- "session[-_.]?id",
1863
- "sessionid",
1864
- "sid",
1865
- "cookie",
1866
- "cookies",
1867
- "set[-_.]?cookie",
1868
- // Signatures / MAC
1869
- "signature",
1870
- "x[-_.]?hub[-_.]?signature",
1871
- "x[-_.]?signature",
1872
- "sig",
1873
- "hmac",
1874
- "mac",
1875
- // Crypto artifacts
1876
- "salt",
1877
- "nonce",
1878
- // Multi-factor / verification
1879
- "otp",
1880
- "totp",
1881
- "mfa",
1882
- "mfa[-_.]?code",
1883
- "2fa",
1884
- "two[-_.]?factor",
1885
- "twofactor",
1886
- "verification[-_.]?code",
1887
- "verify[-_.]?code",
1888
- "confirm(?:ation)?[-_.]?code",
1889
- "sms[-_.]?code",
1890
- "email[-_.]?code",
1891
- // Recovery & seed phrases
1892
- "seed[-_.]?phrase",
1893
- "mnemonic",
1894
- "recovery[-_.]?key",
1895
- "recovery[-_.]?code",
1896
- "recovery[-_.]?phrase",
1897
- // PII / financial
1898
- "card[-_.]?number",
1899
- "card[-_.]?code",
1900
- "cvv",
1901
- "cvc",
1902
- "ccv",
1903
- "cc[-_.]?num(?:ber)?",
1904
- "pan",
1905
- "ssn",
1906
- "social[-_.]?security",
1907
- "license[-_.]?key"
1908
- ];
1909
- var URL_FORM_SECRET_KEY_ATOMS = [...CORE_SECRET_KEY_ATOMS, "code"];
1910
- var buildKeyBoundaryPattern = (atoms, flags) => new RegExp(`(?:^|[^A-Za-z0-9])(?:${atoms.join("|")})(?=[^A-Za-z0-9]|$)`, flags);
1911
- var SECRET_KEY_PATTERN = buildKeyBoundaryPattern(CORE_SECRET_KEY_ATOMS, "i");
1912
- var URL_FORM_SECRET_KEY_PATTERN = buildKeyBoundaryPattern(URL_FORM_SECRET_KEY_ATOMS, "i");
1913
- var NON_SECRET_KEY_EXACT = /* @__PURE__ */ new Set([
1914
- "token_type",
1915
- "token-type",
1916
- "tokentype",
1917
- "token_kind",
1918
- "token-kind",
1919
- "tokenkind",
1920
- "token_ttl",
1921
- "token-ttl",
1922
- "token_expires_in",
1923
- "token-expires-in",
1924
- "token_expiry",
1925
- "signature_method",
1926
- "signature-method",
1927
- "signature_type",
1928
- "signature-type",
1929
- "signature_version",
1930
- "signature-version",
1931
- "auth_type",
1932
- "auth-type",
1933
- "auth_method",
1934
- "auth-method",
1935
- "authentication_type",
1936
- "authentication-type",
1937
- "authentication_method",
1938
- "authentication-method",
1939
- "grant_type",
1940
- "grant-type",
1941
- "password_strength",
1942
- "password-strength",
1943
- "password_policy",
1944
- "password-policy",
1945
- "key_type",
1946
- "key-type",
1947
- "key_name",
1948
- "key-name",
1949
- "key_id",
1950
- "key-id",
1951
- "kid"
1952
- ]);
1953
- var isSecretKeyName = (name) => {
1954
- let normalized = name.toLowerCase();
1955
- if (NON_SECRET_KEY_EXACT.has(normalized)) return false;
1956
- return SECRET_KEY_PATTERN.test(normalized);
1957
- };
1958
- var isUrlFormSecretKeyName = (name) => {
1959
- let normalized = name.toLowerCase();
1960
- if (NON_SECRET_KEY_EXACT.has(normalized)) return false;
1961
- return URL_FORM_SECRET_KEY_PATTERN.test(normalized);
2210
+ // src/action/triggerGroup.ts
2211
+ var import_zod2 = require("zod");
2212
+ var SlateDefaultPollingIntervalSeconds = 60 * 10;
2213
+ var SlateTriggerGroup = class _SlateTriggerGroup {
2214
+ constructor(_spec, _params) {
2215
+ this._spec = _spec;
2216
+ this._params = _params;
2217
+ }
2218
+ _spec;
2219
+ _params;
2220
+ static create(spec2, params) {
2221
+ return new SlateTriggerGroupBuilder(spec2, params, (p) => new _SlateTriggerGroup(spec2, p));
2222
+ }
2223
+ get spec() {
2224
+ return this._spec;
2225
+ }
2226
+ get key() {
2227
+ return this._params.key;
2228
+ }
2229
+ get name() {
2230
+ return this._params.name;
2231
+ }
2232
+ get description() {
2233
+ return this._params.description;
2234
+ }
2235
+ get metadata() {
2236
+ return this._params.metadata;
2237
+ }
2238
+ get eventSchema() {
2239
+ return this._params.eventSchema ?? import_zod2.z.object({}).passthrough();
2240
+ }
2241
+ get source() {
2242
+ return this._params.source;
2243
+ }
2244
+ get polling() {
2245
+ return this._params.polling;
2246
+ }
2247
+ get webhook() {
2248
+ return this._params.webhook;
2249
+ }
2250
+ get gateway() {
2251
+ return this._params.gateway;
2252
+ }
2253
+ get routingMatchers() {
2254
+ return this._params.routingMatchers;
2255
+ }
1962
2256
  };
1963
- var KNOWN_SECRET_VALUE_PATTERNS = [
1964
- // JSON Web Tokens (header.payload.signature)
1965
- /\beyJ[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\b/g,
1966
- // AWS access key IDs
1967
- /\b(?:AKIA|ASIA|AGPA|AIDA|ANPA|ANVA|AROA|APKA|ASCA)[A-Z0-9]{16}\b/g,
1968
- // GitHub tokens (PAT / OAuth / server-to-server / user-to-server / refresh)
1969
- /\bgh[pousr]_[A-Za-z0-9]{30,}\b/g,
1970
- // Slack tokens
1971
- /\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g,
1972
- // Stripe secret / public / restricted keys
1973
- /\b(?:sk|rk|pk)_(?:test|live)_[A-Za-z0-9]{16,}\b/g,
1974
- // OpenAI API keys
1975
- /\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b/g,
1976
- // Anthropic API keys
1977
- /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g,
1978
- // Google API keys
1979
- /\bAIza[A-Za-z0-9_-]{35}\b/g,
1980
- // SendGrid API keys
1981
- /\bSG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\b/g,
1982
- // Twilio API keys
1983
- /\bSK[0-9a-fA-F]{32}\b/g,
1984
- // PEM-encoded private keys (multi-line)
1985
- /-----BEGIN[A-Z ]*PRIVATE KEY-----[\s\S]*?-----END[A-Z ]*PRIVATE KEY-----/g,
1986
- // SSH private keys (OpenSSH format)
1987
- /-----BEGIN OPENSSH PRIVATE KEY-----[\s\S]*?-----END OPENSSH PRIVATE KEY-----/g
1988
- ];
1989
- var HTTP_AUTH_SCHEME_PATTERN = /\b(bearer|basic|digest|token|negotiate|apikey)\s+([A-Za-z0-9_\-.~+/=]{4,})/gi;
1990
- var GENERIC_KEY_VALUE_PATTERN = /(?<![A-Za-z0-9])([A-Za-z0-9][A-Za-z0-9_\-.]*)(\s*=\s*)([^&#\s;]+)/g;
1991
- var GENERIC_JSON_KEY_VALUE_PATTERN = /"([^"\\]*(?:\\.[^"\\]*)*)"(\s*:\s*)"([^"\\]*(?:\\.[^"\\]*)*)"/g;
1992
- var SAFE_HEADER_NAMES = /* @__PURE__ */ new Set([
1993
- "accept",
1994
- "accept-encoding",
1995
- "accept-language",
1996
- "cache-control",
1997
- "connection",
1998
- "content-encoding",
1999
- "content-language",
2000
- "content-length",
2001
- "content-type",
2002
- "date",
2003
- "etag",
2004
- "expires",
2005
- "if-modified-since",
2006
- "if-none-match",
2007
- "keep-alive",
2008
- "last-modified",
2009
- "location",
2010
- "origin",
2011
- "pragma",
2012
- "referer",
2013
- "referrer-policy",
2014
- "request-id",
2015
- "retry-after",
2016
- "server",
2017
- "transfer-encoding",
2018
- "user-agent",
2019
- "vary",
2020
- "via",
2021
- "x-correlation-id",
2022
- "x-powered-by",
2023
- "x-request-id",
2024
- "x-slates-provider",
2025
- "x-trace-id"
2026
- ]);
2027
- var SAFE_HEADER_PREFIXES = ["ratelimit-", "x-ratelimit-"];
2028
- var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2029
- var isObjectLike = (value) => typeof value === "object" && value !== null;
2030
- var normalizeContentType = (value) => value?.split(";")[0]?.trim().toLowerCase() || void 0;
2031
- var isTextContentType = (contentType) => !contentType || /(^text\/)|json|xml|html|javascript|graphql|x-www-form-urlencoded|svg/.test(contentType);
2032
- var isSafeHeaderName = (name) => {
2033
- let normalized = name.toLowerCase();
2034
- if (isSecretKeyName(normalized)) return false;
2035
- if (SAFE_HEADER_NAMES.has(normalized)) return true;
2036
- return SAFE_HEADER_PREFIXES.some((prefix) => normalized.startsWith(prefix));
2257
+ var SlateTriggerGroupBuilder = class {
2258
+ constructor(spec2, params, factory) {
2259
+ this.spec = spec2;
2260
+ this.params = params;
2261
+ this.factory = factory;
2262
+ }
2263
+ spec;
2264
+ params;
2265
+ factory;
2266
+ #source = null;
2267
+ #polling = null;
2268
+ #webhook = null;
2269
+ #gateway = null;
2270
+ #routingMatchers = null;
2271
+ polling(props) {
2272
+ if (this.#source) {
2273
+ throw new SlateDeclarationError("Trigger group invocation is already defined");
2274
+ }
2275
+ this.#source = "polling";
2276
+ this.#polling = {
2277
+ intervalSeconds: props.intervalSeconds ?? SlateDefaultPollingIntervalSeconds,
2278
+ pollEvents: props.pollEvents
2279
+ };
2280
+ return this;
2281
+ }
2282
+ webhook(props) {
2283
+ if (this.#source) {
2284
+ throw new SlateDeclarationError("Trigger group invocation is already defined");
2285
+ }
2286
+ if (!!props.autoRegistration === !!props.manualRegistration) {
2287
+ throw new SlateDeclarationError(
2288
+ "Webhook trigger groups require exactly one of autoRegistration or manualRegistration"
2289
+ );
2290
+ }
2291
+ this.#source = "webhook";
2292
+ this.#webhook = {
2293
+ autoRegistration: props.autoRegistration,
2294
+ manualRegistration: props.manualRegistration,
2295
+ process: props.process
2296
+ };
2297
+ return this;
2298
+ }
2299
+ /** Receive events over a platform-managed persistent connection (e.g. a WebSocket gateway). */
2300
+ gateway(props) {
2301
+ if (this.#source) {
2302
+ throw new SlateDeclarationError("Trigger group invocation is already defined");
2303
+ }
2304
+ this.#source = "gateway";
2305
+ this.#gateway = { connect: props.connect, receive: props.receive };
2306
+ return this;
2307
+ }
2308
+ routingMatchers(handler) {
2309
+ this.#routingMatchers = handler;
2310
+ return this;
2311
+ }
2312
+ build() {
2313
+ if (!this.#source) {
2314
+ throw new SlateDeclarationError(
2315
+ "Trigger group invocation (polling, webhook, or gateway) is not defined"
2316
+ );
2317
+ }
2318
+ if (!this.#routingMatchers) {
2319
+ throw new SlateDeclarationError("Trigger group routing matchers handler is not defined");
2320
+ }
2321
+ return this.factory({
2322
+ ...this.params,
2323
+ source: this.#source,
2324
+ polling: this.#polling ?? void 0,
2325
+ webhook: this.#webhook ?? void 0,
2326
+ gateway: this.#gateway ?? void 0,
2327
+ routingMatchers: this.#routingMatchers
2328
+ });
2329
+ }
2037
2330
  };
2038
- var truncateText = (text) => {
2039
- if (text.length <= TRACE_TEXT_LIMIT) {
2040
- return { text, truncated: false };
2331
+ var triggerGroup = (spec2, params) => SlateTriggerGroup.create(spec2, params);
2332
+
2333
+ // src/action/attachment.ts
2334
+ var createUrlAttachment = (url, opts = {}) => {
2335
+ if (opts.refreshReference !== void 0 && !opts.refreshAt) {
2336
+ throw new Error("createUrlAttachment: refreshAt is required when refreshReference is set");
2041
2337
  }
2042
2338
  return {
2043
- text: `${text.slice(0, TRACE_TEXT_LIMIT)}...[truncated]`,
2044
- truncated: true
2339
+ mimeType: opts.mimeType,
2340
+ attachmentHash: opts.attachmentHash,
2341
+ content: {
2342
+ type: "url",
2343
+ url,
2344
+ ...opts.headers ? { headers: opts.headers } : {},
2345
+ ...opts.query ? { query: opts.query } : {},
2346
+ ...opts.refreshReference !== void 0 ? { refreshReference: opts.refreshReference } : {},
2347
+ ...opts.refreshAt ? { refreshAt: opts.refreshAt } : {}
2348
+ }
2045
2349
  };
2046
2350
  };
2047
- var sanitizeFreeText = (text, redactor) => {
2048
- if (!text) return text;
2049
- let result = redactor ? redactor.redact(text) : text;
2050
- result = result.replace(
2051
- HTTP_AUTH_SCHEME_PATTERN,
2052
- (_match, scheme) => `${scheme} ${REDACTED_VALUE}`
2053
- );
2054
- for (let pattern of KNOWN_SECRET_VALUE_PATTERNS) {
2055
- result = result.replace(pattern, REDACTED_VALUE);
2351
+ var createBase64Attachment = (content, mimeType, attachmentHash) => ({
2352
+ mimeType,
2353
+ attachmentHash,
2354
+ content: {
2355
+ type: "content",
2356
+ encoding: "base64",
2357
+ content
2056
2358
  }
2057
- result = result.replace(
2058
- GENERIC_KEY_VALUE_PATTERN,
2059
- (match, key, equals, _value) => isUrlFormSecretKeyName(key) ? `${key}${equals}${REDACTED_VALUE}` : match
2060
- );
2061
- result = result.replace(
2062
- GENERIC_JSON_KEY_VALUE_PATTERN,
2063
- (match, key, colon, _value) => isSecretKeyName(key) ? `"${key}"${colon}"${REDACTED_VALUE}"` : match
2064
- );
2065
- return result;
2066
- };
2067
- var sanitizeScalar = (value, redactor) => truncateText(sanitizeFreeText(value, redactor));
2068
- var redactStructuredValue = (value, depth = 0, redactor) => {
2069
- if (value == null) return value;
2070
- if (depth >= STRUCTURED_DEPTH_LIMIT) return "[truncated]";
2071
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
2072
- return typeof value === "string" ? sanitizeFreeText(value, redactor) : value;
2359
+ });
2360
+ var createTextAttachment = (content, mimeType, attachmentHash) => ({
2361
+ mimeType,
2362
+ attachmentHash,
2363
+ content: {
2364
+ type: "content",
2365
+ encoding: "utf-8",
2366
+ content
2367
+ }
2368
+ });
2369
+
2370
+ // src/action/directUpload.ts
2371
+ var bufferAttachmentBody = async (body, maxSizeBytes) => {
2372
+ if (body instanceof Uint8Array) {
2373
+ if (body.byteLength > maxSizeBytes) {
2374
+ throw new Error(`Attachment exceeds the maximum size of ${maxSizeBytes} bytes`);
2375
+ }
2376
+ let buffered2 = new ArrayBuffer(body.byteLength);
2377
+ new Uint8Array(buffered2).set(body);
2378
+ return buffered2;
2073
2379
  }
2074
- if (Array.isArray(value)) {
2075
- return value.slice(0, STRUCTURED_ENTRY_LIMIT).map((entry) => redactStructuredValue(entry, depth + 1, redactor));
2380
+ let reader = body.getReader();
2381
+ let chunks = [];
2382
+ let sizeBytes = 0;
2383
+ while (true) {
2384
+ let { done, value } = await reader.read();
2385
+ if (done) break;
2386
+ if (!value) continue;
2387
+ sizeBytes += value.byteLength;
2388
+ if (sizeBytes > maxSizeBytes) {
2389
+ await reader.cancel();
2390
+ throw new Error(`Attachment exceeds the maximum size of ${maxSizeBytes} bytes`);
2391
+ }
2392
+ chunks.push(value);
2076
2393
  }
2077
- if (isRecord2(value)) {
2078
- return Object.fromEntries(
2079
- Object.entries(value).slice(0, STRUCTURED_ENTRY_LIMIT).map(([key, entry]) => [
2080
- key,
2081
- isSecretKeyName(key) ? REDACTED_VALUE : redactStructuredValue(entry, depth + 1, redactor)
2082
- ])
2083
- );
2394
+ let buffered = new ArrayBuffer(sizeBytes);
2395
+ let bufferedView = new Uint8Array(buffered);
2396
+ let offset = 0;
2397
+ for (let chunk of chunks) {
2398
+ bufferedView.set(chunk, offset);
2399
+ offset += chunk.byteLength;
2084
2400
  }
2085
- return String(value);
2401
+ return buffered;
2086
2402
  };
2087
- var maybeParseJson = (text, contentType) => {
2088
- let trimmed = text.trim();
2089
- if (!trimmed) return null;
2090
- if (!contentType?.includes("json") && !/^[[{]/.test(trimmed)) {
2091
- return null;
2403
+ var uploadAttachmentDirect = async (d) => {
2404
+ let baseUrl = d.live.baseUrl.replace(/\/$/, "");
2405
+ let body = await bufferAttachmentBody(d.body, d.live.maxAttachmentSizeBytes);
2406
+ let registerRes = await fetch(`${baseUrl}/slates-hub/live-invocation/attachments`, {
2407
+ method: "POST",
2408
+ headers: {
2409
+ "content-type": "application/json",
2410
+ authorization: `Bearer ${d.live.token}`
2411
+ },
2412
+ body: JSON.stringify({
2413
+ attachments: [
2414
+ {
2415
+ mimeType: d.mimeType,
2416
+ filename: d.filename,
2417
+ sizeBytes: body.byteLength || void 0
2418
+ }
2419
+ ]
2420
+ })
2421
+ });
2422
+ if (!registerRes.ok) {
2423
+ throw new Error(
2424
+ `Failed to register attachment for direct upload (status ${registerRes.status})`
2425
+ );
2092
2426
  }
2093
- try {
2094
- return JSON.parse(trimmed);
2095
- } catch {
2096
- return null;
2427
+ let { attachments } = await registerRes.json();
2428
+ let registration = attachments[0];
2429
+ if (!registration) {
2430
+ throw new Error("Live invocation API returned no attachment registrations");
2431
+ }
2432
+ let putRes = await fetch(registration.uploadUrl, {
2433
+ method: "PUT",
2434
+ headers: {
2435
+ ...d.mimeType ? { "content-type": d.mimeType } : {},
2436
+ "content-length": String(body.byteLength)
2437
+ },
2438
+ body
2439
+ });
2440
+ if (!putRes.ok) {
2441
+ throw new Error(`Failed to upload attachment content (status ${putRes.status})`);
2097
2442
  }
2098
- };
2099
- var sanitizeTextBody = (text, contentType, redactor) => {
2100
- if (!text) return void 0;
2101
- let normalizedContentType = normalizeContentType(contentType);
2102
- let parsedJson = maybeParseJson(text, normalizedContentType);
2103
- let normalizedText = parsedJson !== null ? JSON.stringify(redactStructuredValue(parsedJson, 0, redactor)) : sanitizeFreeText(text, redactor);
2104
- let { text: truncatedText, truncated } = truncateText(normalizedText);
2105
2443
  return {
2106
- ...normalizedContentType ? { contentType: normalizedContentType } : {},
2107
- text: truncatedText,
2108
- ...truncated ? { truncated: true } : {}
2444
+ mimeType: d.mimeType,
2445
+ content: { type: "upload_reference", referenceId: registration.referenceId }
2109
2446
  };
2110
2447
  };
2111
- var isBinaryLike = (value) => {
2112
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) return true;
2113
- if (value instanceof ArrayBuffer) return true;
2114
- if (ArrayBuffer.isView(value)) return true;
2115
- if (typeof Blob !== "undefined" && value instanceof Blob) return true;
2116
- if (typeof FormData !== "undefined" && value instanceof FormData) return true;
2117
- return false;
2118
- };
2119
- var serializeTextBody = (value, contentType, redactor) => {
2120
- let normalizedContentType = normalizeContentType(contentType);
2121
- if (value == null || isBinaryLike(value) || !isTextContentType(normalizedContentType)) {
2122
- return void 0;
2448
+
2449
+ // src/adapter/adapter.ts
2450
+ var SlateAdapter = class {
2451
+ constructor(_spec, _tools, _triggers) {
2452
+ this._spec = _spec;
2453
+ this._tools = _tools;
2454
+ this._triggers = _triggers;
2123
2455
  }
2124
- if (typeof value === "string") {
2125
- return sanitizeTextBody(value, normalizedContentType, redactor);
2456
+ _spec;
2457
+ _tools;
2458
+ _triggers;
2459
+ get spec() {
2460
+ return this._spec;
2126
2461
  }
2127
- if (value instanceof URLSearchParams) {
2128
- return sanitizeTextBody(value.toString(), normalizedContentType, redactor);
2462
+ get id() {
2463
+ return this._spec.id;
2129
2464
  }
2130
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
2131
- return sanitizeTextBody(String(value), normalizedContentType, redactor);
2465
+ get name() {
2466
+ return this._spec.name;
2132
2467
  }
2133
- if (Array.isArray(value) || isRecord2(value)) {
2134
- return sanitizeTextBody(
2135
- JSON.stringify(redactStructuredValue(value, 0, redactor)),
2136
- "application/json",
2137
- redactor
2138
- );
2468
+ get capabilities() {
2469
+ return this._spec.capabilities;
2139
2470
  }
2140
- return void 0;
2141
- };
2142
- var buildUrl = (baseURL, url) => {
2143
- if (!url) return "";
2144
- if (!baseURL) return url;
2145
- try {
2146
- return new URL(url, baseURL).toString();
2147
- } catch {
2148
- return url;
2471
+ get tools() {
2472
+ return this._tools;
2473
+ }
2474
+ get triggers() {
2475
+ return this._triggers;
2476
+ }
2477
+ get actions() {
2478
+ return [...this._triggers, ...this._tools];
2149
2479
  }
2150
2480
  };
2151
- var REDACTED_ENCODED = encodeURIComponent(REDACTED_VALUE);
2152
- var decodeRedactedMarker = (value) => REDACTED_ENCODED === REDACTED_VALUE ? value : value.split(REDACTED_ENCODED).join(REDACTED_VALUE);
2153
- var redactHashFragment = (hash, redactor) => {
2154
- if (!hash?.includes("=")) return hash;
2155
- let withoutHash = hash.startsWith("#") ? hash.slice(1) : hash;
2156
- let redacted = withoutHash.replace(
2157
- /(?<![A-Za-z0-9])([A-Za-z0-9][A-Za-z0-9_\-.]*)=([^&]*)/g,
2158
- (match, key, rawValue) => {
2159
- if (isUrlFormSecretKeyName(key)) return `${key}=${REDACTED_VALUE}`;
2160
- let literalRedacted = redactor ? redactor.redact(rawValue) : rawValue;
2161
- return literalRedacted !== rawValue ? `${key}=${literalRedacted}` : match;
2481
+
2482
+ // src/adapter/spec.ts
2483
+ var SlateAdapterSpec = class _SlateAdapterSpec {
2484
+ constructor(_params) {
2485
+ this._params = _params;
2486
+ }
2487
+ _params;
2488
+ static create(params) {
2489
+ let id = params.id?.trim();
2490
+ let name = params.name?.trim();
2491
+ if (!id) {
2492
+ throw new SlateDeclarationError("Adapter id must be a non-empty string");
2162
2493
  }
2163
- );
2164
- return redacted ? `#${redacted}` : "";
2165
- };
2166
- var isEmbeddedPathSecret = (secret, path) => secret.length >= 8 && isSecretKeyName(path.split(".").pop() ?? "");
2167
- var sanitizeUrl = (value, redactor) => {
2168
- if (!value) return value;
2169
- try {
2170
- let url = new URL(value);
2171
- if (url.username || url.password) {
2172
- url.username = "";
2173
- url.password = "";
2494
+ if (!name) {
2495
+ throw new SlateDeclarationError("Adapter name must be a non-empty string");
2174
2496
  }
2175
- if (redactor) url.pathname = redactor.redactEmbedded(url.pathname, isEmbeddedPathSecret);
2176
- for (let key of Array.from(url.searchParams.keys())) {
2177
- if (isUrlFormSecretKeyName(key)) {
2178
- url.searchParams.set(key, REDACTED_VALUE);
2179
- continue;
2497
+ return new _SlateAdapterSpec({
2498
+ id,
2499
+ name,
2500
+ capabilities: validateCapabilities(params.capabilities ?? [])
2501
+ });
2502
+ }
2503
+ get id() {
2504
+ return this._params.id;
2505
+ }
2506
+ get name() {
2507
+ return this._params.name;
2508
+ }
2509
+ get capabilities() {
2510
+ return this._params.capabilities;
2511
+ }
2512
+ get parameters() {
2513
+ return this._params;
2514
+ }
2515
+ tool(spec2, params) {
2516
+ return SlateTool.create(spec2, this.linkAction(params));
2517
+ }
2518
+ publicTool(spec2, params) {
2519
+ return SlatePublicTool.create(spec2, this.linkAction(params));
2520
+ }
2521
+ trigger(spec2, params) {
2522
+ return SlateTrigger.create(spec2, this.linkAction(params));
2523
+ }
2524
+ register(params) {
2525
+ let actions = [...params.tools, ...params.triggers];
2526
+ let seenKeys = /* @__PURE__ */ new Set();
2527
+ for (let action of actions) {
2528
+ if (action.adapter && action.adapter !== this.id) {
2529
+ throw new SlateDeclarationError(
2530
+ `Action "${action.key}" is linked to adapter "${action.adapter}", not "${this.id}"`
2531
+ );
2180
2532
  }
2181
- let rawValue = url.searchParams.get(key) ?? "";
2182
- let literalRedacted = redactor ? redactor.redact(rawValue) : rawValue;
2183
- if (literalRedacted !== rawValue) url.searchParams.set(key, literalRedacted);
2533
+ if (!action.adapter) {
2534
+ throw new SlateDeclarationError(
2535
+ `Action "${action.key}" must be created with this adapter's tool(), publicTool(), or trigger() helpers`
2536
+ );
2537
+ }
2538
+ if (seenKeys.has(action.key)) {
2539
+ throw new SlateDeclarationError(
2540
+ `Adapter "${this.id}" already has an action with key "${action.key}"`
2541
+ );
2542
+ }
2543
+ seenKeys.add(action.key);
2184
2544
  }
2185
- url.hash = redactHashFragment(url.hash, redactor);
2186
- return decodeRedactedMarker(url.toString());
2187
- } catch {
2188
- let text = redactor ? redactor.redactEmbedded(value, isEmbeddedPathSecret) : value;
2189
- return text.replace(
2190
- /([?&]([^=&#]+)=)([^&#]+)/g,
2191
- (_match, prefix, key, rawValue) => isUrlFormSecretKeyName(key) ? `${prefix}${REDACTED_VALUE}` : `${prefix}${rawValue}`
2192
- );
2545
+ return new SlateAdapter(this, params.tools, params.triggers);
2546
+ }
2547
+ linkAction(params) {
2548
+ if (params.adapter != null && params.adapter !== this.id) {
2549
+ throw new SlateDeclarationError(
2550
+ `Action "${params.key}" cannot be linked to adapter "${this.id}" because it is already linked to "${params.adapter}"`
2551
+ );
2552
+ }
2553
+ return {
2554
+ ...params,
2555
+ adapter: this.id
2556
+ };
2193
2557
  }
2194
2558
  };
2195
- var flattenHeaderValue = (value) => {
2196
- if (typeof value === "string") return value;
2197
- if (typeof value === "number" || typeof value === "boolean") return String(value);
2198
- if (Array.isArray(value)) {
2199
- let normalized = value.map((entry) => flattenHeaderValue(entry)).filter((entry) => typeof entry === "string" && entry.length > 0);
2200
- return normalized.length > 0 ? normalized.join(", ") : void 0;
2201
- }
2202
- return void 0;
2559
+ var adapterSpec = (params) => SlateAdapterSpec.create(params);
2560
+ var validateCapabilities = (capabilities) => {
2561
+ let seenIds = /* @__PURE__ */ new Set();
2562
+ return capabilities.map((capability) => {
2563
+ let id = capability.id?.trim();
2564
+ if (!id) {
2565
+ throw new SlateDeclarationError("Adapter capability ids must be non-empty strings");
2566
+ }
2567
+ if (seenIds.has(id)) {
2568
+ throw new SlateDeclarationError(`Adapter capability "${id}" is defined more than once`);
2569
+ }
2570
+ seenIds.add(id);
2571
+ return {
2572
+ id,
2573
+ value: capability.value
2574
+ };
2575
+ });
2203
2576
  };
2204
- var headerEntries = (headers) => {
2205
- if (!headers) return [];
2206
- if (typeof headers.toJSON === "function") {
2207
- let json = headers.toJSON();
2208
- if (isRecord2(json)) {
2209
- return Object.entries(json).map(([key, value]) => {
2210
- let flattened = flattenHeaderValue(value);
2211
- return flattened ? [key, flattened] : null;
2212
- }).filter((entry) => entry !== null);
2577
+
2578
+ // src/auth/auth.ts
2579
+ var SlateAuth = class _SlateAuth {
2580
+ #outputSchema = null;
2581
+ #authStack = [];
2582
+ constructor() {
2583
+ }
2584
+ static create() {
2585
+ return new _SlateAuth();
2586
+ }
2587
+ output(schema) {
2588
+ this.#outputSchema = schema;
2589
+ return this;
2590
+ }
2591
+ addAuth(auth2) {
2592
+ let existingKeys = this.#authStack.map((a) => a.key);
2593
+ if (existingKeys.includes(auth2.key)) {
2594
+ throw new Error(`Auth with key "${auth2.key}" already exists in the auth stack`);
2213
2595
  }
2596
+ this.#authStack.push(auth2);
2597
+ return this;
2214
2598
  }
2215
- if (typeof headers.entries === "function") {
2216
- return Array.from(
2217
- headers.entries()
2218
- ).map(([key, value]) => [key, value]);
2599
+ addOauth(auth2) {
2600
+ this.addAuth(auth2);
2601
+ return this;
2219
2602
  }
2220
- if (isRecord2(headers)) {
2221
- return Object.entries(headers).map(([key, value]) => {
2222
- let flattened = flattenHeaderValue(value);
2223
- return flattened ? [key, flattened] : null;
2224
- }).filter((entry) => entry !== null);
2603
+ addTokenAuth(auth2) {
2604
+ this.addAuth(auth2);
2605
+ return this;
2225
2606
  }
2226
- return [];
2227
- };
2228
- var sanitizeHeaders = (headers, redactor) => {
2229
- let entries = headerEntries(headers).map(
2230
- ([key, value]) => [key.toLowerCase(), sanitizeScalar(value, redactor).text]
2231
- ).filter(([key]) => isSafeHeaderName(key));
2232
- if (entries.length === 0) return void 0;
2233
- return Object.fromEntries(entries);
2234
- };
2235
- var getContentType = (headers) => headerEntries(headers).find(([key]) => key.toLowerCase() === "content-type")?.[1];
2236
- var takeTraceDraft = (config2) => {
2237
- if (!config2) return void 0;
2238
- let draft = config2.__slatesHttpTraceDraft ?? (isObjectLike(config2) ? traceDraftsByConfig.get(config2) : void 0) ?? (isObjectLike(config2.headers) ? traceDraftsByHeaders.get(config2.headers) : void 0);
2239
- if (!draft) return void 0;
2240
- return draft;
2241
- };
2242
- var clearTraceDraft = (config2, draft) => {
2243
- if (!config2) return;
2244
- if (config2.__slatesHttpTraceDraft === draft) {
2245
- config2.__slatesHttpTraceDraft = void 0;
2607
+ addServiceAccountAuth(auth2) {
2608
+ this.addAuth(auth2);
2609
+ return this;
2246
2610
  }
2247
- if (isObjectLike(config2)) {
2248
- traceDraftsByConfig.delete(config2);
2611
+ addCustomAuth(auth2) {
2612
+ this.addAuth(auth2);
2613
+ return this;
2249
2614
  }
2250
- if (isObjectLike(config2.headers)) {
2251
- traceDraftsByHeaders.delete(config2.headers);
2615
+ addNone() {
2616
+ this.addAuth({
2617
+ type: "auth.none",
2618
+ name: "No Authentication",
2619
+ key: "none"
2620
+ });
2621
+ return this;
2622
+ }
2623
+ get authStack() {
2624
+ return this.#authStack.filter((a) => a.type !== "auth.none");
2625
+ }
2626
+ get outputSchema() {
2627
+ if (!this.#outputSchema) {
2628
+ throw new Error("Output schema is not defined for this auth");
2629
+ }
2630
+ return this.#outputSchema;
2252
2631
  }
2253
2632
  };
2254
- var attachHttpTraceDraft = (config2, context) => {
2255
- let traceAwareConfig = config2;
2256
- let contentType = getContentType(config2.headers);
2257
- let redactor = new AuthConfigSecretRedactor(context._getAuthConfigForRedaction());
2258
- traceAwareConfig.__slatesHttpTraceDraft = {
2259
- context,
2260
- startedAt: (/* @__PURE__ */ new Date()).toISOString(),
2261
- startedAtMs: Date.now(),
2262
- request: {
2263
- method: (config2.method ?? "GET").toUpperCase(),
2264
- url: sanitizeUrl(buildUrl(config2.baseURL, config2.url), redactor),
2265
- ...sanitizeHeaders(config2.headers, redactor) ? { headers: sanitizeHeaders(config2.headers, redactor) } : {},
2266
- ...serializeTextBody(config2.data, contentType, redactor) ? { body: serializeTextBody(config2.data, contentType, redactor) } : {}
2633
+ var auth = () => SlateAuth.create();
2634
+
2635
+ // src/auth/oauth.ts
2636
+ var isOAuthTokenResponse = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2637
+ var formatOAuthTokenResponseMessage = (fieldLabel, providerLabel = "OAuth provider", operation = "token response") => `${providerLabel} OAuth ${operation} did not return ${fieldLabel}.`;
2638
+ var getOAuthExpiresAtFromExpiresIn = (expiresIn, options = {}) => {
2639
+ let {
2640
+ nowMs = Date.now(),
2641
+ providerLabel,
2642
+ operation,
2643
+ required = false,
2644
+ expiresInType = "numberLike",
2645
+ message
2646
+ } = options;
2647
+ if (expiresIn === void 0 || expiresIn === null || expiresIn === "") {
2648
+ if (required) {
2649
+ throw createApiServiceError(
2650
+ message ?? formatOAuthTokenResponseMessage(
2651
+ "a valid expires_in value",
2652
+ providerLabel,
2653
+ operation
2654
+ ),
2655
+ { reason: "oauth_token_response" }
2656
+ );
2267
2657
  }
2268
- };
2269
- if (isObjectLike(traceAwareConfig)) {
2270
- traceDraftsByConfig.set(traceAwareConfig, traceAwareConfig.__slatesHttpTraceDraft);
2658
+ return void 0;
2271
2659
  }
2272
- if (isObjectLike(traceAwareConfig.headers)) {
2273
- traceDraftsByHeaders.set(
2274
- traceAwareConfig.headers,
2275
- traceAwareConfig.__slatesHttpTraceDraft
2660
+ let seconds = typeof expiresIn === "number" ? expiresIn : expiresInType === "numberLike" && typeof expiresIn === "string" ? Number(expiresIn) : Number.NaN;
2661
+ if (!Number.isFinite(seconds)) {
2662
+ throw createApiServiceError(
2663
+ message ?? formatOAuthTokenResponseMessage("a valid expires_in value", providerLabel, operation),
2664
+ { reason: "oauth_token_response" }
2276
2665
  );
2277
2666
  }
2278
- return config2;
2667
+ return new Date(nowMs + seconds * 1e3).toISOString();
2279
2668
  };
2280
- var recordHttpTraceFromResponse = (response) => {
2281
- let config2 = response.config;
2282
- let draft = takeTraceDraft(config2);
2283
- if (!draft) return response;
2284
- clearTraceDraft(config2, draft);
2285
- let redactor = new AuthConfigSecretRedactor(draft.context._getAuthConfigForRedaction());
2286
- let contentType = getContentType(response.headers);
2287
- draft.context.recordHttpTrace({
2288
- startedAt: draft.startedAt,
2289
- durationMs: Math.max(Date.now() - draft.startedAtMs, 0),
2290
- request: draft.request,
2291
- response: {
2292
- status: response.status,
2293
- ...response.statusText ? { statusText: response.statusText } : {},
2294
- ...sanitizeHeaders(response.headers, redactor) ? { headers: sanitizeHeaders(response.headers, redactor) } : {},
2295
- ...serializeTextBody(response.data, contentType, redactor) ? { body: serializeTextBody(response.data, contentType, redactor) } : {}
2669
+ var getRefreshToken = (refreshToken, previousRefreshToken, fallbackMode) => {
2670
+ if (typeof refreshToken === "string") {
2671
+ if (fallbackMode === "falsy" && !refreshToken) {
2672
+ return previousRefreshToken;
2296
2673
  }
2297
- });
2298
- return response;
2674
+ return refreshToken;
2675
+ }
2676
+ if (fallbackMode === "falsy" && !refreshToken) {
2677
+ return previousRefreshToken;
2678
+ }
2679
+ return refreshToken === void 0 || refreshToken === null ? previousRefreshToken : void 0;
2299
2680
  };
2300
- var recordHttpTraceFromError = (error) => {
2301
- let config2 = error.config;
2302
- let draft = takeTraceDraft(config2);
2303
- if (!draft) return;
2304
- clearTraceDraft(config2, draft);
2305
- let redactor = new AuthConfigSecretRedactor(draft.context._getAuthConfigForRedaction());
2306
- let responseContentType = getContentType(error.response?.headers);
2307
- draft.context.recordHttpTrace({
2308
- startedAt: draft.startedAt,
2309
- durationMs: Math.max(Date.now() - draft.startedAtMs, 0),
2310
- request: draft.request,
2311
- ...error.response ? {
2312
- response: {
2313
- status: error.response.status,
2314
- ...error.response.statusText ? { statusText: error.response.statusText } : {},
2315
- ...sanitizeHeaders(error.response.headers, redactor) ? { headers: sanitizeHeaders(error.response.headers, redactor) } : {},
2316
- ...serializeTextBody(error.response.data, responseContentType, redactor) ? { body: serializeTextBody(error.response.data, responseContentType, redactor) } : {}
2317
- }
2318
- } : {},
2319
- error: {
2320
- ...error.code ? { code: error.code } : {},
2321
- message: error.message
2322
- }
2323
- });
2681
+ var normalizeOAuthTokenResponse = (data, options = {}) => {
2682
+ let {
2683
+ providerLabel,
2684
+ operation,
2685
+ previousRefreshToken,
2686
+ refreshTokenFallbackMode = "nullish",
2687
+ accessTokenMessage,
2688
+ expiresInMessage,
2689
+ ...expiresAtOptions
2690
+ } = options;
2691
+ if (!isOAuthTokenResponse(data)) {
2692
+ throw createApiServiceError(
2693
+ accessTokenMessage ?? formatOAuthTokenResponseMessage("a token response object", providerLabel, operation),
2694
+ { reason: "oauth_token_response" }
2695
+ );
2696
+ }
2697
+ if (typeof data.access_token !== "string" || !data.access_token) {
2698
+ throw createApiServiceError(
2699
+ accessTokenMessage ?? formatOAuthTokenResponseMessage("an access token", providerLabel, operation),
2700
+ { reason: "oauth_token_response" }
2701
+ );
2702
+ }
2703
+ return {
2704
+ token: data.access_token,
2705
+ refreshToken: getRefreshToken(
2706
+ data.refresh_token,
2707
+ previousRefreshToken,
2708
+ refreshTokenFallbackMode
2709
+ ),
2710
+ expiresAt: getOAuthExpiresAtFromExpiresIn(data.expires_in, {
2711
+ ...expiresAtOptions,
2712
+ providerLabel,
2713
+ operation,
2714
+ message: expiresInMessage
2715
+ })
2716
+ };
2324
2717
  };
2325
2718
 
2326
2719
  // src/axios/index.ts
2720
+ var import_axios3 = __toESM(require("axios"), 1);
2327
2721
  var applySlateInterceptors = (instance, errorMapping) => {
2328
2722
  instance.interceptors.request.use(
2329
2723
  (request) => {
@@ -2981,6 +3375,9 @@ var skipWebhook = (reason, response) => ({
2981
3375
  });
2982
3376
  // Annotate the CommonJS export names for ESM import in node:
2983
3377
  0 && (module.exports = {
3378
+ API_ERROR_MAX_DETAILS,
3379
+ API_ERROR_MAX_MESSAGE_LENGTH,
3380
+ API_ERROR_TRUNCATED_PLACEHOLDER,
2984
3381
  AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX,
2985
3382
  AuthConfigSecretRedactor,
2986
3383
  GET_FILE_URL_TOOL_ID,
@@ -3019,8 +3416,10 @@ var skipWebhook = (reason, response) => ({
3019
3416
  createSlateError,
3020
3417
  createTextAttachment,
3021
3418
  createUrlAttachment,
3419
+ decodeApiErrorBody,
3022
3420
  extractApiErrorMessage,
3023
3421
  getApiErrorResponse,
3422
+ getApiErrorResponseWithBody,
3024
3423
  getApiErrorStatus,
3025
3424
  getBase64ByteLength,
3026
3425
  getCurrentContext,
@@ -3038,6 +3437,7 @@ var skipWebhook = (reason, response) => ({
3038
3437
  isAxiosErrorLike,
3039
3438
  isServiceErrorData,
3040
3439
  isUrlEmbeddedCredential,
3440
+ looksLikeHtmlErrorBody,
3041
3441
  mapServiceErrorCode,
3042
3442
  mapServiceErrorToSlateErrorInput,
3043
3443
  mergeScopes,
@@ -3045,6 +3445,8 @@ var skipWebhook = (reason, response) => ({
3045
3445
  normalizeOAuthTokenResponse,
3046
3446
  pickDefined,
3047
3447
  publicTool,
3448
+ pushBoundedApiErrorDetail,
3449
+ readApiErrorText,
3048
3450
  redactUrlAttachmentSecrets,
3049
3451
  requestAxios,
3050
3452
  requestAxiosData,
@@ -3057,6 +3459,7 @@ var skipWebhook = (reason, response) => ({
3057
3459
  tool,
3058
3460
  trigger,
3059
3461
  triggerGroup,
3462
+ truncateApiErrorMessage,
3060
3463
  uploadAttachmentDirect,
3061
3464
  validateScopes,
3062
3465
  verifyHmacSignature