@slates/provider 1.0.0-rc.31 → 1.0.0-rc.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -86,6 +86,7 @@ __export(index_exports, {
86
86
  getMetaWebhookVerificationResponse: () => getMetaWebhookVerificationResponse,
87
87
  getOAuthExpiresAtFromExpiresIn: () => getOAuthExpiresAtFromExpiresIn,
88
88
  getResponseHeaderValue: () => getResponseHeaderValue,
89
+ getRuntimeInfo: () => getRuntimeInfo,
89
90
  getServiceErrorData: () => getServiceErrorData,
90
91
  graphWebhookHttp: () => graphWebhookHttp,
91
92
  inferSlateErrorFromAxios: () => inferSlateErrorFromAxios,
@@ -1024,6 +1025,7 @@ var getCurrentContext = () => {
1024
1025
  }
1025
1026
  return context;
1026
1027
  };
1028
+ var getRuntimeInfo = () => asyncLocalStorage.getStore()?.runtimeInfo ?? null;
1027
1029
 
1028
1030
  // src/error/defaults.ts
1029
1031
  var DEFAULT_CODE = "internal.unexpected";
@@ -1309,6 +1311,8 @@ var sanitizeForBaggage = (value, options = {}) => {
1309
1311
  return BAGGAGE_UNSERIALIZABLE_VALUE;
1310
1312
  }
1311
1313
  };
1314
+ var UPSTREAM_CODE_PATTERN = /^[\w.:-]{1,128}$/;
1315
+ var normalizeUpstreamCode = (value) => typeof value === "string" && UPSTREAM_CODE_PATTERN.test(value) ? value : void 0;
1312
1316
  var normalizeSlateErrorInput = (input) => {
1313
1317
  let code = input.code || DEFAULT_CODE;
1314
1318
  return {
@@ -1323,6 +1327,7 @@ var normalizeSlateErrorInput = (input) => {
1323
1327
  ...input.upstream,
1324
1328
  status: input.upstream?.status ?? input.status
1325
1329
  }),
1330
+ upstreamCode: normalizeUpstreamCode(input.upstreamCode) ?? normalizeUpstreamCode(input.upstream?.code),
1326
1331
  baggage: cleanRecord(input.baggage),
1327
1332
  requestTraces: input.requestTraces
1328
1333
  };
@@ -1785,6 +1790,7 @@ var mapServiceErrorToSlateErrorInput = (error, defaults = {}) => {
1785
1790
  issues: defaults.issues ?? normalizeServiceErrorIssues(data.errors),
1786
1791
  provider: defaults.provider,
1787
1792
  upstream: defaults.upstream,
1793
+ upstreamCode: normalizeUpstreamCode(defaults.upstreamCode) ?? normalizeUpstreamCode(data.upstreamCode),
1788
1794
  baggage: cleanRecord({
1789
1795
  ...defaults.baggage ?? {},
1790
1796
  ...getServiceErrorBaggage(data)
@@ -2890,6 +2896,10 @@ var resolveDefaultExport = (value) => {
2890
2896
  var PQueue = resolveDefaultExport(import_p_queue.default);
2891
2897
 
2892
2898
  // src/context/context.ts
2899
+ var freezeRuntimeInfo = (runtimeInfo) => Object.freeze({
2900
+ ...runtimeInfo,
2901
+ ...runtimeInfo.metorial ? { metorial: Object.freeze({ ...runtimeInfo.metorial }) } : {}
2902
+ });
2893
2903
  var isBufferLike = (value) => value instanceof Uint8Array || value instanceof ArrayBuffer;
2894
2904
  var toUint8Array = (value) => value instanceof ArrayBuffer ? new Uint8Array(value) : value;
2895
2905
  var isReadableStream = (value) => typeof ReadableStream !== "undefined" && value instanceof ReadableStream;
@@ -2906,17 +2916,19 @@ var readStreamToBuffer = async (stream) => {
2906
2916
  return Buffer.concat(chunks);
2907
2917
  };
2908
2918
  var SlatePublicContext = class {
2909
- constructor(input, spec2, logger, liveInvocation = null) {
2919
+ constructor(input, spec2, logger, liveInvocation = null, runtimeInfo = null) {
2910
2920
  this.spec = spec2;
2911
2921
  this.logger = logger;
2912
2922
  this.#input = input;
2913
2923
  this.#liveInvocation = liveInvocation;
2924
+ this.#runtimeInfo = runtimeInfo && freezeRuntimeInfo(runtimeInfo);
2914
2925
  }
2915
2926
  spec;
2916
2927
  logger;
2917
2928
  #input;
2918
2929
  #httpTraces = [];
2919
2930
  #liveInvocation;
2931
+ #runtimeInfo;
2920
2932
  #attachmentsDisabled = false;
2921
2933
  #attachments = [];
2922
2934
  #pendingUploads = [];
@@ -2927,6 +2939,9 @@ var SlatePublicContext = class {
2927
2939
  }
2928
2940
  return this.#uploadQueue;
2929
2941
  }
2942
+ get runtimeInfo() {
2943
+ return this.#runtimeInfo;
2944
+ }
2930
2945
  get specification() {
2931
2946
  return this.spec;
2932
2947
  }
@@ -3067,8 +3082,8 @@ var SlatePublicContext = class {
3067
3082
  var SlateContext = class extends SlatePublicContext {
3068
3083
  #config;
3069
3084
  #auth;
3070
- constructor(config2, input, auth2, spec2, logger, liveInvocation = null) {
3071
- super(input, spec2, logger, liveInvocation);
3085
+ constructor(config2, input, auth2, spec2, logger, liveInvocation = null, runtimeInfo = null) {
3086
+ super(input, spec2, logger, liveInvocation, runtimeInfo);
3072
3087
  this.#config = config2;
3073
3088
  this.#auth = auth2;
3074
3089
  }
@@ -3546,6 +3561,7 @@ var skipWebhook = (reason, response) => ({
3546
3561
  getMetaWebhookVerificationResponse,
3547
3562
  getOAuthExpiresAtFromExpiresIn,
3548
3563
  getResponseHeaderValue,
3564
+ getRuntimeInfo,
3549
3565
  getServiceErrorData,
3550
3566
  graphWebhookHttp,
3551
3567
  inferSlateErrorFromAxios,
package/dist/index.d.cts CHANGED
@@ -192,6 +192,7 @@ type SlateAuthWithOauth<InputType extends {}, OutputType extends {
192
192
  adapters?: string[];
193
193
  syncTokensAcrossConnections?: boolean;
194
194
  adminSetup?: {
195
+ required?: boolean;
195
196
  getAuthorizationUrl?: (ctx: SlateOauthAuthorizationUrlContext<InputType>) => Promise<SlateOauthAuthorizationUrlResult<InputType>>;
196
197
  handleCallback?: (ctx: SlateOauthAdminCallbackContext<InputType>) => Promise<{
197
198
  instructions?: string;
@@ -458,6 +459,13 @@ declare class SlateSpecification<ConfigType extends {}, AuthType extends {}> {
458
459
  }
459
460
  declare let spec: <ConfigType extends {}, AuthType extends {}>(params: SlateSpecificationCreateParameters<ConfigType, AuthType>) => SlateSpecification<ConfigType, AuthType>;
460
461
 
462
+ interface SlateRuntimeInfo {
463
+ metorial?: {
464
+ apiUrl: string;
465
+ region?: string | null;
466
+ environment?: string | null;
467
+ };
468
+ }
461
469
  type SlateAddAttachmentContent = Buffer | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array> | NodeJS.ReadableStream | Response;
462
470
  type SlateAddAttachmentInput = {
463
471
  type: 'url';
@@ -478,7 +486,8 @@ declare class SlatePublicContext<InputType extends {}> {
478
486
  #private;
479
487
  private readonly spec;
480
488
  private readonly logger;
481
- constructor(input: InputType, spec: SlateSpecification<any, any>, logger: SlateLogger, liveInvocation?: SlateLiveInvocationInfo | null);
489
+ constructor(input: InputType, spec: SlateSpecification<any, any>, logger: SlateLogger, liveInvocation?: SlateLiveInvocationInfo | null, runtimeInfo?: SlateRuntimeInfo | null);
490
+ get runtimeInfo(): Readonly<SlateRuntimeInfo> | null;
482
491
  get specification(): SlateSpecification<any, any>;
483
492
  get input(): Readonly<InputType>;
484
493
  get event(): Readonly<InputType>;
@@ -516,7 +525,7 @@ declare class SlatePublicContext<InputType extends {}> {
516
525
  }
517
526
  declare class SlateContext<ConfigType extends {}, AuthType extends {}, InputType extends {}> extends SlatePublicContext<InputType> {
518
527
  #private;
519
- constructor(config: ConfigType, input: InputType, auth: AuthType, spec: SlateSpecification<ConfigType, AuthType>, logger: SlateLogger, liveInvocation?: SlateLiveInvocationInfo | null);
528
+ constructor(config: ConfigType, input: InputType, auth: AuthType, spec: SlateSpecification<ConfigType, AuthType>, logger: SlateLogger, liveInvocation?: SlateLiveInvocationInfo | null, runtimeInfo?: SlateRuntimeInfo | null);
520
529
  get config(): Readonly<ConfigType>;
521
530
  get auth(): Readonly<AuthType>;
522
531
  _getAuthConfigForRedaction(): Record<string, unknown> | undefined;
@@ -524,6 +533,7 @@ declare class SlateContext<ConfigType extends {}, AuthType extends {}, InputType
524
533
 
525
534
  declare let runWithContext: <InputType extends {}, RV>(context: SlatePublicContext<InputType>, fn: () => Promise<RV>) => Promise<RV>;
526
535
  declare let getCurrentContext: <ConfigType extends {}, AuthType extends {}, InputType extends {}>() => SlateContext<ConfigType, AuthType, InputType>;
536
+ declare let getRuntimeInfo: () => Readonly<SlateRuntimeInfo> | null;
527
537
 
528
538
  declare let SlateDefaultPollingIntervalSeconds: number;
529
539
  type SlateTriggerRoutingMatcher = Record<string, any>;
@@ -1076,6 +1086,7 @@ interface SlateErrorResponse {
1076
1086
  issues?: SlateErrorIssue[];
1077
1087
  provider?: SlateErrorProviderInfo;
1078
1088
  upstream?: SlateErrorUpstreamInfo;
1089
+ upstreamCode?: string;
1079
1090
  baggage?: Record<string, unknown>;
1080
1091
  requestTraces?: SlateHttpTrace[];
1081
1092
  }
@@ -1204,4 +1215,4 @@ declare let skipWebhook: (reason: string, response?: Response | SlateWebhookHttp
1204
1215
  response: Response | SlateWebhookHttpResponseInit;
1205
1216
  };
1206
1217
 
1207
- export { API_ERROR_MAX_DETAILS, API_ERROR_MAX_MESSAGE_LENGTH, API_ERROR_TRUNCATED_PLACEHOLDER, AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX, type ApiErrorBuildHelpers, type ApiErrorDetailOptions, type ApiErrorResponse, type ApiErrorStatus, type ApiErrorTextOptions, type ApiServiceError, type AuthConfigSecretFilter, AuthConfigSecretRedactor, type BoundedApiErrorDetailOptions, type BuildApiServiceErrorOptions, type CreateHmacSignatureOptions, type DecodeApiErrorBodyOptions, GET_FILE_URL_TOOL_ID, type GetFileUrlHandler, type GetFileUrlToolInput, type GetFileUrlToolOutput, type NormalizeOAuthTokenResponseOptions, type OAuthExpiresAtOptions, type OAuthRefreshTokenFallbackMode, type OAuthTokenResponse, Slate, SlateAction, SlateActionBuilder, type SlateActionCreateParameters, type SlateActionDocsReference, type SlateActionParameters, type SlateActionParametersAny, type SlateActionParametersTool, type SlateActionParametersTrigger, type SlateActionScopeClause, type SlateActionScopeClauseInput, type SlateActionScopeValue, type SlateActionScopes, type SlateActionScopesInput, type SlateActionType, SlateAdapter, type SlateAdapterCapability, SlateAdapterSpec, type SlateAdapterSpecParameters, type SlateAddAttachmentContent, type SlateAddAttachmentInput, type SlateAttachment, type SlateAttachmentInlineContent, type SlateAttachmentUploadReferenceContent, type SlateAttachmentUrlContent, SlateAuth, type SlateAuthDocsReference, type SlateAuthType, type SlateAuthWithCustomData, type SlateAuthWithNone, type SlateAuthWithOauth, type SlateAuthWithServiceAccount, type SlateAuthWithToken, type SlateAuthenticatedAxiosDefaults, type SlateAxiosDefaults, type SlateAxiosErrorAdapter, type SlateAxiosErrorOptions, SlateConfig, type SlateConfigDocsReference, SlateContext, SlateDeclarationError, SlateDefaultPollingIntervalSeconds, type SlateDirectUploadInput, type SlateDocsReference, SlateError, type SlateErrorInput, type SlateErrorIssue, type SlateErrorKind, type SlateErrorProviderInfo, type SlateErrorResponse, type SlateErrorUpstreamInfo, type SlateGatewayEvent, type SlateLiveInvocationInfo, type SlateLogEntry, type SlateLogFields, type SlateLogListener, type SlateLogMessageInput, type SlateLogType, SlateLogger, type SlateProviderDocsReference, SlatePublicContext, SlatePublicTool, type SlatePublicToolInvocationHandler, type SlatePublicToolParameters, type SlateServiceErrorData, SlateSpecification, type SlateSpecificationCreateParameters, type SlateSpecificationParameters, SlateTool, SlateToolCategory, type SlateToolCategoryParameters, type SlateToolInvocationHandler, type SlateToolParameters, SlateTrigger, SlateTriggerGroup, SlateTriggerGroupBuilder, type SlateTriggerGroupCreateParameters, type SlateTriggerGroupGatewayConnectHandler, type SlateTriggerGroupGatewayParameters, type SlateTriggerGroupGatewayReceiveHandler, type SlateTriggerGroupParameters, type SlateTriggerGroupPollHandler, type SlateTriggerGroupPollingParameters, type SlateTriggerGroupRoutingMatchersHandler, type SlateTriggerGroupWebhookAutoRegistrationParameters, type SlateTriggerGroupWebhookManualRegistrationParameters, type SlateTriggerGroupWebhookParameters, type SlateTriggerMappingHandler, type SlateTriggerMatchesHandler, type SlateTriggerParameters, type SlateTriggerRoutingMatcher, type SlateTypedDocsReference, type SlateWebhookHttpResponseInit, type SlateWebhookManualFinishHandler, type SlateWebhookManualSetupHandler, type SlateWebhookProcessHandler, type SlateWebhookRegisterHandler, type SlateWebhookSkipped, type SlateWebhookTarget, type SlateWebhookTargetListHandler, type SlateWebhookTargetOwnership, type SlateWebhookUnregisterHandler, type VerifyHmacSignatureOptions, adapterSpec, allOf, anyOf, auth, axios, buildApiServiceError, collectApiErrorDetails, config, createApiServiceError, createAuthenticatedAxios, createAxios, createBase64Attachment, createHmacSignature, createSlateError, createTextAttachment, createUrlAttachment, decodeApiErrorBody, extractApiErrorMessage, getApiErrorResponse, getApiErrorResponseWithBody, getApiErrorStatus, getBase64ByteLength, getCurrentContext, getFileUrlTool, getFileUrlToolInputSchema, getFileUrlToolOutputSchema, getGraphWebhookValidationResponse, getMetaWebhookVerificationResponse, getOAuthExpiresAtFromExpiresIn, getResponseHeaderValue, getServiceErrorData, graphWebhookHttp, inferSlateErrorFromAxios, isApiErrorRecord, isAxiosErrorLike, isServiceErrorData, isUrlEmbeddedCredential, looksLikeHtmlErrorBody, mapServiceErrorCode, mapServiceErrorToSlateErrorInput, mergeScopes, metaWebhookHttp, normalizeOAuthTokenResponse, pickDefined, publicTool, pushBoundedApiErrorDetail, readApiErrorText, redactUrlAttachmentSecrets, requestAxios, requestAxiosData, runWithContext, scopeClause, setIfDefined, skipWebhook, spec, statusLabelForApiError, tool, toolCategory, trigger, triggerGroup, truncateApiErrorMessage, uploadAttachmentDirect, validateScopes, verifyHmacSignature };
1218
+ export { API_ERROR_MAX_DETAILS, API_ERROR_MAX_MESSAGE_LENGTH, API_ERROR_TRUNCATED_PLACEHOLDER, AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX, type ApiErrorBuildHelpers, type ApiErrorDetailOptions, type ApiErrorResponse, type ApiErrorStatus, type ApiErrorTextOptions, type ApiServiceError, type AuthConfigSecretFilter, AuthConfigSecretRedactor, type BoundedApiErrorDetailOptions, type BuildApiServiceErrorOptions, type CreateHmacSignatureOptions, type DecodeApiErrorBodyOptions, GET_FILE_URL_TOOL_ID, type GetFileUrlHandler, type GetFileUrlToolInput, type GetFileUrlToolOutput, type NormalizeOAuthTokenResponseOptions, type OAuthExpiresAtOptions, type OAuthRefreshTokenFallbackMode, type OAuthTokenResponse, Slate, SlateAction, SlateActionBuilder, type SlateActionCreateParameters, type SlateActionDocsReference, type SlateActionParameters, type SlateActionParametersAny, type SlateActionParametersTool, type SlateActionParametersTrigger, type SlateActionScopeClause, type SlateActionScopeClauseInput, type SlateActionScopeValue, type SlateActionScopes, type SlateActionScopesInput, type SlateActionType, SlateAdapter, type SlateAdapterCapability, SlateAdapterSpec, type SlateAdapterSpecParameters, type SlateAddAttachmentContent, type SlateAddAttachmentInput, type SlateAttachment, type SlateAttachmentInlineContent, type SlateAttachmentUploadReferenceContent, type SlateAttachmentUrlContent, SlateAuth, type SlateAuthDocsReference, type SlateAuthType, type SlateAuthWithCustomData, type SlateAuthWithNone, type SlateAuthWithOauth, type SlateAuthWithServiceAccount, type SlateAuthWithToken, type SlateAuthenticatedAxiosDefaults, type SlateAxiosDefaults, type SlateAxiosErrorAdapter, type SlateAxiosErrorOptions, SlateConfig, type SlateConfigDocsReference, SlateContext, SlateDeclarationError, SlateDefaultPollingIntervalSeconds, type SlateDirectUploadInput, type SlateDocsReference, SlateError, type SlateErrorInput, type SlateErrorIssue, type SlateErrorKind, type SlateErrorProviderInfo, type SlateErrorResponse, type SlateErrorUpstreamInfo, type SlateGatewayEvent, type SlateLiveInvocationInfo, type SlateLogEntry, type SlateLogFields, type SlateLogListener, type SlateLogMessageInput, type SlateLogType, SlateLogger, type SlateProviderDocsReference, SlatePublicContext, SlatePublicTool, type SlatePublicToolInvocationHandler, type SlatePublicToolParameters, type SlateRuntimeInfo, type SlateServiceErrorData, SlateSpecification, type SlateSpecificationCreateParameters, type SlateSpecificationParameters, SlateTool, SlateToolCategory, type SlateToolCategoryParameters, type SlateToolInvocationHandler, type SlateToolParameters, SlateTrigger, SlateTriggerGroup, SlateTriggerGroupBuilder, type SlateTriggerGroupCreateParameters, type SlateTriggerGroupGatewayConnectHandler, type SlateTriggerGroupGatewayParameters, type SlateTriggerGroupGatewayReceiveHandler, type SlateTriggerGroupParameters, type SlateTriggerGroupPollHandler, type SlateTriggerGroupPollingParameters, type SlateTriggerGroupRoutingMatchersHandler, type SlateTriggerGroupWebhookAutoRegistrationParameters, type SlateTriggerGroupWebhookManualRegistrationParameters, type SlateTriggerGroupWebhookParameters, type SlateTriggerMappingHandler, type SlateTriggerMatchesHandler, type SlateTriggerParameters, type SlateTriggerRoutingMatcher, type SlateTypedDocsReference, type SlateWebhookHttpResponseInit, type SlateWebhookManualFinishHandler, type SlateWebhookManualSetupHandler, type SlateWebhookProcessHandler, type SlateWebhookRegisterHandler, type SlateWebhookSkipped, type SlateWebhookTarget, type SlateWebhookTargetListHandler, type SlateWebhookTargetOwnership, type SlateWebhookUnregisterHandler, type VerifyHmacSignatureOptions, adapterSpec, allOf, anyOf, auth, axios, buildApiServiceError, collectApiErrorDetails, config, createApiServiceError, createAuthenticatedAxios, createAxios, createBase64Attachment, createHmacSignature, createSlateError, createTextAttachment, createUrlAttachment, decodeApiErrorBody, extractApiErrorMessage, getApiErrorResponse, getApiErrorResponseWithBody, getApiErrorStatus, getBase64ByteLength, getCurrentContext, getFileUrlTool, getFileUrlToolInputSchema, getFileUrlToolOutputSchema, getGraphWebhookValidationResponse, getMetaWebhookVerificationResponse, getOAuthExpiresAtFromExpiresIn, getResponseHeaderValue, getRuntimeInfo, getServiceErrorData, graphWebhookHttp, inferSlateErrorFromAxios, isApiErrorRecord, isAxiosErrorLike, isServiceErrorData, isUrlEmbeddedCredential, looksLikeHtmlErrorBody, mapServiceErrorCode, mapServiceErrorToSlateErrorInput, mergeScopes, metaWebhookHttp, normalizeOAuthTokenResponse, pickDefined, publicTool, pushBoundedApiErrorDetail, readApiErrorText, redactUrlAttachmentSecrets, requestAxios, requestAxiosData, runWithContext, scopeClause, setIfDefined, skipWebhook, spec, statusLabelForApiError, tool, toolCategory, trigger, triggerGroup, truncateApiErrorMessage, uploadAttachmentDirect, validateScopes, verifyHmacSignature };
package/dist/index.d.ts CHANGED
@@ -192,6 +192,7 @@ type SlateAuthWithOauth<InputType extends {}, OutputType extends {
192
192
  adapters?: string[];
193
193
  syncTokensAcrossConnections?: boolean;
194
194
  adminSetup?: {
195
+ required?: boolean;
195
196
  getAuthorizationUrl?: (ctx: SlateOauthAuthorizationUrlContext<InputType>) => Promise<SlateOauthAuthorizationUrlResult<InputType>>;
196
197
  handleCallback?: (ctx: SlateOauthAdminCallbackContext<InputType>) => Promise<{
197
198
  instructions?: string;
@@ -458,6 +459,13 @@ declare class SlateSpecification<ConfigType extends {}, AuthType extends {}> {
458
459
  }
459
460
  declare let spec: <ConfigType extends {}, AuthType extends {}>(params: SlateSpecificationCreateParameters<ConfigType, AuthType>) => SlateSpecification<ConfigType, AuthType>;
460
461
 
462
+ interface SlateRuntimeInfo {
463
+ metorial?: {
464
+ apiUrl: string;
465
+ region?: string | null;
466
+ environment?: string | null;
467
+ };
468
+ }
461
469
  type SlateAddAttachmentContent = Buffer | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array> | NodeJS.ReadableStream | Response;
462
470
  type SlateAddAttachmentInput = {
463
471
  type: 'url';
@@ -478,7 +486,8 @@ declare class SlatePublicContext<InputType extends {}> {
478
486
  #private;
479
487
  private readonly spec;
480
488
  private readonly logger;
481
- constructor(input: InputType, spec: SlateSpecification<any, any>, logger: SlateLogger, liveInvocation?: SlateLiveInvocationInfo | null);
489
+ constructor(input: InputType, spec: SlateSpecification<any, any>, logger: SlateLogger, liveInvocation?: SlateLiveInvocationInfo | null, runtimeInfo?: SlateRuntimeInfo | null);
490
+ get runtimeInfo(): Readonly<SlateRuntimeInfo> | null;
482
491
  get specification(): SlateSpecification<any, any>;
483
492
  get input(): Readonly<InputType>;
484
493
  get event(): Readonly<InputType>;
@@ -516,7 +525,7 @@ declare class SlatePublicContext<InputType extends {}> {
516
525
  }
517
526
  declare class SlateContext<ConfigType extends {}, AuthType extends {}, InputType extends {}> extends SlatePublicContext<InputType> {
518
527
  #private;
519
- constructor(config: ConfigType, input: InputType, auth: AuthType, spec: SlateSpecification<ConfigType, AuthType>, logger: SlateLogger, liveInvocation?: SlateLiveInvocationInfo | null);
528
+ constructor(config: ConfigType, input: InputType, auth: AuthType, spec: SlateSpecification<ConfigType, AuthType>, logger: SlateLogger, liveInvocation?: SlateLiveInvocationInfo | null, runtimeInfo?: SlateRuntimeInfo | null);
520
529
  get config(): Readonly<ConfigType>;
521
530
  get auth(): Readonly<AuthType>;
522
531
  _getAuthConfigForRedaction(): Record<string, unknown> | undefined;
@@ -524,6 +533,7 @@ declare class SlateContext<ConfigType extends {}, AuthType extends {}, InputType
524
533
 
525
534
  declare let runWithContext: <InputType extends {}, RV>(context: SlatePublicContext<InputType>, fn: () => Promise<RV>) => Promise<RV>;
526
535
  declare let getCurrentContext: <ConfigType extends {}, AuthType extends {}, InputType extends {}>() => SlateContext<ConfigType, AuthType, InputType>;
536
+ declare let getRuntimeInfo: () => Readonly<SlateRuntimeInfo> | null;
527
537
 
528
538
  declare let SlateDefaultPollingIntervalSeconds: number;
529
539
  type SlateTriggerRoutingMatcher = Record<string, any>;
@@ -1076,6 +1086,7 @@ interface SlateErrorResponse {
1076
1086
  issues?: SlateErrorIssue[];
1077
1087
  provider?: SlateErrorProviderInfo;
1078
1088
  upstream?: SlateErrorUpstreamInfo;
1089
+ upstreamCode?: string;
1079
1090
  baggage?: Record<string, unknown>;
1080
1091
  requestTraces?: SlateHttpTrace[];
1081
1092
  }
@@ -1204,4 +1215,4 @@ declare let skipWebhook: (reason: string, response?: Response | SlateWebhookHttp
1204
1215
  response: Response | SlateWebhookHttpResponseInit;
1205
1216
  };
1206
1217
 
1207
- export { API_ERROR_MAX_DETAILS, API_ERROR_MAX_MESSAGE_LENGTH, API_ERROR_TRUNCATED_PLACEHOLDER, AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX, type ApiErrorBuildHelpers, type ApiErrorDetailOptions, type ApiErrorResponse, type ApiErrorStatus, type ApiErrorTextOptions, type ApiServiceError, type AuthConfigSecretFilter, AuthConfigSecretRedactor, type BoundedApiErrorDetailOptions, type BuildApiServiceErrorOptions, type CreateHmacSignatureOptions, type DecodeApiErrorBodyOptions, GET_FILE_URL_TOOL_ID, type GetFileUrlHandler, type GetFileUrlToolInput, type GetFileUrlToolOutput, type NormalizeOAuthTokenResponseOptions, type OAuthExpiresAtOptions, type OAuthRefreshTokenFallbackMode, type OAuthTokenResponse, Slate, SlateAction, SlateActionBuilder, type SlateActionCreateParameters, type SlateActionDocsReference, type SlateActionParameters, type SlateActionParametersAny, type SlateActionParametersTool, type SlateActionParametersTrigger, type SlateActionScopeClause, type SlateActionScopeClauseInput, type SlateActionScopeValue, type SlateActionScopes, type SlateActionScopesInput, type SlateActionType, SlateAdapter, type SlateAdapterCapability, SlateAdapterSpec, type SlateAdapterSpecParameters, type SlateAddAttachmentContent, type SlateAddAttachmentInput, type SlateAttachment, type SlateAttachmentInlineContent, type SlateAttachmentUploadReferenceContent, type SlateAttachmentUrlContent, SlateAuth, type SlateAuthDocsReference, type SlateAuthType, type SlateAuthWithCustomData, type SlateAuthWithNone, type SlateAuthWithOauth, type SlateAuthWithServiceAccount, type SlateAuthWithToken, type SlateAuthenticatedAxiosDefaults, type SlateAxiosDefaults, type SlateAxiosErrorAdapter, type SlateAxiosErrorOptions, SlateConfig, type SlateConfigDocsReference, SlateContext, SlateDeclarationError, SlateDefaultPollingIntervalSeconds, type SlateDirectUploadInput, type SlateDocsReference, SlateError, type SlateErrorInput, type SlateErrorIssue, type SlateErrorKind, type SlateErrorProviderInfo, type SlateErrorResponse, type SlateErrorUpstreamInfo, type SlateGatewayEvent, type SlateLiveInvocationInfo, type SlateLogEntry, type SlateLogFields, type SlateLogListener, type SlateLogMessageInput, type SlateLogType, SlateLogger, type SlateProviderDocsReference, SlatePublicContext, SlatePublicTool, type SlatePublicToolInvocationHandler, type SlatePublicToolParameters, type SlateServiceErrorData, SlateSpecification, type SlateSpecificationCreateParameters, type SlateSpecificationParameters, SlateTool, SlateToolCategory, type SlateToolCategoryParameters, type SlateToolInvocationHandler, type SlateToolParameters, SlateTrigger, SlateTriggerGroup, SlateTriggerGroupBuilder, type SlateTriggerGroupCreateParameters, type SlateTriggerGroupGatewayConnectHandler, type SlateTriggerGroupGatewayParameters, type SlateTriggerGroupGatewayReceiveHandler, type SlateTriggerGroupParameters, type SlateTriggerGroupPollHandler, type SlateTriggerGroupPollingParameters, type SlateTriggerGroupRoutingMatchersHandler, type SlateTriggerGroupWebhookAutoRegistrationParameters, type SlateTriggerGroupWebhookManualRegistrationParameters, type SlateTriggerGroupWebhookParameters, type SlateTriggerMappingHandler, type SlateTriggerMatchesHandler, type SlateTriggerParameters, type SlateTriggerRoutingMatcher, type SlateTypedDocsReference, type SlateWebhookHttpResponseInit, type SlateWebhookManualFinishHandler, type SlateWebhookManualSetupHandler, type SlateWebhookProcessHandler, type SlateWebhookRegisterHandler, type SlateWebhookSkipped, type SlateWebhookTarget, type SlateWebhookTargetListHandler, type SlateWebhookTargetOwnership, type SlateWebhookUnregisterHandler, type VerifyHmacSignatureOptions, adapterSpec, allOf, anyOf, auth, axios, buildApiServiceError, collectApiErrorDetails, config, createApiServiceError, createAuthenticatedAxios, createAxios, createBase64Attachment, createHmacSignature, createSlateError, createTextAttachment, createUrlAttachment, decodeApiErrorBody, extractApiErrorMessage, getApiErrorResponse, getApiErrorResponseWithBody, getApiErrorStatus, getBase64ByteLength, getCurrentContext, getFileUrlTool, getFileUrlToolInputSchema, getFileUrlToolOutputSchema, getGraphWebhookValidationResponse, getMetaWebhookVerificationResponse, getOAuthExpiresAtFromExpiresIn, getResponseHeaderValue, getServiceErrorData, graphWebhookHttp, inferSlateErrorFromAxios, isApiErrorRecord, isAxiosErrorLike, isServiceErrorData, isUrlEmbeddedCredential, looksLikeHtmlErrorBody, mapServiceErrorCode, mapServiceErrorToSlateErrorInput, mergeScopes, metaWebhookHttp, normalizeOAuthTokenResponse, pickDefined, publicTool, pushBoundedApiErrorDetail, readApiErrorText, redactUrlAttachmentSecrets, requestAxios, requestAxiosData, runWithContext, scopeClause, setIfDefined, skipWebhook, spec, statusLabelForApiError, tool, toolCategory, trigger, triggerGroup, truncateApiErrorMessage, uploadAttachmentDirect, validateScopes, verifyHmacSignature };
1218
+ export { API_ERROR_MAX_DETAILS, API_ERROR_MAX_MESSAGE_LENGTH, API_ERROR_TRUNCATED_PLACEHOLDER, AUTH_CONFIG_SECRET_PLACEHOLDER_PREFIX, type ApiErrorBuildHelpers, type ApiErrorDetailOptions, type ApiErrorResponse, type ApiErrorStatus, type ApiErrorTextOptions, type ApiServiceError, type AuthConfigSecretFilter, AuthConfigSecretRedactor, type BoundedApiErrorDetailOptions, type BuildApiServiceErrorOptions, type CreateHmacSignatureOptions, type DecodeApiErrorBodyOptions, GET_FILE_URL_TOOL_ID, type GetFileUrlHandler, type GetFileUrlToolInput, type GetFileUrlToolOutput, type NormalizeOAuthTokenResponseOptions, type OAuthExpiresAtOptions, type OAuthRefreshTokenFallbackMode, type OAuthTokenResponse, Slate, SlateAction, SlateActionBuilder, type SlateActionCreateParameters, type SlateActionDocsReference, type SlateActionParameters, type SlateActionParametersAny, type SlateActionParametersTool, type SlateActionParametersTrigger, type SlateActionScopeClause, type SlateActionScopeClauseInput, type SlateActionScopeValue, type SlateActionScopes, type SlateActionScopesInput, type SlateActionType, SlateAdapter, type SlateAdapterCapability, SlateAdapterSpec, type SlateAdapterSpecParameters, type SlateAddAttachmentContent, type SlateAddAttachmentInput, type SlateAttachment, type SlateAttachmentInlineContent, type SlateAttachmentUploadReferenceContent, type SlateAttachmentUrlContent, SlateAuth, type SlateAuthDocsReference, type SlateAuthType, type SlateAuthWithCustomData, type SlateAuthWithNone, type SlateAuthWithOauth, type SlateAuthWithServiceAccount, type SlateAuthWithToken, type SlateAuthenticatedAxiosDefaults, type SlateAxiosDefaults, type SlateAxiosErrorAdapter, type SlateAxiosErrorOptions, SlateConfig, type SlateConfigDocsReference, SlateContext, SlateDeclarationError, SlateDefaultPollingIntervalSeconds, type SlateDirectUploadInput, type SlateDocsReference, SlateError, type SlateErrorInput, type SlateErrorIssue, type SlateErrorKind, type SlateErrorProviderInfo, type SlateErrorResponse, type SlateErrorUpstreamInfo, type SlateGatewayEvent, type SlateLiveInvocationInfo, type SlateLogEntry, type SlateLogFields, type SlateLogListener, type SlateLogMessageInput, type SlateLogType, SlateLogger, type SlateProviderDocsReference, SlatePublicContext, SlatePublicTool, type SlatePublicToolInvocationHandler, type SlatePublicToolParameters, type SlateRuntimeInfo, type SlateServiceErrorData, SlateSpecification, type SlateSpecificationCreateParameters, type SlateSpecificationParameters, SlateTool, SlateToolCategory, type SlateToolCategoryParameters, type SlateToolInvocationHandler, type SlateToolParameters, SlateTrigger, SlateTriggerGroup, SlateTriggerGroupBuilder, type SlateTriggerGroupCreateParameters, type SlateTriggerGroupGatewayConnectHandler, type SlateTriggerGroupGatewayParameters, type SlateTriggerGroupGatewayReceiveHandler, type SlateTriggerGroupParameters, type SlateTriggerGroupPollHandler, type SlateTriggerGroupPollingParameters, type SlateTriggerGroupRoutingMatchersHandler, type SlateTriggerGroupWebhookAutoRegistrationParameters, type SlateTriggerGroupWebhookManualRegistrationParameters, type SlateTriggerGroupWebhookParameters, type SlateTriggerMappingHandler, type SlateTriggerMatchesHandler, type SlateTriggerParameters, type SlateTriggerRoutingMatcher, type SlateTypedDocsReference, type SlateWebhookHttpResponseInit, type SlateWebhookManualFinishHandler, type SlateWebhookManualSetupHandler, type SlateWebhookProcessHandler, type SlateWebhookRegisterHandler, type SlateWebhookSkipped, type SlateWebhookTarget, type SlateWebhookTargetListHandler, type SlateWebhookTargetOwnership, type SlateWebhookUnregisterHandler, type VerifyHmacSignatureOptions, adapterSpec, allOf, anyOf, auth, axios, buildApiServiceError, collectApiErrorDetails, config, createApiServiceError, createAuthenticatedAxios, createAxios, createBase64Attachment, createHmacSignature, createSlateError, createTextAttachment, createUrlAttachment, decodeApiErrorBody, extractApiErrorMessage, getApiErrorResponse, getApiErrorResponseWithBody, getApiErrorStatus, getBase64ByteLength, getCurrentContext, getFileUrlTool, getFileUrlToolInputSchema, getFileUrlToolOutputSchema, getGraphWebhookValidationResponse, getMetaWebhookVerificationResponse, getOAuthExpiresAtFromExpiresIn, getResponseHeaderValue, getRuntimeInfo, getServiceErrorData, graphWebhookHttp, inferSlateErrorFromAxios, isApiErrorRecord, isAxiosErrorLike, isServiceErrorData, isUrlEmbeddedCredential, looksLikeHtmlErrorBody, mapServiceErrorCode, mapServiceErrorToSlateErrorInput, mergeScopes, metaWebhookHttp, normalizeOAuthTokenResponse, pickDefined, publicTool, pushBoundedApiErrorDetail, readApiErrorText, redactUrlAttachmentSecrets, requestAxios, requestAxiosData, runWithContext, scopeClause, setIfDefined, skipWebhook, spec, statusLabelForApiError, tool, toolCategory, trigger, triggerGroup, truncateApiErrorMessage, uploadAttachmentDirect, validateScopes, verifyHmacSignature };
@@ -899,6 +899,7 @@ var getCurrentContext = () => {
899
899
  }
900
900
  return context;
901
901
  };
902
+ var getRuntimeInfo = () => asyncLocalStorage.getStore()?.runtimeInfo ?? null;
902
903
 
903
904
  // src/error/defaults.ts
904
905
  var DEFAULT_CODE = "internal.unexpected";
@@ -1184,6 +1185,8 @@ var sanitizeForBaggage = (value, options = {}) => {
1184
1185
  return BAGGAGE_UNSERIALIZABLE_VALUE;
1185
1186
  }
1186
1187
  };
1188
+ var UPSTREAM_CODE_PATTERN = /^[\w.:-]{1,128}$/;
1189
+ var normalizeUpstreamCode = (value) => typeof value === "string" && UPSTREAM_CODE_PATTERN.test(value) ? value : void 0;
1187
1190
  var normalizeSlateErrorInput = (input) => {
1188
1191
  let code = input.code || DEFAULT_CODE;
1189
1192
  return {
@@ -1198,6 +1201,7 @@ var normalizeSlateErrorInput = (input) => {
1198
1201
  ...input.upstream,
1199
1202
  status: input.upstream?.status ?? input.status
1200
1203
  }),
1204
+ upstreamCode: normalizeUpstreamCode(input.upstreamCode) ?? normalizeUpstreamCode(input.upstream?.code),
1201
1205
  baggage: cleanRecord(input.baggage),
1202
1206
  requestTraces: input.requestTraces
1203
1207
  };
@@ -1660,6 +1664,7 @@ var mapServiceErrorToSlateErrorInput = (error, defaults = {}) => {
1660
1664
  issues: defaults.issues ?? normalizeServiceErrorIssues(data.errors),
1661
1665
  provider: defaults.provider,
1662
1666
  upstream: defaults.upstream,
1667
+ upstreamCode: normalizeUpstreamCode(defaults.upstreamCode) ?? normalizeUpstreamCode(data.upstreamCode),
1663
1668
  baggage: cleanRecord({
1664
1669
  ...defaults.baggage ?? {},
1665
1670
  ...getServiceErrorBaggage(data)
@@ -2765,6 +2770,10 @@ var resolveDefaultExport = (value) => {
2765
2770
  var PQueue = resolveDefaultExport(PQueueImport);
2766
2771
 
2767
2772
  // src/context/context.ts
2773
+ var freezeRuntimeInfo = (runtimeInfo) => Object.freeze({
2774
+ ...runtimeInfo,
2775
+ ...runtimeInfo.metorial ? { metorial: Object.freeze({ ...runtimeInfo.metorial }) } : {}
2776
+ });
2768
2777
  var isBufferLike = (value) => value instanceof Uint8Array || value instanceof ArrayBuffer;
2769
2778
  var toUint8Array = (value) => value instanceof ArrayBuffer ? new Uint8Array(value) : value;
2770
2779
  var isReadableStream = (value) => typeof ReadableStream !== "undefined" && value instanceof ReadableStream;
@@ -2781,17 +2790,19 @@ var readStreamToBuffer = async (stream) => {
2781
2790
  return Buffer.concat(chunks);
2782
2791
  };
2783
2792
  var SlatePublicContext = class {
2784
- constructor(input, spec2, logger, liveInvocation = null) {
2793
+ constructor(input, spec2, logger, liveInvocation = null, runtimeInfo = null) {
2785
2794
  this.spec = spec2;
2786
2795
  this.logger = logger;
2787
2796
  this.#input = input;
2788
2797
  this.#liveInvocation = liveInvocation;
2798
+ this.#runtimeInfo = runtimeInfo && freezeRuntimeInfo(runtimeInfo);
2789
2799
  }
2790
2800
  spec;
2791
2801
  logger;
2792
2802
  #input;
2793
2803
  #httpTraces = [];
2794
2804
  #liveInvocation;
2805
+ #runtimeInfo;
2795
2806
  #attachmentsDisabled = false;
2796
2807
  #attachments = [];
2797
2808
  #pendingUploads = [];
@@ -2802,6 +2813,9 @@ var SlatePublicContext = class {
2802
2813
  }
2803
2814
  return this.#uploadQueue;
2804
2815
  }
2816
+ get runtimeInfo() {
2817
+ return this.#runtimeInfo;
2818
+ }
2805
2819
  get specification() {
2806
2820
  return this.spec;
2807
2821
  }
@@ -2942,8 +2956,8 @@ var SlatePublicContext = class {
2942
2956
  var SlateContext = class extends SlatePublicContext {
2943
2957
  #config;
2944
2958
  #auth;
2945
- constructor(config2, input, auth2, spec2, logger, liveInvocation = null) {
2946
- super(input, spec2, logger, liveInvocation);
2959
+ constructor(config2, input, auth2, spec2, logger, liveInvocation = null, runtimeInfo = null) {
2960
+ super(input, spec2, logger, liveInvocation, runtimeInfo);
2947
2961
  this.#config = config2;
2948
2962
  this.#auth = auth2;
2949
2963
  }
@@ -3420,6 +3434,7 @@ export {
3420
3434
  getMetaWebhookVerificationResponse,
3421
3435
  getOAuthExpiresAtFromExpiresIn,
3422
3436
  getResponseHeaderValue,
3437
+ getRuntimeInfo,
3423
3438
  getServiceErrorData,
3424
3439
  graphWebhookHttp,
3425
3440
  inferSlateErrorFromAxios,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/provider",
3
- "version": "1.0.0-rc.31",
3
+ "version": "1.0.0-rc.33",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/auth/types.ts CHANGED
@@ -65,8 +65,11 @@ export type SlateAuthWithOauth<
65
65
  syncTokensAcrossConnections?: boolean;
66
66
 
67
67
  // Missing hooks fall back to the regular flow (callback output discarded).
68
- // Returned instructions are markdown shown to the admin.
68
+ // Returned instructions are markdown shown to the admin. `required` means users
69
+ // can't connect until an admin has completed setup; otherwise it is optional.
69
70
  adminSetup?: {
71
+ required?: boolean;
72
+
70
73
  getAuthorizationUrl?: (
71
74
  ctx: SlateOauthAuthorizationUrlContext<InputType>
72
75
  ) => Promise<SlateOauthAuthorizationUrlResult<InputType>>;
@@ -12,6 +12,20 @@ import { PQueue } from './pQueue';
12
12
 
13
13
  export type { SlateLiveInvocationInfo };
14
14
 
15
+ export interface SlateRuntimeInfo {
16
+ metorial?: {
17
+ apiUrl: string;
18
+ region?: string | null;
19
+ environment?: string | null;
20
+ };
21
+ }
22
+
23
+ let freezeRuntimeInfo = (runtimeInfo: SlateRuntimeInfo): Readonly<SlateRuntimeInfo> =>
24
+ Object.freeze({
25
+ ...runtimeInfo,
26
+ ...(runtimeInfo.metorial ? { metorial: Object.freeze({ ...runtimeInfo.metorial }) } : {})
27
+ });
28
+
15
29
  export type SlateAddAttachmentContent =
16
30
  | Buffer
17
31
  | Uint8Array
@@ -80,6 +94,7 @@ export class SlatePublicContext<InputType extends {}> {
80
94
  #httpTraces: SlateHttpTrace[] = [];
81
95
 
82
96
  #liveInvocation: SlateLiveInvocationInfo | null;
97
+ #runtimeInfo: Readonly<SlateRuntimeInfo> | null;
83
98
  #attachmentsDisabled = false;
84
99
  #attachments: SlateAttachment[] = [];
85
100
  #pendingUploads: Promise<void>[] = [];
@@ -96,10 +111,16 @@ export class SlatePublicContext<InputType extends {}> {
96
111
  input: InputType,
97
112
  private readonly spec: SlateSpecification<any, any>,
98
113
  private readonly logger: SlateLogger,
99
- liveInvocation: SlateLiveInvocationInfo | null = null
114
+ liveInvocation: SlateLiveInvocationInfo | null = null,
115
+ runtimeInfo: SlateRuntimeInfo | null = null
100
116
  ) {
101
117
  this.#input = input;
102
118
  this.#liveInvocation = liveInvocation;
119
+ this.#runtimeInfo = runtimeInfo && freezeRuntimeInfo(runtimeInfo);
120
+ }
121
+
122
+ get runtimeInfo() {
123
+ return this.#runtimeInfo;
103
124
  }
104
125
 
105
126
  get specification() {
@@ -294,9 +315,10 @@ export class SlateContext<
294
315
  auth: AuthType,
295
316
  spec: SlateSpecification<ConfigType, AuthType>,
296
317
  logger: SlateLogger,
297
- liveInvocation: SlateLiveInvocationInfo | null = null
318
+ liveInvocation: SlateLiveInvocationInfo | null = null,
319
+ runtimeInfo: SlateRuntimeInfo | null = null
298
320
  ) {
299
- super(input, spec, logger, liveInvocation);
321
+ super(input, spec, logger, liveInvocation, runtimeInfo);
300
322
  this.#config = config;
301
323
  this.#auth = auth;
302
324
  }
@@ -30,3 +30,5 @@ export let getCurrentContext = <
30
30
  }
31
31
  return context as SlateContext<ConfigType, AuthType, InputType>;
32
32
  };
33
+
34
+ export let getRuntimeInfo = () => asyncLocalStorage.getStore()?.runtimeInfo ?? null;
@@ -17,6 +17,7 @@ import {
17
17
  } from '@lowerdeck/error';
18
18
  import { AxiosError, type AxiosResponse, type InternalAxiosRequestConfig } from 'axios';
19
19
  import { describe, expect, it } from 'vitest';
20
+ import { createApiServiceError } from './api';
20
21
  import { SlateError } from './base';
21
22
 
22
23
  let createConfig = (overrides: Partial<InternalAxiosRequestConfig> = {}) =>
@@ -175,4 +176,80 @@ describe('SlateError', () => {
175
176
  });
176
177
  }
177
178
  });
179
+
180
+ it('exposes the upstream API error code as a top-level upstreamCode', () => {
181
+ expect(
182
+ new SlateError({ code: 'upstream.error', message: 'x', upstream: { code: 'E42' } }).data
183
+ .upstreamCode
184
+ ).toBe('E42');
185
+ expect(
186
+ new SlateError({
187
+ code: 'upstream.error',
188
+ message: 'x',
189
+ upstream: { code: 'nested' },
190
+ upstreamCode: 'explicit'
191
+ }).data.upstreamCode
192
+ ).toBe('explicit');
193
+ expect(
194
+ SlateError.fromServiceError(
195
+ createApiServiceError('x', { upstreamCode: 'card_declined' })
196
+ ).data.upstreamCode
197
+ ).toBe('card_declined');
198
+ expect(new SlateError({ code: 'upstream.error', message: 'x' }).data.upstreamCode).toBe(
199
+ undefined
200
+ );
201
+ });
202
+
203
+ it('accepts only code-shaped upstreamCode values', () => {
204
+ for (let code of [
205
+ 'AADSTS700016',
206
+ 'invalid_grant',
207
+ 'RATE_LIMITED',
208
+ 'request.bad',
209
+ 'a:b-c'
210
+ ]) {
211
+ expect(
212
+ new SlateError({ code: 'upstream.error', message: 'x', upstreamCode: code }).data
213
+ .upstreamCode
214
+ ).toBe(code);
215
+ }
216
+
217
+ for (let code of ['', 'x'.repeat(129), 'has space', 'token=abc&x', 'line\nbreak', '`x`']) {
218
+ expect(
219
+ new SlateError({ code: 'upstream.error', message: 'x', upstreamCode: code }).data
220
+ .upstreamCode
221
+ ).toBe(undefined);
222
+ expect(
223
+ SlateError.fromServiceError(createApiServiceError('x', { upstreamCode: code })).data
224
+ .upstreamCode
225
+ ).toBe(undefined);
226
+ }
227
+
228
+ expect(
229
+ SlateError.fromServiceError(
230
+ createApiServiceError('x', { upstreamCode: { nested: true } as unknown as string })
231
+ ).data.upstreamCode
232
+ ).toBe(undefined);
233
+ expect(
234
+ new SlateError({ code: 'upstream.error', message: 'x', upstreamCode: 'x'.repeat(128) })
235
+ .data.upstreamCode
236
+ ).toBe('x'.repeat(128));
237
+ expect(
238
+ new SlateError({
239
+ code: 'upstream.error',
240
+ message: 'x',
241
+ upstreamCode: 'bad value',
242
+ upstream: { code: 'fallback_code' }
243
+ }).data.upstreamCode
244
+ ).toBe('fallback_code');
245
+ });
246
+
247
+ it('also keeps upstreamCode in service error baggage for older hubs', () => {
248
+ let error = SlateError.fromServiceError(
249
+ createApiServiceError('x', { upstreamCode: 'card_declined' })
250
+ );
251
+ expect(error.data.baggage?.serviceErrorData).toMatchObject({
252
+ upstreamCode: 'card_declined'
253
+ });
254
+ });
178
255
  });
@@ -7,6 +7,7 @@ import {
7
7
  isRecord,
8
8
  normalizeKind,
9
9
  normalizeRetryable,
10
+ normalizeUpstreamCode,
10
11
  sanitizeForBaggage
11
12
  } from './utils';
12
13
 
@@ -162,6 +163,8 @@ export let mapServiceErrorToSlateErrorInput = (
162
163
  issues: defaults.issues ?? normalizeServiceErrorIssues(data.errors),
163
164
  provider: defaults.provider,
164
165
  upstream: defaults.upstream,
166
+ upstreamCode:
167
+ normalizeUpstreamCode(defaults.upstreamCode) ?? normalizeUpstreamCode(data.upstreamCode),
165
168
  baggage: cleanRecord({
166
169
  ...(defaults.baggage ?? {}),
167
170
  ...getServiceErrorBaggage(data)
@@ -45,6 +45,8 @@ export interface SlateErrorResponse {
45
45
  issues?: SlateErrorIssue[];
46
46
  provider?: SlateErrorProviderInfo;
47
47
  upstream?: SlateErrorUpstreamInfo;
48
+ // The upstream API's own error code, next to the normalized protocol `code`.
49
+ upstreamCode?: string;
48
50
  baggage?: Record<string, unknown>;
49
51
  requestTraces?: SlateHttpTrace[];
50
52
  }
@@ -389,6 +389,13 @@ export let sanitizeForBaggage = (
389
389
  }
390
390
  };
391
391
 
392
+ let UPSTREAM_CODE_PATTERN = /^[\w.:-]{1,128}$/;
393
+
394
+ // upstreamCode is copied from untrusted upstream responses to the top level of the
395
+ // error, outside the baggage sanitizer, so anything not code-shaped is dropped.
396
+ export let normalizeUpstreamCode = (value: unknown): string | undefined =>
397
+ typeof value === 'string' && UPSTREAM_CODE_PATTERN.test(value) ? value : undefined;
398
+
392
399
  export let normalizeSlateErrorInput = (input: SlateErrorInput): SlateErrorResponse => {
393
400
  let code = input.code || DEFAULT_CODE;
394
401
  return {
@@ -405,6 +412,8 @@ export let normalizeSlateErrorInput = (input: SlateErrorInput): SlateErrorRespon
405
412
  ...input.upstream,
406
413
  status: input.upstream?.status ?? input.status
407
414
  }) as SlateErrorUpstreamInfo | undefined,
415
+ upstreamCode:
416
+ normalizeUpstreamCode(input.upstreamCode) ?? normalizeUpstreamCode(input.upstream?.code),
408
417
  baggage: cleanRecord(input.baggage),
409
418
  requestTraces: input.requestTraces
410
419
  };