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