@tinycloud/node-sdk 3.12.0-beta.2 → 3.12.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +499 -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 +525 -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 +516 -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 +526 -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,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24207
24400
|
}
|
|
24208
24401
|
stagedSessionExpiry = signedExpiry ?? persistedPolicyExpiry ?? persistedExpiry(void 0);
|
|
24209
24402
|
}
|
|
24210
|
-
const
|
|
24211
|
-
|
|
24212
|
-
restoredAddress,
|
|
24213
|
-
sessionData.chainId
|
|
24214
|
-
);
|
|
24215
|
-
const stagedHost = resolvedHost ?? this.config.host;
|
|
24403
|
+
const restoreHints = this.explicitHost ? [this.explicitHost] : sessionData.tinycloudHosts ?? [];
|
|
24404
|
+
const stagedHost = (0, import_sdk_core10.exactHttpOrigin)(restoreHints[0] ?? this.config.host, "restored host hint");
|
|
24216
24405
|
let restoredNodeFeatures;
|
|
24217
24406
|
let replicaProtocolMismatch = false;
|
|
24218
24407
|
if (this.config.replication?.enabled) {
|
|
@@ -24329,7 +24518,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24329
24518
|
this.sessionManager = stagedManager;
|
|
24330
24519
|
this.sessionKeyId = stagedKeyId;
|
|
24331
24520
|
this.sessionKeyJwk = stagedJwk;
|
|
24332
|
-
|
|
24521
|
+
this.config.host = stagedHost;
|
|
24333
24522
|
if (spaceOwnerKey(serviceSession.spaceId) !== this.currentStorageOwner()) {
|
|
24334
24523
|
this.storageFull.clear();
|
|
24335
24524
|
this._requestLog?.clear();
|
|
@@ -24396,6 +24585,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24396
24585
|
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
24397
24586
|
this.assertSessionEpoch(epoch, "Session restore");
|
|
24398
24587
|
}
|
|
24588
|
+
if (this.config.replication?.enabled) {
|
|
24589
|
+
if (stagedAddress !== void 0) this.refreshRegistryOwner((0, import_sdk_core10.pkhDid)(stagedAddress, stagedChainId));
|
|
24590
|
+
this.refreshRegistryForCapabilities(this.getVerifiedSessionCapabilities());
|
|
24591
|
+
}
|
|
24399
24592
|
}
|
|
24400
24593
|
stagePrimarySessionState(session, verificationMethod, host, sessionExpiry, recap) {
|
|
24401
24594
|
if (!session?.siwe) return { cache: void 0, grants: [] };
|
|
@@ -24444,7 +24637,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24444
24637
|
};
|
|
24445
24638
|
}
|
|
24446
24639
|
stageRestoredServiceGraph(input) {
|
|
24447
|
-
const graph = this.createServiceGraphLifetime();
|
|
24640
|
+
const graph = this.createServiceGraphLifetime(input.serviceSession);
|
|
24448
24641
|
const core = this.auth ? new import_sdk_core10.TinyCloud(this.auth, {
|
|
24449
24642
|
invokeAny: graph.invokeAny,
|
|
24450
24643
|
telemetry: this.config.telemetry,
|
|
@@ -24669,56 +24862,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24669
24862
|
spaceService.updateConfig({ sharingService });
|
|
24670
24863
|
return { core, graph, serviceContext, kv, sql, duckdb, hooks, vault, encryption, capabilityRegistry, keyProvider, sharingService, delegationManager, spaceService };
|
|
24671
24864
|
}
|
|
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
24865
|
/**
|
|
24723
24866
|
* Resolve the currently-active TinyCloudSession, preferring the auth
|
|
24724
24867
|
* layer's value (wallet mode) and falling back to the node-level
|
|
@@ -25193,10 +25336,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25193
25336
|
* second time. Only a value recorded for this exact host qualifies; older
|
|
25194
25337
|
* nodes that omit `nodeId` fall through to the fetch.
|
|
25195
25338
|
*/
|
|
25196
|
-
async fetchNodeId() {
|
|
25197
|
-
const cached = this.auth?.nodeIdForHost(
|
|
25339
|
+
async fetchNodeId(host = this.config.host) {
|
|
25340
|
+
const cached = this.auth?.nodeIdForHost(host);
|
|
25198
25341
|
if (cached) return cached;
|
|
25199
|
-
const response = await fetch(`${
|
|
25342
|
+
const response = await fetch(`${host}/info`);
|
|
25200
25343
|
if (!response.ok) {
|
|
25201
25344
|
throw await (0, import_sdk_core10.httpResponseError)(response, "Failed to fetch node info");
|
|
25202
25345
|
}
|
|
@@ -25244,10 +25387,24 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25244
25387
|
)
|
|
25245
25388
|
};
|
|
25246
25389
|
}
|
|
25247
|
-
async
|
|
25248
|
-
const
|
|
25249
|
-
|
|
25250
|
-
);
|
|
25390
|
+
async encryptionDestination(networkId) {
|
|
25391
|
+
const destination = (await this.routingDestinations(networkId, "encryption"))[0];
|
|
25392
|
+
if (!destination) throw new Error("No encryption destination is registered");
|
|
25393
|
+
await (0, import_sdk_services5.verifyResourceDestination)(destination, globalThis.fetch.bind(globalThis));
|
|
25394
|
+
return { ...destination, nodeDid: destination.nodeDid ?? await this.fetchNodeId(destination.url) };
|
|
25395
|
+
}
|
|
25396
|
+
async fetchEncryptionNetworkAt(host, networkId, fetchFn, callerSignal) {
|
|
25397
|
+
let response;
|
|
25398
|
+
const timeout = AbortSignal.timeout(5e3);
|
|
25399
|
+
try {
|
|
25400
|
+
response = await fetchFn(`${host}/encryption/networks/${encodeURIComponent(networkId)}`, {
|
|
25401
|
+
signal: callerSignal ? AbortSignal.any([callerSignal, timeout]) : timeout,
|
|
25402
|
+
redirect: "error"
|
|
25403
|
+
});
|
|
25404
|
+
} catch (error) {
|
|
25405
|
+
if ((0, import_sdk_services5.routingFailure)(error) || callerSignal?.aborted || !timeout.aborted && error instanceof Error && error.name === "AbortError") throw error;
|
|
25406
|
+
throw new import_sdk_services5.NodeNotRespondingError([host], error);
|
|
25407
|
+
}
|
|
25251
25408
|
if (response.status === 404) return null;
|
|
25252
25409
|
if (!response.ok) {
|
|
25253
25410
|
throw await (0, import_sdk_core10.httpResponseError)(response, `Failed to fetch encryption network ${networkId}`);
|
|
@@ -25257,18 +25414,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25257
25414
|
}
|
|
25258
25415
|
createEncryptionService(binding) {
|
|
25259
25416
|
const graph = binding?.graph ?? this._serviceGraph;
|
|
25260
|
-
const host = binding?.host ?? this.config.host;
|
|
25261
25417
|
const session = binding?.session ?? this.requireEncryptionSession();
|
|
25262
25418
|
const did = binding?.did ?? this.did;
|
|
25263
25419
|
const address = binding?.address ?? this._address;
|
|
25264
25420
|
const chainId = binding?.chainId ?? this._chainId;
|
|
25265
25421
|
const crypto3 = this.createEncryptionCrypto();
|
|
25266
|
-
const descriptorCache = /* @__PURE__ */ new Map();
|
|
25267
25422
|
const transport = {
|
|
25268
|
-
postDecrypt: async ({ networkId, authorization, canonicalBody, signal }) => {
|
|
25423
|
+
postDecrypt: async ({ targetNode, networkId, authorization, canonicalBody, signal }) => {
|
|
25269
25424
|
graph.assertActive();
|
|
25425
|
+
const destination = await this.encryptionDestination(networkId);
|
|
25426
|
+
if (destination.nodeDid !== targetNode) throw new import_sdk_services5.NodeIdentityMismatchError(destination.url, destination.nodeDid, targetNode);
|
|
25270
25427
|
const response = await graph.fetch(
|
|
25271
|
-
`${
|
|
25428
|
+
`${destination.url}/encryption/networks/${encodeURIComponent(networkId)}/decrypt`,
|
|
25272
25429
|
{
|
|
25273
25430
|
method: "POST",
|
|
25274
25431
|
headers: {
|
|
@@ -25281,7 +25438,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25281
25438
|
);
|
|
25282
25439
|
graph.assertActive();
|
|
25283
25440
|
if (!response.ok) {
|
|
25284
|
-
const permissionHint = response.status === 401 || response.status === 403 ? (0,
|
|
25441
|
+
const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services6.parsePermissionHint)({
|
|
25285
25442
|
service: "tinycloud.encryption",
|
|
25286
25443
|
path: networkId,
|
|
25287
25444
|
actions: ["tinycloud.encryption/decrypt"]
|
|
@@ -25296,6 +25453,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25296
25453
|
}
|
|
25297
25454
|
};
|
|
25298
25455
|
return new import_sdk_core10.EncryptionService({
|
|
25456
|
+
resolveTargetNode: async (networkId) => (await this.encryptionDestination(networkId)).nodeDid,
|
|
25299
25457
|
crypto: crypto3,
|
|
25300
25458
|
signer: {
|
|
25301
25459
|
signDecryptInvocation: async (input) => {
|
|
@@ -25319,18 +25477,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25319
25477
|
node: {
|
|
25320
25478
|
fetchByNetworkId: async (networkId) => {
|
|
25321
25479
|
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;
|
|
25480
|
+
const destination = await this.encryptionDestination(networkId);
|
|
25481
|
+
const descriptor = await this.fetchEncryptionNetworkAt(destination.url, networkId, graph.fetch, graph.signal);
|
|
25334
25482
|
graph.assertActive();
|
|
25335
25483
|
return descriptor;
|
|
25336
25484
|
}
|
|
@@ -25338,13 +25486,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25338
25486
|
wellKnown: {
|
|
25339
25487
|
fetchWellKnown: async (principal, discoveryKey) => {
|
|
25340
25488
|
graph.assertActive();
|
|
25489
|
+
const destination = await this.encryptionDestination(this.getDefaultEncryptionNetworkId());
|
|
25490
|
+
if (this.auth?.registryRecordPresent) return null;
|
|
25341
25491
|
if (!address || !didPrincipalMatches2(principal, did)) {
|
|
25342
25492
|
return null;
|
|
25343
25493
|
}
|
|
25344
25494
|
const publicSpaceId = (0, import_sdk_core10.makePublicSpaceId)(address, chainId);
|
|
25345
25495
|
const encodedKey = discoveryKey.split("/").map(encodeURIComponent).join("/");
|
|
25346
25496
|
const response = await graph.fetch(
|
|
25347
|
-
`${
|
|
25497
|
+
`${destination.url}/public/${encodeURIComponent(publicSpaceId)}/kv/${encodedKey}`,
|
|
25348
25498
|
{ method: "GET" }
|
|
25349
25499
|
);
|
|
25350
25500
|
graph.assertActive();
|
|
@@ -25714,7 +25864,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25714
25864
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
25715
25865
|
assertOwnerGraphActive();
|
|
25716
25866
|
const delegationSession = this.wasmBindings.completeSessionSetup({ ...prepared, signature: signature2 });
|
|
25717
|
-
const activation = await (
|
|
25867
|
+
const activation = await this.activateSignedSession(delegationSession, prepared.siwe, host);
|
|
25718
25868
|
assertOwnerGraphActive();
|
|
25719
25869
|
if (!activation.success) {
|
|
25720
25870
|
throw Object.assign(
|
|
@@ -26033,15 +26183,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26033
26183
|
async getEncryptionNetwork(nameOrNetworkId = this.getDefaultEncryptionNetworkId()) {
|
|
26034
26184
|
const networkId = nameOrNetworkId.startsWith("urn:tinycloud:encryption:") ? nameOrNetworkId : this.getDefaultEncryptionNetworkId(nameOrNetworkId);
|
|
26035
26185
|
return this.fetchEncryptionNetworkAt(
|
|
26036
|
-
this.
|
|
26186
|
+
(await this.encryptionDestination(networkId)).url,
|
|
26037
26187
|
networkId,
|
|
26038
26188
|
globalThis.fetch.bind(globalThis)
|
|
26039
26189
|
);
|
|
26040
26190
|
}
|
|
26041
26191
|
async createEncryptionNetwork(name = DEFAULT_ENCRYPTION_NETWORK_NAME) {
|
|
26042
|
-
const targetNode = await this.fetchNodeId();
|
|
26043
26192
|
const ownerDid = this.did;
|
|
26044
26193
|
const networkId = this.getDefaultEncryptionNetworkId(name);
|
|
26194
|
+
const destination = await this.encryptionDestination(networkId);
|
|
26195
|
+
const targetNode = destination.nodeDid;
|
|
26045
26196
|
const body = {
|
|
26046
26197
|
name,
|
|
26047
26198
|
ownerDid,
|
|
@@ -26064,7 +26215,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26064
26215
|
action: NETWORK_CREATE_ACTION2,
|
|
26065
26216
|
facts
|
|
26066
26217
|
});
|
|
26067
|
-
const response = await fetch(`${
|
|
26218
|
+
const response = await this._serviceGraph.fetch(`${destination.url}/encryption/networks`, {
|
|
26068
26219
|
method: "POST",
|
|
26069
26220
|
headers: {
|
|
26070
26221
|
Authorization: signed2.authorization,
|
|
@@ -26157,7 +26308,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26157
26308
|
);
|
|
26158
26309
|
if (result.status !== "ok") {
|
|
26159
26310
|
if (result.status === "permission_required") {
|
|
26160
|
-
const hint = (0,
|
|
26311
|
+
const hint = (0, import_sdk_services6.parsePermissionHint)(result.hint);
|
|
26161
26312
|
if (hint === void 0) return { status: "read_failed" };
|
|
26162
26313
|
return {
|
|
26163
26314
|
status: "permission_required",
|
|
@@ -26404,6 +26555,97 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26404
26555
|
}
|
|
26405
26556
|
return { recap: exactVerifiedRecap(verified), expiresAt };
|
|
26406
26557
|
}
|
|
26558
|
+
async activateResourceSession(delegationHeader, resources, hostHint, signal) {
|
|
26559
|
+
const targets = /* @__PURE__ */ new Map();
|
|
26560
|
+
const routedSpaces = [];
|
|
26561
|
+
let unserved;
|
|
26562
|
+
let requestedResource;
|
|
26563
|
+
for (const resource of new Set(resources)) {
|
|
26564
|
+
requestedResource ?? (requestedResource = resource);
|
|
26565
|
+
signal?.throwIfAborted();
|
|
26566
|
+
try {
|
|
26567
|
+
const encryption = resource.startsWith("urn:tinycloud:encryption:");
|
|
26568
|
+
const destinations = await this.routingDestinations(
|
|
26569
|
+
resource,
|
|
26570
|
+
encryption ? "encryption" : "host",
|
|
26571
|
+
[hostHint ?? this.config.host]
|
|
26572
|
+
);
|
|
26573
|
+
if (!encryption && destinations.some(({ nodeDid }) => nodeDid !== void 0)) routedSpaces.push(resource);
|
|
26574
|
+
for (const destination of destinations) {
|
|
26575
|
+
let target = targets.get(destination.url);
|
|
26576
|
+
if (!target) {
|
|
26577
|
+
target = { destination, spaces: [] };
|
|
26578
|
+
targets.set(destination.url, target);
|
|
26579
|
+
}
|
|
26580
|
+
if (!encryption && destination.nodeDid !== void 0) target.spaces.push(resource);
|
|
26581
|
+
}
|
|
26582
|
+
} catch (error) {
|
|
26583
|
+
if (!(error instanceof import_sdk_core10.NodeNotFoundError)) throw error;
|
|
26584
|
+
unserved ?? (unserved = error);
|
|
26585
|
+
}
|
|
26586
|
+
}
|
|
26587
|
+
if (targets.size === 0) throw unserved ?? new import_sdk_services5.ResourceNotRoutedError(requestedResource ?? "session grant");
|
|
26588
|
+
const succeeded = [];
|
|
26589
|
+
const accepted = [];
|
|
26590
|
+
const failed = [];
|
|
26591
|
+
let refusal;
|
|
26592
|
+
for (const { destination: target, spaces } of targets.values()) {
|
|
26593
|
+
signal?.throwIfAborted();
|
|
26594
|
+
try {
|
|
26595
|
+
await (0, import_sdk_services5.verifyResourceDestination)(target, globalThis.fetch.bind(globalThis));
|
|
26596
|
+
const timeout = AbortSignal.timeout(5e3);
|
|
26597
|
+
const result = await (0, import_sdk_core10.activateSessionWithHost)(
|
|
26598
|
+
target.url,
|
|
26599
|
+
delegationHeader,
|
|
26600
|
+
signal ? AbortSignal.any([signal, timeout]) : timeout
|
|
26601
|
+
);
|
|
26602
|
+
this.throwRegistryRefusal(result.status, result.error ?? "");
|
|
26603
|
+
if (result.success) {
|
|
26604
|
+
const skipped = result.skipped?.find((space) => spaces.some((expected) => this.spaceIdsEqual(space, expected)));
|
|
26605
|
+
if (skipped) {
|
|
26606
|
+
failed.push({ url: target.url, status: result.status, cause: new import_sdk_services5.ResourceNotRoutedError(skipped) });
|
|
26607
|
+
continue;
|
|
26608
|
+
}
|
|
26609
|
+
succeeded.push(target.url);
|
|
26610
|
+
accepted.push(result);
|
|
26611
|
+
} else {
|
|
26612
|
+
refusal = result;
|
|
26613
|
+
failed.push({ url: target.url, status: result.status, cause: result });
|
|
26614
|
+
}
|
|
26615
|
+
} catch (error) {
|
|
26616
|
+
if (signal?.aborted) throw error;
|
|
26617
|
+
failed.push({ url: target.url, cause: (0, import_sdk_services5.routingFailure)(error) ? error : new import_sdk_services5.NodeNotRespondingError([target.url], error) });
|
|
26618
|
+
}
|
|
26619
|
+
}
|
|
26620
|
+
if (failed.length > 0) {
|
|
26621
|
+
if (targets.size > 1) throw new import_sdk_services5.PartialNodeWriteError(succeeded, failed);
|
|
26622
|
+
if (refusal) return refusal;
|
|
26623
|
+
throw failed[0].cause;
|
|
26624
|
+
}
|
|
26625
|
+
const activated = new Set(accepted.flatMap((result) => result.activated ?? []));
|
|
26626
|
+
return {
|
|
26627
|
+
...accepted[0],
|
|
26628
|
+
activated: [...activated],
|
|
26629
|
+
skipped: [...new Set(accepted.flatMap((result) => result.skipped ?? []))].filter((space) => !activated.has(space) && !routedSpaces.some((expected) => this.spaceIdsEqual(space, expected)))
|
|
26630
|
+
};
|
|
26631
|
+
}
|
|
26632
|
+
activateRoutedDelegation(delegation, signal) {
|
|
26633
|
+
const resources = this.operationsFromDelegation(delegation).map(
|
|
26634
|
+
(operation) => operation.resource?.startsWith("urn:tinycloud:encryption:") ? operation.resource.split("/")[0] : operation.spaceId ?? delegation.spaceId
|
|
26635
|
+
);
|
|
26636
|
+
return this.activateResourceSession(delegation.delegationHeader, resources, delegation.host, signal);
|
|
26637
|
+
}
|
|
26638
|
+
activateSignedSession(session, siwe, hostHint, signal) {
|
|
26639
|
+
const resources = this.parseRecapWithCaveats(siwe).map(
|
|
26640
|
+
(entry) => this.isEncryptionNetworkOperation(this.invocationServiceName(entry.service), entry.path, entry.space) ? entry.path.split("/")[0] : entry.space.startsWith("tinycloud:") ? entry.space : session.spaceId
|
|
26641
|
+
);
|
|
26642
|
+
return this.activateResourceSession(
|
|
26643
|
+
session.delegationHeader,
|
|
26644
|
+
resources.length > 0 ? resources : [session.spaceId],
|
|
26645
|
+
hostHint,
|
|
26646
|
+
signal
|
|
26647
|
+
);
|
|
26648
|
+
}
|
|
26407
26649
|
/**
|
|
26408
26650
|
* Install a portable runtime permission delegation into this SDK instance so
|
|
26409
26651
|
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
@@ -26423,16 +26665,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26423
26665
|
`Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
|
|
26424
26666
|
);
|
|
26425
26667
|
}
|
|
26426
|
-
const targetHost = delegation.host ?? this.config.host;
|
|
26427
26668
|
let activateResult;
|
|
26428
26669
|
try {
|
|
26429
|
-
activateResult = await (
|
|
26430
|
-
targetHost,
|
|
26431
|
-
delegation.delegationHeader,
|
|
26432
|
-
graph.signal
|
|
26433
|
-
);
|
|
26670
|
+
activateResult = await this.activateRoutedDelegation(delegation, graph.signal);
|
|
26434
26671
|
} catch (cause) {
|
|
26435
26672
|
graph.assertActive();
|
|
26673
|
+
if ((0, import_sdk_services5.routingFailure)(cause)) throw cause;
|
|
26436
26674
|
throw Object.assign(
|
|
26437
26675
|
new Error("The TinyCloud host could not be reached to activate the delegation."),
|
|
26438
26676
|
{ code: "ACTIVATION_TRANSPORT_FAILED", cause }
|
|
@@ -26588,11 +26826,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26588
26826
|
...prepared,
|
|
26589
26827
|
signature: signature2
|
|
26590
26828
|
});
|
|
26591
|
-
const
|
|
26592
|
-
|
|
26593
|
-
|
|
26594
|
-
|
|
26595
|
-
|
|
26829
|
+
const delegation = this.runtimeDelegationFromSession(
|
|
26830
|
+
delegatedSession,
|
|
26831
|
+
delegatedEntries,
|
|
26832
|
+
spaceId,
|
|
26833
|
+
captured,
|
|
26834
|
+
expiresAt,
|
|
26835
|
+
{ siwe: prepared.siwe, signature: signature2 }
|
|
26836
|
+
);
|
|
26837
|
+
const activateResult = await this.activateRoutedDelegation(delegation, graph.signal).catch((error) => {
|
|
26596
26838
|
graph.assertActive();
|
|
26597
26839
|
throw error;
|
|
26598
26840
|
});
|
|
@@ -26608,14 +26850,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26608
26850
|
{ cause: activateResult }
|
|
26609
26851
|
);
|
|
26610
26852
|
}
|
|
26611
|
-
const delegation = this.runtimeDelegationFromSession(
|
|
26612
|
-
delegatedSession,
|
|
26613
|
-
delegatedEntries,
|
|
26614
|
-
spaceId,
|
|
26615
|
-
captured,
|
|
26616
|
-
expiresAt,
|
|
26617
|
-
{ siwe: prepared.siwe, signature: signature2 }
|
|
26618
|
-
);
|
|
26619
26853
|
graph.assertActive();
|
|
26620
26854
|
assertCapturedKey?.();
|
|
26621
26855
|
this.runtimePermissionGrants.push({
|
|
@@ -26760,7 +26994,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26760
26994
|
if (!publicSpaceId) {
|
|
26761
26995
|
throw new Error("Public space not enabled. Set enablePublicSpace: true in config.");
|
|
26762
26996
|
}
|
|
26763
|
-
await this.assertMayCreateSpace();
|
|
26997
|
+
await this.assertMayCreateSpace(publicSpaceId);
|
|
26764
26998
|
await this.auth.hostPublicSpace(publicSpaceId);
|
|
26765
26999
|
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
27000
|
const abilities = { kv: { "": kvActions } };
|
|
@@ -26783,10 +27017,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26783
27017
|
...prepared,
|
|
26784
27018
|
signature: signature2
|
|
26785
27019
|
});
|
|
26786
|
-
const activateResult = await (
|
|
26787
|
-
this.config.host,
|
|
26788
|
-
delegationSession.delegationHeader
|
|
26789
|
-
);
|
|
27020
|
+
const activateResult = await this.activateSignedSession(delegationSession, prepared.siwe);
|
|
26790
27021
|
if (!activateResult.success) {
|
|
26791
27022
|
throw Object.assign(
|
|
26792
27023
|
new Error(`Failed to activate public space delegation: ${describeHostFailure2(activateResult)}`),
|
|
@@ -27336,10 +27567,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
27336
27567
|
if (onPrepared) {
|
|
27337
27568
|
await onPrepared(delegation);
|
|
27338
27569
|
}
|
|
27339
|
-
const activateResult = await (
|
|
27340
|
-
this.config.host,
|
|
27341
|
-
delegationHeader
|
|
27342
|
-
);
|
|
27570
|
+
const activateResult = await this.activateRoutedDelegation(delegation);
|
|
27343
27571
|
assertDelegationActivated(activateResult, delegation, requireActivation);
|
|
27344
27572
|
return delegation;
|
|
27345
27573
|
}
|
|
@@ -27373,10 +27601,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
27373
27601
|
if (onPrepared) {
|
|
27374
27602
|
await onPrepared(delegation);
|
|
27375
27603
|
}
|
|
27376
|
-
const activateResult = await (
|
|
27377
|
-
targetHost,
|
|
27378
|
-
delegationHeader
|
|
27379
|
-
);
|
|
27604
|
+
const activateResult = await this.activateRoutedDelegation(delegation);
|
|
27380
27605
|
assertDelegationActivated(activateResult, delegation, requireActivation);
|
|
27381
27606
|
return delegation;
|
|
27382
27607
|
}
|
|
@@ -28028,10 +28253,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
28028
28253
|
...prepared,
|
|
28029
28254
|
signature: signature2
|
|
28030
28255
|
});
|
|
28031
|
-
const activateResult = await (
|
|
28032
|
-
this.config.host,
|
|
28033
|
-
delegationSession.delegationHeader
|
|
28034
|
-
);
|
|
28256
|
+
const activateResult = await this.activateSignedSession(delegationSession, prepared.siwe);
|
|
28035
28257
|
if (!activateResult.success) {
|
|
28036
28258
|
throw Object.assign(
|
|
28037
28259
|
new Error(`Failed to activate delegation: ${describeHostFailure2(activateResult)}`),
|
|
@@ -28076,10 +28298,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
28076
28298
|
...publicPrepared,
|
|
28077
28299
|
signature: publicSignature
|
|
28078
28300
|
});
|
|
28079
|
-
const publicActivateResult = await (
|
|
28080
|
-
this.config.host,
|
|
28081
|
-
publicSession.delegationHeader
|
|
28082
|
-
);
|
|
28301
|
+
const publicActivateResult = await this.activateSignedSession(publicSession, publicPrepared.siwe);
|
|
28083
28302
|
if (publicActivateResult.success) {
|
|
28084
28303
|
result.publicDelegation = {
|
|
28085
28304
|
cid: publicSession.delegationCid,
|
|
@@ -28185,11 +28404,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
28185
28404
|
...prepared,
|
|
28186
28405
|
signature: signature2
|
|
28187
28406
|
});
|
|
28188
|
-
const activateResult = await (
|
|
28189
|
-
targetHost,
|
|
28190
|
-
invokerSession.delegationHeader,
|
|
28191
|
-
graph.signal
|
|
28192
|
-
).catch((error) => {
|
|
28407
|
+
const activateResult = await this.activateSignedSession(invokerSession, prepared.siwe, targetHost, graph.signal).catch((error) => {
|
|
28193
28408
|
graph.assertActive();
|
|
28194
28409
|
throw error;
|
|
28195
28410
|
});
|
|
@@ -28316,10 +28531,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
28316
28531
|
...prepared,
|
|
28317
28532
|
signature: signature2
|
|
28318
28533
|
});
|
|
28319
|
-
const activateResult = await (
|
|
28320
|
-
targetHost,
|
|
28321
|
-
subDelegationSession.delegationHeader
|
|
28322
|
-
);
|
|
28534
|
+
const activateResult = await this.activateSignedSession(subDelegationSession, prepared.siwe, targetHost);
|
|
28323
28535
|
if (!activateResult.success) {
|
|
28324
28536
|
throw Object.assign(
|
|
28325
28537
|
new Error(`Failed to activate sub-delegation: ${describeHostFailure2(activateResult)}`),
|
|
@@ -28383,6 +28595,7 @@ registerReplicationLoaders({
|
|
|
28383
28595
|
|
|
28384
28596
|
// src/index.ts
|
|
28385
28597
|
var import_sdk_core15 = require("@tinycloud/sdk-core");
|
|
28598
|
+
var import_sdk_services8 = require("@tinycloud/sdk-services");
|
|
28386
28599
|
var import_sdk_core16 = require("@tinycloud/sdk-core");
|
|
28387
28600
|
|
|
28388
28601
|
// src/storage/FileSessionStorage.ts
|
|
@@ -28582,7 +28795,7 @@ var import_node_fs = require("fs");
|
|
|
28582
28795
|
var import_promises = require("fs/promises");
|
|
28583
28796
|
var import_node_path = require("path");
|
|
28584
28797
|
var import_sdk_core14 = require("@tinycloud/sdk-core");
|
|
28585
|
-
var
|
|
28798
|
+
var import_sdk_services7 = require("@tinycloud/sdk-services");
|
|
28586
28799
|
var import_contractConstants = require("@tinycloud/sdk-services/kv/replication/contractConstants");
|
|
28587
28800
|
init_authority();
|
|
28588
28801
|
var REPLICA_LOGOUT_PENDING_FILE = "replica-logout-pending.json";
|
|
@@ -29144,7 +29357,7 @@ function sha256Base32(material) {
|
|
|
29144
29357
|
return out.slice(0, 26);
|
|
29145
29358
|
}
|
|
29146
29359
|
function partitionDirOf(root, identity) {
|
|
29147
|
-
return (0, import_node_path.join)(root, sha256Base32((0,
|
|
29360
|
+
return (0, import_node_path.join)(root, sha256Base32((0, import_sdk_services7.replicationIdentityKey)(identity)));
|
|
29148
29361
|
}
|
|
29149
29362
|
function replicaHashOf(prefix, deviceDid) {
|
|
29150
29363
|
return sha256Base32(`${prefix}
|
|
@@ -29218,8 +29431,8 @@ function deviceRecordOf(value) {
|
|
|
29218
29431
|
}
|
|
29219
29432
|
function sameIdentity(a, b) {
|
|
29220
29433
|
try {
|
|
29221
|
-
const left = (0,
|
|
29222
|
-
const right = (0,
|
|
29434
|
+
const left = (0, import_sdk_services7.canonicalReplicationIdentity)(a);
|
|
29435
|
+
const right = (0, import_sdk_services7.canonicalReplicationIdentity)(b);
|
|
29223
29436
|
return left.host === right.host && left.space === right.space && left.principal === right.principal;
|
|
29224
29437
|
} catch {
|
|
29225
29438
|
return false;
|
|
@@ -29235,7 +29448,7 @@ async function ensurePartitionIdentity(dir, identity, dirSync) {
|
|
|
29235
29448
|
const file = (0, import_node_path.join)(dir, "identity.json");
|
|
29236
29449
|
const existing = await readJsonFile(file);
|
|
29237
29450
|
if (existing === void 0) {
|
|
29238
|
-
await writeJsonAtomic(file, { v: 1, ...(0,
|
|
29451
|
+
await writeJsonAtomic(file, { v: 1, ...(0, import_sdk_services7.canonicalReplicationIdentity)(identity) }, dirSync);
|
|
29239
29452
|
return;
|
|
29240
29453
|
}
|
|
29241
29454
|
const record = identityRecordOf(existing);
|
|
@@ -29334,7 +29547,7 @@ withGate_fn = async function(section) {
|
|
|
29334
29547
|
if (snapshot === void 0) throw gated("gate_unavailable");
|
|
29335
29548
|
const [principalHash, identityKeyHash] = await Promise.all([
|
|
29336
29549
|
gate.principalHashOf(snapshot.salt, this.identity.principal),
|
|
29337
|
-
gate.identityHashOf(snapshot.salt, (0,
|
|
29550
|
+
gate.identityHashOf(snapshot.salt, (0, import_sdk_services7.replicationIdentityKey)(this.identity))
|
|
29338
29551
|
]);
|
|
29339
29552
|
const access = {
|
|
29340
29553
|
stamp: __privateGet(this, _stamp),
|
|
@@ -29835,7 +30048,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
29835
30048
|
if (snapshot === void 0) throw gated("gate_unavailable");
|
|
29836
30049
|
const [principalHash, identityKeyHash] = await Promise.all([
|
|
29837
30050
|
gate.principalHashOf(snapshot.salt, principal),
|
|
29838
|
-
identity === void 0 ? Promise.resolve(void 0) : gate.identityHashOf(snapshot.salt, (0,
|
|
30051
|
+
identity === void 0 ? Promise.resolve(void 0) : gate.identityHashOf(snapshot.salt, (0, import_sdk_services7.replicationIdentityKey)(identity))
|
|
29839
30052
|
]);
|
|
29840
30053
|
return profileSection(async () => {
|
|
29841
30054
|
assertLogoutClear(options.logoutPendingFile);
|
|
@@ -29858,7 +30071,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
29858
30071
|
if (snapshot === void 0) throw gated("gate_unavailable");
|
|
29859
30072
|
const [principalHash, identityKeyHash] = await Promise.all([
|
|
29860
30073
|
gate.principalHashOf(snapshot.salt, spec.identity.principal),
|
|
29861
|
-
gate.identityHashOf(snapshot.salt, (0,
|
|
30074
|
+
gate.identityHashOf(snapshot.salt, (0, import_sdk_services7.replicationIdentityKey)(spec.identity))
|
|
29862
30075
|
]);
|
|
29863
30076
|
const access = {
|
|
29864
30077
|
stamp: spec.stamp,
|
|
@@ -29942,7 +30155,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
29942
30155
|
const identity = identityRecordOf(await readJsonFile((0, import_node_path.join)(idDir, "identity.json")));
|
|
29943
30156
|
if (identity === void 0) throw new ReplicaStorageError("STORAGE_ERROR", `Missing identity at ${idDir}.`);
|
|
29944
30157
|
if (await gate.principalHashOf(salt, identity.principal) !== principalHash) continue;
|
|
29945
|
-
const identityKeyHash = await gate.identityHashOf(salt, (0,
|
|
30158
|
+
const identityKeyHash = await gate.identityHashOf(salt, (0, import_sdk_services7.replicationIdentityKey)(identity));
|
|
29946
30159
|
const recordedAt = Date.now();
|
|
29947
30160
|
if (await pathExists((0, import_node_path.join)(idDir, "pending.json")) || await pathExists((0, import_node_path.join)(idDir, "device.jwk"))) {
|
|
29948
30161
|
intents.push({ id: `pending:${identityKeyHash}`, kind: "pending", identityKeyHash, principalHash, recordedAt });
|
|
@@ -30620,7 +30833,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
30620
30833
|
for (const dir of await identityDirs()) {
|
|
30621
30834
|
const identity = identityRecordOf(await readJsonFile((0, import_node_path.join)(dir, "identity.json")));
|
|
30622
30835
|
if (identity === void 0) throw new ReplicaStorageError("STORAGE_ERROR", `Missing identity at ${dir}.`);
|
|
30623
|
-
const hash3 = await gate.identityHashOf(state.salt, (0,
|
|
30836
|
+
const hash3 = await gate.identityHashOf(state.salt, (0, import_sdk_services7.replicationIdentityKey)(identity));
|
|
30624
30837
|
if (intent.kind === "pending" ? hash3 === intent.identityKeyHash : intent.partitionId.startsWith(`${hash3}:`)) {
|
|
30625
30838
|
idDir = dir;
|
|
30626
30839
|
break;
|
|
@@ -30766,7 +30979,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
30766
30979
|
const gate = await fileGate();
|
|
30767
30980
|
const snapshot = await gate.readGateSnapshot(profileDir);
|
|
30768
30981
|
if (snapshot === void 0) throw gated("gate_unavailable");
|
|
30769
|
-
const identityKeyHash = await gate.identityHashOf(snapshot.salt, (0,
|
|
30982
|
+
const identityKeyHash = await gate.identityHashOf(snapshot.salt, (0, import_sdk_services7.replicationIdentityKey)(spec.identity));
|
|
30770
30983
|
const resolvePolicy = async (at, recordFirst) => {
|
|
30771
30984
|
const policy = spec.grantPolicy;
|
|
30772
30985
|
if (!Number.isSafeInteger(policy.grantTtlMs) || policy.grantTtlMs <= 0 || policy.grantTtlMs > import_contractConstants.MAX_GRANT_TTL_MS) {
|
|
@@ -30788,7 +31001,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
30788
31001
|
let partitionId;
|
|
30789
31002
|
const storeGuard = (section) => guarded(spec.identity.principal, spec.stamp, spec.identity, partitionId, section);
|
|
30790
31003
|
return guarded(spec.identity.principal, spec.stamp, spec.identity, void 0, async () => {
|
|
30791
|
-
if ((0,
|
|
31004
|
+
if ((0, import_sdk_services7.requiresSecretsOptIn)(spec.space, spec.prefix) && spec.allowSecrets !== true) {
|
|
30792
31005
|
throw new replica.ReplicaError(
|
|
30793
31006
|
replica.ReplicaErrorCode.SECRETS_OPT_IN_REQUIRED,
|
|
30794
31007
|
`Replicating ${spec.space}/kv/${spec.prefix} copies secret material to disk; pass allowSecrets to opt in.`
|
|
@@ -31034,7 +31247,7 @@ function createSqliteReplicaStorage(options) {
|
|
|
31034
31247
|
const gate = await fileGate();
|
|
31035
31248
|
const currentGate = await gate.readGateSnapshot(profileDir);
|
|
31036
31249
|
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,
|
|
31250
|
+
const identityKeyHash = await gate.identityHashOf(currentGate.salt, (0, import_sdk_services7.replicationIdentityKey)(target.identity));
|
|
31038
31251
|
await retainGrantInstalls(gate, currentGate, identityKeyHash, store);
|
|
31039
31252
|
}
|
|
31040
31253
|
if (state.revoked === null) {
|
|
@@ -31130,8 +31343,11 @@ function sqliteReplicaStorage(options) {
|
|
|
31130
31343
|
MemorySessionStorage,
|
|
31131
31344
|
NETWORK_NAME_PATTERN,
|
|
31132
31345
|
NetworkIdError,
|
|
31346
|
+
NodeIdentityMismatchError,
|
|
31347
|
+
NodeNotRespondingError,
|
|
31133
31348
|
NodeUserAuthorization,
|
|
31134
31349
|
NodeWasmBindings,
|
|
31350
|
+
PartialNodeWriteError,
|
|
31135
31351
|
PermissionNotInManifestError,
|
|
31136
31352
|
PrefixedKVService,
|
|
31137
31353
|
PrivateKeySigner,
|