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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -64,2152 +64,2537 @@ 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;
288
- return void 0;
289
- };
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";
293
- };
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.";
297
- };
298
- var cleanRecord = (value) => {
299
- if (!value) return void 0;
300
- let entries = Object.entries(value).filter(([, entry]) => entry !== void 0);
301
- if (entries.length === 0) return void 0;
302
- return Object.fromEntries(entries);
303
- };
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
- };
328
- };
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;
337
- }
338
- if (Array.isArray(value)) {
339
- return value.slice(0, 20).map((item) => sanitizeForBaggage(item, depth + 1));
340
- }
341
- if (isRecord(value)) {
342
- return Object.fromEntries(
343
- Object.entries(value).slice(0, 30).map(([key, entry]) => [key, sanitizeForBaggage(entry, depth + 1)])
344
- );
345
- }
346
- return String(value);
347
- };
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
364
- };
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;
388
- }
389
- let errorDescription = getResponseField(value, "error_description");
390
- if (typeof errorDescription === "string" && errorDescription.trim()) {
391
- return errorDescription;
392
- }
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;
407
- };
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;
418
- };
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;
432
- }
433
- }
434
- }
435
- return void 0;
436
- };
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
- }
447
- };
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 {};
459
- }
460
- };
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";
482
- };
483
- var inferAxiosMessage = (error, data, code) => {
484
- return getNestedMessage(data) ?? error.response?.statusText ?? error.message ?? getDefaultMessage(code);
485
- };
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);
490
- };
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
- });
521
- };
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"
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"
535
362
  ]);
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;
552
- };
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;
570
- };
571
- var getServiceErrorBaggage = (data) => {
572
- let extraEntries = Object.entries(data).filter(
573
- ([key]) => !SERVICE_ERROR_DATA_RESERVED_KEYS.has(key)
574
- );
575
- 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
- } : {}
586
- });
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);
587
367
  };
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;
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);
603
497
  }
604
- return null;
498
+ return result;
605
499
  };
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
- };
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 };
619
509
  }
620
- let code = defaults.code ?? mapServiceErrorCode(data.code, data.status);
621
510
  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
- })
511
+ text: `${text.slice(0, TRACE_TEXT_LIMIT)}...[truncated]`,
512
+ truncated: true
634
513
  };
635
514
  };
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;
647
- }
648
- get code() {
649
- return this.data.code;
650
- }
651
- get kind() {
652
- return this.data.kind;
653
- }
654
- get status() {
655
- return this.data.status;
656
- }
657
- get retryable() {
658
- return this.data.retryable;
659
- }
660
- toResponse() {
661
- return {
662
- ...this.data
663
- };
664
- }
665
- toJSON() {
666
- return this.toResponse();
667
- }
668
- static is(error) {
669
- return error instanceof _SlateError;
670
- }
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
- });
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}`;
691
611
  }
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
- });
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;
705
629
  }
706
- static fromServiceError(error, defaults = {}) {
707
- return new _SlateError(mapServiceErrorToSlateErrorInput(error, defaults));
630
+ if (Array.isArray(value)) {
631
+ return value.slice(0, STRUCTURED_ENTRY_LIMIT).map((entry) => redactStructuredValue(entry, depth + 1, redactor));
708
632
  }
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));
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
+ );
718
640
  }
641
+ return String(value);
719
642
  };
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
730
- });
731
- this.name = "SlateError.DeclarationError";
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;
732
648
  }
733
- static is(error) {
734
- return error instanceof _SlateDeclarationError;
649
+ try {
650
+ return JSON.parse(trimmed);
651
+ } catch {
652
+ return null;
735
653
  }
736
654
  };
737
-
738
- // src/action/scopes.ts
739
- var scopeClause = (...scopes) => {
740
- assertScopeValues(scopes);
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);
741
661
  return {
742
- OR: [...scopes]
662
+ ...normalizedContentType ? { contentType: normalizedContentType } : {},
663
+ text: truncatedText,
664
+ ...truncated ? { truncated: true } : {}
743
665
  };
744
666
  };
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 });
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;
751
674
  };
752
- var mergeScopes = (...inputs) => {
753
- let AND = inputs.flatMap((input) => input ? input.AND : []);
754
- if (AND.length === 0) {
675
+ var serializeTextBody = (value, contentType, redactor) => {
676
+ let normalizedContentType = normalizeContentType(contentType);
677
+ if (value == null || isBinaryLike(value) || !isTextContentType(normalizedContentType)) {
755
678
  return void 0;
756
679
  }
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");
762
- }
763
- return {
764
- AND: scopes.AND.map((clause) => normalizeClause(clause))
765
- };
766
- };
767
- var normalizeScopes = (input) => {
768
- if (isScopes(input)) {
769
- return validateScopes(input);
680
+ if (typeof value === "string") {
681
+ return sanitizeTextBody(value, normalizedContentType, redactor);
770
682
  }
771
- return {
772
- AND: [normalizeClause(input)]
773
- };
774
- };
775
- var normalizeClause = (input) => {
776
- if (typeof input === "string") {
777
- return scopeClause(input);
683
+ if (value instanceof URLSearchParams) {
684
+ return sanitizeTextBody(value.toString(), normalizedContentType, redactor);
778
685
  }
779
- if (Array.isArray(input)) {
780
- return scopeClause(...input);
686
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
687
+ return sanitizeTextBody(String(value), normalizedContentType, redactor);
781
688
  }
782
- if (!isClause(input)) {
783
- throw new SlateDeclarationError("Action scope clauses must be strings or OR clauses");
689
+ if (Array.isArray(value) || isRecord(value)) {
690
+ return sanitizeTextBody(
691
+ JSON.stringify(redactStructuredValue(value, 0, redactor)),
692
+ "application/json",
693
+ redactor
694
+ );
784
695
  }
785
- assertScopeValues(input.OR);
786
- return {
787
- OR: [...input.OR]
788
- };
696
+ return void 0;
789
697
  };
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
- );
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;
795
705
  }
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");
706
+ };
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;
799
721
  }
800
- }
722
+ );
723
+ return redacted ? `#${redacted}` : "";
801
724
  };
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;
815
- }
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");
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 = "";
835
734
  }
836
- this.#inputSchema = schema;
837
- return this;
838
- }
839
- output(schema) {
840
- if (this.#interfaceLocked) {
841
- throw new SlateDeclarationError("Adapter contract output schema cannot be changed");
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);
842
744
  }
843
- this.#outputSchema = schema;
844
- return this;
845
- }
846
- lockInterface() {
847
- this.#interfaceLocked = true;
848
- return this;
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
+ );
849
753
  }
850
- scopes(scopes) {
851
- validateScopes(scopes);
852
- this.#scopes = scopes;
853
- return this;
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;
854
761
  }
855
- authMethods(authMethods) {
856
- if (this.isPublicTool) {
857
- throw new SlateDeclarationError("Public tools cannot require authentication methods");
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);
858
773
  }
859
- this.#authMethods = this.validateAuthMethods(authMethods);
860
- return this;
861
774
  }
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");
867
- }
868
- return normalized;
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 [];
787
+ };
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));
792
+ if (entries.length === 0) return void 0;
793
+ return Object.fromEntries(entries);
794
+ };
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;
801
+ };
802
+ var clearTraceDraft = (config2, draft) => {
803
+ if (!config2) return;
804
+ if (config2.__slatesHttpTraceDraft === draft) {
805
+ config2.__slatesHttpTraceDraft = void 0;
869
806
  }
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;
807
+ if (isObjectLike(config2)) {
808
+ traceDraftsByConfig.delete(config2);
879
809
  }
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;
810
+ if (isObjectLike(config2.headers)) {
811
+ traceDraftsByHeaders.delete(config2.headers);
886
812
  }
887
- matches(handler) {
888
- if (this.type !== "trigger") {
889
- throw new SlateDeclarationError("matches can only be set for trigger actions");
813
+ };
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) } : {}
890
827
  }
891
- this.#triggerMatches = handler;
892
- return this;
828
+ };
829
+ if (isObjectLike(traceAwareConfig)) {
830
+ traceDraftsByConfig.set(traceAwareConfig, traceAwareConfig.__slatesHttpTraceDraft);
893
831
  }
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;
832
+ if (isObjectLike(traceAwareConfig.headers)) {
833
+ traceDraftsByHeaders.set(
834
+ traceAwareConfig.headers,
835
+ traceAwareConfig.__slatesHttpTraceDraft
836
+ );
900
837
  }
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");
838
+ return config2;
839
+ };
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) } : {}
924
856
  }
925
- if (this.type === "trigger" && !this.#triggerMap) {
926
- throw new SlateDeclarationError("Trigger map handler is not defined");
857
+ });
858
+ return response;
859
+ };
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) } : {}
877
+ }
878
+ } : {},
879
+ error: {
880
+ ...error.code ? { code: error.code } : {},
881
+ message: error.message
927
882
  }
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
- });
883
+ });
884
+ };
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);
894
+ };
895
+ var getCurrentContext = () => {
896
+ let context = asyncLocalStorage.getStore();
897
+ if (!context) {
898
+ throw new Error("No Slate context is available");
946
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."
934
+ };
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"
951
+ };
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";
967
+ };
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;
989
+ };
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";
993
+ };
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.";
997
+ };
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);
947
1003
  };
948
-
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);
1004
+ var mergeRecords = (left, right) => {
1005
+ if (!left && !right) return void 0;
1006
+ return cleanRecord({
1007
+ ...left ?? {},
1008
+ ...right ?? {}
1009
+ });
1010
+ };
1011
+ var mergeSlateErrorData = (base, override) => {
1012
+ if (!override) return base;
1013
+ return {
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
1027
+ };
1028
+ };
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;
958
1049
  }
959
- redact(value) {
960
- return this.transform(value, (stringValue) => {
961
- return this.secretToPlaceholder.get(stringValue) ?? stringValue;
962
- });
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));
963
1087
  }
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"
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
973
1097
  );
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
- });
1098
+ } catch {
1099
+ return value;
982
1100
  }
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
- }
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}`;
1003
1107
  }
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;
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);
1017
1116
  }
1117
+ }
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;
1018
1125
  return value;
1019
1126
  }
1020
- isPlainObject(value) {
1021
- return typeof value === "object" && value !== null && !Array.isArray(value);
1127
+ if (depth >= maxDepth) {
1128
+ state.remaining -= jsonLength(BAGGAGE_TRUNCATED_VALUE);
1129
+ return BAGGAGE_TRUNCATED_VALUE;
1022
1130
  }
1023
- };
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;
1032
- 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
- }
1040
- };
1041
- });
1042
- };
1043
-
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;
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;
1050
1135
  }
1051
- static create(spec2, params) {
1052
- return new SlateActionBuilder("tool", spec2, params, (params2) => {
1053
- return _SlateTool.fromCreateParameters(spec2, params2);
1054
- });
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));
1149
+ }
1150
+ return items;
1055
1151
  }
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);
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);
1059
1174
  }
1060
- get handleInvocation() {
1061
- return this.#handleInvocation;
1175
+ return sanitizeBaggageString(String(value), state);
1176
+ };
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()
1182
+ });
1183
+ } catch {
1184
+ return BAGGAGE_UNSERIALIZABLE_VALUE;
1062
1185
  }
1063
1186
  };
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());
1187
+ var normalizeSlateErrorInput = (input) => {
1188
+ let code = input.code || DEFAULT_CODE;
1085
1189
  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"
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
1093
1203
  };
1094
- }).build();
1204
+ };
1205
+ var isSlateErrorResponse = (error) => {
1206
+ if (!isRecord2(error)) return false;
1207
+ return typeof error.code === "string" && typeof error.message === "string";
1208
+ };
1095
1209
 
1096
- // src/action/publicTool.ts
1097
- var SlatePublicTool = class {
1098
- constructor() {
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;
1099
1217
  }
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
- );
1218
+ let detail = String(value).trim();
1219
+ if (detail && !details.includes(detail)) {
1220
+ details.push(detail);
1113
1221
  }
1114
1222
  };
1115
- var publicTool = (spec2, params) => SlatePublicTool.create(spec2, params);
1116
-
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;
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;
1127
1229
  }
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
- });
1230
+ if (!isApiErrorRecord(value)) {
1231
+ pushDetail(details, value, options);
1232
+ return;
1133
1233
  }
1134
- get triggerGroup() {
1135
- return this.#triggerGroup;
1234
+ for (let key of options.detailKeys ?? DEFAULT_DETAIL_KEYS) {
1235
+ pushDetail(details, value[key], options);
1136
1236
  }
1137
- get matches() {
1138
- return this.#matches;
1237
+ for (let key of options.nestedKeys ?? DEFAULT_NESTED_KEYS) {
1238
+ collectApiErrorDetails(value[key], details, options);
1139
1239
  }
1140
- get map() {
1141
- return this.#map;
1240
+ };
1241
+ var getSlateErrorResponse = (error) => {
1242
+ if (error.name !== "SlateError" || !isApiErrorRecord(error.data)) {
1243
+ return void 0;
1142
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;
1143
1249
  };
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;
1250
+ var getApiErrorResponse = (error) => {
1251
+ if (!isApiErrorRecord(error)) {
1252
+ return void 0;
1153
1253
  }
1154
- _spec;
1155
- _params;
1156
- static create(spec2, params) {
1157
- return new SlateTriggerGroupBuilder(spec2, params, (p) => new _SlateTriggerGroup(spec2, p));
1254
+ if (!isApiErrorRecord(error.response)) {
1255
+ return getSlateErrorResponse(error);
1158
1256
  }
1159
- get spec() {
1160
- return this._spec;
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;
1161
1288
  }
1162
- get key() {
1163
- return this._params.key;
1289
+ let text = String(value).trim();
1290
+ if (!text || BAGGAGE_PLACEHOLDERS.has(text) || looksLikeHtmlErrorBody(text)) {
1291
+ return void 0;
1164
1292
  }
1165
- get name() {
1166
- return this._params.name;
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);
1167
1302
  }
1168
- get description() {
1169
- return this._params.description;
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);
1312
+ }
1313
+ text = new TextDecoder("utf-8").decode(bytes);
1314
+ } else {
1315
+ return data;
1170
1316
  }
1171
- get metadata() {
1172
- return this._params.metadata;
1317
+ let trimmed = text.trim();
1318
+ if (/^[{[]/.test(trimmed)) {
1319
+ try {
1320
+ return JSON.parse(trimmed);
1321
+ } catch {
1322
+ }
1173
1323
  }
1174
- get eventSchema() {
1175
- return this._params.eventSchema ?? z2.object({}).passthrough();
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 ?? " - ");
1176
1333
  }
1177
- get source() {
1178
- return this._params.source;
1334
+ if (error instanceof Error && error.message) {
1335
+ return error.message;
1179
1336
  }
1180
- get polling() {
1181
- return this._params.polling;
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;
1182
1343
  }
1183
- get webhook() {
1184
- return this._params.webhook;
1344
+ if ("upstreamStatus" in options) {
1345
+ error.data.upstreamStatus = options.upstreamStatus;
1185
1346
  }
1186
- get gateway() {
1187
- return this._params.gateway;
1347
+ if ("upstreamCode" in options) {
1348
+ error.data.upstreamCode = options.upstreamCode;
1188
1349
  }
1189
- get routingMatchers() {
1190
- return this._params.routingMatchers;
1350
+ if (options.parent instanceof Error) {
1351
+ error.setParent(options.parent);
1191
1352
  }
1353
+ return error;
1192
1354
  };
1193
- var SlateTriggerGroupBuilder = class {
1194
- constructor(spec2, params, factory) {
1195
- this.spec = spec2;
1196
- this.params = params;
1197
- this.factory = factory;
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;
1198
1367
  }
1199
- spec;
1200
- params;
1201
- 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");
1210
- }
1211
- this.#source = "polling";
1212
- this.#polling = {
1213
- intervalSeconds: props.intervalSeconds ?? SlateDefaultPollingIntervalSeconds,
1214
- pollEvents: props.pollEvents
1215
- };
1216
- return this;
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
+ });
1387
+ };
1388
+
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;
1217
1407
  }
1218
- webhook(props) {
1219
- if (this.#source) {
1220
- throw new SlateDeclarationError("Trigger group invocation is already defined");
1221
- }
1222
- if (!!props.autoRegistration === !!props.manualRegistration) {
1223
- throw new SlateDeclarationError(
1224
- "Webhook trigger groups require exactly one of autoRegistration or manualRegistration"
1225
- );
1226
- }
1227
- this.#source = "webhook";
1228
- this.#webhook = {
1229
- autoRegistration: props.autoRegistration,
1230
- manualRegistration: props.manualRegistration,
1231
- process: props.process
1232
- };
1233
- return this;
1408
+ let errorDescription = getResponseField(value, "error_description");
1409
+ if (typeof errorDescription === "string" && errorDescription.trim()) {
1410
+ return errorDescription;
1234
1411
  }
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");
1239
- }
1240
- this.#source = "gateway";
1241
- this.#gateway = { connect: props.connect, receive: props.receive };
1242
- return this;
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;
1243
1435
  }
1244
- routingMatchers(handler) {
1245
- this.#routingMatchers = handler;
1246
- return this;
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;
1247
1443
  }
1248
- build() {
1249
- if (!this.#source) {
1250
- throw new SlateDeclarationError(
1251
- "Trigger group invocation (polling, webhook, or gateway) is not defined"
1252
- );
1253
- }
1254
- if (!this.#routingMatchers) {
1255
- throw new SlateDeclarationError("Trigger group routing matchers handler is not defined");
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
+ }
1256
1452
  }
1257
- return this.factory({
1258
- ...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
1264
- });
1265
1453
  }
1454
+ return void 0;
1266
1455
  };
1267
- var triggerGroup = (spec2, params) => SlateTriggerGroup.create(spec2, params);
1268
-
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
- };
1456
+ var sanitizeRequestUrl = (url, redactor) => {
1457
+ try {
1458
+ return sanitizeUrl(url, redactor);
1459
+ } catch {
1460
+ return sanitizeUrl(url);
1461
+ }
1286
1462
  };
1287
- var createBase64Attachment = (content, mimeType, attachmentHash) => ({
1288
- mimeType,
1289
- attachmentHash,
1290
- content: {
1291
- type: "content",
1292
- encoding: "base64",
1293
- content
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 {
1294
1472
  }
1295
- });
1296
- var createTextAttachment = (content, mimeType, attachmentHash) => ({
1297
- mimeType,
1298
- attachmentHash,
1299
- content: {
1300
- type: "content",
1301
- encoding: "utf-8",
1302
- content
1473
+ return sanitizeRequestUrl(absoluteUrl, redactor);
1474
+ };
1475
+ var getProviderDefaults = () => {
1476
+ try {
1477
+ let ctx = getCurrentContext();
1478
+ return {
1479
+ provider: {
1480
+ key: ctx.specification.key
1481
+ },
1482
+ ...ctx.getHttpTraces().length > 0 ? { requestTraces: ctx.getHttpTraces() } : {}
1483
+ };
1484
+ } catch {
1485
+ return {};
1303
1486
  }
1304
- });
1305
-
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;
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";
1315
1494
  }
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);
1495
+ if (!error.response) {
1496
+ return "upstream.network_error";
1329
1497
  }
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;
1498
+ if (status === 401) return "auth.invalid";
1499
+ if (status === 403) {
1500
+ return remoteCode?.includes("rate") ? "upstream.rate_limited" : "permission.denied";
1336
1501
  }
1337
- return buffered;
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";
1338
1509
  };
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}`
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 ?? {}
1347
1536
  },
1348
- body: JSON.stringify({
1349
- attachments: [
1350
- {
1351
- mimeType: d.mimeType,
1352
- filename: d.filename,
1353
- sizeBytes: body.byteLength || void 0
1354
- }
1355
- ]
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
+ })
1356
1552
  })
1357
1553
  });
1358
- if (!registerRes.ok) {
1359
- throw new Error(
1360
- `Failed to register attachment for direct upload (status ${registerRes.status})`
1361
- );
1362
- }
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");
1367
- }
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)
1554
+ };
1555
+
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
1373
1615
  },
1374
- body
1616
+ ...extraEntries.length > 0 ? {
1617
+ serviceErrorData: sanitizeForBaggage(Object.fromEntries(extraEntries))
1618
+ } : {}
1375
1619
  });
1376
- if (!putRes.ok) {
1377
- throw new Error(`Failed to upload attachment content (status ${putRes.status})`);
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;
1626
+ }
1627
+ if (isServiceErrorData(error)) {
1628
+ return error;
1629
+ }
1630
+ if (isStructuredValue(error) && "data" in error && isServiceErrorData(error.data)) {
1631
+ return error.data;
1632
+ }
1633
+ if (isStructuredValue(error) && "toResponse" in error && typeof error.toResponse === "function") {
1634
+ let response = error.toResponse();
1635
+ return isServiceErrorData(response) ? response : null;
1636
+ }
1637
+ return null;
1638
+ };
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
+ };
1378
1652
  }
1653
+ let code = defaults.code ?? mapServiceErrorCode(data.code, data.status);
1379
1654
  return {
1380
- mimeType: d.mimeType,
1381
- content: { type: "upload_reference", referenceId: registration.referenceId }
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
+ })
1382
1667
  };
1383
1668
  };
1384
1669
 
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;
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;
1397
1680
  }
1398
- get id() {
1399
- return this._spec.id;
1681
+ get code() {
1682
+ return this.data.code;
1400
1683
  }
1401
- get name() {
1402
- return this._spec.name;
1684
+ get kind() {
1685
+ return this.data.kind;
1403
1686
  }
1404
- get capabilities() {
1405
- return this._spec.capabilities;
1687
+ get status() {
1688
+ return this.data.status;
1406
1689
  }
1407
- get tools() {
1408
- return this._tools;
1690
+ get retryable() {
1691
+ return this.data.retryable;
1409
1692
  }
1410
- get triggers() {
1411
- return this._triggers;
1693
+ toResponse() {
1694
+ return {
1695
+ ...this.data
1696
+ };
1412
1697
  }
1413
- get actions() {
1414
- return [...this._triggers, ...this._tools];
1698
+ toJSON() {
1699
+ return this.toResponse();
1415
1700
  }
1416
- };
1417
-
1418
- // src/adapter/spec.ts
1419
- var SlateAdapterSpec = class _SlateAdapterSpec {
1420
- constructor(_params) {
1421
- this._params = _params;
1701
+ static is(error) {
1702
+ return error instanceof _SlateError;
1422
1703
  }
1423
- _params;
1424
- 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");
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
+ });
1432
1724
  }
1433
- return new _SlateAdapterSpec({
1434
- id,
1435
- name,
1436
- capabilities: validateCapabilities(params.capabilities ?? [])
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
+ })
1437
1737
  });
1438
1738
  }
1439
- get id() {
1440
- return this._params.id;
1739
+ static fromServiceError(error, defaults = {}) {
1740
+ return new _SlateError(mapServiceErrorToSlateErrorInput(error, defaults));
1441
1741
  }
1442
- get name() {
1443
- return this._params.name;
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));
1444
1751
  }
1445
- get capabilities() {
1446
- return this._params.capabilities;
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";
1447
1765
  }
1448
- get parameters() {
1449
- return this._params;
1766
+ static is(error) {
1767
+ return error instanceof _SlateDeclarationError;
1450
1768
  }
1451
- tool(spec2, params) {
1452
- return SlateTool.create(spec2, this.linkAction(params));
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;
1453
1789
  }
1454
- publicTool(spec2, params) {
1455
- return SlatePublicTool.create(spec2, this.linkAction(params));
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");
1456
1795
  }
1457
- trigger(spec2, params) {
1458
- return SlateTrigger.create(spec2, this.linkAction(params));
1796
+ return {
1797
+ AND: scopes.AND.map((clause) => normalizeClause(clause))
1798
+ };
1799
+ };
1800
+ var normalizeScopes = (input) => {
1801
+ if (isScopes(input)) {
1802
+ return validateScopes(input);
1459
1803
  }
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);
1804
+ return {
1805
+ AND: [normalizeClause(input)]
1806
+ };
1807
+ };
1808
+ var normalizeClause = (input) => {
1809
+ if (typeof input === "string") {
1810
+ return scopeClause(input);
1482
1811
  }
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
- };
1812
+ if (Array.isArray(input)) {
1813
+ return scopeClause(...input);
1814
+ }
1815
+ if (!isClause(input)) {
1816
+ throw new SlateDeclarationError("Action scope clauses must be strings or OR clauses");
1493
1817
  }
1818
+ assertScopeValues(input.OR);
1819
+ return {
1820
+ OR: [...input.OR]
1821
+ };
1494
1822
  };
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`);
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");
1505
1832
  }
1506
- seenIds.add(id);
1507
- return {
1508
- id,
1509
- value: capability.value
1510
- };
1511
- });
1833
+ }
1512
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);
1513
1837
 
1514
- // src/auth/auth.ts
1515
- var SlateAuth = class _SlateAuth {
1516
- #outputSchema = null;
1517
- #authStack = [];
1518
- constructor() {
1838
+ // src/action/builder.ts
1839
+ var SlateActionBuilder = class {
1840
+ constructor(type, spec2, params, factory, isPublicTool = false) {
1841
+ this.type = type;
1842
+ this.spec = spec2;
1843
+ this.params = params;
1844
+ this.factory = factory;
1845
+ this.isPublicTool = isPublicTool;
1846
+ this.#configSchema = spec2.configSchema;
1847
+ this.#authSchema = spec2.authSchema;
1519
1848
  }
1520
- static create() {
1521
- return new _SlateAuth();
1849
+ type;
1850
+ spec;
1851
+ params;
1852
+ factory;
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;
1522
1871
  }
1523
1872
  output(schema) {
1873
+ if (this.#interfaceLocked) {
1874
+ throw new SlateDeclarationError("Adapter contract output schema cannot be changed");
1875
+ }
1524
1876
  this.#outputSchema = schema;
1525
1877
  return this;
1526
1878
  }
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);
1879
+ lockInterface() {
1880
+ this.#interfaceLocked = true;
1533
1881
  return this;
1534
1882
  }
1535
- addOauth(auth2) {
1536
- this.addAuth(auth2);
1883
+ scopes(scopes) {
1884
+ validateScopes(scopes);
1885
+ this.#scopes = scopes;
1537
1886
  return this;
1538
1887
  }
1539
- addTokenAuth(auth2) {
1540
- this.addAuth(auth2);
1888
+ authMethods(authMethods) {
1889
+ if (this.isPublicTool) {
1890
+ throw new SlateDeclarationError("Public tools cannot require authentication methods");
1891
+ }
1892
+ this.#authMethods = this.validateAuthMethods(authMethods);
1541
1893
  return this;
1542
1894
  }
1543
- addServiceAccountAuth(auth2) {
1544
- this.addAuth(auth2);
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");
1900
+ }
1901
+ return normalized;
1902
+ }
1903
+ handleInvocation(handler) {
1904
+ if (this.type !== "tool") {
1905
+ throw new SlateDeclarationError("handleInvocation can only be set for tool actions");
1906
+ }
1907
+ this.#toolParams = {
1908
+ type: "tool",
1909
+ handleInvocation: handler
1910
+ };
1545
1911
  return this;
1546
1912
  }
1547
- addCustomAuth(auth2) {
1548
- this.addAuth(auth2);
1913
+ triggerGroup(group) {
1914
+ if (this.type !== "trigger") {
1915
+ throw new SlateDeclarationError("triggerGroup can only be set for trigger actions");
1916
+ }
1917
+ this.#triggerGroup = group;
1549
1918
  return this;
1550
1919
  }
1551
- addNone() {
1552
- this.addAuth({
1553
- type: "auth.none",
1554
- name: "No Authentication",
1555
- key: "none"
1556
- });
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;
1557
1925
  return this;
1558
1926
  }
1559
- get authStack() {
1560
- return this.#authStack.filter((a) => a.type !== "auth.none");
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;
1932
+ return this;
1561
1933
  }
1562
- get outputSchema() {
1934
+ build() {
1935
+ let scopes = this.#scopes ?? this.params.scopes;
1936
+ if (scopes) {
1937
+ validateScopes(scopes);
1938
+ }
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
+ }
1563
1946
  if (!this.#outputSchema) {
1564
- throw new Error("Output schema is not defined for this auth");
1947
+ throw new SlateDeclarationError("Output schema is not defined");
1565
1948
  }
1566
- return this.#outputSchema;
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");
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;
1967
+ return this.factory({
1968
+ ...this.params,
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
1978
+ });
1567
1979
  }
1568
1980
  };
1569
- var auth = () => SlateAuth.create();
1570
1981
 
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;
1982
+ // src/action/getFileUrlTool.ts
1983
+ import { z } from "zod";
1984
+
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;
1595
1991
  }
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" }
1992
+ static create(spec2, params) {
1993
+ return new SlateActionBuilder("tool", spec2, params, (params2) => {
1994
+ return _SlateTool.fromCreateParameters(spec2, params2);
1995
+ });
1996
+ }
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);
2000
+ }
2001
+ get handleInvocation() {
2002
+ return this.#handleInvocation;
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());
2026
+ return {
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"
2034
+ };
2035
+ }).build();
2036
+
2037
+ // src/action/publicTool.ts
2038
+ var SlatePublicTool = class {
2039
+ constructor() {
2040
+ }
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
1601
2053
  );
1602
2054
  }
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;
2055
+ };
2056
+ var publicTool = (spec2, params) => SlatePublicTool.create(spec2, params);
2057
+
2058
+ // src/action/trigger.ts
2059
+ var SlateTrigger = class _SlateTrigger extends SlateAction {
2060
+ #triggerGroup;
2061
+ #matches;
2062
+ #map;
2063
+ constructor(spec2, inputSchema, outputSchema, params) {
2064
+ super("trigger", spec2, inputSchema, outputSchema, params);
2065
+ this.#triggerGroup = params.triggerGroup;
2066
+ this.#matches = params.matches;
2067
+ this.#map = params.map;
2068
+ }
2069
+ static create(spec2, params) {
2070
+ return new SlateActionBuilder("trigger", spec2, params, (params2) => {
2071
+ if (params2.type !== "trigger") throw new Error("Invalid action type for trigger");
2072
+ return new _SlateTrigger(spec2, params2.inputSchema, params2.outputSchema, params2);
2073
+ });
1611
2074
  }
1612
- if (fallbackMode === "falsy" && !refreshToken) {
1613
- return previousRefreshToken;
2075
+ get triggerGroup() {
2076
+ return this.#triggerGroup;
1614
2077
  }
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
- );
2078
+ get matches() {
2079
+ return this.#matches;
1632
2080
  }
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
- );
2081
+ get map() {
2082
+ return this.#map;
1638
2083
  }
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
2084
  };
2085
+ var trigger = (spec2, params) => SlateTrigger.create(spec2, params);
1654
2086
 
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);
1843
- };
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);
2087
+ // src/action/triggerGroup.ts
2088
+ import { z as z2 } from "zod";
2089
+ var SlateDefaultPollingIntervalSeconds = 60 * 10;
2090
+ var SlateTriggerGroup = class _SlateTriggerGroup {
2091
+ constructor(_spec, _params) {
2092
+ this._spec = _spec;
2093
+ this._params = _params;
2094
+ }
2095
+ _spec;
2096
+ _params;
2097
+ static create(spec2, params) {
2098
+ return new SlateTriggerGroupBuilder(spec2, params, (p) => new _SlateTriggerGroup(spec2, p));
2099
+ }
2100
+ get spec() {
2101
+ return this._spec;
2102
+ }
2103
+ get key() {
2104
+ return this._params.key;
2105
+ }
2106
+ get name() {
2107
+ return this._params.name;
2108
+ }
2109
+ get description() {
2110
+ return this._params.description;
2111
+ }
2112
+ get metadata() {
2113
+ return this._params.metadata;
2114
+ }
2115
+ get eventSchema() {
2116
+ return this._params.eventSchema ?? z2.object({}).passthrough();
2117
+ }
2118
+ get source() {
2119
+ return this._params.source;
2120
+ }
2121
+ get polling() {
2122
+ return this._params.polling;
2123
+ }
2124
+ get webhook() {
2125
+ return this._params.webhook;
2126
+ }
2127
+ get gateway() {
2128
+ return this._params.gateway;
2129
+ }
2130
+ get routingMatchers() {
2131
+ return this._params.routingMatchers;
2132
+ }
1848
2133
  };
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));
2134
+ var SlateTriggerGroupBuilder = class {
2135
+ constructor(spec2, params, factory) {
2136
+ this.spec = spec2;
2137
+ this.params = params;
2138
+ this.factory = factory;
2139
+ }
2140
+ spec;
2141
+ params;
2142
+ factory;
2143
+ #source = null;
2144
+ #polling = null;
2145
+ #webhook = null;
2146
+ #gateway = null;
2147
+ #routingMatchers = null;
2148
+ polling(props) {
2149
+ if (this.#source) {
2150
+ throw new SlateDeclarationError("Trigger group invocation is already defined");
2151
+ }
2152
+ this.#source = "polling";
2153
+ this.#polling = {
2154
+ intervalSeconds: props.intervalSeconds ?? SlateDefaultPollingIntervalSeconds,
2155
+ pollEvents: props.pollEvents
2156
+ };
2157
+ return this;
2158
+ }
2159
+ webhook(props) {
2160
+ if (this.#source) {
2161
+ throw new SlateDeclarationError("Trigger group invocation is already defined");
2162
+ }
2163
+ if (!!props.autoRegistration === !!props.manualRegistration) {
2164
+ throw new SlateDeclarationError(
2165
+ "Webhook trigger groups require exactly one of autoRegistration or manualRegistration"
2166
+ );
2167
+ }
2168
+ this.#source = "webhook";
2169
+ this.#webhook = {
2170
+ autoRegistration: props.autoRegistration,
2171
+ manualRegistration: props.manualRegistration,
2172
+ process: props.process
2173
+ };
2174
+ return this;
2175
+ }
2176
+ /** Receive events over a platform-managed persistent connection (e.g. a WebSocket gateway). */
2177
+ gateway(props) {
2178
+ if (this.#source) {
2179
+ throw new SlateDeclarationError("Trigger group invocation is already defined");
2180
+ }
2181
+ this.#source = "gateway";
2182
+ this.#gateway = { connect: props.connect, receive: props.receive };
2183
+ return this;
2184
+ }
2185
+ routingMatchers(handler) {
2186
+ this.#routingMatchers = handler;
2187
+ return this;
2188
+ }
2189
+ build() {
2190
+ if (!this.#source) {
2191
+ throw new SlateDeclarationError(
2192
+ "Trigger group invocation (polling, webhook, or gateway) is not defined"
2193
+ );
2194
+ }
2195
+ if (!this.#routingMatchers) {
2196
+ throw new SlateDeclarationError("Trigger group routing matchers handler is not defined");
2197
+ }
2198
+ return this.factory({
2199
+ ...this.params,
2200
+ source: this.#source,
2201
+ polling: this.#polling ?? void 0,
2202
+ webhook: this.#webhook ?? void 0,
2203
+ gateway: this.#gateway ?? void 0,
2204
+ routingMatchers: this.#routingMatchers
2205
+ });
2206
+ }
1923
2207
  };
1924
- var truncateText = (text) => {
1925
- if (text.length <= TRACE_TEXT_LIMIT) {
1926
- return { text, truncated: false };
2208
+ var triggerGroup = (spec2, params) => SlateTriggerGroup.create(spec2, params);
2209
+
2210
+ // src/action/attachment.ts
2211
+ var createUrlAttachment = (url, opts = {}) => {
2212
+ if (opts.refreshReference !== void 0 && !opts.refreshAt) {
2213
+ throw new Error("createUrlAttachment: refreshAt is required when refreshReference is set");
1927
2214
  }
1928
2215
  return {
1929
- text: `${text.slice(0, TRACE_TEXT_LIMIT)}...[truncated]`,
1930
- truncated: true
2216
+ mimeType: opts.mimeType,
2217
+ attachmentHash: opts.attachmentHash,
2218
+ content: {
2219
+ type: "url",
2220
+ url,
2221
+ ...opts.headers ? { headers: opts.headers } : {},
2222
+ ...opts.query ? { query: opts.query } : {},
2223
+ ...opts.refreshReference !== void 0 ? { refreshReference: opts.refreshReference } : {},
2224
+ ...opts.refreshAt ? { refreshAt: opts.refreshAt } : {}
2225
+ }
1931
2226
  };
1932
2227
  };
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);
2228
+ var createBase64Attachment = (content, mimeType, attachmentHash) => ({
2229
+ mimeType,
2230
+ attachmentHash,
2231
+ content: {
2232
+ type: "content",
2233
+ encoding: "base64",
2234
+ content
1942
2235
  }
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;
2236
+ });
2237
+ var createTextAttachment = (content, mimeType, attachmentHash) => ({
2238
+ mimeType,
2239
+ attachmentHash,
2240
+ content: {
2241
+ type: "content",
2242
+ encoding: "utf-8",
2243
+ content
2244
+ }
2245
+ });
2246
+
2247
+ // src/action/directUpload.ts
2248
+ var bufferAttachmentBody = async (body, maxSizeBytes) => {
2249
+ if (body instanceof Uint8Array) {
2250
+ if (body.byteLength > maxSizeBytes) {
2251
+ throw new Error(`Attachment exceeds the maximum size of ${maxSizeBytes} bytes`);
2252
+ }
2253
+ let buffered2 = new ArrayBuffer(body.byteLength);
2254
+ new Uint8Array(buffered2).set(body);
2255
+ return buffered2;
1959
2256
  }
1960
- if (Array.isArray(value)) {
1961
- return value.slice(0, STRUCTURED_ENTRY_LIMIT).map((entry) => redactStructuredValue(entry, depth + 1, redactor));
2257
+ let reader = body.getReader();
2258
+ let chunks = [];
2259
+ let sizeBytes = 0;
2260
+ while (true) {
2261
+ let { done, value } = await reader.read();
2262
+ if (done) break;
2263
+ if (!value) continue;
2264
+ sizeBytes += value.byteLength;
2265
+ if (sizeBytes > maxSizeBytes) {
2266
+ await reader.cancel();
2267
+ throw new Error(`Attachment exceeds the maximum size of ${maxSizeBytes} bytes`);
2268
+ }
2269
+ chunks.push(value);
1962
2270
  }
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
- );
2271
+ let buffered = new ArrayBuffer(sizeBytes);
2272
+ let bufferedView = new Uint8Array(buffered);
2273
+ let offset = 0;
2274
+ for (let chunk of chunks) {
2275
+ bufferedView.set(chunk, offset);
2276
+ offset += chunk.byteLength;
1970
2277
  }
1971
- return String(value);
2278
+ return buffered;
1972
2279
  };
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;
2280
+ var uploadAttachmentDirect = async (d) => {
2281
+ let baseUrl = d.live.baseUrl.replace(/\/$/, "");
2282
+ let body = await bufferAttachmentBody(d.body, d.live.maxAttachmentSizeBytes);
2283
+ let registerRes = await fetch(`${baseUrl}/slates-hub/live-invocation/attachments`, {
2284
+ method: "POST",
2285
+ headers: {
2286
+ "content-type": "application/json",
2287
+ authorization: `Bearer ${d.live.token}`
2288
+ },
2289
+ body: JSON.stringify({
2290
+ attachments: [
2291
+ {
2292
+ mimeType: d.mimeType,
2293
+ filename: d.filename,
2294
+ sizeBytes: body.byteLength || void 0
2295
+ }
2296
+ ]
2297
+ })
2298
+ });
2299
+ if (!registerRes.ok) {
2300
+ throw new Error(
2301
+ `Failed to register attachment for direct upload (status ${registerRes.status})`
2302
+ );
1978
2303
  }
1979
- try {
1980
- return JSON.parse(trimmed);
1981
- } catch {
1982
- return null;
2304
+ let { attachments } = await registerRes.json();
2305
+ let registration = attachments[0];
2306
+ if (!registration) {
2307
+ throw new Error("Live invocation API returned no attachment registrations");
2308
+ }
2309
+ let putRes = await fetch(registration.uploadUrl, {
2310
+ method: "PUT",
2311
+ headers: {
2312
+ ...d.mimeType ? { "content-type": d.mimeType } : {},
2313
+ "content-length": String(body.byteLength)
2314
+ },
2315
+ body
2316
+ });
2317
+ if (!putRes.ok) {
2318
+ throw new Error(`Failed to upload attachment content (status ${putRes.status})`);
1983
2319
  }
1984
- };
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
2320
  return {
1992
- ...normalizedContentType ? { contentType: normalizedContentType } : {},
1993
- text: truncatedText,
1994
- ...truncated ? { truncated: true } : {}
2321
+ mimeType: d.mimeType,
2322
+ content: { type: "upload_reference", referenceId: registration.referenceId }
1995
2323
  };
1996
2324
  };
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;
2325
+
2326
+ // src/adapter/adapter.ts
2327
+ var SlateAdapter = class {
2328
+ constructor(_spec, _tools, _triggers) {
2329
+ this._spec = _spec;
2330
+ this._tools = _tools;
2331
+ this._triggers = _triggers;
2009
2332
  }
2010
- if (typeof value === "string") {
2011
- return sanitizeTextBody(value, normalizedContentType, redactor);
2333
+ _spec;
2334
+ _tools;
2335
+ _triggers;
2336
+ get spec() {
2337
+ return this._spec;
2012
2338
  }
2013
- if (value instanceof URLSearchParams) {
2014
- return sanitizeTextBody(value.toString(), normalizedContentType, redactor);
2339
+ get id() {
2340
+ return this._spec.id;
2015
2341
  }
2016
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
2017
- return sanitizeTextBody(String(value), normalizedContentType, redactor);
2342
+ get name() {
2343
+ return this._spec.name;
2018
2344
  }
2019
- if (Array.isArray(value) || isRecord2(value)) {
2020
- return sanitizeTextBody(
2021
- JSON.stringify(redactStructuredValue(value, 0, redactor)),
2022
- "application/json",
2023
- redactor
2024
- );
2345
+ get capabilities() {
2346
+ return this._spec.capabilities;
2025
2347
  }
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;
2348
+ get tools() {
2349
+ return this._tools;
2350
+ }
2351
+ get triggers() {
2352
+ return this._triggers;
2353
+ }
2354
+ get actions() {
2355
+ return [...this._triggers, ...this._tools];
2035
2356
  }
2036
2357
  };
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;
2358
+
2359
+ // src/adapter/spec.ts
2360
+ var SlateAdapterSpec = class _SlateAdapterSpec {
2361
+ constructor(_params) {
2362
+ this._params = _params;
2363
+ }
2364
+ _params;
2365
+ static create(params) {
2366
+ let id = params.id?.trim();
2367
+ let name = params.name?.trim();
2368
+ if (!id) {
2369
+ throw new SlateDeclarationError("Adapter id must be a non-empty string");
2048
2370
  }
2049
- );
2050
- return redacted ? `#${redacted}` : "";
2051
- };
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 = "";
2371
+ if (!name) {
2372
+ throw new SlateDeclarationError("Adapter name must be a non-empty string");
2060
2373
  }
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;
2374
+ return new _SlateAdapterSpec({
2375
+ id,
2376
+ name,
2377
+ capabilities: validateCapabilities(params.capabilities ?? [])
2378
+ });
2379
+ }
2380
+ get id() {
2381
+ return this._params.id;
2382
+ }
2383
+ get name() {
2384
+ return this._params.name;
2385
+ }
2386
+ get capabilities() {
2387
+ return this._params.capabilities;
2388
+ }
2389
+ get parameters() {
2390
+ return this._params;
2391
+ }
2392
+ tool(spec2, params) {
2393
+ return SlateTool.create(spec2, this.linkAction(params));
2394
+ }
2395
+ publicTool(spec2, params) {
2396
+ return SlatePublicTool.create(spec2, this.linkAction(params));
2397
+ }
2398
+ trigger(spec2, params) {
2399
+ return SlateTrigger.create(spec2, this.linkAction(params));
2400
+ }
2401
+ register(params) {
2402
+ let actions = [...params.tools, ...params.triggers];
2403
+ let seenKeys = /* @__PURE__ */ new Set();
2404
+ for (let action of actions) {
2405
+ if (action.adapter && action.adapter !== this.id) {
2406
+ throw new SlateDeclarationError(
2407
+ `Action "${action.key}" is linked to adapter "${action.adapter}", not "${this.id}"`
2408
+ );
2066
2409
  }
2067
- let rawValue = url.searchParams.get(key) ?? "";
2068
- let literalRedacted = redactor ? redactor.redact(rawValue) : rawValue;
2069
- if (literalRedacted !== rawValue) url.searchParams.set(key, literalRedacted);
2410
+ if (!action.adapter) {
2411
+ throw new SlateDeclarationError(
2412
+ `Action "${action.key}" must be created with this adapter's tool(), publicTool(), or trigger() helpers`
2413
+ );
2414
+ }
2415
+ if (seenKeys.has(action.key)) {
2416
+ throw new SlateDeclarationError(
2417
+ `Adapter "${this.id}" already has an action with key "${action.key}"`
2418
+ );
2419
+ }
2420
+ seenKeys.add(action.key);
2070
2421
  }
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
- );
2422
+ return new SlateAdapter(this, params.tools, params.triggers);
2423
+ }
2424
+ linkAction(params) {
2425
+ if (params.adapter != null && params.adapter !== this.id) {
2426
+ throw new SlateDeclarationError(
2427
+ `Action "${params.key}" cannot be linked to adapter "${this.id}" because it is already linked to "${params.adapter}"`
2428
+ );
2429
+ }
2430
+ return {
2431
+ ...params,
2432
+ adapter: this.id
2433
+ };
2079
2434
  }
2080
2435
  };
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;
2087
- }
2088
- return void 0;
2436
+ var adapterSpec = (params) => SlateAdapterSpec.create(params);
2437
+ var validateCapabilities = (capabilities) => {
2438
+ let seenIds = /* @__PURE__ */ new Set();
2439
+ return capabilities.map((capability) => {
2440
+ let id = capability.id?.trim();
2441
+ if (!id) {
2442
+ throw new SlateDeclarationError("Adapter capability ids must be non-empty strings");
2443
+ }
2444
+ if (seenIds.has(id)) {
2445
+ throw new SlateDeclarationError(`Adapter capability "${id}" is defined more than once`);
2446
+ }
2447
+ seenIds.add(id);
2448
+ return {
2449
+ id,
2450
+ value: capability.value
2451
+ };
2452
+ });
2089
2453
  };
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);
2454
+
2455
+ // src/auth/auth.ts
2456
+ var SlateAuth = class _SlateAuth {
2457
+ #outputSchema = null;
2458
+ #authStack = [];
2459
+ constructor() {
2460
+ }
2461
+ static create() {
2462
+ return new _SlateAuth();
2463
+ }
2464
+ output(schema) {
2465
+ this.#outputSchema = schema;
2466
+ return this;
2467
+ }
2468
+ addAuth(auth2) {
2469
+ let existingKeys = this.#authStack.map((a) => a.key);
2470
+ if (existingKeys.includes(auth2.key)) {
2471
+ throw new Error(`Auth with key "${auth2.key}" already exists in the auth stack`);
2099
2472
  }
2473
+ this.#authStack.push(auth2);
2474
+ return this;
2100
2475
  }
2101
- if (typeof headers.entries === "function") {
2102
- return Array.from(
2103
- headers.entries()
2104
- ).map(([key, value]) => [key, value]);
2476
+ addOauth(auth2) {
2477
+ this.addAuth(auth2);
2478
+ return this;
2105
2479
  }
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);
2480
+ addTokenAuth(auth2) {
2481
+ this.addAuth(auth2);
2482
+ return this;
2111
2483
  }
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;
2484
+ addServiceAccountAuth(auth2) {
2485
+ this.addAuth(auth2);
2486
+ return this;
2132
2487
  }
2133
- if (isObjectLike(config2)) {
2134
- traceDraftsByConfig.delete(config2);
2488
+ addCustomAuth(auth2) {
2489
+ this.addAuth(auth2);
2490
+ return this;
2135
2491
  }
2136
- if (isObjectLike(config2.headers)) {
2137
- traceDraftsByHeaders.delete(config2.headers);
2492
+ addNone() {
2493
+ this.addAuth({
2494
+ type: "auth.none",
2495
+ name: "No Authentication",
2496
+ key: "none"
2497
+ });
2498
+ return this;
2499
+ }
2500
+ get authStack() {
2501
+ return this.#authStack.filter((a) => a.type !== "auth.none");
2502
+ }
2503
+ get outputSchema() {
2504
+ if (!this.#outputSchema) {
2505
+ throw new Error("Output schema is not defined for this auth");
2506
+ }
2507
+ return this.#outputSchema;
2138
2508
  }
2139
2509
  };
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) } : {}
2510
+ var auth = () => SlateAuth.create();
2511
+
2512
+ // src/auth/oauth.ts
2513
+ var isOAuthTokenResponse = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2514
+ var formatOAuthTokenResponseMessage = (fieldLabel, providerLabel = "OAuth provider", operation = "token response") => `${providerLabel} OAuth ${operation} did not return ${fieldLabel}.`;
2515
+ var getOAuthExpiresAtFromExpiresIn = (expiresIn, options = {}) => {
2516
+ let {
2517
+ nowMs = Date.now(),
2518
+ providerLabel,
2519
+ operation,
2520
+ required = false,
2521
+ expiresInType = "numberLike",
2522
+ message
2523
+ } = options;
2524
+ if (expiresIn === void 0 || expiresIn === null || expiresIn === "") {
2525
+ if (required) {
2526
+ throw createApiServiceError(
2527
+ message ?? formatOAuthTokenResponseMessage(
2528
+ "a valid expires_in value",
2529
+ providerLabel,
2530
+ operation
2531
+ ),
2532
+ { reason: "oauth_token_response" }
2533
+ );
2153
2534
  }
2154
- };
2155
- if (isObjectLike(traceAwareConfig)) {
2156
- traceDraftsByConfig.set(traceAwareConfig, traceAwareConfig.__slatesHttpTraceDraft);
2535
+ return void 0;
2157
2536
  }
2158
- if (isObjectLike(traceAwareConfig.headers)) {
2159
- traceDraftsByHeaders.set(
2160
- traceAwareConfig.headers,
2161
- traceAwareConfig.__slatesHttpTraceDraft
2537
+ let seconds = typeof expiresIn === "number" ? expiresIn : expiresInType === "numberLike" && typeof expiresIn === "string" ? Number(expiresIn) : Number.NaN;
2538
+ if (!Number.isFinite(seconds)) {
2539
+ throw createApiServiceError(
2540
+ message ?? formatOAuthTokenResponseMessage("a valid expires_in value", providerLabel, operation),
2541
+ { reason: "oauth_token_response" }
2162
2542
  );
2163
2543
  }
2164
- return config2;
2544
+ return new Date(nowMs + seconds * 1e3).toISOString();
2165
2545
  };
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) } : {}
2546
+ var getRefreshToken = (refreshToken, previousRefreshToken, fallbackMode) => {
2547
+ if (typeof refreshToken === "string") {
2548
+ if (fallbackMode === "falsy" && !refreshToken) {
2549
+ return previousRefreshToken;
2182
2550
  }
2183
- });
2184
- return response;
2551
+ return refreshToken;
2552
+ }
2553
+ if (fallbackMode === "falsy" && !refreshToken) {
2554
+ return previousRefreshToken;
2555
+ }
2556
+ return refreshToken === void 0 || refreshToken === null ? previousRefreshToken : void 0;
2185
2557
  };
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
- });
2558
+ var normalizeOAuthTokenResponse = (data, options = {}) => {
2559
+ let {
2560
+ providerLabel,
2561
+ operation,
2562
+ previousRefreshToken,
2563
+ refreshTokenFallbackMode = "nullish",
2564
+ accessTokenMessage,
2565
+ expiresInMessage,
2566
+ ...expiresAtOptions
2567
+ } = options;
2568
+ if (!isOAuthTokenResponse(data)) {
2569
+ throw createApiServiceError(
2570
+ accessTokenMessage ?? formatOAuthTokenResponseMessage("a token response object", providerLabel, operation),
2571
+ { reason: "oauth_token_response" }
2572
+ );
2573
+ }
2574
+ if (typeof data.access_token !== "string" || !data.access_token) {
2575
+ throw createApiServiceError(
2576
+ accessTokenMessage ?? formatOAuthTokenResponseMessage("an access token", providerLabel, operation),
2577
+ { reason: "oauth_token_response" }
2578
+ );
2579
+ }
2580
+ return {
2581
+ token: data.access_token,
2582
+ refreshToken: getRefreshToken(
2583
+ data.refresh_token,
2584
+ previousRefreshToken,
2585
+ refreshTokenFallbackMode
2586
+ ),
2587
+ expiresAt: getOAuthExpiresAtFromExpiresIn(data.expires_in, {
2588
+ ...expiresAtOptions,
2589
+ providerLabel,
2590
+ operation,
2591
+ message: expiresInMessage
2592
+ })
2593
+ };
2210
2594
  };
2211
2595
 
2212
2596
  // src/axios/index.ts
2597
+ import baseAxios, { getAdapter, isAxiosError as isAxiosError2 } from "axios";
2213
2598
  var applySlateInterceptors = (instance, errorMapping) => {
2214
2599
  instance.interceptors.request.use(
2215
2600
  (request) => {
@@ -2866,6 +3251,9 @@ var skipWebhook = (reason, response) => ({
2866
3251
  response: response ?? { status: 200, body: "" }
2867
3252
  });
2868
3253
  export {
3254
+ API_ERROR_MAX_DETAILS,
3255
+ API_ERROR_MAX_MESSAGE_LENGTH,
3256
+ API_ERROR_TRUNCATED_PLACEHOLDER,
2869
3257
  AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX,
2870
3258
  AuthConfigSecretRedactor,
2871
3259
  GET_FILE_URL_TOOL_ID,
@@ -2904,8 +3292,10 @@ export {
2904
3292
  createSlateError,
2905
3293
  createTextAttachment,
2906
3294
  createUrlAttachment,
3295
+ decodeApiErrorBody,
2907
3296
  extractApiErrorMessage,
2908
3297
  getApiErrorResponse,
3298
+ getApiErrorResponseWithBody,
2909
3299
  getApiErrorStatus,
2910
3300
  getBase64ByteLength,
2911
3301
  getCurrentContext,
@@ -2923,6 +3313,7 @@ export {
2923
3313
  isAxiosErrorLike,
2924
3314
  isServiceErrorData,
2925
3315
  isUrlEmbeddedCredential,
3316
+ looksLikeHtmlErrorBody,
2926
3317
  mapServiceErrorCode,
2927
3318
  mapServiceErrorToSlateErrorInput,
2928
3319
  mergeScopes,
@@ -2930,6 +3321,8 @@ export {
2930
3321
  normalizeOAuthTokenResponse,
2931
3322
  pickDefined,
2932
3323
  publicTool,
3324
+ pushBoundedApiErrorDetail,
3325
+ readApiErrorText,
2933
3326
  redactUrlAttachmentSecrets,
2934
3327
  requestAxios,
2935
3328
  requestAxiosData,
@@ -2942,6 +3335,7 @@ export {
2942
3335
  tool,
2943
3336
  trigger,
2944
3337
  triggerGroup,
3338
+ truncateApiErrorMessage,
2945
3339
  uploadAttachmentDirect,
2946
3340
  validateScopes,
2947
3341
  verifyHmacSignature