@tinycloud/node-sdk 3.12.0-beta.2 → 3.12.0-beta.3
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/README.md +39 -0
- package/dist/{NodeUserAuthorization-B05Wjjpb.d.cts → NodeUserAuthorization-B_TFUlua.d.cts} +18 -52
- package/dist/{NodeUserAuthorization-B05Wjjpb.d.ts → NodeUserAuthorization-B_TFUlua.d.ts} +18 -52
- package/dist/{TinyCloudNode-CEFGtSWn.d.ts → TinyCloudNode-Brcu8QoX.d.cts} +31 -59
- package/dist/{TinyCloudNode-6_IumWu0.d.cts → TinyCloudNode-DBJUnsMN.d.ts} +31 -59
- package/dist/{authority-DXpnuId1.d.ts → authority-BFc5lesl.d.ts} +1 -1
- package/dist/{authority-DODDXxoP.d.cts → authority-DQ6R1HEG.d.cts} +1 -1
- package/dist/core.cjs +500 -283
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +5 -5
- package/dist/core.d.ts +5 -5
- package/dist/core.js +526 -287
- 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-BQbAuKad.d.cts → delegation-CeOWDnBB.d.cts} +7 -0
- package/dist/{delegation-BQbAuKad.d.ts → delegation-CeOWDnBB.d.ts} +7 -0
- package/dist/encryption-keys.d.cts +3 -3
- package/dist/encryption-keys.d.ts +3 -3
- package/dist/index.cjs +517 -300
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +527 -288
- package/dist/index.js.map +1 -1
- package/dist/replication/authority.d.cts +4 -4
- package/dist/replication/authority.d.ts +4 -4
- package/dist/space-hosting.d.cts +1 -1
- package/dist/space-hosting.d.ts +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -17045,7 +17045,7 @@ function augmentSignInEntriesWithReplication(input) {
|
|
|
17045
17045
|
for (const prefix of replication.prefixes) {
|
|
17046
17046
|
(0, import_prefix.assertFolderPrefix)(prefix);
|
|
17047
17047
|
const path = prefix === "/" ? "" : prefix;
|
|
17048
|
-
if ((0,
|
|
17048
|
+
if ((0, import_sdk_services3.requiresSecretsOptIn)(input.primarySpaceId, prefix) && replication.allowSecrets !== true) {
|
|
17049
17049
|
continue;
|
|
17050
17050
|
}
|
|
17051
17051
|
if (!hasUnrestrictedGetCoverage(input.entries, input.primarySpaceId, path)) {
|
|
@@ -17071,12 +17071,12 @@ function augmentSignInEntriesWithReplication(input) {
|
|
|
17071
17071
|
}
|
|
17072
17072
|
return out;
|
|
17073
17073
|
}
|
|
17074
|
-
var import_sdk_core2,
|
|
17074
|
+
var import_sdk_core2, import_sdk_services3, import_prefix, KV_GET, KV_SYNC, KV_SERVICE;
|
|
17075
17075
|
var init_authority_sign_in = __esm({
|
|
17076
17076
|
"src/replication/authority-sign-in.ts"() {
|
|
17077
17077
|
"use strict";
|
|
17078
17078
|
import_sdk_core2 = require("@tinycloud/sdk-core");
|
|
17079
|
-
|
|
17079
|
+
import_sdk_services3 = require("@tinycloud/sdk-services");
|
|
17080
17080
|
import_prefix = require("@tinycloud/sdk-services/kv/replication/prefix");
|
|
17081
17081
|
KV_GET = import_sdk_core2.KV.GET;
|
|
17082
17082
|
KV_SYNC = import_sdk_core2.KV.SYNC;
|
|
@@ -17875,8 +17875,11 @@ __export(src_exports, {
|
|
|
17875
17875
|
MemorySessionStorage: () => MemorySessionStorage,
|
|
17876
17876
|
NETWORK_NAME_PATTERN: () => import_sdk_core22.NETWORK_NAME_PATTERN,
|
|
17877
17877
|
NetworkIdError: () => import_sdk_core22.NetworkIdError,
|
|
17878
|
+
NodeIdentityMismatchError: () => import_sdk_services8.NodeIdentityMismatchError,
|
|
17879
|
+
NodeNotRespondingError: () => import_sdk_services8.NodeNotRespondingError,
|
|
17878
17880
|
NodeUserAuthorization: () => NodeUserAuthorization,
|
|
17879
17881
|
NodeWasmBindings: () => NodeWasmBindings,
|
|
17882
|
+
PartialNodeWriteError: () => import_sdk_services8.PartialNodeWriteError,
|
|
17880
17883
|
PermissionNotInManifestError: () => import_sdk_core17.PermissionNotInManifestError,
|
|
17881
17884
|
PrefixedKVService: () => import_sdk_core18.PrefixedKVService,
|
|
17882
17885
|
PrivateKeySigner: () => PrivateKeySigner,
|
|
@@ -18275,6 +18278,7 @@ function rememberInvokeAny(invokeAny2, sink, pending) {
|
|
|
18275
18278
|
|
|
18276
18279
|
// src/delegation.ts
|
|
18277
18280
|
var import_sdk_core = require("@tinycloud/sdk-core");
|
|
18281
|
+
var import_sdk_services2 = require("@tinycloud/sdk-services");
|
|
18278
18282
|
var RUNTIME_DELEGATION_REJECTIONS = [
|
|
18279
18283
|
"host_mismatch",
|
|
18280
18284
|
"expired",
|
|
@@ -18316,7 +18320,8 @@ var SERVICE_BY_SHORT_NAME = {
|
|
|
18316
18320
|
kv: "tinycloud.kv",
|
|
18317
18321
|
sql: "tinycloud.sql",
|
|
18318
18322
|
duckdb: "tinycloud.duckdb",
|
|
18319
|
-
hooks: "tinycloud.hooks"
|
|
18323
|
+
hooks: "tinycloud.hooks",
|
|
18324
|
+
capabilities: "tinycloud.capabilities"
|
|
18320
18325
|
};
|
|
18321
18326
|
function authorizationWithoutBearer(authorization) {
|
|
18322
18327
|
return authorization.replace(/^Bearer /i, "");
|
|
@@ -18447,8 +18452,8 @@ function signedAuthorityFromCompactUcan(authorization) {
|
|
|
18447
18452
|
));
|
|
18448
18453
|
continue;
|
|
18449
18454
|
}
|
|
18450
|
-
const match = /^(?:tinycloud:\/\/([^/]+)|(tinycloud:[^/]+))\/(
|
|
18451
|
-
if (!match) {
|
|
18455
|
+
const match = /^(?:tinycloud:\/\/([^/]+)|(tinycloud:[^/]+))\/([^/]+)(?:\/|$)(.*)$/.exec(resource);
|
|
18456
|
+
if (!match || !Object.prototype.hasOwnProperty.call(SERVICE_BY_SHORT_NAME, match[3])) {
|
|
18452
18457
|
throw new Error(
|
|
18453
18458
|
`Validated runtime delegation has an unsupported signed resource '${resource}'.`
|
|
18454
18459
|
);
|
|
@@ -18593,13 +18598,8 @@ function resourcesMatch(actual, expected) {
|
|
|
18593
18598
|
return JSON.stringify(actual.map(comparable)) === JSON.stringify(expected.map(comparable));
|
|
18594
18599
|
}
|
|
18595
18600
|
async function activateValidatedRuntimeDelegation(node, delegation, options) {
|
|
18596
|
-
|
|
18597
|
-
|
|
18598
|
-
reject(
|
|
18599
|
-
"host_mismatch",
|
|
18600
|
-
`Runtime delegation host '${delegation.host}' does not match expected host '${options.host}'.`
|
|
18601
|
-
);
|
|
18602
|
-
}
|
|
18601
|
+
let host = normalizedHost(options.host);
|
|
18602
|
+
const differentHost = delegation.host !== void 0 && normalizedHost(delegation.host) !== host;
|
|
18603
18603
|
if (!(delegation.expiry instanceof Date) || Number.isNaN(delegation.expiry.getTime())) {
|
|
18604
18604
|
reject("authority_invalid", "Runtime delegation has an invalid expiry.");
|
|
18605
18605
|
}
|
|
@@ -18643,6 +18643,13 @@ async function activateValidatedRuntimeDelegation(node, delegation, options) {
|
|
|
18643
18643
|
if (options.authorize !== void 0 && !options.authorize(signed2.permissions)) {
|
|
18644
18644
|
throw new Error("Runtime delegation is not authorized for this runtime.");
|
|
18645
18645
|
}
|
|
18646
|
+
if (differentHost) {
|
|
18647
|
+
const registeredHost = await node.resolveRegisteredDelegationHost?.(signed2.permissions, host);
|
|
18648
|
+
if (registeredHost === void 0) {
|
|
18649
|
+
reject("host_mismatch", `Runtime delegation host '${delegation.host}' does not match expected host '${options.host}'.`);
|
|
18650
|
+
}
|
|
18651
|
+
host = normalizedHost(registeredHost);
|
|
18652
|
+
}
|
|
18646
18653
|
const previouslyInstalled = node.getRuntimePermissionDelegations().find((candidate) => candidate.cid === cid);
|
|
18647
18654
|
if (previouslyInstalled !== void 0 && previouslyInstalled.delegationHeader.Authorization !== authorization) {
|
|
18648
18655
|
reject(
|
|
@@ -18686,6 +18693,7 @@ async function activateValidatedRuntimeDelegation(node, delegation, options) {
|
|
|
18686
18693
|
await node.useRuntimeDelegation(installedCandidate);
|
|
18687
18694
|
}
|
|
18688
18695
|
} catch (error) {
|
|
18696
|
+
if ((0, import_sdk_services2.routingFailure)(error)) throw error;
|
|
18689
18697
|
reject(
|
|
18690
18698
|
activationRejectionReason(error),
|
|
18691
18699
|
error instanceof Error ? error.message : String(error)
|
|
@@ -18704,6 +18712,7 @@ async function activateValidatedRuntimeDelegation(node, delegation, options) {
|
|
|
18704
18712
|
"Runtime delegation activation installed authority that differs from the validated authority."
|
|
18705
18713
|
);
|
|
18706
18714
|
}
|
|
18715
|
+
node.refreshRegistryForCapabilities?.(signed2.permissions);
|
|
18707
18716
|
return {
|
|
18708
18717
|
cid,
|
|
18709
18718
|
delegation: installed,
|
|
@@ -18813,6 +18822,7 @@ function deserializeDelegation(data) {
|
|
|
18813
18822
|
}
|
|
18814
18823
|
|
|
18815
18824
|
// src/TinyCloudNode.ts
|
|
18825
|
+
var import_sdk_services5 = require("@tinycloud/sdk-services");
|
|
18816
18826
|
var import_siwe2 = require("siwe");
|
|
18817
18827
|
var import_share_envelope = require("@tinycloud/share-envelope");
|
|
18818
18828
|
|
|
@@ -18830,7 +18840,7 @@ function getNodeReplicationLoaders() {
|
|
|
18830
18840
|
|
|
18831
18841
|
// src/TinyCloudNode.ts
|
|
18832
18842
|
var import_sdk_core10 = require("@tinycloud/sdk-core");
|
|
18833
|
-
var
|
|
18843
|
+
var import_sdk_services6 = require("@tinycloud/sdk-services");
|
|
18834
18844
|
var import_requestLog2 = require("@tinycloud/sdk-services/telemetry/requestLog");
|
|
18835
18845
|
var import_resource2 = require("@tinycloud/sdk-services/encryption/resource");
|
|
18836
18846
|
|
|
@@ -18839,7 +18849,7 @@ var import_node_crypto = require("crypto");
|
|
|
18839
18849
|
var import_siwe = require("siwe");
|
|
18840
18850
|
var import_sdk_core5 = require("@tinycloud/sdk-core");
|
|
18841
18851
|
var import_resource = require("@tinycloud/sdk-services/encryption/resource");
|
|
18842
|
-
var
|
|
18852
|
+
var import_sdk_services4 = require("@tinycloud/sdk-services");
|
|
18843
18853
|
|
|
18844
18854
|
// src/authorization/appKeyHostBinding.ts
|
|
18845
18855
|
var DOMAIN_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
@@ -19114,11 +19124,12 @@ var NodeUserAuthorization = class {
|
|
|
19114
19124
|
this.tinycloudHosts = config.tinycloudHosts;
|
|
19115
19125
|
this.tinycloudRegistryUrl = config.tinycloudRegistryUrl;
|
|
19116
19126
|
this.tinycloudFallbackHosts = config.tinycloudFallbackHosts;
|
|
19117
|
-
this.registryPolicy = config.registryPolicy;
|
|
19118
19127
|
this.newUserHost = config.newUserHost;
|
|
19119
19128
|
this.registryChainId = config.registryChainId;
|
|
19120
19129
|
this.registrySequenceStore = config.registrySequenceStore ?? (0, import_sdk_core5.createInMemoryRegistrySequenceStore)();
|
|
19130
|
+
this.registryCacheStore = config.registryCacheStore ?? (0, import_sdk_core5.createInMemoryRegistryCacheStore)();
|
|
19121
19131
|
this.onNodeNotFound = config.onNodeNotFound;
|
|
19132
|
+
this.onRegistryFallback = config.onRegistryFallback;
|
|
19122
19133
|
this.autoDiscoverLocalNode = config.autoDiscoverLocalNode;
|
|
19123
19134
|
this.localNodeUrl = config.localNodeUrl;
|
|
19124
19135
|
this.localLinkName = config.localLinkName;
|
|
@@ -19186,13 +19197,8 @@ var NodeUserAuthorization = class {
|
|
|
19186
19197
|
* undefined for missing SIWEs and the SDK then treats the session as
|
|
19187
19198
|
* expired-at-epoch-zero.
|
|
19188
19199
|
*
|
|
19189
|
-
* @param hosts -
|
|
19190
|
-
*
|
|
19191
|
-
* present (and non-empty) they are adopted directly so the restored
|
|
19192
|
-
* session resolves to the same node as the original sign-in without
|
|
19193
|
-
* re-running registry/fallback resolution. When absent (old session)
|
|
19194
|
-
* hosts are resolved lazily on the first host-needing call via
|
|
19195
|
-
* {@link ensureTinyCloudHosts}.
|
|
19200
|
+
* @param hosts - Persisted host hints for genuine no-entry onboarding.
|
|
19201
|
+
* Current signed registry membership always takes precedence.
|
|
19196
19202
|
*/
|
|
19197
19203
|
setRestoredTinyCloudSession(session, hosts) {
|
|
19198
19204
|
const address = (0, import_sdk_core5.canonicalizeAddress)(session.address);
|
|
@@ -19254,89 +19260,84 @@ var NodeUserAuthorization = class {
|
|
|
19254
19260
|
signature: session.signature
|
|
19255
19261
|
};
|
|
19256
19262
|
}
|
|
19257
|
-
/**
|
|
19258
|
-
* Ensure `tinycloudHosts` are resolved before a host-needing call.
|
|
19259
|
-
*
|
|
19260
|
-
* Fresh sign-in resolves hosts up front; a restored session may not have
|
|
19261
|
-
* (old persisted sessions predate {@link PersistedSessionData.tinycloudHosts}).
|
|
19262
|
-
* This guard makes a restored session resolve the node exactly like a fresh
|
|
19263
|
-
* sign-in — persisted hosts are preferred (already set by
|
|
19264
|
-
* {@link setRestoredTinyCloudSession}), otherwise the registry/fallback
|
|
19265
|
-
* resolution runs lazily here. Idempotent: {@link resolveTinyCloudHostsForSignIn}
|
|
19266
|
-
* early-returns when hosts are already set.
|
|
19267
|
-
*
|
|
19268
|
-
* Throws if hosts are unset and the restored session has no address/chainId
|
|
19269
|
-
* to resolve from — a real failure that must surface, not be masked.
|
|
19270
|
-
*/
|
|
19263
|
+
/** Refresh the primary space's registry destinations, including after restore. */
|
|
19271
19264
|
async ensureTinyCloudHosts() {
|
|
19272
|
-
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
19273
|
-
return;
|
|
19274
|
-
}
|
|
19275
19265
|
if (this._address === void 0 || this._chainId === void 0) {
|
|
19276
|
-
throw new Error(
|
|
19277
|
-
"Cannot resolve TinyCloud hosts: no address/chainId available. Sign in or restore a session first."
|
|
19278
|
-
);
|
|
19266
|
+
throw new Error("Cannot resolve TinyCloud hosts: sign in or restore a session first.");
|
|
19279
19267
|
}
|
|
19280
|
-
await this.resolveTinyCloudHostsForSignIn(this._address, this._chainId);
|
|
19268
|
+
await this.resolveTinyCloudHostsForSignIn(this._address, this._chainId, this._tinyCloudSession?.spaceId);
|
|
19281
19269
|
}
|
|
19282
|
-
async resolveTinyCloudHostsForSignIn(address, chainId) {
|
|
19283
|
-
|
|
19284
|
-
|
|
19285
|
-
|
|
19286
|
-
|
|
19287
|
-
const resolved2 = await (0, import_sdk_core5.resolveFailClosedTinyCloudHosts)(address, {
|
|
19288
|
-
registryUrl: this.tinycloudRegistryUrl,
|
|
19289
|
-
registryChainId: this.registryChainId,
|
|
19290
|
-
newUserHost: this.newUserHost,
|
|
19291
|
-
sequenceStore: this.registrySequenceStore,
|
|
19292
|
-
onNodeNotFound: this.onNodeNotFound,
|
|
19293
|
-
autoDiscoverLocalNode: this.autoDiscoverLocalNode,
|
|
19294
|
-
localNodeUrl: this.localNodeUrl,
|
|
19295
|
-
localLinkName: this.localLinkName,
|
|
19296
|
-
expectedNodeDid: this.expectedNodeDid,
|
|
19297
|
-
localNodeIdentityStore: this.localNodeIdentityStore
|
|
19298
|
-
});
|
|
19299
|
-
this.tinycloudHosts = resolved2.hosts;
|
|
19300
|
-
this.registryVerdict = resolved2.verdict;
|
|
19301
|
-
return;
|
|
19302
|
-
}
|
|
19303
|
-
const subject = (0, import_sdk_core5.pkhDid)(address, chainId);
|
|
19304
|
-
const resolved = await (0, import_sdk_core5.resolveTinyCloudHosts)(subject, {
|
|
19305
|
-
registryUrl: this.tinycloudRegistryUrl,
|
|
19306
|
-
fallbackHosts: this.tinycloudFallbackHosts,
|
|
19307
|
-
autoDiscoverLocalNode: this.autoDiscoverLocalNode,
|
|
19308
|
-
localNodeUrl: this.localNodeUrl,
|
|
19309
|
-
localLinkName: this.localLinkName,
|
|
19310
|
-
expectedNodeDid: this.expectedNodeDid,
|
|
19311
|
-
localNodeIdentityStore: this.localNodeIdentityStore
|
|
19312
|
-
});
|
|
19313
|
-
this.tinycloudHosts = resolved.hosts;
|
|
19270
|
+
async resolveTinyCloudHostsForSignIn(address, chainId, restoredSpaceId) {
|
|
19271
|
+
const spaceId = restoredSpaceId ?? this.resolveSignInCapabilities(address, chainId).spaceId;
|
|
19272
|
+
const destinations = await this.resolveResourceDestinations(spaceId, "read");
|
|
19273
|
+
for (const destination of destinations) await (0, import_sdk_services4.verifyResourceDestination)(destination, globalThis.fetch.bind(globalThis));
|
|
19274
|
+
this.tinycloudHosts = destinations.map(({ url }) => url);
|
|
19314
19275
|
}
|
|
19315
|
-
/**
|
|
19316
|
-
|
|
19317
|
-
|
|
19318
|
-
|
|
19319
|
-
|
|
19320
|
-
|
|
19321
|
-
|
|
19322
|
-
|
|
19323
|
-
|
|
19324
|
-
|
|
19325
|
-
|
|
19326
|
-
|
|
19327
|
-
|
|
19276
|
+
/** Current full-resource registry routing; saved hosts are only no-entry hints. */
|
|
19277
|
+
async resolveResourceDestinations(resource, access, noEntryHosts = this.tinycloudHosts ?? []) {
|
|
19278
|
+
const owner = resource.startsWith("urn:tinycloud:encryption:") ? (0, import_sdk_services4.parseNetworkId)(resource.split("/")[0]).ownerDid : (0, import_sdk_core5.parseSpaceUri)(resource)?.owner ?? (() => {
|
|
19279
|
+
const key2 = /^tinycloud:key:(z[^:]+):[^/]+$/.exec(resource);
|
|
19280
|
+
return key2 ? `did:key:${key2[1]}` : void 0;
|
|
19281
|
+
})();
|
|
19282
|
+
if (!owner) throw new Error(`Cannot determine registry owner for ${resource}`);
|
|
19283
|
+
const subject = owner.startsWith("did:pkh:") ? (0, import_sdk_core5.registryOwnerSubjectV1)(owner.slice(owner.lastIndexOf(":") + 1), this.registryChainId) : owner;
|
|
19284
|
+
for (let attempt = 1; ; attempt++) {
|
|
19285
|
+
try {
|
|
19286
|
+
const resolved = await (0, import_sdk_core5.resolveRegistryResource)(subject, resource, access, {
|
|
19287
|
+
registryUrl: this.tinycloudRegistryUrl,
|
|
19288
|
+
registryChainId: this.registryChainId,
|
|
19289
|
+
sequenceStore: this.registrySequenceStore,
|
|
19290
|
+
cacheStore: this.registryCacheStore,
|
|
19291
|
+
onRegistryFallback: this.onRegistryFallback
|
|
19292
|
+
});
|
|
19293
|
+
this.registryVerdict = resolved.verdict;
|
|
19294
|
+
if (resolved.verdict.status === "unregistered") {
|
|
19295
|
+
if (noEntryHosts.length === 0 && (this.autoDiscoverLocalNode ?? true)) {
|
|
19296
|
+
const local = await (0, import_sdk_core5.discoverLocalTinyCloudNode)({
|
|
19297
|
+
localNodeUrl: this.localNodeUrl,
|
|
19298
|
+
localLinkName: this.localLinkName,
|
|
19299
|
+
expectedNodeDid: this.expectedNodeDid,
|
|
19300
|
+
identityStore: this.localNodeIdentityStore
|
|
19301
|
+
});
|
|
19302
|
+
if (local) {
|
|
19303
|
+
(0, import_sdk_core5.warnRegistryDefaultNode)(resolved.verdict, this.registryCacheStore, this.onRegistryFallback);
|
|
19304
|
+
return [{ url: local.url }];
|
|
19305
|
+
}
|
|
19306
|
+
}
|
|
19307
|
+
const host = noEntryHosts[0] ?? this.newUserHost ?? (this.tinycloudFallbackHosts === void 0 ? "https://node.tinycloud.xyz" : this.tinycloudFallbackHosts?.[0]);
|
|
19308
|
+
if (!host || this.newUserHost === null && noEntryHosts.length === 0) throw new import_sdk_core5.NodeNotFoundError(subject, resolved.verdict);
|
|
19309
|
+
const url = (0, import_sdk_core5.exactHttpOrigin)(host, "new-user host");
|
|
19310
|
+
(0, import_sdk_core5.warnRegistryDefaultNode)(resolved.verdict, this.registryCacheStore, this.onRegistryFallback);
|
|
19311
|
+
return [{ url }];
|
|
19312
|
+
}
|
|
19313
|
+
const destinations = resolved.hosts.flatMap((host) => host.urls.map((url) => ({ url, nodeDid: host.nodeDid })));
|
|
19314
|
+
return destinations;
|
|
19315
|
+
} catch (error) {
|
|
19316
|
+
if (!(error instanceof import_sdk_core5.NodeNotFoundError) && !(error instanceof import_sdk_core5.RegistryUnavailableError)) throw error;
|
|
19317
|
+
if (!this.onNodeNotFound) throw error;
|
|
19318
|
+
const decision = await this.onNodeNotFound({ error, attempt });
|
|
19319
|
+
if (decision.action === "retry") continue;
|
|
19320
|
+
if (decision.action === "use-host" && error.verdict?.status === "unregistered") {
|
|
19321
|
+
const url = (0, import_sdk_core5.exactHttpOrigin)(decision.host, "new-user host");
|
|
19322
|
+
(0, import_sdk_core5.warnRegistryDefaultNode)(error.verdict, this.registryCacheStore, this.onRegistryFallback);
|
|
19323
|
+
return [{ url }];
|
|
19324
|
+
}
|
|
19325
|
+
throw error;
|
|
19326
|
+
}
|
|
19328
19327
|
}
|
|
19329
|
-
|
|
19330
|
-
|
|
19331
|
-
|
|
19332
|
-
|
|
19333
|
-
|
|
19334
|
-
|
|
19335
|
-
|
|
19336
|
-
|
|
19337
|
-
|
|
19328
|
+
}
|
|
19329
|
+
get registryRecordPresent() {
|
|
19330
|
+
return this.registryVerdict?.status === "registered";
|
|
19331
|
+
}
|
|
19332
|
+
/** Refresh membership before hosting; a saved no-entry verdict never authorizes a later creation. */
|
|
19333
|
+
async assertMayCreateSpace(spaceId = this._tinyCloudSession?.spaceId, host = this.primaryTinyCloudHost) {
|
|
19334
|
+
if (!spaceId) throw new Error("Must be signed in to create a space");
|
|
19335
|
+
const destinations = await this.resolveResourceDestinations(spaceId, "host");
|
|
19336
|
+
if (!destinations.some((destination) => destination.url === host)) {
|
|
19337
|
+
const subject = (0, import_sdk_core5.parseSpaceUri)(spaceId)?.owner;
|
|
19338
|
+
if (!subject || !this.registryVerdict) throw new Error("Cannot resolve space owner");
|
|
19339
|
+
(0, import_sdk_core5.assertSpaceCreationAllowed)(this.registryVerdict, host, spaceId);
|
|
19338
19340
|
}
|
|
19339
|
-
(0, import_sdk_core5.assertSpaceCreationAllowed)(verdict, this.primaryTinyCloudHost);
|
|
19340
19341
|
}
|
|
19341
19342
|
requireTinyCloudHosts() {
|
|
19342
19343
|
if (!this.tinycloudHosts || this.tinycloudHosts.length === 0) {
|
|
@@ -19653,7 +19654,7 @@ var NodeUserAuthorization = class {
|
|
|
19653
19654
|
if (entry.service !== import_sdk_core5.ENCRYPTION_PERMISSION_SERVICE) {
|
|
19654
19655
|
return true;
|
|
19655
19656
|
}
|
|
19656
|
-
const parsed = entry.path.includes("/") ? (0, import_resource.parseEncryptionResource)(entry.path) : { ...(0,
|
|
19657
|
+
const parsed = entry.path.includes("/") ? (0, import_resource.parseEncryptionResource)(entry.path) : { ...(0, import_sdk_services4.parseNetworkId)(entry.path), kind: "network" };
|
|
19657
19658
|
const sharePrefix = parsed.kind === "prefix" && parsed.network === "default" && parsed.prefix === "share" && entry.actions.length > 0 && entry.actions.every((action) => action === DECRYPT_ACTION || action === KEY_CREATE_ACTION) && didPrincipalMatches(parsed.ownerDid, currentDid);
|
|
19658
19659
|
if (parsed.kind !== "network" && !sharePrefix) {
|
|
19659
19660
|
throw new import_sdk_core5.ManifestValidationError("named keys go in manifest.keys");
|
|
@@ -19782,6 +19783,31 @@ var NodeUserAuthorization = class {
|
|
|
19782
19783
|
checkCurrent();
|
|
19783
19784
|
const host = context?.host ?? this.primaryTinyCloudHost;
|
|
19784
19785
|
const spaceId = context?.spaceId ?? (typeof targetSpaceId === "string" ? targetSpaceId : this._tinyCloudSession.spaceId);
|
|
19786
|
+
const destinations = await this.resolveResourceDestinations(spaceId, "host");
|
|
19787
|
+
if (this.registryVerdict?.status === "registered") {
|
|
19788
|
+
const results = [];
|
|
19789
|
+
for (const destination of destinations) {
|
|
19790
|
+
checkCurrent();
|
|
19791
|
+
try {
|
|
19792
|
+
await (0, import_sdk_services4.verifyResourceDestination)(destination, globalThis.fetch.bind(globalThis));
|
|
19793
|
+
const result = await (0, import_sdk_core5.activateSessionWithHost)(destination.url, this._tinyCloudSession.delegationHeader, signal);
|
|
19794
|
+
results.push(result.skipped?.includes(spaceId) ? { ...result, success: false, status: 403, error: "The session does not activate the requested space" } : result);
|
|
19795
|
+
} catch (error) {
|
|
19796
|
+
if ((0, import_sdk_services4.routingFailure)(error) || signal?.aborted) throw error;
|
|
19797
|
+
throw new import_sdk_services4.NodeNotRespondingError([destination.url], error);
|
|
19798
|
+
}
|
|
19799
|
+
}
|
|
19800
|
+
const failed = results.flatMap((result, index) => result.success ? [] : [{ url: destinations[index].url, status: result.status }]);
|
|
19801
|
+
if (failed.length) {
|
|
19802
|
+
if (destinations.length === 1) return results[0];
|
|
19803
|
+
throw new import_sdk_services4.PartialNodeWriteError(destinations.filter((_, index) => results[index].success).map(({ url }) => url), failed);
|
|
19804
|
+
}
|
|
19805
|
+
return {
|
|
19806
|
+
...results[0],
|
|
19807
|
+
activated: [...new Set(results.flatMap((result) => result.activated ?? []))],
|
|
19808
|
+
skipped: [...new Set(results.flatMap((result) => result.skipped ?? []))]
|
|
19809
|
+
};
|
|
19810
|
+
}
|
|
19785
19811
|
const peerId = await (0, import_sdk_core5.fetchPeerId)(host, spaceId, signal);
|
|
19786
19812
|
checkCurrent();
|
|
19787
19813
|
const siwe = this.wasm.generateHostSIWEMessage(
|
|
@@ -19852,13 +19878,45 @@ var NodeUserAuthorization = class {
|
|
|
19852
19878
|
if (!this._tinyCloudSession) {
|
|
19853
19879
|
throw new Error("Must be signed in to ensure space exists");
|
|
19854
19880
|
}
|
|
19855
|
-
await this.ensureTinyCloudHosts();
|
|
19856
|
-
const host = this.primaryTinyCloudHost;
|
|
19857
19881
|
const primarySpaceId = this._tinyCloudSession.spaceId;
|
|
19858
|
-
const
|
|
19859
|
-
|
|
19860
|
-
|
|
19861
|
-
)
|
|
19882
|
+
const primary = await this.resolveResourceDestinations(primarySpaceId, "read");
|
|
19883
|
+
this.tinycloudHosts = primary.map(({ url }) => url);
|
|
19884
|
+
const targets = new Map(primary.map((destination) => [destination.url, destination]));
|
|
19885
|
+
if (this.registryVerdict?.status === "registered" && this.registryVerdict.record) {
|
|
19886
|
+
const record = this.registryVerdict.record;
|
|
19887
|
+
const resources = Object.keys((0, import_sdk_core5.extractRecapAttenuations)(this._tinyCloudSession.siwe ?? ""));
|
|
19888
|
+
for (const space of record.spaces) {
|
|
19889
|
+
const registeredSpace = (0, import_sdk_core5.parseSpaceUri)(space.space);
|
|
19890
|
+
if (!resources.some((resource) => {
|
|
19891
|
+
const fullSpace = resource.split("/")[0];
|
|
19892
|
+
const requestedSpace = (0, import_sdk_core5.parseSpaceUri)(fullSpace);
|
|
19893
|
+
return fullSpace === space.space || registeredSpace !== null && requestedSpace !== null && registeredSpace.owner === requestedSpace.owner && registeredSpace.name === requestedSpace.name;
|
|
19894
|
+
})) continue;
|
|
19895
|
+
for (const membership of space.nodes) {
|
|
19896
|
+
const node = record.nodes.find((candidate) => candidate.did === membership.did);
|
|
19897
|
+
targets.set(node.url, { url: node.url, nodeDid: node.did });
|
|
19898
|
+
}
|
|
19899
|
+
}
|
|
19900
|
+
if (record.encryptionNode && resources.some((resource) => resource.startsWith("urn:tinycloud:encryption:"))) {
|
|
19901
|
+
const node = record.nodes.find((candidate) => candidate.did === record.encryptionNode);
|
|
19902
|
+
targets.set(node.url, { url: node.url, nodeDid: node.did });
|
|
19903
|
+
}
|
|
19904
|
+
}
|
|
19905
|
+
let result;
|
|
19906
|
+
for (const destination of targets.values()) {
|
|
19907
|
+
await (0, import_sdk_services4.verifyResourceDestination)(destination, globalThis.fetch.bind(globalThis));
|
|
19908
|
+
let activated;
|
|
19909
|
+
try {
|
|
19910
|
+
activated = await (0, import_sdk_core5.activateSessionWithHost)(destination.url, this._tinyCloudSession.delegationHeader);
|
|
19911
|
+
} catch (error) {
|
|
19912
|
+
throw new import_sdk_services4.NodeNotRespondingError([destination.url], error);
|
|
19913
|
+
}
|
|
19914
|
+
if (!activated.success && activated.status !== 404) {
|
|
19915
|
+
throw Object.assign(new Error(`Failed to activate session: ${describeHostFailure(activated)}`), { cause: activated });
|
|
19916
|
+
}
|
|
19917
|
+
if (destination.url === primary[0].url) result = activated;
|
|
19918
|
+
}
|
|
19919
|
+
if (!result) throw new Error("Primary space activation did not return a result");
|
|
19862
19920
|
this.recordActivationSkippedSpaces(result, primarySpaceId);
|
|
19863
19921
|
if (!result.success && result.status !== 404) {
|
|
19864
19922
|
throw Object.assign(
|
|
@@ -19906,7 +19964,7 @@ var NodeUserAuthorization = class {
|
|
|
19906
19964
|
/** {@link assertMayCreateSpace}, reporting a refusal to the creation handler before rethrowing it. */
|
|
19907
19965
|
async guardSpaceCreation(handler, context) {
|
|
19908
19966
|
try {
|
|
19909
|
-
await this.assertMayCreateSpace();
|
|
19967
|
+
await this.assertMayCreateSpace(context.spaceId, context.host);
|
|
19910
19968
|
} catch (error) {
|
|
19911
19969
|
const failure = error instanceof Error ? error : new Error(String(error));
|
|
19912
19970
|
handler.onSpaceCreationFailed?.(context, failure);
|
|
@@ -21813,6 +21871,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21813
21871
|
* ```
|
|
21814
21872
|
*/
|
|
21815
21873
|
constructor(config = {}) {
|
|
21874
|
+
this.registryRefreshOwners = /* @__PURE__ */ new Set();
|
|
21816
21875
|
this.signer = null;
|
|
21817
21876
|
this.auth = null;
|
|
21818
21877
|
this.consumedOpenKeyPendings = /* @__PURE__ */ new WeakSet();
|
|
@@ -21976,8 +22035,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21976
22035
|
this.config = {
|
|
21977
22036
|
...config,
|
|
21978
22037
|
host: config.host ?? DEFAULT_HOST,
|
|
22038
|
+
registryPolicy: "fail-closed",
|
|
21979
22039
|
// One store for every authorization this client creates.
|
|
21980
|
-
registrySequenceStore: config.registrySequenceStore ?? (0, import_sdk_core10.createInMemoryRegistrySequenceStore)()
|
|
22040
|
+
registrySequenceStore: config.registrySequenceStore ?? (0, import_sdk_core10.createInMemoryRegistrySequenceStore)(),
|
|
22041
|
+
registryCacheStore: config.registryCacheStore ?? (0, import_sdk_core10.createInMemoryRegistryCacheStore)()
|
|
21981
22042
|
};
|
|
21982
22043
|
if (this.config.replication?.enabled) {
|
|
21983
22044
|
const runtime = getNodeReplicationLoaders().runtime().then(({ ReplicationRuntime: ReplicationRuntime2 }) => {
|
|
@@ -22281,7 +22342,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22281
22342
|
// A session saved but never registered on this node is refused: it registers once.
|
|
22282
22343
|
activate: (signal) => {
|
|
22283
22344
|
assertCurrent();
|
|
22284
|
-
|
|
22345
|
+
const activationSignal = AbortSignal.any([signal, graph.signal]);
|
|
22346
|
+
if (primary && primary.delegationCid === session.delegationCid) {
|
|
22347
|
+
return this.activateSignedSession(primary, primary.siwe, host, activationSignal);
|
|
22348
|
+
}
|
|
22349
|
+
return this.activateResourceSession(session.delegationHeader, [spaceId], host, activationSignal);
|
|
22285
22350
|
}
|
|
22286
22351
|
});
|
|
22287
22352
|
assertCurrent();
|
|
@@ -22417,14 +22482,38 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22417
22482
|
get requests() {
|
|
22418
22483
|
return this._requestLog === void 0 ? void 0 : (0, import_requestLog2.readOnlyRequestLog)(this._requestLog);
|
|
22419
22484
|
}
|
|
22420
|
-
|
|
22485
|
+
throwRegistryRefusal(status, text) {
|
|
22486
|
+
if (status !== 403 && status !== 503 || !text.startsWith("registry_unavailable:") && !text.startsWith("registry_hosting_denied:")) return;
|
|
22487
|
+
const code = status === 503 ? "registry_unavailable" : "node_registry_entry_exists";
|
|
22488
|
+
throw Object.assign(new Error(status === 503 ? "The location registry is unavailable for this resource." : "The registry does not authorize this node for the requested resource."), { code, meta: { status } });
|
|
22489
|
+
}
|
|
22490
|
+
createServiceGraphLifetime(session) {
|
|
22491
|
+
const routedFetch = (0, import_sdk_services5.createResourceRoutingFetch)(
|
|
22492
|
+
async (url, init2) => {
|
|
22493
|
+
try {
|
|
22494
|
+
const response = await globalThis.fetch(url, init2);
|
|
22495
|
+
if (response.status === 403 || response.status === 503) {
|
|
22496
|
+
this.throwRegistryRefusal(response.status, await response.clone().text());
|
|
22497
|
+
}
|
|
22498
|
+
return response;
|
|
22499
|
+
} catch (error) {
|
|
22500
|
+
if ((0, import_sdk_services5.routingFailure)(error)) throw error;
|
|
22501
|
+
if (new URL(url).pathname.startsWith("/encryption/") && !init2?.signal?.aborted) {
|
|
22502
|
+
throw new import_sdk_services5.NodeNotRespondingError([new URL(url).origin], error);
|
|
22503
|
+
}
|
|
22504
|
+
throw error;
|
|
22505
|
+
}
|
|
22506
|
+
},
|
|
22507
|
+
{
|
|
22508
|
+
resolveResource: (resource, access) => this.routingDestinations(resource, access),
|
|
22509
|
+
bindAudience: (authorization, nodeDid) => this.bindRoutedAudience(authorization, nodeDid, session),
|
|
22510
|
+
verifyDestination: (target) => (0, import_sdk_services5.verifyResourceDestination)(target, globalThis.fetch.bind(globalThis))
|
|
22511
|
+
}
|
|
22512
|
+
);
|
|
22421
22513
|
return new ServiceGraphLifetime(
|
|
22422
22514
|
this.invokeWithRuntimePermissions,
|
|
22423
22515
|
this.invokeAnyWithRuntimePermissions,
|
|
22424
|
-
|
|
22425
|
-
// signal while preserving the SDK's existing injectable global fetch
|
|
22426
|
-
// behavior (including adapters that install it after construction).
|
|
22427
|
-
(url, init2) => globalThis.fetch(url, init2),
|
|
22516
|
+
routedFetch,
|
|
22428
22517
|
(context) => {
|
|
22429
22518
|
this.storageFull.observe(context);
|
|
22430
22519
|
if (this._requestLog) (0, import_requestLog2.observeReplicaReads)(context, this._requestLog);
|
|
@@ -22432,6 +22521,75 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22432
22521
|
this._requestLog
|
|
22433
22522
|
);
|
|
22434
22523
|
}
|
|
22524
|
+
async routingDestinations(resource, access, noEntryHosts) {
|
|
22525
|
+
const session = this.currentTinyCloudSession();
|
|
22526
|
+
if (session) this.refreshRegistryOwner((0, import_sdk_core10.pkhDid)(session.address, session.chainId));
|
|
22527
|
+
if (this.auth) return this.auth.resolveResourceDestinations(resource, access, noEntryHosts);
|
|
22528
|
+
const owner = resource.startsWith("urn:tinycloud:encryption:") ? (0, import_sdk_core10.parseNetworkId)(resource.split("/")[0]).ownerDid : (0, import_sdk_core10.parseSpaceUri)(resource)?.owner ?? (() => {
|
|
22529
|
+
const key2 = /^tinycloud:key:(z[^:]+):[^/]+$/.exec(resource);
|
|
22530
|
+
return key2 ? `did:key:${key2[1]}` : void 0;
|
|
22531
|
+
})();
|
|
22532
|
+
if (!owner) throw new Error(`Cannot determine registry owner for ${resource}`);
|
|
22533
|
+
const subject = owner.startsWith("did:pkh:") ? (0, import_sdk_core10.pkhDid)(owner.slice(owner.lastIndexOf(":") + 1), this.config.registryChainId ?? 1) : owner;
|
|
22534
|
+
const resolved = await (0, import_sdk_core10.resolveRegistryResource)(subject, resource, access, {
|
|
22535
|
+
registryUrl: this.config.tinycloudRegistryUrl,
|
|
22536
|
+
registryChainId: this.config.registryChainId,
|
|
22537
|
+
sequenceStore: this.config.registrySequenceStore,
|
|
22538
|
+
cacheStore: this.config.registryCacheStore,
|
|
22539
|
+
onRegistryFallback: this.config.onRegistryFallback
|
|
22540
|
+
});
|
|
22541
|
+
if (resolved.verdict.status === "unregistered") {
|
|
22542
|
+
const hint = noEntryHosts === void 0 ? this.explicitHost ?? this.config.host : noEntryHosts[0];
|
|
22543
|
+
const host = hint ?? this.config.newUserHost ?? (this.config.tinycloudFallbackHosts === void 0 ? DEFAULT_HOST : this.config.tinycloudFallbackHosts?.[0]);
|
|
22544
|
+
if (!host || !hint && this.config.newUserHost === null) throw new import_sdk_core10.NodeNotFoundError(subject, resolved.verdict);
|
|
22545
|
+
const url = (0, import_sdk_core10.exactHttpOrigin)(host, "new-user host");
|
|
22546
|
+
(0, import_sdk_core10.warnRegistryDefaultNode)(resolved.verdict, this.config.registryCacheStore, this.config.onRegistryFallback);
|
|
22547
|
+
return [{ url }];
|
|
22548
|
+
}
|
|
22549
|
+
const destinations = resolved.hosts.flatMap((host) => host.urls.map((url) => ({ url, nodeDid: host.nodeDid })));
|
|
22550
|
+
return destinations;
|
|
22551
|
+
}
|
|
22552
|
+
/** Transport hints cannot override verified full-resource registry routing. */
|
|
22553
|
+
async resolveRegisteredDelegationHost(permissions, noEntryHost) {
|
|
22554
|
+
const resources = /* @__PURE__ */ new Map();
|
|
22555
|
+
let hasData = false;
|
|
22556
|
+
for (const permission of permissions) {
|
|
22557
|
+
const encryption = this.isEncryptionNetworkOperation(this.invocationServiceName(permission.service), permission.path, permission.space);
|
|
22558
|
+
const resource = encryption ? permission.path.split("/")[0] : permission.space;
|
|
22559
|
+
if (!resource) throw new import_sdk_services5.ResourceNotRoutedError("delegation");
|
|
22560
|
+
resources.set(resource, encryption ? "encryption" : "host");
|
|
22561
|
+
hasData || (hasData = !encryption);
|
|
22562
|
+
}
|
|
22563
|
+
let dataHost;
|
|
22564
|
+
let encryptionHost;
|
|
22565
|
+
let unserved;
|
|
22566
|
+
for (const [resource, access] of resources) {
|
|
22567
|
+
try {
|
|
22568
|
+
const destinations = await this.routingDestinations(resource, access, [noEntryHost]);
|
|
22569
|
+
if (destinations.some(({ nodeDid }) => nodeDid === void 0)) return void 0;
|
|
22570
|
+
if (access === "host") dataHost ?? (dataHost = destinations[0]?.url);
|
|
22571
|
+
else encryptionHost ?? (encryptionHost = destinations[0]?.url);
|
|
22572
|
+
} catch (error) {
|
|
22573
|
+
if (!(error instanceof import_sdk_core10.NodeNotFoundError) || error.verdict.status !== "registered") throw error;
|
|
22574
|
+
unserved ?? (unserved = error);
|
|
22575
|
+
}
|
|
22576
|
+
}
|
|
22577
|
+
const host = hasData ? dataHost : encryptionHost;
|
|
22578
|
+
if (!host) throw unserved ?? new import_sdk_services5.ResourceNotRoutedError("delegation");
|
|
22579
|
+
return host;
|
|
22580
|
+
}
|
|
22581
|
+
async bindRoutedAudience(authorization, nodeDid, stagedSession) {
|
|
22582
|
+
const payload = JSON.parse(new TextDecoder().decode(base64UrlDecode(authorization.split(".")[1])));
|
|
22583
|
+
const issuer = typeof payload === "object" && payload !== null && "iss" in payload ? payload.iss : void 0;
|
|
22584
|
+
const session = [
|
|
22585
|
+
stagedSession,
|
|
22586
|
+
this._serviceContext?.session,
|
|
22587
|
+
this.auth?.tinyCloudSession,
|
|
22588
|
+
...this.runtimePermissionGrants.map((grant) => grant.session)
|
|
22589
|
+
].find((candidate) => candidate?.verificationMethod === issuer);
|
|
22590
|
+
if (!session) throw new Error("Invocation signing session is not active");
|
|
22591
|
+
return rewriteInvocationAudience(authorization, nodeDid, session.jwk);
|
|
22592
|
+
}
|
|
22435
22593
|
syncResolvedHostFromAuth() {
|
|
22436
22594
|
const host = this.auth?.hosts[0];
|
|
22437
22595
|
if (host) {
|
|
@@ -22545,6 +22703,29 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22545
22703
|
const session = this.currentTinyCloudSession();
|
|
22546
22704
|
return session?.siwe ? this.projectSignedRecapCapabilities(session.siwe) : [];
|
|
22547
22705
|
}
|
|
22706
|
+
/** Start one background refresh for each owner derived from verified authority. */
|
|
22707
|
+
refreshRegistryForCapabilities(permissions) {
|
|
22708
|
+
for (const permission of permissions) {
|
|
22709
|
+
try {
|
|
22710
|
+
const owner = permission.service === "tinycloud.encryption" && permission.path.startsWith("urn:tinycloud:encryption:") ? (0, import_sdk_core10.parseNetworkId)(permission.path.split("/")[0]).ownerDid : permission.space ? this.ownerDidFromSpaceId(permission.space) : void 0;
|
|
22711
|
+
if (owner) this.refreshRegistryOwner(owner);
|
|
22712
|
+
} catch {
|
|
22713
|
+
}
|
|
22714
|
+
}
|
|
22715
|
+
}
|
|
22716
|
+
refreshRegistryOwner(owner) {
|
|
22717
|
+
if (this.config.tinycloudRegistryUrl === null) return;
|
|
22718
|
+
const subject = owner.startsWith("did:pkh:") ? (0, import_sdk_core10.pkhDid)(owner.slice(owner.lastIndexOf(":") + 1), this.config.registryChainId ?? 1) : owner;
|
|
22719
|
+
const key2 = (0, import_sdk_core10.registryOwnerKeyV2)(subject);
|
|
22720
|
+
if (this.registryRefreshOwners.has(key2)) return;
|
|
22721
|
+
this.registryRefreshOwners.add(key2);
|
|
22722
|
+
void (0, import_sdk_core10.refreshOwnerRegistry)(subject, {
|
|
22723
|
+
registryUrl: this.config.tinycloudRegistryUrl,
|
|
22724
|
+
registryChainId: this.config.registryChainId,
|
|
22725
|
+
sequenceStore: this.config.registrySequenceStore,
|
|
22726
|
+
cacheStore: this.config.registryCacheStore
|
|
22727
|
+
}).catch(() => void 0);
|
|
22728
|
+
}
|
|
22548
22729
|
/** Normalize signed capabilities without collapsing nested encryption into raw authority. */
|
|
22549
22730
|
projectSignedRecapCapabilities(siwe) {
|
|
22550
22731
|
const projected = this.parseRecapWithCaveats(siwe).map((entry) => {
|
|
@@ -22976,6 +23157,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22976
23157
|
const primarySession = this.currentTinyCloudSession();
|
|
22977
23158
|
if (primarySession) {
|
|
22978
23159
|
this.registerPrimarySessionGrant(primarySession);
|
|
23160
|
+
this.refreshRegistryOwner((0, import_sdk_core10.pkhDid)(primarySession.address, primarySession.chainId));
|
|
23161
|
+
this.refreshRegistryForCapabilities(this.getVerifiedSessionCapabilities());
|
|
22979
23162
|
if (this.auth?.spaceHosting === "unknown") {
|
|
22980
23163
|
await this.checkSpaceHosting();
|
|
22981
23164
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
@@ -23198,8 +23381,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23198
23381
|
const primarySession = auth.tinyCloudSession;
|
|
23199
23382
|
const defaultSpaceId = this.ownedSpaceId("default");
|
|
23200
23383
|
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === import_sdk_core10.BOOTSTRAP_SESSION_REQUESTS.default;
|
|
23201
|
-
|
|
23202
|
-
await this.assertMayCreateSpace();
|
|
23384
|
+
for (const step of steps) {
|
|
23385
|
+
if (step.kind === "host") await this.assertMayCreateSpace(step.spaceId);
|
|
23203
23386
|
}
|
|
23204
23387
|
for (const step of steps) {
|
|
23205
23388
|
if (step.kind !== "session") continue;
|
|
@@ -23248,10 +23431,20 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23248
23431
|
if (!session) {
|
|
23249
23432
|
throw new Error(`Missing bootstrap session for ${step.space}`);
|
|
23250
23433
|
}
|
|
23251
|
-
const
|
|
23252
|
-
|
|
23253
|
-
|
|
23254
|
-
|
|
23434
|
+
const destinations = await this.routingDestinations(step.spaceId, "host");
|
|
23435
|
+
let activated;
|
|
23436
|
+
for (const destination of destinations) {
|
|
23437
|
+
try {
|
|
23438
|
+
await (0, import_sdk_services5.verifyResourceDestination)(destination, globalThis.fetch.bind(globalThis));
|
|
23439
|
+
const result = await (0, import_sdk_core10.activateSessionWithHost)(destination.url, session.delegationHeader, graph.signal);
|
|
23440
|
+
if (!result.success) throw Object.assign(new Error("Bootstrap activation failed"), { cause: result });
|
|
23441
|
+
activated = result;
|
|
23442
|
+
} catch (error) {
|
|
23443
|
+
graph.assertActive();
|
|
23444
|
+
throw error;
|
|
23445
|
+
}
|
|
23446
|
+
}
|
|
23447
|
+
if (!activated) throw new Error("Bootstrap space has no destination");
|
|
23255
23448
|
graph.assertActive();
|
|
23256
23449
|
if (!activated.success || activated.skipped?.includes(step.spaceId)) {
|
|
23257
23450
|
throw Object.assign(
|
|
@@ -23581,7 +23774,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23581
23774
|
if (!this.currentSessionCoversAccountRegistry()) {
|
|
23582
23775
|
if (!_TinyCloudNode.accountRegistrySkipLogged) {
|
|
23583
23776
|
_TinyCloudNode.accountRegistrySkipLogged = true;
|
|
23584
|
-
|
|
23777
|
+
import_sdk_services6.tinyCloudDebugLogger.log("registry.skip");
|
|
23585
23778
|
}
|
|
23586
23779
|
return;
|
|
23587
23780
|
}
|
|
@@ -23834,6 +24027,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23834
24027
|
if (!session) {
|
|
23835
24028
|
throw new Error("Owned space hosting requires an active session");
|
|
23836
24029
|
}
|
|
24030
|
+
await this.assertMayCreateSpace(spaceId);
|
|
24031
|
+
if (this.auth.registryRecordPresent) {
|
|
24032
|
+
const hosted = await this.hostOwnedSpaceOnce(spaceId, signal);
|
|
24033
|
+
if (!hosted.success) throw Object.assign(new Error(`Failed to activate listed space ${spaceId}: ${describeHostFailure2(hosted)}`), { cause: hosted });
|
|
24034
|
+
if (this.auth.tinyCloudSession === session) this.confirmedHostedSpaceIds.add(spaceId);
|
|
24035
|
+
return;
|
|
24036
|
+
}
|
|
23837
24037
|
if (this.confirmedHostedSpaceIds.has(spaceId) || this.hostedOwnedSpaceIds.has(spaceId)) {
|
|
23838
24038
|
return;
|
|
23839
24039
|
}
|
|
@@ -23852,7 +24052,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23852
24052
|
{ cause: activation }
|
|
23853
24053
|
);
|
|
23854
24054
|
}
|
|
23855
|
-
await this.assertMayCreateSpace();
|
|
24055
|
+
await this.assertMayCreateSpace(spaceId);
|
|
23856
24056
|
if (signal?.aborted) throw signal.reason;
|
|
23857
24057
|
const created = await this.hostOwnedSpaceOnce(spaceId, signal);
|
|
23858
24058
|
if (!created.success) {
|
|
@@ -23913,17 +24113,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23913
24113
|
{ cause: hosted }
|
|
23914
24114
|
);
|
|
23915
24115
|
}
|
|
23916
|
-
|
|
23917
|
-
|
|
23918
|
-
|
|
23919
|
-
|
|
23920
|
-
if (!activation.success || activation.skipped?.includes(spaceId)) {
|
|
23921
|
-
throw Object.assign(
|
|
23922
|
-
new Error(
|
|
23923
|
-
`Failed to activate session for owned space ${spaceId}: ${activation.success ? "space was skipped" : describeHostFailure2(activation)}`
|
|
23924
|
-
),
|
|
23925
|
-
{ cause: activation }
|
|
24116
|
+
if (!this.auth.registryRecordPresent) {
|
|
24117
|
+
const activation = await (0, import_sdk_core10.activateSessionWithHost)(
|
|
24118
|
+
host,
|
|
24119
|
+
session.delegationHeader
|
|
23926
24120
|
);
|
|
24121
|
+
if (!activation.success || activation.skipped?.includes(spaceId)) {
|
|
24122
|
+
throw Object.assign(
|
|
24123
|
+
new Error(
|
|
24124
|
+
`Failed to activate session for owned space ${spaceId}: ${activation.success ? "space was skipped" : describeHostFailure2(activation)}`
|
|
24125
|
+
),
|
|
24126
|
+
{ cause: activation }
|
|
24127
|
+
);
|
|
24128
|
+
}
|
|
23927
24129
|
}
|
|
23928
24130
|
if (this.auth?.tinyCloudSession === session) this.hostedOwnedSpaceIds.add(spaceId);
|
|
23929
24131
|
try {
|
|
@@ -23967,11 +24169,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23967
24169
|
* session's recap doesn't cover it and the registry has no record; the host
|
|
23968
24170
|
* SIWE is idempotent server-side. Must be called after {@link signIn}.
|
|
23969
24171
|
*
|
|
23970
|
-
*
|
|
23971
|
-
*
|
|
23972
|
-
*
|
|
23973
|
-
* verdict. {@link hostOwnedSpace} itself is an explicit action and is not
|
|
23974
|
-
* guarded.
|
|
24172
|
+
* Current signed per-space membership is checked before both automatic and
|
|
24173
|
+
* explicit hosting. Registered replicas use the session grant; no-entry
|
|
24174
|
+
* onboarding retains the host-SIWE flow.
|
|
23975
24175
|
*
|
|
23976
24176
|
* @param name - The owned space name (e.g. `"secrets"`).
|
|
23977
24177
|
* @returns The hosted owned-space URI.
|
|
@@ -23981,27 +24181,20 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23981
24181
|
throw new Error("Not signed in. Call signIn() first.");
|
|
23982
24182
|
}
|
|
23983
24183
|
const spaceId = this.ownedSpaceId(name);
|
|
24184
|
+
await this.assertMayCreateSpace(spaceId);
|
|
23984
24185
|
if (this.hostedOwnedSpaceIds.has(spaceId) || await this.isOwnedSpaceRegistered(spaceId)) {
|
|
23985
24186
|
return spaceId;
|
|
23986
24187
|
}
|
|
23987
|
-
await this.assertMayCreateSpace();
|
|
23988
24188
|
return this.hostOwnedSpace(name);
|
|
23989
24189
|
}
|
|
23990
|
-
/**
|
|
23991
|
-
|
|
23992
|
-
|
|
23993
|
-
* {@link ensurePublicSpace}. Only `registryPolicy: "fail-closed"` consults
|
|
23994
|
-
* the registry ({@link NodeUserAuthorization.assertMayCreateSpace}); the
|
|
23995
|
-
* default policy performs no lookup.
|
|
23996
|
-
*/
|
|
23997
|
-
async assertMayCreateSpace() {
|
|
23998
|
-
if (this.config.registryPolicy !== "fail-closed") return;
|
|
23999
|
-
await this.auth.assertMayCreateSpace();
|
|
24190
|
+
/** Refresh full-space membership before any automatic or explicit hosting. */
|
|
24191
|
+
async assertMayCreateSpace(spaceId) {
|
|
24192
|
+
await this.routingDestinations(spaceId, "host");
|
|
24000
24193
|
}
|
|
24001
24194
|
/** Registry-policy settings shared by every authorization this client creates. */
|
|
24002
24195
|
registryPolicyConfig() {
|
|
24003
|
-
const { registryPolicy, newUserHost, registryChainId, registrySequenceStore, onNodeNotFound } = this.config;
|
|
24004
|
-
return { registryPolicy, newUserHost, registryChainId, registrySequenceStore, onNodeNotFound };
|
|
24196
|
+
const { registryPolicy, newUserHost, registryChainId, registrySequenceStore, registryCacheStore, onNodeNotFound, onRegistryFallback } = this.config;
|
|
24197
|
+
return { registryPolicy, newUserHost, registryChainId, registrySequenceStore, registryCacheStore, onNodeNotFound, onRegistryFallback };
|
|
24005
24198
|
}
|
|
24006
24199
|
/**
|
|
24007
24200
|
* Submit the host delegation for an owned space, sharing one in-flight
|
|
@@ -24207,12 +24400,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24207
24400
|
}
|
|
24208
24401
|
stagedSessionExpiry = signedExpiry ?? persistedPolicyExpiry ?? persistedExpiry(void 0);
|
|
24209
24402
|
}
|
|
24210
|
-
const
|
|
24211
|
-
|
|
24212
|
-
|
|
24213
|
-
sessionData.chainId
|
|
24214
|
-
);
|
|
24215
|
-
const stagedHost = resolvedHost ?? this.config.host;
|
|
24403
|
+
const restoreHints = this.explicitHost ? [this.explicitHost] : sessionData.tinycloudHosts ?? [];
|
|
24404
|
+
const resolvedHost = this.config.replication?.enabled ? (await this.routingDestinations(sessionData.spaceId, "read", restoreHints))[0]?.url : void 0;
|
|
24405
|
+
const stagedHost = resolvedHost ?? (0, import_sdk_core10.exactHttpOrigin)(restoreHints[0] ?? this.config.host, "restored host hint");
|
|
24216
24406
|
let restoredNodeFeatures;
|
|
24217
24407
|
let replicaProtocolMismatch = false;
|
|
24218
24408
|
if (this.config.replication?.enabled) {
|
|
@@ -24329,7 +24519,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24329
24519
|
this.sessionManager = stagedManager;
|
|
24330
24520
|
this.sessionKeyId = stagedKeyId;
|
|
24331
24521
|
this.sessionKeyJwk = stagedJwk;
|
|
24332
|
-
|
|
24522
|
+
this.config.host = stagedHost;
|
|
24333
24523
|
if (spaceOwnerKey(serviceSession.spaceId) !== this.currentStorageOwner()) {
|
|
24334
24524
|
this.storageFull.clear();
|
|
24335
24525
|
this._requestLog?.clear();
|
|
@@ -24396,6 +24586,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24396
24586
|
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
24397
24587
|
this.assertSessionEpoch(epoch, "Session restore");
|
|
24398
24588
|
}
|
|
24589
|
+
if (this.config.replication?.enabled) {
|
|
24590
|
+
if (stagedAddress !== void 0) this.refreshRegistryOwner((0, import_sdk_core10.pkhDid)(stagedAddress, stagedChainId));
|
|
24591
|
+
this.refreshRegistryForCapabilities(this.getVerifiedSessionCapabilities());
|
|
24592
|
+
}
|
|
24399
24593
|
}
|
|
24400
24594
|
stagePrimarySessionState(session, verificationMethod, host, sessionExpiry, recap) {
|
|
24401
24595
|
if (!session?.siwe) return { cache: void 0, grants: [] };
|
|
@@ -24444,7 +24638,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24444
24638
|
};
|
|
24445
24639
|
}
|
|
24446
24640
|
stageRestoredServiceGraph(input) {
|
|
24447
|
-
const graph = this.createServiceGraphLifetime();
|
|
24641
|
+
const graph = this.createServiceGraphLifetime(input.serviceSession);
|
|
24448
24642
|
const core = this.auth ? new import_sdk_core10.TinyCloud(this.auth, {
|
|
24449
24643
|
invokeAny: graph.invokeAny,
|
|
24450
24644
|
telemetry: this.config.telemetry,
|
|
@@ -24669,56 +24863,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24669
24863
|
spaceService.updateConfig({ sharingService });
|
|
24670
24864
|
return { core, graph, serviceContext, kv, sql, duckdb, hooks, vault, encryption, capabilityRegistry, keyProvider, sharingService, delegationManager, spaceService };
|
|
24671
24865
|
}
|
|
24672
|
-
/**
|
|
24673
|
-
* Resolve the host a restored session should target.
|
|
24674
|
-
*
|
|
24675
|
-
* Mirrors fresh sign-in host resolution but for the restore path:
|
|
24676
|
-
* an explicit/pinned host always wins, then the hosts the session was
|
|
24677
|
-
* persisted with, then a lazy registry/fallback resolution for sessions
|
|
24678
|
-
* that predate the persisted `tinycloudHosts` field. Returns `undefined`
|
|
24679
|
-
* only when there's nothing to resolve from (no explicit host, no
|
|
24680
|
-
* persisted hosts, and no address/chainId) — in which case the existing
|
|
24681
|
-
* `config.host` (default) is left in place.
|
|
24682
|
-
*
|
|
24683
|
-
* Resolution failures are surfaced, not swallowed: a genuinely broken
|
|
24684
|
-
* registry lookup throws rather than silently falling back to a wrong host.
|
|
24685
|
-
*/
|
|
24686
|
-
async resolveRestoredHost(persistedHosts, address, chainId) {
|
|
24687
|
-
if (this.explicitHost) {
|
|
24688
|
-
return this.explicitHost;
|
|
24689
|
-
}
|
|
24690
|
-
if (persistedHosts && persistedHosts.length > 0) {
|
|
24691
|
-
return persistedHosts[0];
|
|
24692
|
-
}
|
|
24693
|
-
if (address === void 0 || chainId === void 0) {
|
|
24694
|
-
return void 0;
|
|
24695
|
-
}
|
|
24696
|
-
if (this.config.registryPolicy === "fail-closed") {
|
|
24697
|
-
const resolved2 = await (0, import_sdk_core10.resolveFailClosedTinyCloudHosts)(address, {
|
|
24698
|
-
registryUrl: this.config.tinycloudRegistryUrl,
|
|
24699
|
-
registryChainId: this.config.registryChainId,
|
|
24700
|
-
newUserHost: this.config.newUserHost,
|
|
24701
|
-
sequenceStore: this.config.registrySequenceStore,
|
|
24702
|
-
onNodeNotFound: this.config.onNodeNotFound,
|
|
24703
|
-
autoDiscoverLocalNode: this.config.autoDiscoverLocalNode,
|
|
24704
|
-
localNodeUrl: this.config.localNodeUrl,
|
|
24705
|
-
localLinkName: this.config.localLinkName,
|
|
24706
|
-
expectedNodeDid: this.config.expectedNodeDid,
|
|
24707
|
-
localNodeIdentityStore: this.config.localNodeIdentityStore
|
|
24708
|
-
});
|
|
24709
|
-
return resolved2.hosts[0];
|
|
24710
|
-
}
|
|
24711
|
-
const resolved = await (0, import_sdk_core10.resolveTinyCloudHosts)((0, import_sdk_core10.pkhDid)(address, chainId), {
|
|
24712
|
-
registryUrl: this.config.tinycloudRegistryUrl,
|
|
24713
|
-
fallbackHosts: this.config.tinycloudFallbackHosts,
|
|
24714
|
-
autoDiscoverLocalNode: this.config.autoDiscoverLocalNode,
|
|
24715
|
-
localNodeUrl: this.config.localNodeUrl,
|
|
24716
|
-
localLinkName: this.config.localLinkName,
|
|
24717
|
-
expectedNodeDid: this.config.expectedNodeDid,
|
|
24718
|
-
localNodeIdentityStore: this.config.localNodeIdentityStore
|
|
24719
|
-
});
|
|
24720
|
-
return resolved.hosts[0];
|
|
24721
|
-
}
|
|
24722
24866
|
/**
|
|
24723
24867
|
* Resolve the currently-active TinyCloudSession, preferring the auth
|
|
24724
24868
|
* layer's value (wallet mode) and falling back to the node-level
|
|
@@ -25193,10 +25337,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25193
25337
|
* second time. Only a value recorded for this exact host qualifies; older
|
|
25194
25338
|
* nodes that omit `nodeId` fall through to the fetch.
|
|
25195
25339
|
*/
|
|
25196
|
-
async fetchNodeId() {
|
|
25197
|
-
const cached = this.auth?.nodeIdForHost(
|
|
25340
|
+
async fetchNodeId(host = this.config.host) {
|
|
25341
|
+
const cached = this.auth?.nodeIdForHost(host);
|
|
25198
25342
|
if (cached) return cached;
|
|
25199
|
-
const response = await fetch(`${
|
|
25343
|
+
const response = await fetch(`${host}/info`);
|
|
25200
25344
|
if (!response.ok) {
|
|
25201
25345
|
throw await (0, import_sdk_core10.httpResponseError)(response, "Failed to fetch node info");
|
|
25202
25346
|
}
|
|
@@ -25244,10 +25388,24 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25244
25388
|
)
|
|
25245
25389
|
};
|
|
25246
25390
|
}
|
|
25247
|
-
async
|
|
25248
|
-
const
|
|
25249
|
-
|
|
25250
|
-
);
|
|
25391
|
+
async encryptionDestination(networkId) {
|
|
25392
|
+
const destination = (await this.routingDestinations(networkId, "encryption"))[0];
|
|
25393
|
+
if (!destination) throw new Error("No encryption destination is registered");
|
|
25394
|
+
await (0, import_sdk_services5.verifyResourceDestination)(destination, globalThis.fetch.bind(globalThis));
|
|
25395
|
+
return { ...destination, nodeDid: destination.nodeDid ?? await this.fetchNodeId(destination.url) };
|
|
25396
|
+
}
|
|
25397
|
+
async fetchEncryptionNetworkAt(host, networkId, fetchFn, callerSignal) {
|
|
25398
|
+
let response;
|
|
25399
|
+
const timeout = AbortSignal.timeout(5e3);
|
|
25400
|
+
try {
|
|
25401
|
+
response = await fetchFn(`${host}/encryption/networks/${encodeURIComponent(networkId)}`, {
|
|
25402
|
+
signal: callerSignal ? AbortSignal.any([callerSignal, timeout]) : timeout,
|
|
25403
|
+
redirect: "error"
|
|
25404
|
+
});
|
|
25405
|
+
} catch (error) {
|
|
25406
|
+
if ((0, import_sdk_services5.routingFailure)(error) || callerSignal?.aborted || !timeout.aborted && error instanceof Error && error.name === "AbortError") throw error;
|
|
25407
|
+
throw new import_sdk_services5.NodeNotRespondingError([host], error);
|
|
25408
|
+
}
|
|
25251
25409
|
if (response.status === 404) return null;
|
|
25252
25410
|
if (!response.ok) {
|
|
25253
25411
|
throw await (0, import_sdk_core10.httpResponseError)(response, `Failed to fetch encryption network ${networkId}`);
|
|
@@ -25257,18 +25415,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25257
25415
|
}
|
|
25258
25416
|
createEncryptionService(binding) {
|
|
25259
25417
|
const graph = binding?.graph ?? this._serviceGraph;
|
|
25260
|
-
const host = binding?.host ?? this.config.host;
|
|
25261
25418
|
const session = binding?.session ?? this.requireEncryptionSession();
|
|
25262
25419
|
const did = binding?.did ?? this.did;
|
|
25263
25420
|
const address = binding?.address ?? this._address;
|
|
25264
25421
|
const chainId = binding?.chainId ?? this._chainId;
|
|
25265
25422
|
const crypto3 = this.createEncryptionCrypto();
|
|
25266
|
-
const descriptorCache = /* @__PURE__ */ new Map();
|
|
25267
25423
|
const transport = {
|
|
25268
|
-
postDecrypt: async ({ networkId, authorization, canonicalBody, signal }) => {
|
|
25424
|
+
postDecrypt: async ({ targetNode, networkId, authorization, canonicalBody, signal }) => {
|
|
25269
25425
|
graph.assertActive();
|
|
25426
|
+
const destination = await this.encryptionDestination(networkId);
|
|
25427
|
+
if (destination.nodeDid !== targetNode) throw new import_sdk_services5.NodeIdentityMismatchError(destination.url, destination.nodeDid, targetNode);
|
|
25270
25428
|
const response = await graph.fetch(
|
|
25271
|
-
`${
|
|
25429
|
+
`${destination.url}/encryption/networks/${encodeURIComponent(networkId)}/decrypt`,
|
|
25272
25430
|
{
|
|
25273
25431
|
method: "POST",
|
|
25274
25432
|
headers: {
|
|
@@ -25281,7 +25439,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25281
25439
|
);
|
|
25282
25440
|
graph.assertActive();
|
|
25283
25441
|
if (!response.ok) {
|
|
25284
|
-
const permissionHint = response.status === 401 || response.status === 403 ? (0,
|
|
25442
|
+
const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services6.parsePermissionHint)({
|
|
25285
25443
|
service: "tinycloud.encryption",
|
|
25286
25444
|
path: networkId,
|
|
25287
25445
|
actions: ["tinycloud.encryption/decrypt"]
|
|
@@ -25296,6 +25454,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25296
25454
|
}
|
|
25297
25455
|
};
|
|
25298
25456
|
return new import_sdk_core10.EncryptionService({
|
|
25457
|
+
resolveTargetNode: async (networkId) => (await this.encryptionDestination(networkId)).nodeDid,
|
|
25299
25458
|
crypto: crypto3,
|
|
25300
25459
|
signer: {
|
|
25301
25460
|
signDecryptInvocation: async (input) => {
|
|
@@ -25319,18 +25478,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25319
25478
|
node: {
|
|
25320
25479
|
fetchByNetworkId: async (networkId) => {
|
|
25321
25480
|
graph.assertActive();
|
|
25322
|
-
|
|
25323
|
-
|
|
25324
|
-
pending = this.fetchEncryptionNetworkAt(host, networkId, graph.fetch).then((descriptor2) => {
|
|
25325
|
-
if (descriptor2 === null) descriptorCache.delete(networkId);
|
|
25326
|
-
return descriptor2;
|
|
25327
|
-
}).catch((error) => {
|
|
25328
|
-
descriptorCache.delete(networkId);
|
|
25329
|
-
throw error;
|
|
25330
|
-
});
|
|
25331
|
-
descriptorCache.set(networkId, pending);
|
|
25332
|
-
}
|
|
25333
|
-
const descriptor = await pending;
|
|
25481
|
+
const destination = await this.encryptionDestination(networkId);
|
|
25482
|
+
const descriptor = await this.fetchEncryptionNetworkAt(destination.url, networkId, graph.fetch, graph.signal);
|
|
25334
25483
|
graph.assertActive();
|
|
25335
25484
|
return descriptor;
|
|
25336
25485
|
}
|
|
@@ -25338,13 +25487,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25338
25487
|
wellKnown: {
|
|
25339
25488
|
fetchWellKnown: async (principal, discoveryKey) => {
|
|
25340
25489
|
graph.assertActive();
|
|
25490
|
+
const destination = await this.encryptionDestination(this.getDefaultEncryptionNetworkId());
|
|
25491
|
+
if (this.auth?.registryRecordPresent) return null;
|
|
25341
25492
|
if (!address || !didPrincipalMatches2(principal, did)) {
|
|
25342
25493
|
return null;
|
|
25343
25494
|
}
|
|
25344
25495
|
const publicSpaceId = (0, import_sdk_core10.makePublicSpaceId)(address, chainId);
|
|
25345
25496
|
const encodedKey = discoveryKey.split("/").map(encodeURIComponent).join("/");
|
|
25346
25497
|
const response = await graph.fetch(
|
|
25347
|
-
`${
|
|
25498
|
+
`${destination.url}/public/${encodeURIComponent(publicSpaceId)}/kv/${encodedKey}`,
|
|
25348
25499
|
{ method: "GET" }
|
|
25349
25500
|
);
|
|
25350
25501
|
graph.assertActive();
|
|
@@ -25714,7 +25865,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25714
25865
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
25715
25866
|
assertOwnerGraphActive();
|
|
25716
25867
|
const delegationSession = this.wasmBindings.completeSessionSetup({ ...prepared, signature: signature2 });
|
|
25717
|
-
const activation = await (
|
|
25868
|
+
const activation = await this.activateSignedSession(delegationSession, prepared.siwe, host);
|
|
25718
25869
|
assertOwnerGraphActive();
|
|
25719
25870
|
if (!activation.success) {
|
|
25720
25871
|
throw Object.assign(
|
|
@@ -26033,15 +26184,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26033
26184
|
async getEncryptionNetwork(nameOrNetworkId = this.getDefaultEncryptionNetworkId()) {
|
|
26034
26185
|
const networkId = nameOrNetworkId.startsWith("urn:tinycloud:encryption:") ? nameOrNetworkId : this.getDefaultEncryptionNetworkId(nameOrNetworkId);
|
|
26035
26186
|
return this.fetchEncryptionNetworkAt(
|
|
26036
|
-
this.
|
|
26187
|
+
(await this.encryptionDestination(networkId)).url,
|
|
26037
26188
|
networkId,
|
|
26038
26189
|
globalThis.fetch.bind(globalThis)
|
|
26039
26190
|
);
|
|
26040
26191
|
}
|
|
26041
26192
|
async createEncryptionNetwork(name = DEFAULT_ENCRYPTION_NETWORK_NAME) {
|
|
26042
|
-
const targetNode = await this.fetchNodeId();
|
|
26043
26193
|
const ownerDid = this.did;
|
|
26044
26194
|
const networkId = this.getDefaultEncryptionNetworkId(name);
|
|
26195
|
+
const destination = await this.encryptionDestination(networkId);
|
|
26196
|
+
const targetNode = destination.nodeDid;
|
|
26045
26197
|
const body = {
|
|
26046
26198
|
name,
|
|
26047
26199
|
ownerDid,
|
|
@@ -26064,7 +26216,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26064
26216
|
action: NETWORK_CREATE_ACTION2,
|
|
26065
26217
|
facts
|
|
26066
26218
|
});
|
|
26067
|
-
const response = await fetch(`${
|
|
26219
|
+
const response = await this._serviceGraph.fetch(`${destination.url}/encryption/networks`, {
|
|
26068
26220
|
method: "POST",
|
|
26069
26221
|
headers: {
|
|
26070
26222
|
Authorization: signed2.authorization,
|
|
@@ -26157,7 +26309,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26157
26309
|
);
|
|
26158
26310
|
if (result.status !== "ok") {
|
|
26159
26311
|
if (result.status === "permission_required") {
|
|
26160
|
-
const hint = (0,
|
|
26312
|
+
const hint = (0, import_sdk_services6.parsePermissionHint)(result.hint);
|
|
26161
26313
|
if (hint === void 0) return { status: "read_failed" };
|
|
26162
26314
|
return {
|
|
26163
26315
|
status: "permission_required",
|
|
@@ -26404,6 +26556,97 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26404
26556
|
}
|
|
26405
26557
|
return { recap: exactVerifiedRecap(verified), expiresAt };
|
|
26406
26558
|
}
|
|
26559
|
+
async activateResourceSession(delegationHeader, resources, hostHint, signal) {
|
|
26560
|
+
const targets = /* @__PURE__ */ new Map();
|
|
26561
|
+
const routedSpaces = [];
|
|
26562
|
+
let unserved;
|
|
26563
|
+
let requestedResource;
|
|
26564
|
+
for (const resource of new Set(resources)) {
|
|
26565
|
+
requestedResource ?? (requestedResource = resource);
|
|
26566
|
+
signal?.throwIfAborted();
|
|
26567
|
+
try {
|
|
26568
|
+
const encryption = resource.startsWith("urn:tinycloud:encryption:");
|
|
26569
|
+
const destinations = await this.routingDestinations(
|
|
26570
|
+
resource,
|
|
26571
|
+
encryption ? "encryption" : "host",
|
|
26572
|
+
[hostHint ?? this.config.host]
|
|
26573
|
+
);
|
|
26574
|
+
if (!encryption && destinations.some(({ nodeDid }) => nodeDid !== void 0)) routedSpaces.push(resource);
|
|
26575
|
+
for (const destination of destinations) {
|
|
26576
|
+
let target = targets.get(destination.url);
|
|
26577
|
+
if (!target) {
|
|
26578
|
+
target = { destination, spaces: [] };
|
|
26579
|
+
targets.set(destination.url, target);
|
|
26580
|
+
}
|
|
26581
|
+
if (!encryption && destination.nodeDid !== void 0) target.spaces.push(resource);
|
|
26582
|
+
}
|
|
26583
|
+
} catch (error) {
|
|
26584
|
+
if (!(error instanceof import_sdk_core10.NodeNotFoundError)) throw error;
|
|
26585
|
+
unserved ?? (unserved = error);
|
|
26586
|
+
}
|
|
26587
|
+
}
|
|
26588
|
+
if (targets.size === 0) throw unserved ?? new import_sdk_services5.ResourceNotRoutedError(requestedResource ?? "session grant");
|
|
26589
|
+
const succeeded = [];
|
|
26590
|
+
const accepted = [];
|
|
26591
|
+
const failed = [];
|
|
26592
|
+
let refusal;
|
|
26593
|
+
for (const { destination: target, spaces } of targets.values()) {
|
|
26594
|
+
signal?.throwIfAborted();
|
|
26595
|
+
try {
|
|
26596
|
+
await (0, import_sdk_services5.verifyResourceDestination)(target, globalThis.fetch.bind(globalThis));
|
|
26597
|
+
const timeout = AbortSignal.timeout(5e3);
|
|
26598
|
+
const result = await (0, import_sdk_core10.activateSessionWithHost)(
|
|
26599
|
+
target.url,
|
|
26600
|
+
delegationHeader,
|
|
26601
|
+
signal ? AbortSignal.any([signal, timeout]) : timeout
|
|
26602
|
+
);
|
|
26603
|
+
this.throwRegistryRefusal(result.status, result.error ?? "");
|
|
26604
|
+
if (result.success) {
|
|
26605
|
+
const skipped = result.skipped?.find((space) => spaces.some((expected) => this.spaceIdsEqual(space, expected)));
|
|
26606
|
+
if (skipped) {
|
|
26607
|
+
failed.push({ url: target.url, status: result.status, cause: new import_sdk_services5.ResourceNotRoutedError(skipped) });
|
|
26608
|
+
continue;
|
|
26609
|
+
}
|
|
26610
|
+
succeeded.push(target.url);
|
|
26611
|
+
accepted.push(result);
|
|
26612
|
+
} else {
|
|
26613
|
+
refusal = result;
|
|
26614
|
+
failed.push({ url: target.url, status: result.status, cause: result });
|
|
26615
|
+
}
|
|
26616
|
+
} catch (error) {
|
|
26617
|
+
if (signal?.aborted) throw error;
|
|
26618
|
+
failed.push({ url: target.url, cause: (0, import_sdk_services5.routingFailure)(error) ? error : new import_sdk_services5.NodeNotRespondingError([target.url], error) });
|
|
26619
|
+
}
|
|
26620
|
+
}
|
|
26621
|
+
if (failed.length > 0) {
|
|
26622
|
+
if (targets.size > 1) throw new import_sdk_services5.PartialNodeWriteError(succeeded, failed);
|
|
26623
|
+
if (refusal) return refusal;
|
|
26624
|
+
throw failed[0].cause;
|
|
26625
|
+
}
|
|
26626
|
+
const activated = new Set(accepted.flatMap((result) => result.activated ?? []));
|
|
26627
|
+
return {
|
|
26628
|
+
...accepted[0],
|
|
26629
|
+
activated: [...activated],
|
|
26630
|
+
skipped: [...new Set(accepted.flatMap((result) => result.skipped ?? []))].filter((space) => !activated.has(space) && !routedSpaces.some((expected) => this.spaceIdsEqual(space, expected)))
|
|
26631
|
+
};
|
|
26632
|
+
}
|
|
26633
|
+
activateRoutedDelegation(delegation, signal) {
|
|
26634
|
+
const resources = this.operationsFromDelegation(delegation).map(
|
|
26635
|
+
(operation) => operation.resource?.startsWith("urn:tinycloud:encryption:") ? operation.resource.split("/")[0] : operation.spaceId ?? delegation.spaceId
|
|
26636
|
+
);
|
|
26637
|
+
return this.activateResourceSession(delegation.delegationHeader, resources, delegation.host, signal);
|
|
26638
|
+
}
|
|
26639
|
+
activateSignedSession(session, siwe, hostHint, signal) {
|
|
26640
|
+
const resources = this.parseRecapWithCaveats(siwe).map(
|
|
26641
|
+
(entry) => this.isEncryptionNetworkOperation(this.invocationServiceName(entry.service), entry.path, entry.space) ? entry.path.split("/")[0] : entry.space.startsWith("tinycloud:") ? entry.space : session.spaceId
|
|
26642
|
+
);
|
|
26643
|
+
return this.activateResourceSession(
|
|
26644
|
+
session.delegationHeader,
|
|
26645
|
+
resources.length > 0 ? resources : [session.spaceId],
|
|
26646
|
+
hostHint,
|
|
26647
|
+
signal
|
|
26648
|
+
);
|
|
26649
|
+
}
|
|
26407
26650
|
/**
|
|
26408
26651
|
* Install a portable runtime permission delegation into this SDK instance so
|
|
26409
26652
|
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
@@ -26423,16 +26666,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26423
26666
|
`Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
|
|
26424
26667
|
);
|
|
26425
26668
|
}
|
|
26426
|
-
const targetHost = delegation.host ?? this.config.host;
|
|
26427
26669
|
let activateResult;
|
|
26428
26670
|
try {
|
|
26429
|
-
activateResult = await (
|
|
26430
|
-
targetHost,
|
|
26431
|
-
delegation.delegationHeader,
|
|
26432
|
-
graph.signal
|
|
26433
|
-
);
|
|
26671
|
+
activateResult = await this.activateRoutedDelegation(delegation, graph.signal);
|
|
26434
26672
|
} catch (cause) {
|
|
26435
26673
|
graph.assertActive();
|
|
26674
|
+
if ((0, import_sdk_services5.routingFailure)(cause)) throw cause;
|
|
26436
26675
|
throw Object.assign(
|
|
26437
26676
|
new Error("The TinyCloud host could not be reached to activate the delegation."),
|
|
26438
26677
|
{ code: "ACTIVATION_TRANSPORT_FAILED", cause }
|
|
@@ -26588,11 +26827,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26588
26827
|
...prepared,
|
|
26589
26828
|
signature: signature2
|
|
26590
26829
|
});
|
|
26591
|
-
const
|
|
26592
|
-
|
|
26593
|
-
|
|
26594
|
-
|
|
26595
|
-
|
|
26830
|
+
const delegation = this.runtimeDelegationFromSession(
|
|
26831
|
+
delegatedSession,
|
|
26832
|
+
delegatedEntries,
|
|
26833
|
+
spaceId,
|
|
26834
|
+
captured,
|
|
26835
|
+
expiresAt,
|
|
26836
|
+
{ siwe: prepared.siwe, signature: signature2 }
|
|
26837
|
+
);
|
|
26838
|
+
const activateResult = await this.activateRoutedDelegation(delegation, graph.signal).catch((error) => {
|
|
26596
26839
|
graph.assertActive();
|
|
26597
26840
|
throw error;
|
|
26598
26841
|
});
|
|
@@ -26608,14 +26851,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26608
26851
|
{ cause: activateResult }
|
|
26609
26852
|
);
|
|
26610
26853
|
}
|
|
26611
|
-
const delegation = this.runtimeDelegationFromSession(
|
|
26612
|
-
delegatedSession,
|
|
26613
|
-
delegatedEntries,
|
|
26614
|
-
spaceId,
|
|
26615
|
-
captured,
|
|
26616
|
-
expiresAt,
|
|
26617
|
-
{ siwe: prepared.siwe, signature: signature2 }
|
|
26618
|
-
);
|
|
26619
26854
|
graph.assertActive();
|
|
26620
26855
|
assertCapturedKey?.();
|
|
26621
26856
|
this.runtimePermissionGrants.push({
|
|
@@ -26760,7 +26995,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26760
26995
|
if (!publicSpaceId) {
|
|
26761
26996
|
throw new Error("Public space not enabled. Set enablePublicSpace: true in config.");
|
|
26762
26997
|
}
|
|
26763
|
-
await this.assertMayCreateSpace();
|
|
26998
|
+
await this.assertMayCreateSpace(publicSpaceId);
|
|
26764
26999
|
await this.auth.hostPublicSpace(publicSpaceId);
|
|
26765
27000
|
const kvActions = [import_sdk_core10.KV.PUT, import_sdk_core10.KV.GET, import_sdk_core10.KV.DEL, import_sdk_core10.KV.LIST, import_sdk_core10.KV.METADATA];
|
|
26766
27001
|
const abilities = { kv: { "": kvActions } };
|
|
@@ -26783,10 +27018,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26783
27018
|
...prepared,
|
|
26784
27019
|
signature: signature2
|
|
26785
27020
|
});
|
|
26786
|
-
const activateResult = await (
|
|
26787
|
-
this.config.host,
|
|
26788
|
-
delegationSession.delegationHeader
|
|
26789
|
-
);
|
|
27021
|
+
const activateResult = await this.activateSignedSession(delegationSession, prepared.siwe);
|
|
26790
27022
|
if (!activateResult.success) {
|
|
26791
27023
|
throw Object.assign(
|
|
26792
27024
|
new Error(`Failed to activate public space delegation: ${describeHostFailure2(activateResult)}`),
|
|
@@ -27336,10 +27568,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
27336
27568
|
if (onPrepared) {
|
|
27337
27569
|
await onPrepared(delegation);
|
|
27338
27570
|
}
|
|
27339
|
-
const activateResult = await (
|
|
27340
|
-
this.config.host,
|
|
27341
|
-
delegationHeader
|
|
27342
|
-
);
|
|
27571
|
+
const activateResult = await this.activateRoutedDelegation(delegation);
|
|
27343
27572
|
assertDelegationActivated(activateResult, delegation, requireActivation);
|
|
27344
27573
|
return delegation;
|
|
27345
27574
|
}
|
|
@@ -27373,10 +27602,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
27373
27602
|
if (onPrepared) {
|
|
27374
27603
|
await onPrepared(delegation);
|
|
27375
27604
|
}
|
|
27376
|
-
const activateResult = await (
|
|
27377
|
-
targetHost,
|
|
27378
|
-
delegationHeader
|
|
27379
|
-
);
|
|
27605
|
+
const activateResult = await this.activateRoutedDelegation(delegation);
|
|
27380
27606
|
assertDelegationActivated(activateResult, delegation, requireActivation);
|
|
27381
27607
|
return delegation;
|
|
27382
27608
|
}
|
|
@@ -28028,10 +28254,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
28028
28254
|
...prepared,
|
|
28029
28255
|
signature: signature2
|
|
28030
28256
|
});
|
|
28031
|
-
const activateResult = await (
|
|
28032
|
-
this.config.host,
|
|
28033
|
-
delegationSession.delegationHeader
|
|
28034
|
-
);
|
|
28257
|
+
const activateResult = await this.activateSignedSession(delegationSession, prepared.siwe);
|
|
28035
28258
|
if (!activateResult.success) {
|
|
28036
28259
|
throw Object.assign(
|
|
28037
28260
|
new Error(`Failed to activate delegation: ${describeHostFailure2(activateResult)}`),
|
|
@@ -28076,10 +28299,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
28076
28299
|
...publicPrepared,
|
|
28077
28300
|
signature: publicSignature
|
|
28078
28301
|
});
|
|
28079
|
-
const publicActivateResult = await (
|
|
28080
|
-
this.config.host,
|
|
28081
|
-
publicSession.delegationHeader
|
|
28082
|
-
);
|
|
28302
|
+
const publicActivateResult = await this.activateSignedSession(publicSession, publicPrepared.siwe);
|
|
28083
28303
|
if (publicActivateResult.success) {
|
|
28084
28304
|
result.publicDelegation = {
|
|
28085
28305
|
cid: publicSession.delegationCid,
|
|
@@ -28185,11 +28405,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
28185
28405
|
...prepared,
|
|
28186
28406
|
signature: signature2
|
|
28187
28407
|
});
|
|
28188
|
-
const activateResult = await (
|
|
28189
|
-
targetHost,
|
|
28190
|
-
invokerSession.delegationHeader,
|
|
28191
|
-
graph.signal
|
|
28192
|
-
).catch((error) => {
|
|
28408
|
+
const activateResult = await this.activateSignedSession(invokerSession, prepared.siwe, targetHost, graph.signal).catch((error) => {
|
|
28193
28409
|
graph.assertActive();
|
|
28194
28410
|
throw error;
|
|
28195
28411
|
});
|
|
@@ -28316,10 +28532,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
28316
28532
|
...prepared,
|
|
28317
28533
|
signature: signature2
|
|
28318
28534
|
});
|
|
28319
|
-
const activateResult = await (
|
|
28320
|
-
targetHost,
|
|
28321
|
-
subDelegationSession.delegationHeader
|
|
28322
|
-
);
|
|
28535
|
+
const activateResult = await this.activateSignedSession(subDelegationSession, prepared.siwe, targetHost);
|
|
28323
28536
|
if (!activateResult.success) {
|
|
28324
28537
|
throw Object.assign(
|
|
28325
28538
|
new Error(`Failed to activate sub-delegation: ${describeHostFailure2(activateResult)}`),
|
|
@@ -28383,6 +28596,7 @@ registerReplicationLoaders({
|
|
|
28383
28596
|
|
|
28384
28597
|
// src/index.ts
|
|
28385
28598
|
var import_sdk_core15 = require("@tinycloud/sdk-core");
|
|
28599
|
+
var import_sdk_services8 = require("@tinycloud/sdk-services");
|
|
28386
28600
|
var import_sdk_core16 = require("@tinycloud/sdk-core");
|
|
28387
28601
|
|
|
28388
28602
|
// src/storage/FileSessionStorage.ts
|
|
@@ -28582,7 +28796,7 @@ var import_node_fs = require("fs");
|
|
|
28582
28796
|
var import_promises = require("fs/promises");
|
|
28583
28797
|
var import_node_path = require("path");
|
|
28584
28798
|
var import_sdk_core14 = require("@tinycloud/sdk-core");
|
|
28585
|
-
var
|
|
28799
|
+
var import_sdk_services7 = require("@tinycloud/sdk-services");
|
|
28586
28800
|
var import_contractConstants = require("@tinycloud/sdk-services/kv/replication/contractConstants");
|
|
28587
28801
|
init_authority();
|
|
28588
28802
|
var REPLICA_LOGOUT_PENDING_FILE = "replica-logout-pending.json";
|
|
@@ -29144,7 +29358,7 @@ function sha256Base32(material) {
|
|
|
29144
29358
|
return out.slice(0, 26);
|
|
29145
29359
|
}
|
|
29146
29360
|
function partitionDirOf(root, identity) {
|
|
29147
|
-
return (0, import_node_path.join)(root, sha256Base32((0,
|
|
29361
|
+
return (0, import_node_path.join)(root, sha256Base32((0, import_sdk_services7.replicationIdentityKey)(identity)));
|
|
29148
29362
|
}
|
|
29149
29363
|
function replicaHashOf(prefix, deviceDid) {
|
|
29150
29364
|
return sha256Base32(`${prefix}
|
|
@@ -29218,8 +29432,8 @@ function deviceRecordOf(value) {
|
|
|
29218
29432
|
}
|
|
29219
29433
|
function sameIdentity(a, b) {
|
|
29220
29434
|
try {
|
|
29221
|
-
const left = (0,
|
|
29222
|
-
const right = (0,
|
|
29435
|
+
const left = (0, import_sdk_services7.canonicalReplicationIdentity)(a);
|
|
29436
|
+
const right = (0, import_sdk_services7.canonicalReplicationIdentity)(b);
|
|
29223
29437
|
return left.host === right.host && left.space === right.space && left.principal === right.principal;
|
|
29224
29438
|
} catch {
|
|
29225
29439
|
return false;
|
|
@@ -29235,7 +29449,7 @@ async function ensurePartitionIdentity(dir, identity, dirSync) {
|
|
|
29235
29449
|
const file = (0, import_node_path.join)(dir, "identity.json");
|
|
29236
29450
|
const existing = await readJsonFile(file);
|
|
29237
29451
|
if (existing === void 0) {
|
|
29238
|
-
await writeJsonAtomic(file, { v: 1, ...(0,
|
|
29452
|
+
await writeJsonAtomic(file, { v: 1, ...(0, import_sdk_services7.canonicalReplicationIdentity)(identity) }, dirSync);
|
|
29239
29453
|
return;
|
|
29240
29454
|
}
|
|
29241
29455
|
const record = identityRecordOf(existing);
|
|
@@ -29334,7 +29548,7 @@ withGate_fn = async function(section) {
|
|
|
29334
29548
|
if (snapshot === void 0) throw gated("gate_unavailable");
|
|
29335
29549
|
const [principalHash, identityKeyHash] = await Promise.all([
|
|
29336
29550
|
gate.principalHashOf(snapshot.salt, this.identity.principal),
|
|
29337
|
-
gate.identityHashOf(snapshot.salt, (0,
|
|
29551
|
+
gate.identityHashOf(snapshot.salt, (0, import_sdk_services7.replicationIdentityKey)(this.identity))
|
|
29338
29552
|
]);
|
|
29339
29553
|
const access = {
|
|
29340
29554
|
stamp: __privateGet(this, _stamp),
|
|
@@ -29835,7 +30049,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
29835
30049
|
if (snapshot === void 0) throw gated("gate_unavailable");
|
|
29836
30050
|
const [principalHash, identityKeyHash] = await Promise.all([
|
|
29837
30051
|
gate.principalHashOf(snapshot.salt, principal),
|
|
29838
|
-
identity === void 0 ? Promise.resolve(void 0) : gate.identityHashOf(snapshot.salt, (0,
|
|
30052
|
+
identity === void 0 ? Promise.resolve(void 0) : gate.identityHashOf(snapshot.salt, (0, import_sdk_services7.replicationIdentityKey)(identity))
|
|
29839
30053
|
]);
|
|
29840
30054
|
return profileSection(async () => {
|
|
29841
30055
|
assertLogoutClear(options.logoutPendingFile);
|
|
@@ -29858,7 +30072,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
29858
30072
|
if (snapshot === void 0) throw gated("gate_unavailable");
|
|
29859
30073
|
const [principalHash, identityKeyHash] = await Promise.all([
|
|
29860
30074
|
gate.principalHashOf(snapshot.salt, spec.identity.principal),
|
|
29861
|
-
gate.identityHashOf(snapshot.salt, (0,
|
|
30075
|
+
gate.identityHashOf(snapshot.salt, (0, import_sdk_services7.replicationIdentityKey)(spec.identity))
|
|
29862
30076
|
]);
|
|
29863
30077
|
const access = {
|
|
29864
30078
|
stamp: spec.stamp,
|
|
@@ -29942,7 +30156,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
29942
30156
|
const identity = identityRecordOf(await readJsonFile((0, import_node_path.join)(idDir, "identity.json")));
|
|
29943
30157
|
if (identity === void 0) throw new ReplicaStorageError("STORAGE_ERROR", `Missing identity at ${idDir}.`);
|
|
29944
30158
|
if (await gate.principalHashOf(salt, identity.principal) !== principalHash) continue;
|
|
29945
|
-
const identityKeyHash = await gate.identityHashOf(salt, (0,
|
|
30159
|
+
const identityKeyHash = await gate.identityHashOf(salt, (0, import_sdk_services7.replicationIdentityKey)(identity));
|
|
29946
30160
|
const recordedAt = Date.now();
|
|
29947
30161
|
if (await pathExists((0, import_node_path.join)(idDir, "pending.json")) || await pathExists((0, import_node_path.join)(idDir, "device.jwk"))) {
|
|
29948
30162
|
intents.push({ id: `pending:${identityKeyHash}`, kind: "pending", identityKeyHash, principalHash, recordedAt });
|
|
@@ -30620,7 +30834,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
30620
30834
|
for (const dir of await identityDirs()) {
|
|
30621
30835
|
const identity = identityRecordOf(await readJsonFile((0, import_node_path.join)(dir, "identity.json")));
|
|
30622
30836
|
if (identity === void 0) throw new ReplicaStorageError("STORAGE_ERROR", `Missing identity at ${dir}.`);
|
|
30623
|
-
const hash3 = await gate.identityHashOf(state.salt, (0,
|
|
30837
|
+
const hash3 = await gate.identityHashOf(state.salt, (0, import_sdk_services7.replicationIdentityKey)(identity));
|
|
30624
30838
|
if (intent.kind === "pending" ? hash3 === intent.identityKeyHash : intent.partitionId.startsWith(`${hash3}:`)) {
|
|
30625
30839
|
idDir = dir;
|
|
30626
30840
|
break;
|
|
@@ -30766,7 +30980,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
30766
30980
|
const gate = await fileGate();
|
|
30767
30981
|
const snapshot = await gate.readGateSnapshot(profileDir);
|
|
30768
30982
|
if (snapshot === void 0) throw gated("gate_unavailable");
|
|
30769
|
-
const identityKeyHash = await gate.identityHashOf(snapshot.salt, (0,
|
|
30983
|
+
const identityKeyHash = await gate.identityHashOf(snapshot.salt, (0, import_sdk_services7.replicationIdentityKey)(spec.identity));
|
|
30770
30984
|
const resolvePolicy = async (at, recordFirst) => {
|
|
30771
30985
|
const policy = spec.grantPolicy;
|
|
30772
30986
|
if (!Number.isSafeInteger(policy.grantTtlMs) || policy.grantTtlMs <= 0 || policy.grantTtlMs > import_contractConstants.MAX_GRANT_TTL_MS) {
|
|
@@ -30788,7 +31002,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
30788
31002
|
let partitionId;
|
|
30789
31003
|
const storeGuard = (section) => guarded(spec.identity.principal, spec.stamp, spec.identity, partitionId, section);
|
|
30790
31004
|
return guarded(spec.identity.principal, spec.stamp, spec.identity, void 0, async () => {
|
|
30791
|
-
if ((0,
|
|
31005
|
+
if ((0, import_sdk_services7.requiresSecretsOptIn)(spec.space, spec.prefix) && spec.allowSecrets !== true) {
|
|
30792
31006
|
throw new replica.ReplicaError(
|
|
30793
31007
|
replica.ReplicaErrorCode.SECRETS_OPT_IN_REQUIRED,
|
|
30794
31008
|
`Replicating ${spec.space}/kv/${spec.prefix} copies secret material to disk; pass allowSecrets to opt in.`
|
|
@@ -31034,7 +31248,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
31034
31248
|
const gate = await fileGate();
|
|
31035
31249
|
const currentGate = await gate.readGateSnapshot(profileDir);
|
|
31036
31250
|
if (currentGate !== void 0 && currentGate.principalHash !== null && currentGate.principalHash === await gate.principalHashOf(currentGate.salt, target.identity.principal)) {
|
|
31037
|
-
const identityKeyHash = await gate.identityHashOf(currentGate.salt, (0,
|
|
31251
|
+
const identityKeyHash = await gate.identityHashOf(currentGate.salt, (0, import_sdk_services7.replicationIdentityKey)(target.identity));
|
|
31038
31252
|
await retainGrantInstalls(gate, currentGate, identityKeyHash, store);
|
|
31039
31253
|
}
|
|
31040
31254
|
if (state.revoked === null) {
|
|
@@ -31130,8 +31344,11 @@ function sqliteReplicaStorage(options) {
|
|
|
31130
31344
|
MemorySessionStorage,
|
|
31131
31345
|
NETWORK_NAME_PATTERN,
|
|
31132
31346
|
NetworkIdError,
|
|
31347
|
+
NodeIdentityMismatchError,
|
|
31348
|
+
NodeNotRespondingError,
|
|
31133
31349
|
NodeUserAuthorization,
|
|
31134
31350
|
NodeWasmBindings,
|
|
31351
|
+
PartialNodeWriteError,
|
|
31135
31352
|
PermissionNotInManifestError,
|
|
31136
31353
|
PrefixedKVService,
|
|
31137
31354
|
PrivateKeySigner,
|