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

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