@tinycloud/operations 0.3.4-beta.2 → 0.3.4-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.
- package/dist/artifacts.cjs +62 -80
- package/dist/artifacts.cjs.map +1 -1
- package/dist/artifacts.d.cts +30 -30
- package/dist/artifacts.d.ts +30 -30
- package/dist/artifacts.js +62 -80
- package/dist/artifacts.js.map +1 -1
- package/dist/cli-runtime.cjs +65 -83
- package/dist/cli-runtime.cjs.map +1 -1
- package/dist/cli-runtime.js +65 -83
- package/dist/cli-runtime.js.map +1 -1
- package/dist/index.cjs +65 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +65 -83
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/artifacts.cjs
CHANGED
|
@@ -1266,6 +1266,20 @@ function storageLimitReachedError(service, message, meta) {
|
|
|
1266
1266
|
meta
|
|
1267
1267
|
};
|
|
1268
1268
|
}
|
|
1269
|
+
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.";
|
|
1270
|
+
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.";
|
|
1271
|
+
function parseStorageQuotaBytes(responseText) {
|
|
1272
|
+
const match = responseText.match(/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i);
|
|
1273
|
+
if (!match) return void 0;
|
|
1274
|
+
return {
|
|
1275
|
+
usedBytes: parseInt(match[1], 10),
|
|
1276
|
+
limitBytes: parseInt(match[2], 10)
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
function storageRejectionError(service, status, meta, responseText) {
|
|
1280
|
+
const quotaMeta = { ...meta, ...parseStorageQuotaBytes(responseText) };
|
|
1281
|
+
return status === 402 ? storageQuotaExceededError(service, STORAGE_FULL_MESSAGE, quotaMeta) : storageLimitReachedError(service, STORAGE_WRITE_TOO_LARGE_MESSAGE, quotaMeta);
|
|
1282
|
+
}
|
|
1269
1283
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
1270
1284
|
if (error instanceof Error) {
|
|
1271
1285
|
if (error.name === "AbortError") {
|
|
@@ -1641,47 +1655,21 @@ var KVService = class extends BaseService {
|
|
|
1641
1655
|
get config() {
|
|
1642
1656
|
return this._config;
|
|
1643
1657
|
}
|
|
1644
|
-
// Parses "Used: X bytes, Limit: Y bytes" from tinycloud-node error responses
|
|
1645
|
-
parseQuotaInfo(errorText) {
|
|
1646
|
-
const match = errorText.match(
|
|
1647
|
-
/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i
|
|
1648
|
-
);
|
|
1649
|
-
if (match) {
|
|
1650
|
-
return {
|
|
1651
|
-
usedBytes: parseInt(match[1], 10),
|
|
1652
|
-
limitBytes: parseInt(match[2], 10)
|
|
1653
|
-
};
|
|
1654
|
-
}
|
|
1655
|
-
return void 0;
|
|
1656
|
-
}
|
|
1657
1658
|
handleQuotaErrorResponse(response, errorText, key) {
|
|
1658
|
-
if (response.status
|
|
1659
|
-
|
|
1660
|
-
return err(
|
|
1661
|
-
storageQuotaExceededError(
|
|
1662
|
-
"kv",
|
|
1663
|
-
`Storage quota exceeded for key ${JSON.stringify(key)}: ${errorText}`,
|
|
1664
|
-
{
|
|
1665
|
-
status: response.status,
|
|
1666
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
1667
|
-
}
|
|
1668
|
-
)
|
|
1669
|
-
);
|
|
1659
|
+
if (response.status !== 402 && response.status !== 413) {
|
|
1660
|
+
return void 0;
|
|
1670
1661
|
}
|
|
1671
|
-
if (response.status === 413) {
|
|
1672
|
-
|
|
1673
|
-
return err(
|
|
1674
|
-
storageLimitReachedError(
|
|
1675
|
-
"kv",
|
|
1676
|
-
`Storage limit reached for key ${JSON.stringify(key)}: ${errorText}`,
|
|
1677
|
-
{
|
|
1678
|
-
status: response.status,
|
|
1679
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
1680
|
-
}
|
|
1681
|
-
)
|
|
1682
|
-
);
|
|
1662
|
+
if (response.status === 413 && !parseStorageQuotaBytes(errorText)) {
|
|
1663
|
+
return void 0;
|
|
1683
1664
|
}
|
|
1684
|
-
return
|
|
1665
|
+
return err(
|
|
1666
|
+
storageRejectionError(
|
|
1667
|
+
"kv",
|
|
1668
|
+
response.status,
|
|
1669
|
+
{ status: response.status, statusText: response.statusText, key },
|
|
1670
|
+
errorText
|
|
1671
|
+
)
|
|
1672
|
+
);
|
|
1685
1673
|
}
|
|
1686
1674
|
/**
|
|
1687
1675
|
* Classify a KV 404 by reading the response body once.
|
|
@@ -3004,21 +2992,24 @@ var SQLService = class extends BaseService {
|
|
|
3004
2992
|
}
|
|
3005
2993
|
async applyMigrationsOnDbUnlocked(dbName, options) {
|
|
3006
2994
|
return this.withTelemetry("migrations.apply", dbName, async () => {
|
|
3007
|
-
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
3008
|
-
if (!created.ok) return created;
|
|
3009
2995
|
const listed = await this.queryOnDb(
|
|
3010
2996
|
dbName,
|
|
3011
2997
|
`SELECT id FROM ${MIGRATIONS_TABLE} WHERE namespace = ? ORDER BY applied_at, id`,
|
|
3012
2998
|
[options.namespace],
|
|
3013
2999
|
{ signal: options.signal }
|
|
3014
3000
|
);
|
|
3015
|
-
|
|
3001
|
+
const tableMissing = !listed.ok && (listed.error.code === ErrorCodes.SQL_DATABASE_NOT_FOUND || isMissingTableError(listed.error.message));
|
|
3002
|
+
if (!listed.ok && !tableMissing) return listed;
|
|
3016
3003
|
const appliedIds = new Set(
|
|
3017
|
-
listed.data.rows.map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
3004
|
+
(listed.ok ? listed.data.rows : []).map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
3018
3005
|
);
|
|
3019
3006
|
const skipped = options.migrations.filter((migration) => appliedIds.has(migration.id)).map((migration) => migration.id);
|
|
3020
3007
|
const pending = options.migrations.filter((migration) => !appliedIds.has(migration.id));
|
|
3021
3008
|
const applied = [];
|
|
3009
|
+
if (pending.length > 0 && tableMissing) {
|
|
3010
|
+
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
3011
|
+
if (!created.ok) return created;
|
|
3012
|
+
}
|
|
3022
3013
|
for (const migration of pending) {
|
|
3023
3014
|
const result = await this.applyOneMigration(dbName, options.namespace, migration, options.signal);
|
|
3024
3015
|
if (!result.ok) return result;
|
|
@@ -3121,6 +3112,10 @@ var SQLService = class extends BaseService {
|
|
|
3121
3112
|
}
|
|
3122
3113
|
async handleErrorResponse(response, operation) {
|
|
3123
3114
|
const errorText = await response.text();
|
|
3115
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3116
|
+
if (response.status === 402) {
|
|
3117
|
+
return err(storageRejectionError("sql", 402, meta, errorText));
|
|
3118
|
+
}
|
|
3124
3119
|
const errorBody = parseServiceErrorBody(errorText);
|
|
3125
3120
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
3126
3121
|
response.status,
|
|
@@ -3133,7 +3128,6 @@ var SQLService = class extends BaseService {
|
|
|
3133
3128
|
errorText,
|
|
3134
3129
|
errorBody
|
|
3135
3130
|
);
|
|
3136
|
-
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3137
3131
|
if (response.status === 401) {
|
|
3138
3132
|
const { resource, action } = parseAuthError(errorText);
|
|
3139
3133
|
if (action) meta.requiredAction = action;
|
|
@@ -3234,6 +3228,9 @@ function serializeSqlValues(values) {
|
|
|
3234
3228
|
(value) => value instanceof Uint8Array ? Array.from(value) : value
|
|
3235
3229
|
);
|
|
3236
3230
|
}
|
|
3231
|
+
function isMissingTableError(message) {
|
|
3232
|
+
return /no such table/i.test(message);
|
|
3233
|
+
}
|
|
3237
3234
|
function migrationKey(namespace, id) {
|
|
3238
3235
|
return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
|
|
3239
3236
|
}
|
|
@@ -3548,6 +3545,10 @@ var DuckDbService = class extends BaseService {
|
|
|
3548
3545
|
}
|
|
3549
3546
|
async handleErrorResponse(response, operation) {
|
|
3550
3547
|
const errorText = await response.text();
|
|
3548
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3549
|
+
if (response.status === 402) {
|
|
3550
|
+
return err(storageRejectionError("duckdb", 402, meta, errorText));
|
|
3551
|
+
}
|
|
3551
3552
|
const errorBody = parseServiceErrorBody(errorText);
|
|
3552
3553
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
3553
3554
|
response.status,
|
|
@@ -3560,7 +3561,6 @@ var DuckDbService = class extends BaseService {
|
|
|
3560
3561
|
errorText,
|
|
3561
3562
|
errorBody
|
|
3562
3563
|
);
|
|
3563
|
-
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3564
3564
|
if (response.status === 401) {
|
|
3565
3565
|
const { resource, action } = parseAuthError(errorText);
|
|
3566
3566
|
if (action) meta.requiredAction = action;
|
|
@@ -4487,6 +4487,9 @@ function defaultVaultMessage(input) {
|
|
|
4487
4487
|
return input.message ?? `Public key not found for ${input.did}`;
|
|
4488
4488
|
case "STORAGE_ERROR":
|
|
4489
4489
|
return input.message ?? input.cause.message;
|
|
4490
|
+
case "STORAGE_QUOTA_EXCEEDED":
|
|
4491
|
+
case "STORAGE_LIMIT_REACHED":
|
|
4492
|
+
return input.message;
|
|
4490
4493
|
}
|
|
4491
4494
|
}
|
|
4492
4495
|
function vaultError(input) {
|
|
@@ -4497,6 +4500,15 @@ function vaultError(input) {
|
|
|
4497
4500
|
};
|
|
4498
4501
|
return { ok: false, error };
|
|
4499
4502
|
}
|
|
4503
|
+
function kvWriteError(context, error) {
|
|
4504
|
+
if (error.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error.code === ErrorCodes.STORAGE_LIMIT_REACHED) {
|
|
4505
|
+
return vaultError({ code: error.code, message: error.message, meta: error.meta });
|
|
4506
|
+
}
|
|
4507
|
+
return vaultError({
|
|
4508
|
+
code: "STORAGE_ERROR",
|
|
4509
|
+
cause: new Error(`${context}: ${error.message}`)
|
|
4510
|
+
});
|
|
4511
|
+
}
|
|
4500
4512
|
var DataVaultService = class extends BaseService {
|
|
4501
4513
|
/**
|
|
4502
4514
|
* Create a new DataVaultService instance.
|
|
@@ -4779,12 +4791,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4779
4791
|
JSON.stringify(envelopeResult.data)
|
|
4780
4792
|
);
|
|
4781
4793
|
if (!valuePutResult.ok) {
|
|
4782
|
-
return
|
|
4783
|
-
code: "STORAGE_ERROR",
|
|
4784
|
-
cause: new Error(
|
|
4785
|
-
`Failed to store encrypted value: ${valuePutResult.error.message}`
|
|
4786
|
-
)
|
|
4787
|
-
});
|
|
4794
|
+
return kvWriteError("Failed to store encrypted value", valuePutResult.error);
|
|
4788
4795
|
}
|
|
4789
4796
|
return { ok: true, data: void 0 };
|
|
4790
4797
|
} catch (error) {
|
|
@@ -5002,12 +5009,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5002
5009
|
keyPayload
|
|
5003
5010
|
);
|
|
5004
5011
|
if (!keyPutResult.ok) {
|
|
5005
|
-
return
|
|
5006
|
-
code: "STORAGE_ERROR",
|
|
5007
|
-
cause: new Error(
|
|
5008
|
-
`Failed to store key blob: ${keyPutResult.error.message}`
|
|
5009
|
-
)
|
|
5010
|
-
});
|
|
5012
|
+
return kvWriteError("Failed to store key blob", keyPutResult.error);
|
|
5011
5013
|
}
|
|
5012
5014
|
const valuePayload = JSON.stringify({
|
|
5013
5015
|
data: base64Encode(encrypted),
|
|
@@ -5018,12 +5020,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5018
5020
|
valuePayload
|
|
5019
5021
|
);
|
|
5020
5022
|
if (!valuePutResult.ok) {
|
|
5021
|
-
return
|
|
5022
|
-
code: "STORAGE_ERROR",
|
|
5023
|
-
cause: new Error(
|
|
5024
|
-
`Failed to store encrypted value: ${valuePutResult.error.message}`
|
|
5025
|
-
)
|
|
5026
|
-
});
|
|
5023
|
+
return kvWriteError("Failed to store encrypted value", valuePutResult.error);
|
|
5027
5024
|
}
|
|
5028
5025
|
return ok(void 0);
|
|
5029
5026
|
} catch (error) {
|
|
@@ -5354,12 +5351,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5354
5351
|
grantPayload
|
|
5355
5352
|
);
|
|
5356
5353
|
if (!grantPutResult.ok) {
|
|
5357
|
-
return
|
|
5358
|
-
code: "STORAGE_ERROR",
|
|
5359
|
-
cause: new Error(
|
|
5360
|
-
`Failed to store grant: ${grantPutResult.error.message}`
|
|
5361
|
-
)
|
|
5362
|
-
});
|
|
5354
|
+
return kvWriteError("Failed to store grant", grantPutResult.error);
|
|
5363
5355
|
}
|
|
5364
5356
|
return ok(void 0);
|
|
5365
5357
|
} catch (error) {
|
|
@@ -5704,12 +5696,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5704
5696
|
keyPayload
|
|
5705
5697
|
);
|
|
5706
5698
|
if (!keyPutResult.ok) {
|
|
5707
|
-
return
|
|
5708
|
-
code: "STORAGE_ERROR",
|
|
5709
|
-
cause: new Error(
|
|
5710
|
-
`Failed to store rotated key blob: ${keyPutResult.error.message}`
|
|
5711
|
-
)
|
|
5712
|
-
});
|
|
5699
|
+
return kvWriteError("Failed to store rotated key blob", keyPutResult.error);
|
|
5713
5700
|
}
|
|
5714
5701
|
const valuePayload = JSON.stringify({
|
|
5715
5702
|
data: base64Encode(encrypted),
|
|
@@ -5720,12 +5707,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5720
5707
|
valuePayload
|
|
5721
5708
|
);
|
|
5722
5709
|
if (!valuePutResult.ok) {
|
|
5723
|
-
return
|
|
5724
|
-
code: "STORAGE_ERROR",
|
|
5725
|
-
cause: new Error(
|
|
5726
|
-
`Failed to store re-encrypted value: ${valuePutResult.error.message}`
|
|
5727
|
-
)
|
|
5728
|
-
});
|
|
5710
|
+
return kvWriteError("Failed to store re-encrypted value", valuePutResult.error);
|
|
5729
5711
|
}
|
|
5730
5712
|
for (const did of remainingGrantees) {
|
|
5731
5713
|
const grantResult = await this.reencrypt(key, did);
|