@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.js
CHANGED
|
@@ -1242,6 +1242,20 @@ function storageLimitReachedError(service, message, meta) {
|
|
|
1242
1242
|
meta
|
|
1243
1243
|
};
|
|
1244
1244
|
}
|
|
1245
|
+
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.";
|
|
1246
|
+
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.";
|
|
1247
|
+
function parseStorageQuotaBytes(responseText) {
|
|
1248
|
+
const match = responseText.match(/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i);
|
|
1249
|
+
if (!match) return void 0;
|
|
1250
|
+
return {
|
|
1251
|
+
usedBytes: parseInt(match[1], 10),
|
|
1252
|
+
limitBytes: parseInt(match[2], 10)
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
function storageRejectionError(service, status, meta, responseText) {
|
|
1256
|
+
const quotaMeta = { ...meta, ...parseStorageQuotaBytes(responseText) };
|
|
1257
|
+
return status === 402 ? storageQuotaExceededError(service, STORAGE_FULL_MESSAGE, quotaMeta) : storageLimitReachedError(service, STORAGE_WRITE_TOO_LARGE_MESSAGE, quotaMeta);
|
|
1258
|
+
}
|
|
1245
1259
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
1246
1260
|
if (error instanceof Error) {
|
|
1247
1261
|
if (error.name === "AbortError") {
|
|
@@ -1617,47 +1631,21 @@ var KVService = class extends BaseService {
|
|
|
1617
1631
|
get config() {
|
|
1618
1632
|
return this._config;
|
|
1619
1633
|
}
|
|
1620
|
-
// Parses "Used: X bytes, Limit: Y bytes" from tinycloud-node error responses
|
|
1621
|
-
parseQuotaInfo(errorText) {
|
|
1622
|
-
const match = errorText.match(
|
|
1623
|
-
/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i
|
|
1624
|
-
);
|
|
1625
|
-
if (match) {
|
|
1626
|
-
return {
|
|
1627
|
-
usedBytes: parseInt(match[1], 10),
|
|
1628
|
-
limitBytes: parseInt(match[2], 10)
|
|
1629
|
-
};
|
|
1630
|
-
}
|
|
1631
|
-
return void 0;
|
|
1632
|
-
}
|
|
1633
1634
|
handleQuotaErrorResponse(response, errorText, key) {
|
|
1634
|
-
if (response.status
|
|
1635
|
-
|
|
1636
|
-
return err(
|
|
1637
|
-
storageQuotaExceededError(
|
|
1638
|
-
"kv",
|
|
1639
|
-
`Storage quota exceeded for key ${JSON.stringify(key)}: ${errorText}`,
|
|
1640
|
-
{
|
|
1641
|
-
status: response.status,
|
|
1642
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
1643
|
-
}
|
|
1644
|
-
)
|
|
1645
|
-
);
|
|
1635
|
+
if (response.status !== 402 && response.status !== 413) {
|
|
1636
|
+
return void 0;
|
|
1646
1637
|
}
|
|
1647
|
-
if (response.status === 413) {
|
|
1648
|
-
|
|
1649
|
-
return err(
|
|
1650
|
-
storageLimitReachedError(
|
|
1651
|
-
"kv",
|
|
1652
|
-
`Storage limit reached for key ${JSON.stringify(key)}: ${errorText}`,
|
|
1653
|
-
{
|
|
1654
|
-
status: response.status,
|
|
1655
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
1656
|
-
}
|
|
1657
|
-
)
|
|
1658
|
-
);
|
|
1638
|
+
if (response.status === 413 && !parseStorageQuotaBytes(errorText)) {
|
|
1639
|
+
return void 0;
|
|
1659
1640
|
}
|
|
1660
|
-
return
|
|
1641
|
+
return err(
|
|
1642
|
+
storageRejectionError(
|
|
1643
|
+
"kv",
|
|
1644
|
+
response.status,
|
|
1645
|
+
{ status: response.status, statusText: response.statusText, key },
|
|
1646
|
+
errorText
|
|
1647
|
+
)
|
|
1648
|
+
);
|
|
1661
1649
|
}
|
|
1662
1650
|
/**
|
|
1663
1651
|
* Classify a KV 404 by reading the response body once.
|
|
@@ -2980,21 +2968,24 @@ var SQLService = class extends BaseService {
|
|
|
2980
2968
|
}
|
|
2981
2969
|
async applyMigrationsOnDbUnlocked(dbName, options) {
|
|
2982
2970
|
return this.withTelemetry("migrations.apply", dbName, async () => {
|
|
2983
|
-
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
2984
|
-
if (!created.ok) return created;
|
|
2985
2971
|
const listed = await this.queryOnDb(
|
|
2986
2972
|
dbName,
|
|
2987
2973
|
`SELECT id FROM ${MIGRATIONS_TABLE} WHERE namespace = ? ORDER BY applied_at, id`,
|
|
2988
2974
|
[options.namespace],
|
|
2989
2975
|
{ signal: options.signal }
|
|
2990
2976
|
);
|
|
2991
|
-
|
|
2977
|
+
const tableMissing = !listed.ok && (listed.error.code === ErrorCodes.SQL_DATABASE_NOT_FOUND || isMissingTableError(listed.error.message));
|
|
2978
|
+
if (!listed.ok && !tableMissing) return listed;
|
|
2992
2979
|
const appliedIds = new Set(
|
|
2993
|
-
listed.data.rows.map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
2980
|
+
(listed.ok ? listed.data.rows : []).map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
2994
2981
|
);
|
|
2995
2982
|
const skipped = options.migrations.filter((migration) => appliedIds.has(migration.id)).map((migration) => migration.id);
|
|
2996
2983
|
const pending = options.migrations.filter((migration) => !appliedIds.has(migration.id));
|
|
2997
2984
|
const applied = [];
|
|
2985
|
+
if (pending.length > 0 && tableMissing) {
|
|
2986
|
+
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
2987
|
+
if (!created.ok) return created;
|
|
2988
|
+
}
|
|
2998
2989
|
for (const migration of pending) {
|
|
2999
2990
|
const result = await this.applyOneMigration(dbName, options.namespace, migration, options.signal);
|
|
3000
2991
|
if (!result.ok) return result;
|
|
@@ -3097,6 +3088,10 @@ var SQLService = class extends BaseService {
|
|
|
3097
3088
|
}
|
|
3098
3089
|
async handleErrorResponse(response, operation) {
|
|
3099
3090
|
const errorText = await response.text();
|
|
3091
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3092
|
+
if (response.status === 402) {
|
|
3093
|
+
return err(storageRejectionError("sql", 402, meta, errorText));
|
|
3094
|
+
}
|
|
3100
3095
|
const errorBody = parseServiceErrorBody(errorText);
|
|
3101
3096
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
3102
3097
|
response.status,
|
|
@@ -3109,7 +3104,6 @@ var SQLService = class extends BaseService {
|
|
|
3109
3104
|
errorText,
|
|
3110
3105
|
errorBody
|
|
3111
3106
|
);
|
|
3112
|
-
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3113
3107
|
if (response.status === 401) {
|
|
3114
3108
|
const { resource, action } = parseAuthError(errorText);
|
|
3115
3109
|
if (action) meta.requiredAction = action;
|
|
@@ -3210,6 +3204,9 @@ function serializeSqlValues(values) {
|
|
|
3210
3204
|
(value) => value instanceof Uint8Array ? Array.from(value) : value
|
|
3211
3205
|
);
|
|
3212
3206
|
}
|
|
3207
|
+
function isMissingTableError(message) {
|
|
3208
|
+
return /no such table/i.test(message);
|
|
3209
|
+
}
|
|
3213
3210
|
function migrationKey(namespace, id) {
|
|
3214
3211
|
return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
|
|
3215
3212
|
}
|
|
@@ -3524,6 +3521,10 @@ var DuckDbService = class extends BaseService {
|
|
|
3524
3521
|
}
|
|
3525
3522
|
async handleErrorResponse(response, operation) {
|
|
3526
3523
|
const errorText = await response.text();
|
|
3524
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3525
|
+
if (response.status === 402) {
|
|
3526
|
+
return err(storageRejectionError("duckdb", 402, meta, errorText));
|
|
3527
|
+
}
|
|
3527
3528
|
const errorBody = parseServiceErrorBody(errorText);
|
|
3528
3529
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
3529
3530
|
response.status,
|
|
@@ -3536,7 +3537,6 @@ var DuckDbService = class extends BaseService {
|
|
|
3536
3537
|
errorText,
|
|
3537
3538
|
errorBody
|
|
3538
3539
|
);
|
|
3539
|
-
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3540
3540
|
if (response.status === 401) {
|
|
3541
3541
|
const { resource, action } = parseAuthError(errorText);
|
|
3542
3542
|
if (action) meta.requiredAction = action;
|
|
@@ -4463,6 +4463,9 @@ function defaultVaultMessage(input) {
|
|
|
4463
4463
|
return input.message ?? `Public key not found for ${input.did}`;
|
|
4464
4464
|
case "STORAGE_ERROR":
|
|
4465
4465
|
return input.message ?? input.cause.message;
|
|
4466
|
+
case "STORAGE_QUOTA_EXCEEDED":
|
|
4467
|
+
case "STORAGE_LIMIT_REACHED":
|
|
4468
|
+
return input.message;
|
|
4466
4469
|
}
|
|
4467
4470
|
}
|
|
4468
4471
|
function vaultError(input) {
|
|
@@ -4473,6 +4476,15 @@ function vaultError(input) {
|
|
|
4473
4476
|
};
|
|
4474
4477
|
return { ok: false, error };
|
|
4475
4478
|
}
|
|
4479
|
+
function kvWriteError(context, error) {
|
|
4480
|
+
if (error.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error.code === ErrorCodes.STORAGE_LIMIT_REACHED) {
|
|
4481
|
+
return vaultError({ code: error.code, message: error.message, meta: error.meta });
|
|
4482
|
+
}
|
|
4483
|
+
return vaultError({
|
|
4484
|
+
code: "STORAGE_ERROR",
|
|
4485
|
+
cause: new Error(`${context}: ${error.message}`)
|
|
4486
|
+
});
|
|
4487
|
+
}
|
|
4476
4488
|
var DataVaultService = class extends BaseService {
|
|
4477
4489
|
/**
|
|
4478
4490
|
* Create a new DataVaultService instance.
|
|
@@ -4755,12 +4767,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4755
4767
|
JSON.stringify(envelopeResult.data)
|
|
4756
4768
|
);
|
|
4757
4769
|
if (!valuePutResult.ok) {
|
|
4758
|
-
return
|
|
4759
|
-
code: "STORAGE_ERROR",
|
|
4760
|
-
cause: new Error(
|
|
4761
|
-
`Failed to store encrypted value: ${valuePutResult.error.message}`
|
|
4762
|
-
)
|
|
4763
|
-
});
|
|
4770
|
+
return kvWriteError("Failed to store encrypted value", valuePutResult.error);
|
|
4764
4771
|
}
|
|
4765
4772
|
return { ok: true, data: void 0 };
|
|
4766
4773
|
} catch (error) {
|
|
@@ -4978,12 +4985,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4978
4985
|
keyPayload
|
|
4979
4986
|
);
|
|
4980
4987
|
if (!keyPutResult.ok) {
|
|
4981
|
-
return
|
|
4982
|
-
code: "STORAGE_ERROR",
|
|
4983
|
-
cause: new Error(
|
|
4984
|
-
`Failed to store key blob: ${keyPutResult.error.message}`
|
|
4985
|
-
)
|
|
4986
|
-
});
|
|
4988
|
+
return kvWriteError("Failed to store key blob", keyPutResult.error);
|
|
4987
4989
|
}
|
|
4988
4990
|
const valuePayload = JSON.stringify({
|
|
4989
4991
|
data: base64Encode(encrypted),
|
|
@@ -4994,12 +4996,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4994
4996
|
valuePayload
|
|
4995
4997
|
);
|
|
4996
4998
|
if (!valuePutResult.ok) {
|
|
4997
|
-
return
|
|
4998
|
-
code: "STORAGE_ERROR",
|
|
4999
|
-
cause: new Error(
|
|
5000
|
-
`Failed to store encrypted value: ${valuePutResult.error.message}`
|
|
5001
|
-
)
|
|
5002
|
-
});
|
|
4999
|
+
return kvWriteError("Failed to store encrypted value", valuePutResult.error);
|
|
5003
5000
|
}
|
|
5004
5001
|
return ok(void 0);
|
|
5005
5002
|
} catch (error) {
|
|
@@ -5330,12 +5327,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5330
5327
|
grantPayload
|
|
5331
5328
|
);
|
|
5332
5329
|
if (!grantPutResult.ok) {
|
|
5333
|
-
return
|
|
5334
|
-
code: "STORAGE_ERROR",
|
|
5335
|
-
cause: new Error(
|
|
5336
|
-
`Failed to store grant: ${grantPutResult.error.message}`
|
|
5337
|
-
)
|
|
5338
|
-
});
|
|
5330
|
+
return kvWriteError("Failed to store grant", grantPutResult.error);
|
|
5339
5331
|
}
|
|
5340
5332
|
return ok(void 0);
|
|
5341
5333
|
} catch (error) {
|
|
@@ -5680,12 +5672,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5680
5672
|
keyPayload
|
|
5681
5673
|
);
|
|
5682
5674
|
if (!keyPutResult.ok) {
|
|
5683
|
-
return
|
|
5684
|
-
code: "STORAGE_ERROR",
|
|
5685
|
-
cause: new Error(
|
|
5686
|
-
`Failed to store rotated key blob: ${keyPutResult.error.message}`
|
|
5687
|
-
)
|
|
5688
|
-
});
|
|
5675
|
+
return kvWriteError("Failed to store rotated key blob", keyPutResult.error);
|
|
5689
5676
|
}
|
|
5690
5677
|
const valuePayload = JSON.stringify({
|
|
5691
5678
|
data: base64Encode(encrypted),
|
|
@@ -5696,12 +5683,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5696
5683
|
valuePayload
|
|
5697
5684
|
);
|
|
5698
5685
|
if (!valuePutResult.ok) {
|
|
5699
|
-
return
|
|
5700
|
-
code: "STORAGE_ERROR",
|
|
5701
|
-
cause: new Error(
|
|
5702
|
-
`Failed to store re-encrypted value: ${valuePutResult.error.message}`
|
|
5703
|
-
)
|
|
5704
|
-
});
|
|
5686
|
+
return kvWriteError("Failed to store re-encrypted value", valuePutResult.error);
|
|
5705
5687
|
}
|
|
5706
5688
|
for (const did of remainingGrantees) {
|
|
5707
5689
|
const grantResult = await this.reencrypt(key, did);
|