@tinycloud/node-sdk 3.8.0-beta.0 → 3.8.0-beta.10
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/{TinyCloudNode-BtKzLDJX.d.ts → TinyCloudNode-DnD-SH6t.d.ts} +27 -4
- package/dist/{TinyCloudNode-ggmlnSfI.d.cts → TinyCloudNode-Dy65bxqs.d.cts} +27 -4
- package/dist/{authority-sJ6buHMj.d.ts → authority-BQnTX3fI.d.ts} +21 -5
- package/dist/{authority-_SYAE-uV.d.cts → authority-Rbye1U4o.d.cts} +21 -5
- package/dist/core.cjs +196 -29
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +5 -4
- package/dist/core.d.ts +5 -4
- package/dist/core.js +190 -25
- package/dist/core.js.map +1 -1
- package/dist/credentials-core.d.cts +1 -1
- package/dist/credentials-core.d.ts +1 -1
- package/dist/credentials.d.cts +1 -1
- package/dist/credentials.d.ts +1 -1
- package/dist/{delegation-0LKZkmP2.d.cts → delegation-Ckc3UETl.d.cts} +1 -1
- package/dist/{delegation-0LKZkmP2.d.ts → delegation-Ckc3UETl.d.ts} +1 -1
- package/dist/encryption-keys.d.cts +2 -2
- package/dist/encryption-keys.d.ts +2 -2
- package/dist/index.cjs +249 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +236 -28
- package/dist/index.js.map +1 -1
- package/dist/replication/authority.cjs +43 -1
- package/dist/replication/authority.cjs.map +1 -1
- package/dist/replication/authority.d.cts +4 -3
- package/dist/replication/authority.d.ts +4 -3
- package/dist/replication/authority.js +42 -1
- package/dist/replication/authority.js.map +1 -1
- package/dist/replication/runtime.cjs +1 -0
- package/dist/replication/runtime.cjs.map +1 -1
- package/dist/replication/runtime.d.cts +1 -1
- package/dist/replication/runtime.d.ts +1 -1
- package/dist/replication/runtime.js +1 -0
- package/dist/replication/runtime.js.map +1 -1
- package/dist/{runtime-v62FzQHz.d.ts → runtime-CO4VXnPq.d.ts} +2 -1
- package/dist/{runtime-D1o9Eybt.d.cts → runtime-mRhSu-vJ.d.cts} +2 -1
- package/package.json +4 -4
package/dist/core.cjs
CHANGED
|
@@ -58,6 +58,7 @@ __export(core_exports, {
|
|
|
58
58
|
PermissionNotInManifestError: () => import_sdk_core14.PermissionNotInManifestError,
|
|
59
59
|
PrefixedKVService: () => import_sdk_core15.PrefixedKVService,
|
|
60
60
|
ProtocolMismatchError: () => import_sdk_core22.ProtocolMismatchError,
|
|
61
|
+
RuntimeDelegationRejectedError: () => RuntimeDelegationRejectedError,
|
|
61
62
|
SECRET_NAME_RE: () => import_sdk_core18.SECRET_NAME_RE,
|
|
62
63
|
SQLAction: () => import_sdk_core16.SQLAction,
|
|
63
64
|
SQLService: () => import_sdk_core16.SQLService,
|
|
@@ -80,6 +81,7 @@ __export(core_exports, {
|
|
|
80
81
|
VersionCheckError: () => import_sdk_core22.VersionCheckError,
|
|
81
82
|
WasmKeyProvider: () => WasmKeyProvider,
|
|
82
83
|
activateCompactRuntimeDelegation: () => activateCompactRuntimeDelegation,
|
|
84
|
+
activateValidatedRuntimeDelegation: () => activateValidatedRuntimeDelegation,
|
|
83
85
|
addressStorageKey: () => import_sdk_core13.addressStorageKey,
|
|
84
86
|
buildSpaceUri: () => import_sdk_core21.buildSpaceUri,
|
|
85
87
|
canonicalizeAddress: () => import_sdk_core13.canonicalizeAddress,
|
|
@@ -345,6 +347,32 @@ var FileSessionStorage = class {
|
|
|
345
347
|
var import_node_crypto = require("crypto");
|
|
346
348
|
var import_siwe = require("siwe");
|
|
347
349
|
var import_sdk_core5 = require("@tinycloud/sdk-core");
|
|
350
|
+
var import_resource = require("@tinycloud/sdk-services/encryption/resource");
|
|
351
|
+
var import_sdk_services2 = require("@tinycloud/sdk-services");
|
|
352
|
+
|
|
353
|
+
// src/authorization/appKeyHostBinding.ts
|
|
354
|
+
var DOMAIN_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
355
|
+
var IPV4 = /^\d+\.\d+\.\d+\.\d+$/;
|
|
356
|
+
var APP_ID = /^[a-z0-9][a-z0-9._-]{0,63}$/;
|
|
357
|
+
function appKeyHostBinding(domain, appId) {
|
|
358
|
+
if (!APP_ID.test(appId)) return false;
|
|
359
|
+
if (domain.endsWith(":")) return false;
|
|
360
|
+
let url;
|
|
361
|
+
try {
|
|
362
|
+
url = new URL(`https://${domain}`);
|
|
363
|
+
} catch {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
if (url.protocol !== "https:" || url.port !== "" || url.username !== "" || url.password !== "") return false;
|
|
367
|
+
if (url.pathname !== "/" || url.search !== "" || url.hash !== "") return false;
|
|
368
|
+
const host = url.hostname;
|
|
369
|
+
if (host.startsWith("[") || host.endsWith(".") || IPV4.test(host)) return false;
|
|
370
|
+
const labels = host.split(".");
|
|
371
|
+
if (labels.length < 2 || labels[labels.length - 1] === "localhost") return false;
|
|
372
|
+
if (!labels.every((label) => DOMAIN_LABEL.test(label))) return false;
|
|
373
|
+
const reversed = labels.reverse().join(".");
|
|
374
|
+
return appId === reversed || appId.startsWith(`${reversed}.`);
|
|
375
|
+
}
|
|
348
376
|
|
|
349
377
|
// src/replication/authority-sign-in.ts
|
|
350
378
|
var import_sdk_core2 = require("@tinycloud/sdk-core");
|
|
@@ -375,7 +403,7 @@ function augmentSignInEntriesWithReplication(input) {
|
|
|
375
403
|
}
|
|
376
404
|
eligiblePaths.push(path);
|
|
377
405
|
}
|
|
378
|
-
if (eligiblePaths.length === replication.prefixes.length && eligiblePaths.length > 0 && hasUnrestrictedGetCoverage(input.entries, input.primarySpaceId, "")) {
|
|
406
|
+
if (replication.syncScope !== "prefixes" && eligiblePaths.length === replication.prefixes.length && eligiblePaths.length > 0 && hasUnrestrictedGetCoverage(input.entries, input.primarySpaceId, "")) {
|
|
379
407
|
return [{
|
|
380
408
|
service: KV_SERVICE,
|
|
381
409
|
space: input.primarySpaceId,
|
|
@@ -832,6 +860,23 @@ var NodeUserAuthorization = class {
|
|
|
832
860
|
);
|
|
833
861
|
return this._capabilityRequest;
|
|
834
862
|
}
|
|
863
|
+
async refreshNamedKeyFeatureForSignIn(address, chainId) {
|
|
864
|
+
const request = this.getCapabilityRequest();
|
|
865
|
+
const siweDomain = this.siweConfig?.domain ?? this.domain;
|
|
866
|
+
const hasNamedKeys = request?.manifests.some((manifest) => manifest.keys?.length && appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id));
|
|
867
|
+
if (hasNamedKeys) {
|
|
868
|
+
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
869
|
+
await this.refreshNodeInfo();
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
/** Manifest key paths that this sign-in cannot grant. */
|
|
873
|
+
get unavailableKeyPaths() {
|
|
874
|
+
const request = this.getCapabilityRequest();
|
|
875
|
+
const siweDomain = this.siweConfig?.domain ?? this.domain;
|
|
876
|
+
return (request?.manifests ?? []).flatMap(
|
|
877
|
+
(manifest) => this._nodeFeatures.includes("encryption-named-keys-v1") && appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id) ? [] : (manifest.keys ?? []).map((entry) => "path" in entry ? entry.path : entry.prefix)
|
|
878
|
+
);
|
|
879
|
+
}
|
|
835
880
|
resolveSpaceName(space, address, chainId) {
|
|
836
881
|
if (space.startsWith("tinycloud:")) {
|
|
837
882
|
return space;
|
|
@@ -1023,15 +1068,31 @@ var NodeUserAuthorization = class {
|
|
|
1023
1068
|
}
|
|
1024
1069
|
const rawAbilities = {};
|
|
1025
1070
|
const currentDid = (0, import_sdk_core5.pkhDid)(address, chainId);
|
|
1071
|
+
if (this._nodeFeatures.includes("encryption-named-keys-v1")) {
|
|
1072
|
+
const siweDomain = this.siweConfig?.domain ?? this.domain;
|
|
1073
|
+
for (const manifest of request.manifests) {
|
|
1074
|
+
if (!appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id)) continue;
|
|
1075
|
+
for (const declaration of manifest.keys ?? []) {
|
|
1076
|
+
const path = "path" in declaration ? declaration.path : declaration.prefix;
|
|
1077
|
+
const resource = `urn:tinycloud:encryption:${currentDid}:default/${path}`;
|
|
1078
|
+
for (const ability of declaration.abilities) {
|
|
1079
|
+
addRawAbility(rawAbilities, resource, `tinycloud.encryption/${ability}`);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1026
1084
|
const spaceResources = request.resources.filter((entry) => {
|
|
1027
1085
|
if (entry.service !== import_sdk_core5.ENCRYPTION_PERMISSION_SERVICE) {
|
|
1028
1086
|
return true;
|
|
1029
1087
|
}
|
|
1088
|
+
const parsed = entry.path.includes("/") ? (0, import_resource.parseEncryptionResource)(entry.path) : { ...(0, import_sdk_services2.parseNetworkId)(entry.path), kind: "network" };
|
|
1089
|
+
if (parsed.kind !== "network") {
|
|
1090
|
+
throw new import_sdk_core5.ManifestValidationError("named keys go in manifest.keys");
|
|
1091
|
+
}
|
|
1030
1092
|
for (const action of entry.actions) {
|
|
1031
1093
|
addRawAbility(rawAbilities, entry.path, action);
|
|
1032
1094
|
}
|
|
1033
|
-
if (entry.actions.includes(DECRYPT_ACTION)) {
|
|
1034
|
-
const parsed = (0, import_sdk_core5.parseNetworkId)(entry.path);
|
|
1095
|
+
if (entry.actions.includes(DECRYPT_ACTION) && parsed.kind === "network") {
|
|
1035
1096
|
if (didPrincipalMatches(parsed.ownerDid, currentDid)) {
|
|
1036
1097
|
addRawAbility(rawAbilities, entry.path, NETWORK_CREATE_ACTION);
|
|
1037
1098
|
}
|
|
@@ -1427,6 +1488,8 @@ var NodeUserAuthorization = class {
|
|
|
1427
1488
|
this._chainId = chainId;
|
|
1428
1489
|
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
1429
1490
|
this.assertSignInCurrent(generation);
|
|
1491
|
+
await this.refreshNamedKeyFeatureForSignIn(address, chainId);
|
|
1492
|
+
this.assertSignInCurrent(generation);
|
|
1430
1493
|
const keyId = `session-${Date.now()}`;
|
|
1431
1494
|
this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
|
|
1432
1495
|
this.activeSessionKeyId = keyId;
|
|
@@ -1573,6 +1636,7 @@ var NodeUserAuthorization = class {
|
|
|
1573
1636
|
refuseCaveated(this.getCapabilityRequest()?.manifests);
|
|
1574
1637
|
const address = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
|
|
1575
1638
|
const chainId = await this.signer.getChainId();
|
|
1639
|
+
await this.refreshNamedKeyFeatureForSignIn(address, chainId);
|
|
1576
1640
|
const keyId = `session-${Date.now()}`;
|
|
1577
1641
|
this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
|
|
1578
1642
|
this.activeSessionKeyId = keyId;
|
|
@@ -2152,7 +2216,7 @@ var NodeUserAuthorization = class {
|
|
|
2152
2216
|
};
|
|
2153
2217
|
|
|
2154
2218
|
// src/recordingServiceContext.ts
|
|
2155
|
-
var
|
|
2219
|
+
var import_sdk_services3 = require("@tinycloud/sdk-services");
|
|
2156
2220
|
var import_requestLog = require("@tinycloud/sdk-services/telemetry/requestLog");
|
|
2157
2221
|
|
|
2158
2222
|
// src/recordingRegistry.ts
|
|
@@ -2197,9 +2261,9 @@ function replicationEvent(sample, op) {
|
|
|
2197
2261
|
}
|
|
2198
2262
|
function createServiceContext(config) {
|
|
2199
2263
|
const { requestSink, ...base } = config;
|
|
2200
|
-
return requestSink === void 0 ? new
|
|
2264
|
+
return requestSink === void 0 ? new import_sdk_services3.ServiceContext(base) : new RecordingServiceContext(base, requestSink);
|
|
2201
2265
|
}
|
|
2202
|
-
var RecordingServiceContext = class extends
|
|
2266
|
+
var RecordingServiceContext = class extends import_sdk_services3.ServiceContext {
|
|
2203
2267
|
constructor(config, sink) {
|
|
2204
2268
|
const pending = {};
|
|
2205
2269
|
super({
|
|
@@ -2793,8 +2857,9 @@ function deserializeDelegation(data) {
|
|
|
2793
2857
|
// src/TinyCloudNode.ts
|
|
2794
2858
|
var import_siwe2 = require("siwe");
|
|
2795
2859
|
var import_sdk_core11 = require("@tinycloud/sdk-core");
|
|
2796
|
-
var
|
|
2860
|
+
var import_sdk_services4 = require("@tinycloud/sdk-services");
|
|
2797
2861
|
var import_requestLog2 = require("@tinycloud/sdk-services/telemetry/requestLog");
|
|
2862
|
+
var import_resource2 = require("@tinycloud/sdk-services/encryption/resource");
|
|
2798
2863
|
|
|
2799
2864
|
// src/account/AccountService.ts
|
|
2800
2865
|
var import_sdk_core7 = require("@tinycloud/sdk-core");
|
|
@@ -3271,6 +3336,7 @@ var ROOT_DELEGATION_ACTIONS = [
|
|
|
3271
3336
|
import_sdk_core11.DUCKDB.ALL
|
|
3272
3337
|
];
|
|
3273
3338
|
var DEFAULT_SESSION_EXPIRATION_MS = import_sdk_core11.EXPIRY.SESSION_MS;
|
|
3339
|
+
var OWNER_REVOCATION_WINDOW_MS = 10 * 6e4;
|
|
3274
3340
|
function unifiedRootAttenuation(capabilities) {
|
|
3275
3341
|
const attenuation = {};
|
|
3276
3342
|
for (const capability of capabilities) {
|
|
@@ -3735,6 +3801,7 @@ function replicaRestoreRefusal(error) {
|
|
|
3735
3801
|
case "purge_pending":
|
|
3736
3802
|
case "logout_pending":
|
|
3737
3803
|
case "gate_unavailable":
|
|
3804
|
+
case "wallet_provider_required":
|
|
3738
3805
|
return error.gate;
|
|
3739
3806
|
}
|
|
3740
3807
|
}
|
|
@@ -3769,6 +3836,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3769
3836
|
this.auth = null;
|
|
3770
3837
|
this.tc = null;
|
|
3771
3838
|
this._chainId = 1;
|
|
3839
|
+
this.replicaPurgeFailedHandlers = /* @__PURE__ */ new Set();
|
|
3772
3840
|
/** Mints the replica session stamp on each fresh sign-in (TC-858 §4.1). Undefined when replication is off. */
|
|
3773
3841
|
this.establishReplicaStamp = async (session) => {
|
|
3774
3842
|
const replication = this.config.replication;
|
|
@@ -3800,6 +3868,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3800
3868
|
return void 0;
|
|
3801
3869
|
}
|
|
3802
3870
|
};
|
|
3871
|
+
this._keysUnavailable = [];
|
|
3803
3872
|
this._baseVaults = /* @__PURE__ */ new Map();
|
|
3804
3873
|
this._baseSecrets = /* @__PURE__ */ new Map();
|
|
3805
3874
|
this._secrets = /* @__PURE__ */ new Map();
|
|
@@ -3975,6 +4044,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3975
4044
|
return instance ? instance.control.purge(input) : runtime.then((ready) => ready.control.purge(input));
|
|
3976
4045
|
},
|
|
3977
4046
|
clearPending: async () => (await runtime).control.clearPending(),
|
|
4047
|
+
purgeLocalCopy: async () => (await this.eraseReplicaLocalCopy("purge_local_copy"))?.purge ?? { ok: false, retryNow: false },
|
|
3978
4048
|
close: async () => (await runtime).control.close()
|
|
3979
4049
|
};
|
|
3980
4050
|
}
|
|
@@ -4029,18 +4099,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4029
4099
|
get freshEncryptionNetworkCreated() {
|
|
4030
4100
|
return this._freshEncryptionNetworkCreated;
|
|
4031
4101
|
}
|
|
4032
|
-
/**
|
|
4033
|
-
* Subscribe to `storage.full`. It fires on the first write any service had
|
|
4034
|
-
* rejected because the owner's TinyCloud storage is full
|
|
4035
|
-
* (`STORAGE_QUOTA_EXCEEDED` or `STORAGE_LIMIT_REACHED`), so an app can show
|
|
4036
|
-
* one read-only banner. Reads keep working. For the signed-in account's own
|
|
4037
|
-
* storage it fires once per episode: the episode ends only when a write to
|
|
4038
|
-
* that storage succeeds, or on sign-out. A `storage.status()` read does not
|
|
4039
|
-
* end it. A rejection on another owner's delegated space fires once per
|
|
4040
|
-
* owner, until that owner's `storage.status()` reports space again. Returns
|
|
4041
|
-
* the unsubscribe function.
|
|
4042
|
-
*/
|
|
4043
4102
|
on(event, handler) {
|
|
4103
|
+
if (event === "replica.purge.failed") {
|
|
4104
|
+
const listener = handler;
|
|
4105
|
+
this.replicaPurgeFailedHandlers.add(listener);
|
|
4106
|
+
return () => {
|
|
4107
|
+
this.replicaPurgeFailedHandlers.delete(listener);
|
|
4108
|
+
};
|
|
4109
|
+
}
|
|
4044
4110
|
if (event !== "storage.full") {
|
|
4045
4111
|
throw new Error(`Unknown TinyCloud event: ${String(event)}`);
|
|
4046
4112
|
}
|
|
@@ -4260,7 +4326,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4260
4326
|
replication: config.replication?.enabled === true ? {
|
|
4261
4327
|
enabled: true,
|
|
4262
4328
|
prefixes: config.replication.prefixes,
|
|
4263
|
-
allowSecrets: config.replication.allowSecrets === true
|
|
4329
|
+
allowSecrets: config.replication.allowSecrets === true,
|
|
4330
|
+
syncScope: config.replication.syncScope
|
|
4264
4331
|
} : void 0
|
|
4265
4332
|
});
|
|
4266
4333
|
this.tc = new import_sdk_core11.TinyCloud(this.auth, {
|
|
@@ -4520,6 +4587,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4520
4587
|
const leavingAuth = this.auth;
|
|
4521
4588
|
const leavingContext = this._serviceContext;
|
|
4522
4589
|
let denied;
|
|
4590
|
+
let erased;
|
|
4523
4591
|
try {
|
|
4524
4592
|
this.teardownSession();
|
|
4525
4593
|
} finally {
|
|
@@ -4530,6 +4598,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4530
4598
|
try {
|
|
4531
4599
|
await this.accountRegistryTail;
|
|
4532
4600
|
await this.quiesceReplicaRuntime();
|
|
4601
|
+
if (denied) erased = await this.eraseReplicaLocalCopy("sign_out", denied.status);
|
|
4533
4602
|
} finally {
|
|
4534
4603
|
if (leavingAddress) {
|
|
4535
4604
|
await (leavingAuth ? leavingAuth.clearPersistedSession(leavingAddress) : this.config.sessionStorage?.clear(leavingAddress));
|
|
@@ -4537,8 +4606,37 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4537
4606
|
}
|
|
4538
4607
|
}
|
|
4539
4608
|
}
|
|
4540
|
-
if (denied?.status === "unguarded") {
|
|
4541
|
-
throw
|
|
4609
|
+
if (denied?.status === "unguarded" && erased?.outcome.status !== "erased") {
|
|
4610
|
+
throw Object.assign(
|
|
4611
|
+
new Error(`Replica gate was not denied (${denied.code ?? "unknown"}); the replica may still be restorable.`),
|
|
4612
|
+
{
|
|
4613
|
+
code: "REPLICA_PURGE_FAILED",
|
|
4614
|
+
reason: "gate_unavailable",
|
|
4615
|
+
retryNow: erased?.outcome.status === "failed"
|
|
4616
|
+
}
|
|
4617
|
+
);
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4620
|
+
/**
|
|
4621
|
+
* Erases the browser local copy after a deny (retry, event and next-load marker live in the lazy
|
|
4622
|
+
* replication authority). Never rejects; `undefined` when replication is off or the storage keeps
|
|
4623
|
+
* no browser database.
|
|
4624
|
+
*/
|
|
4625
|
+
async eraseReplicaLocalCopy(trigger, denyStatus) {
|
|
4626
|
+
const replication = this.config.replication;
|
|
4627
|
+
if (!replication?.enabled) return void 0;
|
|
4628
|
+
try {
|
|
4629
|
+
const { eraseReplicaLocalCopy } = await getNodeReplicationLoaders().authority();
|
|
4630
|
+
const erased = await eraseReplicaLocalCopy(
|
|
4631
|
+
replication.storage.lifecycle,
|
|
4632
|
+
trigger,
|
|
4633
|
+
denyStatus,
|
|
4634
|
+
this.replicaPurgeFailedHandlers
|
|
4635
|
+
);
|
|
4636
|
+
if (erased?.logoutPending) this.replicaRestoreGate = "logout_pending";
|
|
4637
|
+
return erased;
|
|
4638
|
+
} catch {
|
|
4639
|
+
return void 0;
|
|
4542
4640
|
}
|
|
4543
4641
|
}
|
|
4544
4642
|
/**
|
|
@@ -4598,6 +4696,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4598
4696
|
this._hooks = void 0;
|
|
4599
4697
|
this._vault = void 0;
|
|
4600
4698
|
this._encryption = void 0;
|
|
4699
|
+
this._namedKeyClient = void 0;
|
|
4700
|
+
this._keysUnavailable = [];
|
|
4601
4701
|
this._baseVaults.clear();
|
|
4602
4702
|
this._baseSecrets.clear();
|
|
4603
4703
|
this._secrets.clear();
|
|
@@ -4702,6 +4802,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4702
4802
|
const priorPrincipal = this.replicaSessionPrincipal ?? (this.address ? (0, import_sdk_core11.pkhDid)(this.address, this._chainId) : void 0);
|
|
4703
4803
|
if (this.config.replication?.enabled && priorPrincipal && priorPrincipal !== nextPrincipal) {
|
|
4704
4804
|
const denial = await this.denyReplicaGate({ reason: "account_switch", principal: priorPrincipal, next: nextPrincipal });
|
|
4805
|
+
if (denial) {
|
|
4806
|
+
await this.quiesceReplicaRuntime();
|
|
4807
|
+
await this.eraseReplicaLocalCopy("account_switch", denial.status);
|
|
4808
|
+
}
|
|
4705
4809
|
this.replicaRestoreGate = denial?.status === "unguarded" ? "gate_unavailable" : "stamp_stale";
|
|
4706
4810
|
}
|
|
4707
4811
|
if (address !== this._address || chainId !== this._chainId) {
|
|
@@ -4716,6 +4820,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4716
4820
|
this._hooks = void 0;
|
|
4717
4821
|
this._vault = void 0;
|
|
4718
4822
|
this._encryption = void 0;
|
|
4823
|
+
this._namedKeyClient = void 0;
|
|
4824
|
+
this._keysUnavailable = [];
|
|
4719
4825
|
this._baseVaults.clear();
|
|
4720
4826
|
this._baseSecrets.clear();
|
|
4721
4827
|
this._secrets.clear();
|
|
@@ -4768,6 +4874,26 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4768
4874
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4769
4875
|
await this.ensureRequestedEncryptionNetworks();
|
|
4770
4876
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4877
|
+
this._keysUnavailable = this.auth?.unavailableKeyPaths ?? [];
|
|
4878
|
+
if (this._keysUnavailable.length > 0) {
|
|
4879
|
+
this.notificationHandler.warning(`Named keys unavailable: ${this._keysUnavailable.join(", ")}`);
|
|
4880
|
+
}
|
|
4881
|
+
if (this.nodeFeatures.includes("encryption-named-keys-v1")) {
|
|
4882
|
+
for (const manifest of this.auth?.capabilityRequest?.manifests ?? []) {
|
|
4883
|
+
for (const declaration of manifest.keys ?? []) {
|
|
4884
|
+
if ("path" in declaration && declaration.abilities.includes("key.create") && !this._keysUnavailable.includes(declaration.path)) {
|
|
4885
|
+
try {
|
|
4886
|
+
await this.keys.ensureKey(declaration.path);
|
|
4887
|
+
} catch (error) {
|
|
4888
|
+
this._keysUnavailable.push(declaration.path);
|
|
4889
|
+
const code = error && typeof error === "object" && "code" in error && typeof error.code === "string" && /^[A-Z_]+$/.test(error.code) ? error.code : "UNKNOWN";
|
|
4890
|
+
this.notificationHandler.warning(`Named key unavailable: ${declaration.path} (${code})`);
|
|
4891
|
+
}
|
|
4892
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4895
|
+
}
|
|
4896
|
+
}
|
|
4771
4897
|
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
4772
4898
|
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(import_sdk_core11.SECRETS_SPACE));
|
|
4773
4899
|
}
|
|
@@ -5344,7 +5470,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5344
5470
|
if (!this.currentSessionCoversAccountRegistry()) {
|
|
5345
5471
|
if (!_TinyCloudNode.accountRegistrySkipLogged) {
|
|
5346
5472
|
_TinyCloudNode.accountRegistrySkipLogged = true;
|
|
5347
|
-
|
|
5473
|
+
import_sdk_services4.tinyCloudDebugLogger.log("registry.skip");
|
|
5348
5474
|
}
|
|
5349
5475
|
return;
|
|
5350
5476
|
}
|
|
@@ -5555,7 +5681,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5555
5681
|
const networkIds = /* @__PURE__ */ new Set();
|
|
5556
5682
|
for (const resource of request.resources) {
|
|
5557
5683
|
if (resource.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && resource.path.startsWith("urn:tinycloud:encryption:") && resource.actions.includes(DECRYPT_ACTION2)) {
|
|
5558
|
-
|
|
5684
|
+
const parsed = resource.path.includes("/") ? (0, import_resource2.parseEncryptionResource)(resource.path) : { ...(0, import_sdk_core11.parseNetworkId)(resource.path), kind: "network" };
|
|
5685
|
+
if (parsed.kind === "network") networkIds.add(resource.path);
|
|
5559
5686
|
}
|
|
5560
5687
|
}
|
|
5561
5688
|
return [...networkIds];
|
|
@@ -6105,6 +6232,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6105
6232
|
this._hooks = stagedGraph.hooks;
|
|
6106
6233
|
this._vault = stagedGraph.vault;
|
|
6107
6234
|
this._encryption = stagedGraph.encryption;
|
|
6235
|
+
this._namedKeyClient = void 0;
|
|
6236
|
+
this._keysUnavailable = [];
|
|
6108
6237
|
this._capabilityRegistry = stagedGraph.capabilityRegistry;
|
|
6109
6238
|
this._keyProvider = stagedGraph.keyProvider;
|
|
6110
6239
|
this._sharingService = stagedGraph.sharingService;
|
|
@@ -6682,7 +6811,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6682
6811
|
replication: this.config.replication?.enabled === true ? {
|
|
6683
6812
|
enabled: true,
|
|
6684
6813
|
prefixes: this.config.replication.prefixes,
|
|
6685
|
-
allowSecrets: this.config.replication.allowSecrets === true
|
|
6814
|
+
allowSecrets: this.config.replication.allowSecrets === true,
|
|
6815
|
+
syncScope: this.config.replication.syncScope
|
|
6686
6816
|
} : void 0
|
|
6687
6817
|
});
|
|
6688
6818
|
this.tc = new import_sdk_core11.TinyCloud(this.auth, {
|
|
@@ -6744,7 +6874,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6744
6874
|
replication: this.config.replication?.enabled === true ? {
|
|
6745
6875
|
enabled: true,
|
|
6746
6876
|
prefixes: this.config.replication.prefixes,
|
|
6747
|
-
allowSecrets: this.config.replication.allowSecrets === true
|
|
6877
|
+
allowSecrets: this.config.replication.allowSecrets === true,
|
|
6878
|
+
syncScope: this.config.replication.syncScope
|
|
6748
6879
|
} : void 0
|
|
6749
6880
|
});
|
|
6750
6881
|
this.tc = new import_sdk_core11.TinyCloud(this.auth, {
|
|
@@ -7012,7 +7143,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7012
7143
|
);
|
|
7013
7144
|
graph.assertActive();
|
|
7014
7145
|
if (!response.ok) {
|
|
7015
|
-
const permissionHint = response.status === 401 || response.status === 403 ? (0,
|
|
7146
|
+
const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services4.parsePermissionHint)({
|
|
7016
7147
|
service: "tinycloud.encryption",
|
|
7017
7148
|
path: networkId,
|
|
7018
7149
|
actions: ["tinycloud.encryption/decrypt"]
|
|
@@ -7456,7 +7587,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7456
7587
|
* Sign a wallet (CACAO) revocation of the delegation `cid` for the node's
|
|
7457
7588
|
* `POST /revoke`, and return its Authorization header value. The node
|
|
7458
7589
|
* accepts it when the owner delegated `cid` or owns a space its abilities
|
|
7459
|
-
* target, whichever key issued it. Valid for
|
|
7590
|
+
* target, whichever key issued it. Valid for 10 minutes. Requires the
|
|
7460
7591
|
* owner wallet signer.
|
|
7461
7592
|
*/
|
|
7462
7593
|
async signOwnerRevocation(cid) {
|
|
@@ -7472,7 +7603,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7472
7603
|
chainId: session.chainId,
|
|
7473
7604
|
nonce: (0, import_siwe2.generateNonce)(),
|
|
7474
7605
|
issuedAt: issuedAt.toISOString(),
|
|
7475
|
-
expirationTime: new Date(issuedAt.getTime() +
|
|
7606
|
+
expirationTime: new Date(issuedAt.getTime() + OWNER_REVOCATION_WINDOW_MS).toISOString()
|
|
7476
7607
|
}).prepareMessage();
|
|
7477
7608
|
const signature = await this.signer.signMessage(siwe);
|
|
7478
7609
|
return this.wasmBindings.siweToDelegationHeaders({ siwe, signature }).Authorization;
|
|
@@ -7699,6 +7830,40 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7699
7830
|
get encryption() {
|
|
7700
7831
|
return this.getEncryptionService();
|
|
7701
7832
|
}
|
|
7833
|
+
/** Named keys bound to the current session. */
|
|
7834
|
+
get keys() {
|
|
7835
|
+
return new Proxy({}, {
|
|
7836
|
+
get: (_target, property) => {
|
|
7837
|
+
if (property === "refreshNodeInfo") {
|
|
7838
|
+
return () => {
|
|
7839
|
+
void this._namedKeyClient?.then((client) => client.refreshNodeInfo());
|
|
7840
|
+
};
|
|
7841
|
+
}
|
|
7842
|
+
if (typeof property !== "string" || ![
|
|
7843
|
+
"getPublicKey",
|
|
7844
|
+
"describeKey",
|
|
7845
|
+
"createKey",
|
|
7846
|
+
"blockKey",
|
|
7847
|
+
"unblockKey",
|
|
7848
|
+
"ensureKey",
|
|
7849
|
+
"encrypt",
|
|
7850
|
+
"decrypt",
|
|
7851
|
+
"decryptMany"
|
|
7852
|
+
].includes(property)) return void 0;
|
|
7853
|
+
return (...args) => {
|
|
7854
|
+
this._namedKeyClient ?? (this._namedKeyClient = import("./encryption-keys.cjs").then(({ createNamedKeyClient }) => createNamedKeyClient(this)));
|
|
7855
|
+
return this._namedKeyClient.then((client) => {
|
|
7856
|
+
const method = client[property];
|
|
7857
|
+
return method.apply(client, args);
|
|
7858
|
+
});
|
|
7859
|
+
};
|
|
7860
|
+
}
|
|
7861
|
+
});
|
|
7862
|
+
}
|
|
7863
|
+
/** Manifest key paths unavailable during the latest `signIn()` attempt. */
|
|
7864
|
+
get keysUnavailable() {
|
|
7865
|
+
return this._keysUnavailable;
|
|
7866
|
+
}
|
|
7702
7867
|
async getEncryptionNetwork(nameOrNetworkId = this.getDefaultEncryptionNetworkId()) {
|
|
7703
7868
|
const networkId = nameOrNetworkId.startsWith("urn:tinycloud:encryption:") ? nameOrNetworkId : this.getDefaultEncryptionNetworkId(nameOrNetworkId);
|
|
7704
7869
|
return this.fetchEncryptionNetworkAt(
|
|
@@ -7826,7 +7991,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7826
7991
|
);
|
|
7827
7992
|
if (result.status !== "ok") {
|
|
7828
7993
|
if (result.status === "permission_required") {
|
|
7829
|
-
const hint = (0,
|
|
7994
|
+
const hint = (0, import_sdk_services4.parsePermissionHint)(result.hint);
|
|
7830
7995
|
if (hint === void 0) return { status: "read_failed" };
|
|
7831
7996
|
return {
|
|
7832
7997
|
status: "permission_required",
|
|
@@ -10004,6 +10169,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10004
10169
|
PermissionNotInManifestError,
|
|
10005
10170
|
PrefixedKVService,
|
|
10006
10171
|
ProtocolMismatchError,
|
|
10172
|
+
RuntimeDelegationRejectedError,
|
|
10007
10173
|
SECRET_NAME_RE,
|
|
10008
10174
|
SQLAction,
|
|
10009
10175
|
SQLService,
|
|
@@ -10026,6 +10192,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10026
10192
|
VersionCheckError,
|
|
10027
10193
|
WasmKeyProvider,
|
|
10028
10194
|
activateCompactRuntimeDelegation,
|
|
10195
|
+
activateValidatedRuntimeDelegation,
|
|
10029
10196
|
addressStorageKey,
|
|
10030
10197
|
buildSpaceUri,
|
|
10031
10198
|
canonicalizeAddress,
|