@tinycloud/cli 1.0.1-beta.2 → 1.0.1-beta.4

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.
@@ -6888,6 +6888,20 @@ function storageLimitReachedError(service, message, meta) {
6888
6888
  meta
6889
6889
  };
6890
6890
  }
6891
+ 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.";
6892
+ 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.";
6893
+ function parseStorageQuotaBytes(responseText) {
6894
+ const match = responseText.match(/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i);
6895
+ if (!match) return void 0;
6896
+ return {
6897
+ usedBytes: parseInt(match[1], 10),
6898
+ limitBytes: parseInt(match[2], 10)
6899
+ };
6900
+ }
6901
+ function storageRejectionError(service, status, meta, responseText) {
6902
+ const quotaMeta = { ...meta, ...parseStorageQuotaBytes(responseText) };
6903
+ return status === 402 ? storageQuotaExceededError(service, STORAGE_FULL_MESSAGE, quotaMeta) : storageLimitReachedError(service, STORAGE_WRITE_TOO_LARGE_MESSAGE, quotaMeta);
6904
+ }
6891
6905
  function wrapError2(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
6892
6906
  if (error instanceof Error) {
6893
6907
  if (error.name === "AbortError") {
@@ -7263,47 +7277,21 @@ var KVService = class extends BaseService {
7263
7277
  get config() {
7264
7278
  return this._config;
7265
7279
  }
7266
- // Parses "Used: X bytes, Limit: Y bytes" from tinycloud-node error responses
7267
- parseQuotaInfo(errorText) {
7268
- const match = errorText.match(
7269
- /Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i
7270
- );
7271
- if (match) {
7272
- return {
7273
- usedBytes: parseInt(match[1], 10),
7274
- limitBytes: parseInt(match[2], 10)
7275
- };
7276
- }
7277
- return void 0;
7278
- }
7279
7280
  handleQuotaErrorResponse(response, errorText, key) {
7280
- if (response.status === 402) {
7281
- const quotaInfo = this.parseQuotaInfo(errorText);
7282
- return err(
7283
- storageQuotaExceededError(
7284
- "kv",
7285
- `Storage quota exceeded for key ${JSON.stringify(key)}: ${errorText}`,
7286
- {
7287
- status: response.status,
7288
- ...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
7289
- }
7290
- )
7291
- );
7281
+ if (response.status !== 402 && response.status !== 413) {
7282
+ return void 0;
7292
7283
  }
7293
- if (response.status === 413) {
7294
- const quotaInfo = this.parseQuotaInfo(errorText);
7295
- return err(
7296
- storageLimitReachedError(
7297
- "kv",
7298
- `Storage limit reached for key ${JSON.stringify(key)}: ${errorText}`,
7299
- {
7300
- status: response.status,
7301
- ...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
7302
- }
7303
- )
7304
- );
7284
+ if (response.status === 413 && !parseStorageQuotaBytes(errorText)) {
7285
+ return void 0;
7305
7286
  }
7306
- return void 0;
7287
+ return err(
7288
+ storageRejectionError(
7289
+ "kv",
7290
+ response.status,
7291
+ { status: response.status, statusText: response.statusText, key },
7292
+ errorText
7293
+ )
7294
+ );
7307
7295
  }
7308
7296
  /**
7309
7297
  * Classify a KV 404 by reading the response body once.
@@ -8626,21 +8614,24 @@ var SQLService = class extends BaseService {
8626
8614
  }
8627
8615
  async applyMigrationsOnDbUnlocked(dbName, options) {
8628
8616
  return this.withTelemetry("migrations.apply", dbName, async () => {
8629
- const created = await this.ensureMigrationsTable(dbName, options.signal);
8630
- if (!created.ok) return created;
8631
8617
  const listed = await this.queryOnDb(
8632
8618
  dbName,
8633
8619
  `SELECT id FROM ${MIGRATIONS_TABLE} WHERE namespace = ? ORDER BY applied_at, id`,
8634
8620
  [options.namespace],
8635
8621
  { signal: options.signal }
8636
8622
  );
8637
- if (!listed.ok) return listed;
8623
+ const tableMissing = !listed.ok && (listed.error.code === ErrorCodes.SQL_DATABASE_NOT_FOUND || isMissingTableError(listed.error.message));
8624
+ if (!listed.ok && !tableMissing) return listed;
8638
8625
  const appliedIds = new Set(
8639
- listed.data.rows.map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
8626
+ (listed.ok ? listed.data.rows : []).map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
8640
8627
  );
8641
8628
  const skipped = options.migrations.filter((migration) => appliedIds.has(migration.id)).map((migration) => migration.id);
8642
8629
  const pending = options.migrations.filter((migration) => !appliedIds.has(migration.id));
8643
8630
  const applied = [];
8631
+ if (pending.length > 0 && tableMissing) {
8632
+ const created = await this.ensureMigrationsTable(dbName, options.signal);
8633
+ if (!created.ok) return created;
8634
+ }
8644
8635
  for (const migration of pending) {
8645
8636
  const result = await this.applyOneMigration(dbName, options.namespace, migration, options.signal);
8646
8637
  if (!result.ok) return result;
@@ -8743,6 +8734,10 @@ var SQLService = class extends BaseService {
8743
8734
  }
8744
8735
  async handleErrorResponse(response, operation) {
8745
8736
  const errorText = await response.text();
8737
+ const meta = responseErrorMeta(response.status, response.statusText, errorText);
8738
+ if (response.status === 402) {
8739
+ return err(storageRejectionError("sql", 402, meta, errorText));
8740
+ }
8746
8741
  const errorBody = parseServiceErrorBody(errorText);
8747
8742
  const errorCode2 = this.mapHttpStatusToErrorCode(
8748
8743
  response.status,
@@ -8755,7 +8750,6 @@ var SQLService = class extends BaseService {
8755
8750
  errorText,
8756
8751
  errorBody
8757
8752
  );
8758
- const meta = responseErrorMeta(response.status, response.statusText, errorText);
8759
8753
  if (response.status === 401) {
8760
8754
  const { resource, action } = parseAuthError(errorText);
8761
8755
  if (action) meta.requiredAction = action;
@@ -8856,6 +8850,9 @@ function serializeSqlValues(values) {
8856
8850
  (value) => value instanceof Uint8Array ? Array.from(value) : value
8857
8851
  );
8858
8852
  }
8853
+ function isMissingTableError(message) {
8854
+ return /no such table/i.test(message);
8855
+ }
8859
8856
  function migrationKey(namespace, id) {
8860
8857
  return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
8861
8858
  }
@@ -9170,6 +9167,10 @@ var DuckDbService = class extends BaseService {
9170
9167
  }
9171
9168
  async handleErrorResponse(response, operation) {
9172
9169
  const errorText = await response.text();
9170
+ const meta = responseErrorMeta(response.status, response.statusText, errorText);
9171
+ if (response.status === 402) {
9172
+ return err(storageRejectionError("duckdb", 402, meta, errorText));
9173
+ }
9173
9174
  const errorBody = parseServiceErrorBody(errorText);
9174
9175
  const errorCode2 = this.mapHttpStatusToErrorCode(
9175
9176
  response.status,
@@ -9182,7 +9183,6 @@ var DuckDbService = class extends BaseService {
9182
9183
  errorText,
9183
9184
  errorBody
9184
9185
  );
9185
- const meta = responseErrorMeta(response.status, response.statusText, errorText);
9186
9186
  if (response.status === 401) {
9187
9187
  const { resource, action } = parseAuthError(errorText);
9188
9188
  if (action) meta.requiredAction = action;
@@ -10109,6 +10109,9 @@ function defaultVaultMessage(input) {
10109
10109
  return input.message ?? `Public key not found for ${input.did}`;
10110
10110
  case "STORAGE_ERROR":
10111
10111
  return input.message ?? input.cause.message;
10112
+ case "STORAGE_QUOTA_EXCEEDED":
10113
+ case "STORAGE_LIMIT_REACHED":
10114
+ return input.message;
10112
10115
  }
10113
10116
  }
10114
10117
  function vaultError(input) {
@@ -10119,6 +10122,15 @@ function vaultError(input) {
10119
10122
  };
10120
10123
  return { ok: false, error };
10121
10124
  }
10125
+ function kvWriteError(context, error) {
10126
+ if (error.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error.code === ErrorCodes.STORAGE_LIMIT_REACHED) {
10127
+ return vaultError({ code: error.code, message: error.message, meta: error.meta });
10128
+ }
10129
+ return vaultError({
10130
+ code: "STORAGE_ERROR",
10131
+ cause: new Error(`${context}: ${error.message}`)
10132
+ });
10133
+ }
10122
10134
  var DataVaultService = class extends BaseService {
10123
10135
  /**
10124
10136
  * Create a new DataVaultService instance.
@@ -10401,12 +10413,7 @@ var DataVaultService = class extends BaseService {
10401
10413
  JSON.stringify(envelopeResult.data)
10402
10414
  );
10403
10415
  if (!valuePutResult.ok) {
10404
- return vaultError({
10405
- code: "STORAGE_ERROR",
10406
- cause: new Error(
10407
- `Failed to store encrypted value: ${valuePutResult.error.message}`
10408
- )
10409
- });
10416
+ return kvWriteError("Failed to store encrypted value", valuePutResult.error);
10410
10417
  }
10411
10418
  return { ok: true, data: void 0 };
10412
10419
  } catch (error) {
@@ -10624,12 +10631,7 @@ var DataVaultService = class extends BaseService {
10624
10631
  keyPayload
10625
10632
  );
10626
10633
  if (!keyPutResult.ok) {
10627
- return vaultError({
10628
- code: "STORAGE_ERROR",
10629
- cause: new Error(
10630
- `Failed to store key blob: ${keyPutResult.error.message}`
10631
- )
10632
- });
10634
+ return kvWriteError("Failed to store key blob", keyPutResult.error);
10633
10635
  }
10634
10636
  const valuePayload = JSON.stringify({
10635
10637
  data: base64Encode(encrypted),
@@ -10640,12 +10642,7 @@ var DataVaultService = class extends BaseService {
10640
10642
  valuePayload
10641
10643
  );
10642
10644
  if (!valuePutResult.ok) {
10643
- return vaultError({
10644
- code: "STORAGE_ERROR",
10645
- cause: new Error(
10646
- `Failed to store encrypted value: ${valuePutResult.error.message}`
10647
- )
10648
- });
10645
+ return kvWriteError("Failed to store encrypted value", valuePutResult.error);
10649
10646
  }
10650
10647
  return ok(void 0);
10651
10648
  } catch (error) {
@@ -10976,12 +10973,7 @@ var DataVaultService = class extends BaseService {
10976
10973
  grantPayload
10977
10974
  );
10978
10975
  if (!grantPutResult.ok) {
10979
- return vaultError({
10980
- code: "STORAGE_ERROR",
10981
- cause: new Error(
10982
- `Failed to store grant: ${grantPutResult.error.message}`
10983
- )
10984
- });
10976
+ return kvWriteError("Failed to store grant", grantPutResult.error);
10985
10977
  }
10986
10978
  return ok(void 0);
10987
10979
  } catch (error) {
@@ -11326,12 +11318,7 @@ var DataVaultService = class extends BaseService {
11326
11318
  keyPayload
11327
11319
  );
11328
11320
  if (!keyPutResult.ok) {
11329
- return vaultError({
11330
- code: "STORAGE_ERROR",
11331
- cause: new Error(
11332
- `Failed to store rotated key blob: ${keyPutResult.error.message}`
11333
- )
11334
- });
11321
+ return kvWriteError("Failed to store rotated key blob", keyPutResult.error);
11335
11322
  }
11336
11323
  const valuePayload = JSON.stringify({
11337
11324
  data: base64Encode(encrypted),
@@ -11342,12 +11329,7 @@ var DataVaultService = class extends BaseService {
11342
11329
  valuePayload
11343
11330
  );
11344
11331
  if (!valuePutResult.ok) {
11345
- return vaultError({
11346
- code: "STORAGE_ERROR",
11347
- cause: new Error(
11348
- `Failed to store re-encrypted value: ${valuePutResult.error.message}`
11349
- )
11350
- });
11332
+ return kvWriteError("Failed to store re-encrypted value", valuePutResult.error);
11351
11333
  }
11352
11334
  for (const did of remainingGrantees) {
11353
11335
  const grantResult = await this.reencrypt(key, did);