@tinycloud/sdk-services 3.1.0-beta.1 → 3.1.0-beta.2

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
@@ -1101,6 +1101,36 @@ declare function storageQuotaExceededError(service: string, message: string, met
1101
1101
  * Create a service error for storage limit reached (413 Payload Too Large).
1102
1102
  */
1103
1103
  declare function storageLimitReachedError(service: string, message: string, meta?: Record<string, unknown>): ServiceError;
1104
+ /** Shown when a write is rejected because the owner's storage is full. */
1105
+ declare const STORAGE_FULL_MESSAGE = "TinyCloud storage is full, so this change was not saved. Reading still works. Free up space or upgrade your plan to save again.";
1106
+ /** Shown when a write is larger than the storage the owner has left. */
1107
+ declare const STORAGE_WRITE_TOO_LARGE_MESSAGE = "This change is larger than the TinyCloud storage you have left, so it was not saved. Reading still works. Free up space or upgrade your plan to save it.";
1108
+ /**
1109
+ * Parse the byte counts from a node storage rejection
1110
+ * ("... Used: 155744 bytes, Limit: 0 bytes"). The limit is the share of the
1111
+ * owner's account-wide budget left for this space, so it is 0 when the
1112
+ * owner's other spaces already use the whole budget.
1113
+ */
1114
+ declare function parseStorageQuotaBytes(responseText: string): {
1115
+ usedBytes: number;
1116
+ limitBytes: number;
1117
+ } | undefined;
1118
+ /**
1119
+ * Build the error for a write the node rejected for storage: 402 when storage
1120
+ * is already full, 413 when this write is larger than what is left. KV, SQL
1121
+ * and DuckDB all report it with the same codes and message so an app can
1122
+ * detect "storage full" in one place with {@link isStorageFullError}.
1123
+ */
1124
+ declare function storageRejectionError(service: string, status: 402 | 413, meta: Record<string, unknown>, responseText: string): ServiceError;
1125
+ /**
1126
+ * True when a write failed for storage: the owner's TinyCloud storage is full
1127
+ * (`STORAGE_QUOTA_EXCEEDED`), or this write is larger than what is left
1128
+ * (`STORAGE_LIMIT_REACHED`). Reads keep working in both cases, so apps should
1129
+ * stay usable read-only and point the user at freeing up space or upgrading.
1130
+ */
1131
+ declare function isStorageFullError(error: {
1132
+ code?: string;
1133
+ } | null | undefined): boolean;
1104
1134
  /**
1105
1135
  * Wrap an unknown error in a ServiceError.
1106
1136
  */
@@ -1719,6 +1749,10 @@ type VaultErrorInput = {
1719
1749
  code: "STORAGE_ERROR";
1720
1750
  cause: Error;
1721
1751
  message?: string;
1752
+ } | {
1753
+ code: "STORAGE_QUOTA_EXCEEDED" | "STORAGE_LIMIT_REACHED";
1754
+ message: string;
1755
+ meta?: Record<string, unknown>;
1722
1756
  };
1723
1757
  /**
1724
1758
  * Vault error with service field (compatible with ServiceError).
@@ -2263,4 +2297,4 @@ declare class SecretsService implements ISecretsService {
2263
2297
  listAll(): Promise<Result<SecretCatalogEntry[], SecretsError>>;
2264
2298
  }
2265
2299
 
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 };
2300
+ 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, STORAGE_FULL_MESSAGE, STORAGE_WRITE_TOO_LARGE_MESSAGE, 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, isStorageFullError, networkError, notFoundError, parseAuthError, parsePermissionHint, parsePermissionHintFromErrorText, parseSecretCatalogKey, parseStorageQuotaBytes, permissionDeniedError, resolveSecretListPrefix, resolveSecretPath, storageLimitReachedError, storageQuotaExceededError, storageRejectionError, timeoutError, tinyCloudDebugLogger, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, validateTelemetrySpanEvent, wrapError };
package/dist/index.d.ts CHANGED
@@ -1101,6 +1101,36 @@ declare function storageQuotaExceededError(service: string, message: string, met
1101
1101
  * Create a service error for storage limit reached (413 Payload Too Large).
1102
1102
  */
1103
1103
  declare function storageLimitReachedError(service: string, message: string, meta?: Record<string, unknown>): ServiceError;
1104
+ /** Shown when a write is rejected because the owner's storage is full. */
1105
+ declare const STORAGE_FULL_MESSAGE = "TinyCloud storage is full, so this change was not saved. Reading still works. Free up space or upgrade your plan to save again.";
1106
+ /** Shown when a write is larger than the storage the owner has left. */
1107
+ declare const STORAGE_WRITE_TOO_LARGE_MESSAGE = "This change is larger than the TinyCloud storage you have left, so it was not saved. Reading still works. Free up space or upgrade your plan to save it.";
1108
+ /**
1109
+ * Parse the byte counts from a node storage rejection
1110
+ * ("... Used: 155744 bytes, Limit: 0 bytes"). The limit is the share of the
1111
+ * owner's account-wide budget left for this space, so it is 0 when the
1112
+ * owner's other spaces already use the whole budget.
1113
+ */
1114
+ declare function parseStorageQuotaBytes(responseText: string): {
1115
+ usedBytes: number;
1116
+ limitBytes: number;
1117
+ } | undefined;
1118
+ /**
1119
+ * Build the error for a write the node rejected for storage: 402 when storage
1120
+ * is already full, 413 when this write is larger than what is left. KV, SQL
1121
+ * and DuckDB all report it with the same codes and message so an app can
1122
+ * detect "storage full" in one place with {@link isStorageFullError}.
1123
+ */
1124
+ declare function storageRejectionError(service: string, status: 402 | 413, meta: Record<string, unknown>, responseText: string): ServiceError;
1125
+ /**
1126
+ * True when a write failed for storage: the owner's TinyCloud storage is full
1127
+ * (`STORAGE_QUOTA_EXCEEDED`), or this write is larger than what is left
1128
+ * (`STORAGE_LIMIT_REACHED`). Reads keep working in both cases, so apps should
1129
+ * stay usable read-only and point the user at freeing up space or upgrading.
1130
+ */
1131
+ declare function isStorageFullError(error: {
1132
+ code?: string;
1133
+ } | null | undefined): boolean;
1104
1134
  /**
1105
1135
  * Wrap an unknown error in a ServiceError.
1106
1136
  */
@@ -1719,6 +1749,10 @@ type VaultErrorInput = {
1719
1749
  code: "STORAGE_ERROR";
1720
1750
  cause: Error;
1721
1751
  message?: string;
1752
+ } | {
1753
+ code: "STORAGE_QUOTA_EXCEEDED" | "STORAGE_LIMIT_REACHED";
1754
+ message: string;
1755
+ meta?: Record<string, unknown>;
1722
1756
  };
1723
1757
  /**
1724
1758
  * Vault error with service field (compatible with ServiceError).
@@ -2263,4 +2297,4 @@ declare class SecretsService implements ISecretsService {
2263
2297
  listAll(): Promise<Result<SecretCatalogEntry[], SecretsError>>;
2264
2298
  }
2265
2299
 
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 };
2300
+ 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, STORAGE_FULL_MESSAGE, STORAGE_WRITE_TOO_LARGE_MESSAGE, 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, isStorageFullError, networkError, notFoundError, parseAuthError, parsePermissionHint, parsePermissionHintFromErrorText, parseSecretCatalogKey, parseStorageQuotaBytes, permissionDeniedError, resolveSecretListPrefix, resolveSecretPath, storageLimitReachedError, storageQuotaExceededError, storageRejectionError, timeoutError, tinyCloudDebugLogger, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, validateTelemetrySpanEvent, wrapError };
package/dist/index.js CHANGED
@@ -1040,6 +1040,23 @@ function storageLimitReachedError(service, message, meta) {
1040
1040
  meta
1041
1041
  };
1042
1042
  }
1043
+ var STORAGE_FULL_MESSAGE = "TinyCloud storage is full, so this change was not saved. Reading still works. Free up space or upgrade your plan to save again.";
1044
+ var STORAGE_WRITE_TOO_LARGE_MESSAGE = "This change is larger than the TinyCloud storage you have left, so it was not saved. Reading still works. Free up space or upgrade your plan to save it.";
1045
+ function parseStorageQuotaBytes(responseText) {
1046
+ const match = responseText.match(/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i);
1047
+ if (!match) return void 0;
1048
+ return {
1049
+ usedBytes: parseInt(match[1], 10),
1050
+ limitBytes: parseInt(match[2], 10)
1051
+ };
1052
+ }
1053
+ function storageRejectionError(service, status, meta, responseText) {
1054
+ const quotaMeta = { ...meta, ...parseStorageQuotaBytes(responseText) };
1055
+ return status === 402 ? storageQuotaExceededError(service, STORAGE_FULL_MESSAGE, quotaMeta) : storageLimitReachedError(service, STORAGE_WRITE_TOO_LARGE_MESSAGE, quotaMeta);
1056
+ }
1057
+ function isStorageFullError(error) {
1058
+ return error?.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error?.code === ErrorCodes.STORAGE_LIMIT_REACHED;
1059
+ }
1043
1060
  function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
1044
1061
  if (error instanceof Error) {
1045
1062
  if (error.name === "AbortError") {
@@ -1433,47 +1450,21 @@ var KVService = class extends BaseService {
1433
1450
  get config() {
1434
1451
  return this._config;
1435
1452
  }
1436
- // Parses "Used: X bytes, Limit: Y bytes" from tinycloud-node error responses
1437
- parseQuotaInfo(errorText) {
1438
- const match = errorText.match(
1439
- /Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i
1440
- );
1441
- if (match) {
1442
- return {
1443
- usedBytes: parseInt(match[1], 10),
1444
- limitBytes: parseInt(match[2], 10)
1445
- };
1446
- }
1447
- return void 0;
1448
- }
1449
1453
  handleQuotaErrorResponse(response, errorText, key) {
1450
- if (response.status === 402) {
1451
- const quotaInfo = this.parseQuotaInfo(errorText);
1452
- return err(
1453
- storageQuotaExceededError(
1454
- "kv",
1455
- `Storage quota exceeded for key ${JSON.stringify(key)}: ${errorText}`,
1456
- {
1457
- status: response.status,
1458
- ...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
1459
- }
1460
- )
1461
- );
1454
+ if (response.status !== 402 && response.status !== 413) {
1455
+ return void 0;
1462
1456
  }
1463
- if (response.status === 413) {
1464
- const quotaInfo = this.parseQuotaInfo(errorText);
1465
- return err(
1466
- storageLimitReachedError(
1467
- "kv",
1468
- `Storage limit reached for key ${JSON.stringify(key)}: ${errorText}`,
1469
- {
1470
- status: response.status,
1471
- ...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
1472
- }
1473
- )
1474
- );
1457
+ if (response.status === 413 && !parseStorageQuotaBytes(errorText)) {
1458
+ return void 0;
1475
1459
  }
1476
- return void 0;
1460
+ return err(
1461
+ storageRejectionError(
1462
+ "kv",
1463
+ response.status,
1464
+ { status: response.status, statusText: response.statusText, key },
1465
+ errorText
1466
+ )
1467
+ );
1477
1468
  }
1478
1469
  /**
1479
1470
  * Classify a KV 404 by reading the response body once.
@@ -2810,21 +2801,24 @@ var SQLService = class extends BaseService {
2810
2801
  }
2811
2802
  async applyMigrationsOnDbUnlocked(dbName, options) {
2812
2803
  return this.withTelemetry("migrations.apply", dbName, async () => {
2813
- const created = await this.ensureMigrationsTable(dbName, options.signal);
2814
- if (!created.ok) return created;
2815
2804
  const listed = await this.queryOnDb(
2816
2805
  dbName,
2817
2806
  `SELECT id FROM ${MIGRATIONS_TABLE} WHERE namespace = ? ORDER BY applied_at, id`,
2818
2807
  [options.namespace],
2819
2808
  { signal: options.signal }
2820
2809
  );
2821
- if (!listed.ok) return listed;
2810
+ const tableMissing = !listed.ok && (listed.error.code === ErrorCodes.SQL_DATABASE_NOT_FOUND || isMissingTableError(listed.error.message));
2811
+ if (!listed.ok && !tableMissing) return listed;
2822
2812
  const appliedIds = new Set(
2823
- listed.data.rows.map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
2813
+ (listed.ok ? listed.data.rows : []).map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
2824
2814
  );
2825
2815
  const skipped = options.migrations.filter((migration) => appliedIds.has(migration.id)).map((migration) => migration.id);
2826
2816
  const pending = options.migrations.filter((migration) => !appliedIds.has(migration.id));
2827
2817
  const applied = [];
2818
+ if (pending.length > 0 && tableMissing) {
2819
+ const created = await this.ensureMigrationsTable(dbName, options.signal);
2820
+ if (!created.ok) return created;
2821
+ }
2828
2822
  for (const migration of pending) {
2829
2823
  const result = await this.applyOneMigration(dbName, options.namespace, migration, options.signal);
2830
2824
  if (!result.ok) return result;
@@ -2927,6 +2921,10 @@ var SQLService = class extends BaseService {
2927
2921
  }
2928
2922
  async handleErrorResponse(response, operation) {
2929
2923
  const errorText = await response.text();
2924
+ const meta = responseErrorMeta(response.status, response.statusText, errorText);
2925
+ if (response.status === 402) {
2926
+ return err(storageRejectionError("sql", 402, meta, errorText));
2927
+ }
2930
2928
  const errorBody = parseServiceErrorBody(errorText);
2931
2929
  const errorCode = this.mapHttpStatusToErrorCode(
2932
2930
  response.status,
@@ -2939,7 +2937,6 @@ var SQLService = class extends BaseService {
2939
2937
  errorText,
2940
2938
  errorBody
2941
2939
  );
2942
- const meta = responseErrorMeta(response.status, response.statusText, errorText);
2943
2940
  if (response.status === 401) {
2944
2941
  const { resource, action } = parseAuthError(errorText);
2945
2942
  if (action) meta.requiredAction = action;
@@ -3040,6 +3037,9 @@ function serializeSqlValues(values) {
3040
3037
  (value) => value instanceof Uint8Array ? Array.from(value) : value
3041
3038
  );
3042
3039
  }
3040
+ function isMissingTableError(message) {
3041
+ return /no such table/i.test(message);
3042
+ }
3043
3043
  function migrationKey(namespace, id) {
3044
3044
  return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
3045
3045
  }
@@ -3361,6 +3361,10 @@ var DuckDbService = class extends BaseService {
3361
3361
  }
3362
3362
  async handleErrorResponse(response, operation) {
3363
3363
  const errorText = await response.text();
3364
+ const meta = responseErrorMeta(response.status, response.statusText, errorText);
3365
+ if (response.status === 402) {
3366
+ return err(storageRejectionError("duckdb", 402, meta, errorText));
3367
+ }
3364
3368
  const errorBody = parseServiceErrorBody(errorText);
3365
3369
  const errorCode = this.mapHttpStatusToErrorCode(
3366
3370
  response.status,
@@ -3373,7 +3377,6 @@ var DuckDbService = class extends BaseService {
3373
3377
  errorText,
3374
3378
  errorBody
3375
3379
  );
3376
- const meta = responseErrorMeta(response.status, response.statusText, errorText);
3377
3380
  if (response.status === 401) {
3378
3381
  const { resource, action } = parseAuthError(errorText);
3379
3382
  if (action) meta.requiredAction = action;
@@ -4345,6 +4348,9 @@ function defaultVaultMessage(input) {
4345
4348
  return input.message ?? `Public key not found for ${input.did}`;
4346
4349
  case "STORAGE_ERROR":
4347
4350
  return input.message ?? input.cause.message;
4351
+ case "STORAGE_QUOTA_EXCEEDED":
4352
+ case "STORAGE_LIMIT_REACHED":
4353
+ return input.message;
4348
4354
  }
4349
4355
  }
4350
4356
  function vaultError(input) {
@@ -4355,6 +4361,15 @@ function vaultError(input) {
4355
4361
  };
4356
4362
  return { ok: false, error };
4357
4363
  }
4364
+ function kvWriteError(context, error) {
4365
+ if (error.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error.code === ErrorCodes.STORAGE_LIMIT_REACHED) {
4366
+ return vaultError({ code: error.code, message: error.message, meta: error.meta });
4367
+ }
4368
+ return vaultError({
4369
+ code: "STORAGE_ERROR",
4370
+ cause: new Error(`${context}: ${error.message}`)
4371
+ });
4372
+ }
4358
4373
  var DataVaultService = class extends BaseService {
4359
4374
  /**
4360
4375
  * Create a new DataVaultService instance.
@@ -4637,12 +4652,7 @@ var DataVaultService = class extends BaseService {
4637
4652
  JSON.stringify(envelopeResult.data)
4638
4653
  );
4639
4654
  if (!valuePutResult.ok) {
4640
- return vaultError({
4641
- code: "STORAGE_ERROR",
4642
- cause: new Error(
4643
- `Failed to store encrypted value: ${valuePutResult.error.message}`
4644
- )
4645
- });
4655
+ return kvWriteError("Failed to store encrypted value", valuePutResult.error);
4646
4656
  }
4647
4657
  return { ok: true, data: void 0 };
4648
4658
  } catch (error) {
@@ -4860,12 +4870,7 @@ var DataVaultService = class extends BaseService {
4860
4870
  keyPayload
4861
4871
  );
4862
4872
  if (!keyPutResult.ok) {
4863
- return vaultError({
4864
- code: "STORAGE_ERROR",
4865
- cause: new Error(
4866
- `Failed to store key blob: ${keyPutResult.error.message}`
4867
- )
4868
- });
4873
+ return kvWriteError("Failed to store key blob", keyPutResult.error);
4869
4874
  }
4870
4875
  const valuePayload = JSON.stringify({
4871
4876
  data: base64Encode(encrypted),
@@ -4876,12 +4881,7 @@ var DataVaultService = class extends BaseService {
4876
4881
  valuePayload
4877
4882
  );
4878
4883
  if (!valuePutResult.ok) {
4879
- return vaultError({
4880
- code: "STORAGE_ERROR",
4881
- cause: new Error(
4882
- `Failed to store encrypted value: ${valuePutResult.error.message}`
4883
- )
4884
- });
4884
+ return kvWriteError("Failed to store encrypted value", valuePutResult.error);
4885
4885
  }
4886
4886
  return ok(void 0);
4887
4887
  } catch (error) {
@@ -5212,12 +5212,7 @@ var DataVaultService = class extends BaseService {
5212
5212
  grantPayload
5213
5213
  );
5214
5214
  if (!grantPutResult.ok) {
5215
- return vaultError({
5216
- code: "STORAGE_ERROR",
5217
- cause: new Error(
5218
- `Failed to store grant: ${grantPutResult.error.message}`
5219
- )
5220
- });
5215
+ return kvWriteError("Failed to store grant", grantPutResult.error);
5221
5216
  }
5222
5217
  return ok(void 0);
5223
5218
  } catch (error) {
@@ -5562,12 +5557,7 @@ var DataVaultService = class extends BaseService {
5562
5557
  keyPayload
5563
5558
  );
5564
5559
  if (!keyPutResult.ok) {
5565
- return vaultError({
5566
- code: "STORAGE_ERROR",
5567
- cause: new Error(
5568
- `Failed to store rotated key blob: ${keyPutResult.error.message}`
5569
- )
5570
- });
5560
+ return kvWriteError("Failed to store rotated key blob", keyPutResult.error);
5571
5561
  }
5572
5562
  const valuePayload = JSON.stringify({
5573
5563
  data: base64Encode(encrypted),
@@ -5578,12 +5568,7 @@ var DataVaultService = class extends BaseService {
5578
5568
  valuePayload
5579
5569
  );
5580
5570
  if (!valuePutResult.ok) {
5581
- return vaultError({
5582
- code: "STORAGE_ERROR",
5583
- cause: new Error(
5584
- `Failed to store re-encrypted value: ${valuePutResult.error.message}`
5585
- )
5586
- });
5571
+ return kvWriteError("Failed to store re-encrypted value", valuePutResult.error);
5587
5572
  }
5588
5573
  for (const did of remainingGrantees) {
5589
5574
  const grantResult = await this.reencrypt(key, did);
@@ -6912,6 +6897,8 @@ export {
6912
6897
  SQLAction,
6913
6898
  SQLMigrations,
6914
6899
  SQLService,
6900
+ STORAGE_FULL_MESSAGE,
6901
+ STORAGE_WRITE_TOO_LARGE_MESSAGE,
6915
6902
  SecretsService,
6916
6903
  ServiceContext,
6917
6904
  ServiceErrorEventSchema,
@@ -6964,6 +6951,7 @@ export {
6964
6951
  hexEncode2 as hexEncode,
6965
6952
  installTinyCloudDebugGlobals,
6966
6953
  isNetworkId,
6954
+ isStorageFullError,
6967
6955
  networkDiscoveryKey,
6968
6956
  networkError,
6969
6957
  notFoundError,
@@ -6974,12 +6962,14 @@ export {
6974
6962
  parsePermissionHint,
6975
6963
  parsePermissionHintFromErrorText,
6976
6964
  parseSecretCatalogKey,
6965
+ parseStorageQuotaBytes,
6977
6966
  permissionDeniedError,
6978
6967
  resolveSecretListPrefix,
6979
6968
  resolveSecretPath,
6980
6969
  serviceError,
6981
6970
  storageLimitReachedError,
6982
6971
  storageQuotaExceededError,
6972
+ storageRejectionError,
6983
6973
  timeoutError,
6984
6974
  tinyCloudDebugLogger,
6985
6975
  utf8Decode,