@tinycloud/sdk-services 3.0.0-beta.8 → 3.1.0-beta.1

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.d.cts CHANGED
@@ -1075,6 +1075,24 @@ declare function parseAuthError(responseText: string): {
1075
1075
  * Create a service error for unauthorized action (missing capability).
1076
1076
  */
1077
1077
  declare function authUnauthorizedError(service: string, message: string, meta?: Record<string, unknown>): ServiceError;
1078
+ /**
1079
+ * Authorization verdict read from an error's structure, never its message:
1080
+ * - `"unauthenticated"`: HTTP 401 — the session is missing or stale.
1081
+ * - `"forbidden"`: HTTP 403, or `AUTH_UNAUTHORIZED` without a status — the
1082
+ * session is valid but lacks the capability.
1083
+ * - `"other"`: a non-authorization HTTP error status (4xx/5xx).
1084
+ */
1085
+ type AuthorizationVerdict = "unauthenticated" | "forbidden" | "other";
1086
+ /**
1087
+ * Classify an error from its typed HTTP error status (`status`, `statusCode`,
1088
+ * or `meta.status`, 4xx/5xx only) and `AUTH_UNAUTHORIZED` code, following the
1089
+ * `cause` chain outer-first (at most {@link MAX_CAUSE_DEPTH} links, cycles
1090
+ * stop the walk) so wrappers that rethrow with `cause` keep the verdict. The
1091
+ * outermost error status decides, so an outer 5xx keeps its retry budget even
1092
+ * over an inner 401. Returns `undefined` for untyped errors; only then may
1093
+ * callers fall back to message heuristics.
1094
+ */
1095
+ declare function authorizationVerdictOf(error: unknown): AuthorizationVerdict | undefined;
1078
1096
  /**
1079
1097
  * Create a service error for storage quota exceeded (402 Payment Required).
1080
1098
  */
@@ -2245,4 +2263,4 @@ declare class SecretsService implements ISecretsService {
2245
2263
  listAll(): Promise<Result<SecretCatalogEntry[], SecretsError>>;
2246
2264
  }
2247
2265
 
2248
- export { BaseService, type BaseServiceOptions, type ColumnInfo, type DataVaultConfig, DataVaultService, DecryptCapabilityProof, DuckDbAction, type DuckDbActionType, type DuckDbBatchOptions, type BatchResponse as DuckDbBatchResponse, DuckDbDatabaseHandle, type DuckDbExecuteOptions, type ExecuteResponse as DuckDbExecuteResponse, type DuckDbOptions, type DuckDbQueryOptions, type QueryResponse as DuckDbQueryResponse, DuckDbService, type DuckDbServiceConfig, type DuckDbStatement, type DuckDbValue, EventHandler, FetchFunction, GenericKVResponseSchema, type GenericKVResponseType, GenericResultSchema, type HookEvent, type HookServiceName, type HookStreamEvent, type HookSubscription, type HookWebhookListOptions, type HookWebhookRecord, type HookWebhookRegistration, type HookWebhookScope, type HookWebhookUnregisterOptions, HooksService, type HooksServiceConfig, type IDataVaultService, type IDuckDbDatabaseHandle, type IDuckDbService, IEncryptionService, type IHooksService, IKVService, type ISecretsService, IService, IServiceContext, InvokeAnyFunction, InvokeFunction, KVListResponseSchema, type KVListResponseType, KVListResultSchema, type KVListResultType, KVResponseHeadersSchema, type KVResponseHeadersType, type ParsedSecretCatalogKey, PermissionHint, type QuotaConfig, type QuotaStatus, type ResolvedSecretPath, Result, RetryPolicy, RetryPolicySchema, type RetryPolicyType, SECRET_NAME_RE, type SchemaInfo, type SecretCatalogEntry, type SecretPayload, type SecretScopeOptions, type SecretsError, SecretsService, type ServiceConstructor, ServiceContext, type ServiceContextConfig, ServiceError, ServiceErrorEventSchema, type ServiceErrorEventType, ServiceErrorSchema, type ServiceErrorType, type ServiceRegistration, ServiceRequestEventSchema, type ServiceRequestEventType, ServiceResponseEventSchema, type ServiceResponseEventType, ServiceRetryEventSchema, type ServiceRetryEventType, ServiceSession, ServiceSessionSchema, type ServiceSessionType, StorageQuotaInfo, type SubscribeOptions, type TableInfo, TelemetryConfig, TelemetrySpanEventSchema, type TelemetrySpanEventType, type TinyCloudDebugEnableOptions, type TinyCloudDebugEvent, type TinyCloudDebugLevel, TinyCloudDebugLogger, type TinyCloudDebugTimer, TinyCloudQuota, type ValidationError, type VaultCrypto, type VaultEntry, type VaultError, type VaultGetOptions, type VaultGrantOptions, VaultHeaders, type VaultListOptions, type VaultListPage, type VaultNetworkReadResult, VaultPublicSpaceKVActions, type VaultPutOptions, type ViewInfo, type WasmVaultFunctions, abortedError, authExpiredError, authRequiredError, authUnauthorizedError, canonicalizeSecretScope, clearTinyCloudDebugLogs, createKVResponseSchema, createResultSchema, createVaultCrypto, disableTinyCloudDebug, enableTinyCloudDebug, errorResult, getTinyCloudDebugLogs, installTinyCloudDebugGlobals, networkError, notFoundError, parseAuthError, parsePermissionHint, parsePermissionHintFromErrorText, parseSecretCatalogKey, permissionDeniedError, resolveSecretListPrefix, resolveSecretPath, storageLimitReachedError, storageQuotaExceededError, timeoutError, tinyCloudDebugLogger, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, validateTelemetrySpanEvent, wrapError };
2266
+ export { type AuthorizationVerdict, BaseService, type BaseServiceOptions, type ColumnInfo, type DataVaultConfig, DataVaultService, DecryptCapabilityProof, DuckDbAction, type DuckDbActionType, type DuckDbBatchOptions, type BatchResponse as DuckDbBatchResponse, DuckDbDatabaseHandle, type DuckDbExecuteOptions, type ExecuteResponse as DuckDbExecuteResponse, type DuckDbOptions, type DuckDbQueryOptions, type QueryResponse as DuckDbQueryResponse, DuckDbService, type DuckDbServiceConfig, type DuckDbStatement, type DuckDbValue, EventHandler, FetchFunction, GenericKVResponseSchema, type GenericKVResponseType, GenericResultSchema, type HookEvent, type HookServiceName, type HookStreamEvent, type HookSubscription, type HookWebhookListOptions, type HookWebhookRecord, type HookWebhookRegistration, type HookWebhookScope, type HookWebhookUnregisterOptions, HooksService, type HooksServiceConfig, type IDataVaultService, type IDuckDbDatabaseHandle, type IDuckDbService, IEncryptionService, type IHooksService, IKVService, type ISecretsService, IService, IServiceContext, InvokeAnyFunction, InvokeFunction, KVListResponseSchema, type KVListResponseType, KVListResultSchema, type KVListResultType, KVResponseHeadersSchema, type KVResponseHeadersType, type ParsedSecretCatalogKey, PermissionHint, type QuotaConfig, type QuotaStatus, type ResolvedSecretPath, Result, RetryPolicy, RetryPolicySchema, type RetryPolicyType, SECRET_NAME_RE, type SchemaInfo, type SecretCatalogEntry, type SecretPayload, type SecretScopeOptions, type SecretsError, SecretsService, type ServiceConstructor, ServiceContext, type ServiceContextConfig, ServiceError, ServiceErrorEventSchema, type ServiceErrorEventType, ServiceErrorSchema, type ServiceErrorType, type ServiceRegistration, ServiceRequestEventSchema, type ServiceRequestEventType, ServiceResponseEventSchema, type ServiceResponseEventType, ServiceRetryEventSchema, type ServiceRetryEventType, ServiceSession, ServiceSessionSchema, type ServiceSessionType, StorageQuotaInfo, type SubscribeOptions, type TableInfo, TelemetryConfig, TelemetrySpanEventSchema, type TelemetrySpanEventType, type TinyCloudDebugEnableOptions, type TinyCloudDebugEvent, type TinyCloudDebugLevel, TinyCloudDebugLogger, type TinyCloudDebugTimer, TinyCloudQuota, type ValidationError, type VaultCrypto, type VaultEntry, type VaultError, type VaultGetOptions, type VaultGrantOptions, VaultHeaders, type VaultListOptions, type VaultListPage, type VaultNetworkReadResult, VaultPublicSpaceKVActions, type VaultPutOptions, type ViewInfo, type WasmVaultFunctions, abortedError, authExpiredError, authRequiredError, authUnauthorizedError, authorizationVerdictOf, canonicalizeSecretScope, clearTinyCloudDebugLogs, createKVResponseSchema, createResultSchema, createVaultCrypto, disableTinyCloudDebug, enableTinyCloudDebug, errorResult, getTinyCloudDebugLogs, installTinyCloudDebugGlobals, networkError, notFoundError, parseAuthError, parsePermissionHint, parsePermissionHintFromErrorText, parseSecretCatalogKey, permissionDeniedError, resolveSecretListPrefix, resolveSecretPath, storageLimitReachedError, storageQuotaExceededError, timeoutError, tinyCloudDebugLogger, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, validateTelemetrySpanEvent, wrapError };
package/dist/index.d.ts CHANGED
@@ -1075,6 +1075,24 @@ declare function parseAuthError(responseText: string): {
1075
1075
  * Create a service error for unauthorized action (missing capability).
1076
1076
  */
1077
1077
  declare function authUnauthorizedError(service: string, message: string, meta?: Record<string, unknown>): ServiceError;
1078
+ /**
1079
+ * Authorization verdict read from an error's structure, never its message:
1080
+ * - `"unauthenticated"`: HTTP 401 — the session is missing or stale.
1081
+ * - `"forbidden"`: HTTP 403, or `AUTH_UNAUTHORIZED` without a status — the
1082
+ * session is valid but lacks the capability.
1083
+ * - `"other"`: a non-authorization HTTP error status (4xx/5xx).
1084
+ */
1085
+ type AuthorizationVerdict = "unauthenticated" | "forbidden" | "other";
1086
+ /**
1087
+ * Classify an error from its typed HTTP error status (`status`, `statusCode`,
1088
+ * or `meta.status`, 4xx/5xx only) and `AUTH_UNAUTHORIZED` code, following the
1089
+ * `cause` chain outer-first (at most {@link MAX_CAUSE_DEPTH} links, cycles
1090
+ * stop the walk) so wrappers that rethrow with `cause` keep the verdict. The
1091
+ * outermost error status decides, so an outer 5xx keeps its retry budget even
1092
+ * over an inner 401. Returns `undefined` for untyped errors; only then may
1093
+ * callers fall back to message heuristics.
1094
+ */
1095
+ declare function authorizationVerdictOf(error: unknown): AuthorizationVerdict | undefined;
1078
1096
  /**
1079
1097
  * Create a service error for storage quota exceeded (402 Payment Required).
1080
1098
  */
@@ -2245,4 +2263,4 @@ declare class SecretsService implements ISecretsService {
2245
2263
  listAll(): Promise<Result<SecretCatalogEntry[], SecretsError>>;
2246
2264
  }
2247
2265
 
2248
- export { BaseService, type BaseServiceOptions, type ColumnInfo, type DataVaultConfig, DataVaultService, DecryptCapabilityProof, DuckDbAction, type DuckDbActionType, type DuckDbBatchOptions, type BatchResponse as DuckDbBatchResponse, DuckDbDatabaseHandle, type DuckDbExecuteOptions, type ExecuteResponse as DuckDbExecuteResponse, type DuckDbOptions, type DuckDbQueryOptions, type QueryResponse as DuckDbQueryResponse, DuckDbService, type DuckDbServiceConfig, type DuckDbStatement, type DuckDbValue, EventHandler, FetchFunction, GenericKVResponseSchema, type GenericKVResponseType, GenericResultSchema, type HookEvent, type HookServiceName, type HookStreamEvent, type HookSubscription, type HookWebhookListOptions, type HookWebhookRecord, type HookWebhookRegistration, type HookWebhookScope, type HookWebhookUnregisterOptions, HooksService, type HooksServiceConfig, type IDataVaultService, type IDuckDbDatabaseHandle, type IDuckDbService, IEncryptionService, type IHooksService, IKVService, type ISecretsService, IService, IServiceContext, InvokeAnyFunction, InvokeFunction, KVListResponseSchema, type KVListResponseType, KVListResultSchema, type KVListResultType, KVResponseHeadersSchema, type KVResponseHeadersType, type ParsedSecretCatalogKey, PermissionHint, type QuotaConfig, type QuotaStatus, type ResolvedSecretPath, Result, RetryPolicy, RetryPolicySchema, type RetryPolicyType, SECRET_NAME_RE, type SchemaInfo, type SecretCatalogEntry, type SecretPayload, type SecretScopeOptions, type SecretsError, SecretsService, type ServiceConstructor, ServiceContext, type ServiceContextConfig, ServiceError, ServiceErrorEventSchema, type ServiceErrorEventType, ServiceErrorSchema, type ServiceErrorType, type ServiceRegistration, ServiceRequestEventSchema, type ServiceRequestEventType, ServiceResponseEventSchema, type ServiceResponseEventType, ServiceRetryEventSchema, type ServiceRetryEventType, ServiceSession, ServiceSessionSchema, type ServiceSessionType, StorageQuotaInfo, type SubscribeOptions, type TableInfo, TelemetryConfig, TelemetrySpanEventSchema, type TelemetrySpanEventType, type TinyCloudDebugEnableOptions, type TinyCloudDebugEvent, type TinyCloudDebugLevel, TinyCloudDebugLogger, type TinyCloudDebugTimer, TinyCloudQuota, type ValidationError, type VaultCrypto, type VaultEntry, type VaultError, type VaultGetOptions, type VaultGrantOptions, VaultHeaders, type VaultListOptions, type VaultListPage, type VaultNetworkReadResult, VaultPublicSpaceKVActions, type VaultPutOptions, type ViewInfo, type WasmVaultFunctions, abortedError, authExpiredError, authRequiredError, authUnauthorizedError, canonicalizeSecretScope, clearTinyCloudDebugLogs, createKVResponseSchema, createResultSchema, createVaultCrypto, disableTinyCloudDebug, enableTinyCloudDebug, errorResult, getTinyCloudDebugLogs, installTinyCloudDebugGlobals, networkError, notFoundError, parseAuthError, parsePermissionHint, parsePermissionHintFromErrorText, parseSecretCatalogKey, permissionDeniedError, resolveSecretListPrefix, resolveSecretPath, storageLimitReachedError, storageQuotaExceededError, timeoutError, tinyCloudDebugLogger, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, validateTelemetrySpanEvent, wrapError };
2266
+ export { type AuthorizationVerdict, BaseService, type BaseServiceOptions, type ColumnInfo, type DataVaultConfig, DataVaultService, DecryptCapabilityProof, DuckDbAction, type DuckDbActionType, type DuckDbBatchOptions, type BatchResponse as DuckDbBatchResponse, DuckDbDatabaseHandle, type DuckDbExecuteOptions, type ExecuteResponse as DuckDbExecuteResponse, type DuckDbOptions, type DuckDbQueryOptions, type QueryResponse as DuckDbQueryResponse, DuckDbService, type DuckDbServiceConfig, type DuckDbStatement, type DuckDbValue, EventHandler, FetchFunction, GenericKVResponseSchema, type GenericKVResponseType, GenericResultSchema, type HookEvent, type HookServiceName, type HookStreamEvent, type HookSubscription, type HookWebhookListOptions, type HookWebhookRecord, type HookWebhookRegistration, type HookWebhookScope, type HookWebhookUnregisterOptions, HooksService, type HooksServiceConfig, type IDataVaultService, type IDuckDbDatabaseHandle, type IDuckDbService, IEncryptionService, type IHooksService, IKVService, type ISecretsService, IService, IServiceContext, InvokeAnyFunction, InvokeFunction, KVListResponseSchema, type KVListResponseType, KVListResultSchema, type KVListResultType, KVResponseHeadersSchema, type KVResponseHeadersType, type ParsedSecretCatalogKey, PermissionHint, type QuotaConfig, type QuotaStatus, type ResolvedSecretPath, Result, RetryPolicy, RetryPolicySchema, type RetryPolicyType, SECRET_NAME_RE, type SchemaInfo, type SecretCatalogEntry, type SecretPayload, type SecretScopeOptions, type SecretsError, SecretsService, type ServiceConstructor, ServiceContext, type ServiceContextConfig, ServiceError, ServiceErrorEventSchema, type ServiceErrorEventType, ServiceErrorSchema, type ServiceErrorType, type ServiceRegistration, ServiceRequestEventSchema, type ServiceRequestEventType, ServiceResponseEventSchema, type ServiceResponseEventType, ServiceRetryEventSchema, type ServiceRetryEventType, ServiceSession, ServiceSessionSchema, type ServiceSessionType, StorageQuotaInfo, type SubscribeOptions, type TableInfo, TelemetryConfig, TelemetrySpanEventSchema, type TelemetrySpanEventType, type TinyCloudDebugEnableOptions, type TinyCloudDebugEvent, type TinyCloudDebugLevel, TinyCloudDebugLogger, type TinyCloudDebugTimer, TinyCloudQuota, type ValidationError, type VaultCrypto, type VaultEntry, type VaultError, type VaultGetOptions, type VaultGrantOptions, VaultHeaders, type VaultListOptions, type VaultListPage, type VaultNetworkReadResult, VaultPublicSpaceKVActions, type VaultPutOptions, type ViewInfo, type WasmVaultFunctions, abortedError, authExpiredError, authRequiredError, authUnauthorizedError, authorizationVerdictOf, canonicalizeSecretScope, clearTinyCloudDebugLogs, createKVResponseSchema, createResultSchema, createVaultCrypto, disableTinyCloudDebug, enableTinyCloudDebug, errorResult, getTinyCloudDebugLogs, installTinyCloudDebugGlobals, networkError, notFoundError, parseAuthError, parsePermissionHint, parsePermissionHintFromErrorText, parseSecretCatalogKey, permissionDeniedError, resolveSecretListPrefix, resolveSecretPath, storageLimitReachedError, storageQuotaExceededError, timeoutError, tinyCloudDebugLogger, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, validateTelemetrySpanEvent, wrapError };
package/dist/index.js CHANGED
@@ -993,6 +993,37 @@ function parseAuthError(responseText) {
993
993
  function authUnauthorizedError(service, message, meta) {
994
994
  return serviceError(ErrorCodes.AUTH_UNAUTHORIZED, message, service, { meta });
995
995
  }
996
+ var MAX_CAUSE_DEPTH = 8;
997
+ function errorStatusOf(node) {
998
+ const meta = node.meta;
999
+ const candidates = [
1000
+ node.status,
1001
+ node.statusCode,
1002
+ typeof meta === "object" && meta !== null ? meta.status : void 0
1003
+ ];
1004
+ for (const candidate of candidates) {
1005
+ if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 400 && candidate <= 599) {
1006
+ return candidate;
1007
+ }
1008
+ }
1009
+ return void 0;
1010
+ }
1011
+ function authorizationVerdictOf(error) {
1012
+ const seen = /* @__PURE__ */ new Set();
1013
+ let sawUnauthorizedCode = false;
1014
+ let node = error;
1015
+ for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
1016
+ seen.add(node);
1017
+ const record = node;
1018
+ const status = errorStatusOf(record);
1019
+ if (status === 401) return "unauthenticated";
1020
+ if (status === 403) return "forbidden";
1021
+ if (status !== void 0) return "other";
1022
+ if (record.code === ErrorCodes.AUTH_UNAUTHORIZED) sawUnauthorizedCode = true;
1023
+ node = record.cause;
1024
+ }
1025
+ return sawUnauthorizedCode ? "forbidden" : void 0;
1026
+ }
996
1027
  function storageQuotaExceededError(service, message, meta) {
997
1028
  return {
998
1029
  code: ErrorCodes.STORAGE_QUOTA_EXCEEDED,
@@ -1421,7 +1452,7 @@ var KVService = class extends BaseService {
1421
1452
  return err(
1422
1453
  storageQuotaExceededError(
1423
1454
  "kv",
1424
- `Storage quota exceeded for key "${key}": ${errorText}`,
1455
+ `Storage quota exceeded for key ${JSON.stringify(key)}: ${errorText}`,
1425
1456
  {
1426
1457
  status: response.status,
1427
1458
  ...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
@@ -1434,7 +1465,7 @@ var KVService = class extends BaseService {
1434
1465
  return err(
1435
1466
  storageLimitReachedError(
1436
1467
  "kv",
1437
- `Storage limit reached for key "${key}": ${errorText}`,
1468
+ `Storage limit reached for key ${JSON.stringify(key)}: ${errorText}`,
1438
1469
  {
1439
1470
  status: response.status,
1440
1471
  ...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
@@ -1478,7 +1509,7 @@ var KVService = class extends BaseService {
1478
1509
  */
1479
1510
  getFullPath(key, prefixOverride) {
1480
1511
  const prefix = prefixOverride ?? this._config.prefix ?? "";
1481
- return prefix ? `${prefix}/${key}` : key;
1512
+ return prefix ? key === "" ? prefix : `${prefix}/${key}` : key;
1482
1513
  }
1483
1514
  /**
1484
1515
  * Get the host URL.
@@ -1720,12 +1751,11 @@ var KVService = class extends BaseService {
1720
1751
  if (!response.ok) {
1721
1752
  const errorText = await response.text();
1722
1753
  if (response.status === 401 || response.status === 403) {
1723
- const { resource, action: requiredAction } = parseAuthError(errorText);
1724
- return err(authUnauthorizedError("kv", errorText, {
1725
- status: response.status,
1726
- ...requiredAction && { requiredAction },
1727
- ...resource && { resource }
1728
- }));
1754
+ return this.authorizationFailure(
1755
+ `Failed to batch read ${keys.length} key(s)`,
1756
+ response,
1757
+ errorText
1758
+ );
1729
1759
  }
1730
1760
  if (response.status === 413) {
1731
1761
  return err(serviceError(
@@ -1824,23 +1854,39 @@ var KVService = class extends BaseService {
1824
1854
  } catch {
1825
1855
  }
1826
1856
  if (response.status === 401 || response.status === 403) {
1827
- const { resource, action } = parseAuthError(errorText);
1828
- return err(authUnauthorizedError("kv", errorText, {
1829
- status: response.status,
1830
- ...action && { requiredAction: action },
1831
- ...resource && { resource }
1832
- }));
1857
+ return this.authorizationFailure(
1858
+ `Failed to create signed read URL for key ${JSON.stringify(key)}`,
1859
+ response,
1860
+ errorText
1861
+ );
1833
1862
  }
1834
1863
  const code = response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR;
1835
1864
  return err(
1836
1865
  serviceError(
1837
1866
  code,
1838
- `Failed to create signed read URL for key "${key}": ${response.status} - ${errorText}`,
1867
+ `Failed to create signed read URL for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
1839
1868
  "kv",
1840
1869
  { meta: { status: response.status, statusText: response.statusText } }
1841
1870
  )
1842
1871
  );
1843
1872
  }
1873
+ /**
1874
+ * AUTH_UNAUTHORIZED for a 401/403 response. The message keeps the HTTP
1875
+ * status and the server text (`<context>: <status> - <text>`, the same
1876
+ * shape as every other KV failure) so callers that rethrow only the message
1877
+ * still see the status; `meta.status` carries it for typed callers.
1878
+ * Resource/ability hints are parsed from the raw body, never the message.
1879
+ */
1880
+ authorizationFailure(context, response, errorText, extraMeta = {}) {
1881
+ const { resource, action } = parseAuthError(errorText);
1882
+ const detail = errorText.trim().length > 0 ? errorText : response.statusText || "authorization failed";
1883
+ return err(authUnauthorizedError("kv", `${context}: ${response.status} - ${detail}`, {
1884
+ status: response.status,
1885
+ ...action && { requiredAction: action },
1886
+ ...resource && { resource },
1887
+ ...extraMeta
1888
+ }));
1889
+ }
1844
1890
  normalizeSignedReadUrlResponse(data) {
1845
1891
  if (!data || typeof data !== "object") {
1846
1892
  return void 0;
@@ -1883,14 +1929,13 @@ var KVService = class extends BaseService {
1883
1929
  if (!response.ok) {
1884
1930
  if (response.status === 401 || response.status === 403) {
1885
1931
  const errorText2 = await response.text();
1886
- const { resource, action } = parseAuthError(errorText2);
1887
1932
  const permissionHint = parsePermissionHintFromErrorText(errorText2);
1888
- return err(authUnauthorizedError("kv", errorText2, {
1889
- status: response.status,
1890
- ...action && { requiredAction: action },
1891
- ...resource && { resource },
1892
- ...permissionHint === void 0 ? {} : { permissionHint }
1893
- }));
1933
+ return this.authorizationFailure(
1934
+ `Failed to get key ${JSON.stringify(key)}`,
1935
+ response,
1936
+ errorText2,
1937
+ permissionHint === void 0 ? {} : { permissionHint }
1938
+ );
1894
1939
  }
1895
1940
  if (response.status === 404) {
1896
1941
  return this.classifyNotFound(response, key);
@@ -1899,7 +1944,7 @@ var KVService = class extends BaseService {
1899
1944
  if (response.status === 413) {
1900
1945
  return err(serviceError(
1901
1946
  ErrorCodes.KV_RESPONSE_TOO_LARGE,
1902
- `KV value at key "${key}" exceeds the requested response limit`,
1947
+ `KV value at key ${JSON.stringify(key)} exceeds the requested response limit`,
1903
1948
  "kv",
1904
1949
  { meta: { status: response.status, statusText: response.statusText } }
1905
1950
  ));
@@ -1907,7 +1952,7 @@ var KVService = class extends BaseService {
1907
1952
  return err(
1908
1953
  serviceError(
1909
1954
  ErrorCodes.NETWORK_ERROR,
1910
- `Failed to get key "${key}": ${response.status} - ${errorText}`,
1955
+ `Failed to get key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
1911
1956
  "kv",
1912
1957
  { meta: { status: response.status, statusText: response.statusText } }
1913
1958
  )
@@ -1962,21 +2007,19 @@ var KVService = class extends BaseService {
1962
2007
  ...options?.ifNoneMatch === void 0 ? {} : { "if-none-match": options.ifNoneMatch }
1963
2008
  }
1964
2009
  );
2010
+ if (response.status === 401 || response.status === 403) {
2011
+ return this.authorizationFailure(
2012
+ `Failed to put key ${JSON.stringify(key)}`,
2013
+ response,
2014
+ await response.text()
2015
+ );
2016
+ }
1965
2017
  if (!response.ok) {
1966
- if (response.status === 401) {
1967
- const errorText2 = await response.text();
1968
- const { resource, action } = parseAuthError(errorText2);
1969
- return err(authUnauthorizedError("kv", errorText2, {
1970
- status: response.status,
1971
- ...action && { requiredAction: action },
1972
- ...resource && { resource }
1973
- }));
1974
- }
1975
2018
  const errorText = await response.text();
1976
2019
  if (response.status === 412) {
1977
2020
  return err(serviceError(
1978
2021
  ErrorCodes.KV_PRECONDITION_FAILED,
1979
- `KV precondition failed for key "${key}"`,
2022
+ `KV precondition failed for key ${JSON.stringify(key)}`,
1980
2023
  "kv",
1981
2024
  { meta: { status: response.status, statusText: response.statusText } }
1982
2025
  ));
@@ -1984,7 +2027,7 @@ var KVService = class extends BaseService {
1984
2027
  if (response.status === 503 && (options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0)) {
1985
2028
  return err(serviceError(
1986
2029
  ErrorCodes.KV_CONFLICT,
1987
- `Concurrent KV update conflicted for key "${key}"`,
2030
+ `Concurrent KV update conflicted for key ${JSON.stringify(key)}`,
1988
2031
  "kv",
1989
2032
  { meta: { status: response.status, statusText: response.statusText } }
1990
2033
  ));
@@ -2000,7 +2043,7 @@ var KVService = class extends BaseService {
2000
2043
  return err(
2001
2044
  serviceError(
2002
2045
  ErrorCodes.KV_WRITE_FAILED,
2003
- `Failed to put key "${key}": ${response.status} - ${errorText}`,
2046
+ `Failed to put key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
2004
2047
  "kv",
2005
2048
  { meta: { status: response.status, statusText: response.statusText } }
2006
2049
  )
@@ -2094,12 +2137,11 @@ var KVService = class extends BaseService {
2094
2137
  );
2095
2138
  }
2096
2139
  if (response.status === 401 || response.status === 403) {
2097
- const { resource, action } = parseAuthError(errorText);
2098
- return err(authUnauthorizedError("kv", errorText, {
2099
- status: response.status,
2100
- ...action && { requiredAction: action },
2101
- ...resource && { resource }
2102
- }));
2140
+ return this.authorizationFailure(
2141
+ `Failed to batch put ${items.length} key(s)`,
2142
+ response,
2143
+ errorText
2144
+ );
2103
2145
  }
2104
2146
  const quotaError = this.handleQuotaErrorResponse(
2105
2147
  response,
@@ -2220,13 +2262,11 @@ var KVService = class extends BaseService {
2220
2262
  );
2221
2263
  if (!response.ok) {
2222
2264
  if (response.status === 401) {
2223
- const errorText2 = await response.text();
2224
- const { resource, action } = parseAuthError(errorText2);
2225
- return err(authUnauthorizedError("kv", errorText2, {
2226
- status: response.status,
2227
- ...action && { requiredAction: action },
2228
- ...resource && { resource }
2229
- }));
2265
+ return this.authorizationFailure(
2266
+ "Failed to list keys",
2267
+ response,
2268
+ await response.text()
2269
+ );
2230
2270
  }
2231
2271
  const errorText = await response.text();
2232
2272
  return err(
@@ -2275,13 +2315,11 @@ var KVService = class extends BaseService {
2275
2315
  );
2276
2316
  if (!response.ok) {
2277
2317
  if (response.status === 401) {
2278
- const errorText2 = await response.text();
2279
- const { resource, action } = parseAuthError(errorText2);
2280
- return err(authUnauthorizedError("kv", errorText2, {
2281
- status: response.status,
2282
- ...action && { requiredAction: action },
2283
- ...resource && { resource }
2284
- }));
2318
+ return this.authorizationFailure(
2319
+ `Failed to delete key ${JSON.stringify(key)}`,
2320
+ response,
2321
+ await response.text()
2322
+ );
2285
2323
  }
2286
2324
  if (response.status === 404) {
2287
2325
  return this.classifyNotFound(response, key);
@@ -2290,7 +2328,7 @@ var KVService = class extends BaseService {
2290
2328
  if (response.status === 412) {
2291
2329
  return err(serviceError(
2292
2330
  ErrorCodes.KV_PRECONDITION_FAILED,
2293
- `KV precondition failed for key "${key}"`,
2331
+ `KV precondition failed for key ${JSON.stringify(key)}`,
2294
2332
  "kv",
2295
2333
  { meta: { status: response.status, statusText: response.statusText } }
2296
2334
  ));
@@ -2298,7 +2336,7 @@ var KVService = class extends BaseService {
2298
2336
  if (response.status === 503 && options?.ifMatch !== void 0) {
2299
2337
  return err(serviceError(
2300
2338
  ErrorCodes.KV_CONFLICT,
2301
- `Concurrent KV delete conflicted for key "${key}"`,
2339
+ `Concurrent KV delete conflicted for key ${JSON.stringify(key)}`,
2302
2340
  "kv",
2303
2341
  { meta: { status: response.status, statusText: response.statusText } }
2304
2342
  ));
@@ -2306,7 +2344,7 @@ var KVService = class extends BaseService {
2306
2344
  return err(
2307
2345
  serviceError(
2308
2346
  ErrorCodes.NETWORK_ERROR,
2309
- `Failed to delete key "${key}": ${response.status} - ${errorText}`,
2347
+ `Failed to delete key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
2310
2348
  "kv",
2311
2349
  { meta: { status: response.status, statusText: response.statusText } }
2312
2350
  )
@@ -2339,13 +2377,11 @@ var KVService = class extends BaseService {
2339
2377
  );
2340
2378
  if (!response.ok) {
2341
2379
  if (response.status === 401) {
2342
- const errorText2 = await response.text();
2343
- const { resource, action } = parseAuthError(errorText2);
2344
- return err(authUnauthorizedError("kv", errorText2, {
2345
- status: response.status,
2346
- ...action && { requiredAction: action },
2347
- ...resource && { resource }
2348
- }));
2380
+ return this.authorizationFailure(
2381
+ `Failed to get metadata for key ${JSON.stringify(key)}`,
2382
+ response,
2383
+ await response.text()
2384
+ );
2349
2385
  }
2350
2386
  if (response.status === 404) {
2351
2387
  return this.classifyNotFound(response, key);
@@ -2354,7 +2390,7 @@ var KVService = class extends BaseService {
2354
2390
  return err(
2355
2391
  serviceError(
2356
2392
  ErrorCodes.NETWORK_ERROR,
2357
- `Failed to get metadata for key "${key}": ${response.status} - ${errorText}`,
2393
+ `Failed to get metadata for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
2358
2394
  "kv",
2359
2395
  { meta: { status: response.status, statusText: response.statusText } }
2360
2396
  )
@@ -3836,10 +3872,14 @@ async function responseError(service, message, response) {
3836
3872
  }
3837
3873
  } catch {
3838
3874
  }
3839
- return wrapError(
3875
+ const error = wrapError(
3840
3876
  service,
3841
3877
  new Error(`${message}: ${response.status} ${detail}`)
3842
3878
  );
3879
+ return {
3880
+ ...error,
3881
+ meta: { ...error.meta, status: response.status, statusText: response.statusText }
3882
+ };
3843
3883
  }
3844
3884
  function isAbortError(error) {
3845
3885
  return error instanceof DOMException && error.name === "AbortError";
@@ -6890,6 +6930,7 @@ export {
6890
6930
  authExpiredError,
6891
6931
  authRequiredError,
6892
6932
  authUnauthorizedError,
6933
+ authorizationVerdictOf,
6893
6934
  base64Decode2 as base64Decode,
6894
6935
  base64Encode2 as base64Encode,
6895
6936
  buildCanonicalDecryptRequest,