@tinycloud/node-sdk 2.4.0-beta.1 → 2.4.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{core-Dbzm1kA_.d.cts → core--mjBU9Jq.d.cts} +154 -6
- package/dist/{core-Dbzm1kA_.d.ts → core--mjBU9Jq.d.ts} +154 -6
- package/dist/core.cjs +462 -222
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +291 -48
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +533 -265
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +322 -52
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -17186,7 +17186,9 @@ import {
|
|
|
17186
17186
|
verifyDidKeyEd25519Signature,
|
|
17187
17187
|
canonicalizeAddress as canonicalizeAddress2,
|
|
17188
17188
|
pkhDid as pkhDid2,
|
|
17189
|
-
|
|
17189
|
+
resolveTinyCloudHosts as resolveTinyCloudHosts2,
|
|
17190
|
+
principalDidEquals as principalDidEquals2,
|
|
17191
|
+
parseNetworkId as parseNetworkId2
|
|
17190
17192
|
} from "@tinycloud/sdk-core";
|
|
17191
17193
|
|
|
17192
17194
|
// src/authorization/NodeUserAuthorization.ts
|
|
@@ -17199,6 +17201,8 @@ import {
|
|
|
17199
17201
|
DEFAULT_MANIFEST_SPACE,
|
|
17200
17202
|
ENCRYPTION_PERMISSION_SERVICE,
|
|
17201
17203
|
composeManifestRequest,
|
|
17204
|
+
parseNetworkId,
|
|
17205
|
+
principalDidEquals,
|
|
17202
17206
|
resourceCapabilitiesToAbilitiesMap,
|
|
17203
17207
|
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
17204
17208
|
resolveTinyCloudHosts,
|
|
@@ -17283,6 +17287,25 @@ var MemorySessionStorage = class {
|
|
|
17283
17287
|
};
|
|
17284
17288
|
|
|
17285
17289
|
// src/authorization/NodeUserAuthorization.ts
|
|
17290
|
+
var DECRYPT_ACTION = "tinycloud.encryption/decrypt";
|
|
17291
|
+
var NETWORK_CREATE_ACTION = "tinycloud.encryption/network.create";
|
|
17292
|
+
function didPrincipalMatches(actual, expected) {
|
|
17293
|
+
try {
|
|
17294
|
+
return principalDidEquals(actual, expected);
|
|
17295
|
+
} catch {
|
|
17296
|
+
return actual === expected;
|
|
17297
|
+
}
|
|
17298
|
+
}
|
|
17299
|
+
function addRawAbility(rawAbilities, resource, action) {
|
|
17300
|
+
const actions = rawAbilities[resource];
|
|
17301
|
+
if (actions === void 0) {
|
|
17302
|
+
rawAbilities[resource] = [action];
|
|
17303
|
+
return;
|
|
17304
|
+
}
|
|
17305
|
+
if (!actions.includes(action)) {
|
|
17306
|
+
actions.push(action);
|
|
17307
|
+
}
|
|
17308
|
+
}
|
|
17286
17309
|
var NodeUserAuthorization = class {
|
|
17287
17310
|
constructor(config) {
|
|
17288
17311
|
this.extensions = [];
|
|
@@ -17309,6 +17332,7 @@ var NodeUserAuthorization = class {
|
|
|
17309
17332
|
"": [
|
|
17310
17333
|
"tinycloud.sql/read",
|
|
17311
17334
|
"tinycloud.sql/write",
|
|
17335
|
+
"tinycloud.sql/ddl",
|
|
17312
17336
|
"tinycloud.sql/admin",
|
|
17313
17337
|
"tinycloud.sql/export"
|
|
17314
17338
|
]
|
|
@@ -17400,12 +17424,48 @@ var NodeUserAuthorization = class {
|
|
|
17400
17424
|
* `siwe` is the load-bearing one because `extractSiweExpiration` returns
|
|
17401
17425
|
* undefined for missing SIWEs and the SDK then treats the session as
|
|
17402
17426
|
* expired-at-epoch-zero.
|
|
17427
|
+
*
|
|
17428
|
+
* @param hosts - The TinyCloud hosts this session was created against,
|
|
17429
|
+
* as persisted in {@link PersistedSessionData.tinycloudHosts}. When
|
|
17430
|
+
* present (and non-empty) they are adopted directly so the restored
|
|
17431
|
+
* session resolves to the same node as the original sign-in without
|
|
17432
|
+
* re-running registry/fallback resolution. When absent (old session)
|
|
17433
|
+
* hosts are resolved lazily on the first host-needing call via
|
|
17434
|
+
* {@link ensureTinyCloudHosts}.
|
|
17403
17435
|
*/
|
|
17404
|
-
setRestoredTinyCloudSession(session) {
|
|
17436
|
+
setRestoredTinyCloudSession(session, hosts) {
|
|
17405
17437
|
const address = canonicalizeAddress(session.address);
|
|
17406
17438
|
this._tinyCloudSession = { ...session, address };
|
|
17407
17439
|
this._address = address;
|
|
17408
17440
|
this._chainId = session.chainId;
|
|
17441
|
+
if ((!this.tinycloudHosts || this.tinycloudHosts.length === 0) && hosts && hosts.length > 0) {
|
|
17442
|
+
this.tinycloudHosts = [...hosts];
|
|
17443
|
+
}
|
|
17444
|
+
}
|
|
17445
|
+
/**
|
|
17446
|
+
* Ensure `tinycloudHosts` are resolved before a host-needing call.
|
|
17447
|
+
*
|
|
17448
|
+
* Fresh sign-in resolves hosts up front; a restored session may not have
|
|
17449
|
+
* (old persisted sessions predate {@link PersistedSessionData.tinycloudHosts}).
|
|
17450
|
+
* This guard makes a restored session resolve the node exactly like a fresh
|
|
17451
|
+
* sign-in — persisted hosts are preferred (already set by
|
|
17452
|
+
* {@link setRestoredTinyCloudSession}), otherwise the registry/fallback
|
|
17453
|
+
* resolution runs lazily here. Idempotent: {@link resolveTinyCloudHostsForSignIn}
|
|
17454
|
+
* early-returns when hosts are already set.
|
|
17455
|
+
*
|
|
17456
|
+
* Throws if hosts are unset and the restored session has no address/chainId
|
|
17457
|
+
* to resolve from — a real failure that must surface, not be masked.
|
|
17458
|
+
*/
|
|
17459
|
+
async ensureTinyCloudHosts() {
|
|
17460
|
+
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
17461
|
+
return;
|
|
17462
|
+
}
|
|
17463
|
+
if (this._address === void 0 || this._chainId === void 0) {
|
|
17464
|
+
throw new Error(
|
|
17465
|
+
"Cannot resolve TinyCloud hosts: no address/chainId available. Sign in or restore a session first."
|
|
17466
|
+
);
|
|
17467
|
+
}
|
|
17468
|
+
await this.resolveTinyCloudHostsForSignIn(this._address, this._chainId);
|
|
17409
17469
|
}
|
|
17410
17470
|
async resolveTinyCloudHostsForSignIn(address, chainId) {
|
|
17411
17471
|
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
@@ -17512,20 +17572,18 @@ var NodeUserAuthorization = class {
|
|
|
17512
17572
|
};
|
|
17513
17573
|
}
|
|
17514
17574
|
const rawAbilities = {};
|
|
17575
|
+
const currentDid = pkhDid(address, chainId);
|
|
17515
17576
|
const spaceResources = request.resources.filter((entry) => {
|
|
17516
17577
|
if (entry.service !== ENCRYPTION_PERMISSION_SERVICE) {
|
|
17517
17578
|
return true;
|
|
17518
17579
|
}
|
|
17519
|
-
const
|
|
17520
|
-
|
|
17521
|
-
|
|
17522
|
-
|
|
17523
|
-
const
|
|
17524
|
-
|
|
17525
|
-
|
|
17526
|
-
existing.push(action);
|
|
17527
|
-
seen.add(action);
|
|
17528
|
-
}
|
|
17580
|
+
for (const action of entry.actions) {
|
|
17581
|
+
addRawAbility(rawAbilities, entry.path, action);
|
|
17582
|
+
}
|
|
17583
|
+
if (entry.actions.includes(DECRYPT_ACTION)) {
|
|
17584
|
+
const parsed = parseNetworkId(entry.path);
|
|
17585
|
+
if (didPrincipalMatches(parsed.ownerDid, currentDid)) {
|
|
17586
|
+
addRawAbility(rawAbilities, entry.path, NETWORK_CREATE_ACTION);
|
|
17529
17587
|
}
|
|
17530
17588
|
}
|
|
17531
17589
|
return false;
|
|
@@ -17604,6 +17662,7 @@ var NodeUserAuthorization = class {
|
|
|
17604
17662
|
if (!this._tinyCloudSession || !this._address || !this._chainId) {
|
|
17605
17663
|
throw new Error("Must be signed in to host space");
|
|
17606
17664
|
}
|
|
17665
|
+
await this.ensureTinyCloudHosts();
|
|
17607
17666
|
const host = this.primaryTinyCloudHost;
|
|
17608
17667
|
const spaceId = targetSpaceId ?? this._tinyCloudSession.spaceId;
|
|
17609
17668
|
const peerId = await fetchPeerId(host, spaceId);
|
|
@@ -17646,6 +17705,7 @@ var NodeUserAuthorization = class {
|
|
|
17646
17705
|
if (!this._tinyCloudSession) {
|
|
17647
17706
|
throw new Error("Must be signed in to ensure space exists");
|
|
17648
17707
|
}
|
|
17708
|
+
await this.ensureTinyCloudHosts();
|
|
17649
17709
|
const host = this.primaryTinyCloudHost;
|
|
17650
17710
|
const primarySpaceId = this._tinyCloudSession.spaceId;
|
|
17651
17711
|
const result = await activateSessionWithHost(
|
|
@@ -17827,7 +17887,8 @@ var NodeUserAuthorization = class {
|
|
|
17827
17887
|
},
|
|
17828
17888
|
expiresAt: expirationTime.toISOString(),
|
|
17829
17889
|
createdAt: now.toISOString(),
|
|
17830
|
-
version: "1.0"
|
|
17890
|
+
version: "1.0",
|
|
17891
|
+
tinycloudHosts: this.tinycloudHosts
|
|
17831
17892
|
};
|
|
17832
17893
|
await this.sessionStorage.save(address, persistedData);
|
|
17833
17894
|
this._session = clientSession;
|
|
@@ -17994,7 +18055,8 @@ var NodeUserAuthorization = class {
|
|
|
17994
18055
|
},
|
|
17995
18056
|
expiresAt,
|
|
17996
18057
|
createdAt,
|
|
17997
|
-
version: "1.0"
|
|
18058
|
+
version: "1.0",
|
|
18059
|
+
tinycloudHosts: this.tinycloudHosts
|
|
17998
18060
|
};
|
|
17999
18061
|
await this.sessionStorage.save(address, persistedData);
|
|
18000
18062
|
this._session = clientSession;
|
|
@@ -18084,6 +18146,9 @@ var NodeUserAuthorization = class {
|
|
|
18084
18146
|
}
|
|
18085
18147
|
};
|
|
18086
18148
|
|
|
18149
|
+
// src/account/AccountService.ts
|
|
18150
|
+
import { AccountService } from "@tinycloud/sdk-core";
|
|
18151
|
+
|
|
18087
18152
|
// src/DelegatedAccess.ts
|
|
18088
18153
|
import {
|
|
18089
18154
|
KVService,
|
|
@@ -18501,13 +18566,13 @@ var NodeSecretsService = class {
|
|
|
18501
18566
|
// src/TinyCloudNode.ts
|
|
18502
18567
|
var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
18503
18568
|
var DEFAULT_ENCRYPTION_NETWORK_NAME = "default";
|
|
18504
|
-
var
|
|
18505
|
-
var
|
|
18569
|
+
var NETWORK_CREATE_ACTION2 = "tinycloud.encryption/network.create";
|
|
18570
|
+
var DECRYPT_ACTION2 = "tinycloud.encryption/decrypt";
|
|
18506
18571
|
var NETWORK_ADMIN_TYPE = "tinycloud.encryption.network-admin/v1";
|
|
18507
18572
|
var DEFAULT_SESSION_EXPIRATION_MS = EXPIRY3.SESSION_MS;
|
|
18508
|
-
function
|
|
18573
|
+
function didPrincipalMatches2(actual, expected) {
|
|
18509
18574
|
try {
|
|
18510
|
-
return
|
|
18575
|
+
return principalDidEquals2(actual, expected);
|
|
18511
18576
|
} catch {
|
|
18512
18577
|
return actual === expected;
|
|
18513
18578
|
}
|
|
@@ -18844,6 +18909,37 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18844
18909
|
get spaceId() {
|
|
18845
18910
|
return this.auth?.tinyCloudSession?.spaceId;
|
|
18846
18911
|
}
|
|
18912
|
+
/**
|
|
18913
|
+
* Get the account space ID for this wallet identity.
|
|
18914
|
+
* Available after wallet-backed sign-in or a restored session with address metadata.
|
|
18915
|
+
*/
|
|
18916
|
+
get accountSpaceId() {
|
|
18917
|
+
if (!this._address) {
|
|
18918
|
+
return void 0;
|
|
18919
|
+
}
|
|
18920
|
+
return this.wasmBindings.makeSpaceId(this._address, this._chainId, ACCOUNT_REGISTRY_SPACE);
|
|
18921
|
+
}
|
|
18922
|
+
/**
|
|
18923
|
+
* Account-level application and delegation helpers.
|
|
18924
|
+
*/
|
|
18925
|
+
get account() {
|
|
18926
|
+
if (!this._account) {
|
|
18927
|
+
this._account = new AccountService({
|
|
18928
|
+
getDid: () => this.did,
|
|
18929
|
+
getHost: () => this.hosts[0] ?? this.config.host,
|
|
18930
|
+
getPrimarySpaceId: () => this.spaceId,
|
|
18931
|
+
getAccountSpaceId: () => this.accountSpaceId,
|
|
18932
|
+
getSpaces: () => this.spaces,
|
|
18933
|
+
getAccountDb: () => this.accountSpaceId ? this.sqlForSpace(this.accountSpaceId).db("account") : void 0,
|
|
18934
|
+
ensureAccountSpaceHosted: async () => {
|
|
18935
|
+
if (this.accountSpaceId && this.auth) {
|
|
18936
|
+
await this.ensureOwnedSpaceHostedById(this.accountSpaceId);
|
|
18937
|
+
}
|
|
18938
|
+
}
|
|
18939
|
+
});
|
|
18940
|
+
}
|
|
18941
|
+
return this._account;
|
|
18942
|
+
}
|
|
18847
18943
|
/**
|
|
18848
18944
|
* Get the current TinyCloud session.
|
|
18849
18945
|
* Available after signIn().
|
|
@@ -18881,10 +18977,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18881
18977
|
await this.tc.signIn(options);
|
|
18882
18978
|
this.syncResolvedHostFromAuth();
|
|
18883
18979
|
this.initializeServices();
|
|
18980
|
+
await this.ensureRequestedEncryptionNetworks();
|
|
18884
18981
|
if (this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
18885
|
-
await this.
|
|
18982
|
+
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId("secrets"));
|
|
18886
18983
|
}
|
|
18887
|
-
|
|
18984
|
+
this.scheduleAccountRegistrySync();
|
|
18888
18985
|
this.notificationHandler.success("Successfully signed in");
|
|
18889
18986
|
}
|
|
18890
18987
|
ownedSpaceId(name) {
|
|
@@ -18902,22 +18999,68 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18902
18999
|
throw new Error("Manifest registry write requires wallet mode");
|
|
18903
19000
|
}
|
|
18904
19001
|
const accountSpaceId = this.ownedSpaceId(ACCOUNT_REGISTRY_SPACE);
|
|
18905
|
-
await this.
|
|
18906
|
-
const
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18911
|
-
|
|
18912
|
-
|
|
18913
|
-
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
|
|
19002
|
+
await this.ensureOwnedSpaceHostedById(accountSpaceId);
|
|
19003
|
+
const result = await this.account.applications.register(request.manifests);
|
|
19004
|
+
if (!result.ok) {
|
|
19005
|
+
throw new Error(
|
|
19006
|
+
`Failed to write manifest registry records: ${result.error.message}`
|
|
19007
|
+
);
|
|
19008
|
+
}
|
|
19009
|
+
}
|
|
19010
|
+
scheduleAccountRegistrySync() {
|
|
19011
|
+
void this.withAccountRegistryRetry(async () => {
|
|
19012
|
+
await this.writeManifestRegistryRecords();
|
|
19013
|
+
const spaces = await this.account.spaces.syncAccessible();
|
|
19014
|
+
if (!spaces.ok) {
|
|
19015
|
+
throw new Error(`Failed to sync account spaces: ${spaces.error.message}`);
|
|
19016
|
+
}
|
|
19017
|
+
});
|
|
19018
|
+
}
|
|
19019
|
+
async withAccountRegistryRetry(task) {
|
|
19020
|
+
const delays = [250, 1e3, 3e3];
|
|
19021
|
+
let lastError;
|
|
19022
|
+
for (let attempt = 0; attempt < delays.length; attempt += 1) {
|
|
19023
|
+
try {
|
|
19024
|
+
await task();
|
|
19025
|
+
return;
|
|
19026
|
+
} catch (error) {
|
|
19027
|
+
lastError = error;
|
|
19028
|
+
if (attempt < delays.length - 1) {
|
|
19029
|
+
await new Promise((resolve) => setTimeout(resolve, delays[attempt]));
|
|
19030
|
+
}
|
|
19031
|
+
}
|
|
19032
|
+
}
|
|
19033
|
+
console.warn(
|
|
19034
|
+
"TinyCloud account registry sync failed after retries",
|
|
19035
|
+
lastError
|
|
19036
|
+
);
|
|
19037
|
+
}
|
|
19038
|
+
requestedEncryptionNetworkIds() {
|
|
19039
|
+
const request = this.capabilityRequest;
|
|
19040
|
+
if (!request) {
|
|
19041
|
+
return [];
|
|
19042
|
+
}
|
|
19043
|
+
const networkIds = /* @__PURE__ */ new Set();
|
|
19044
|
+
for (const resource of request.resources) {
|
|
19045
|
+
if (resource.service === ENCRYPTION_PERMISSION_SERVICE2 && resource.path.startsWith("urn:tinycloud:encryption:") && resource.actions.includes(DECRYPT_ACTION2)) {
|
|
19046
|
+
networkIds.add(resource.path);
|
|
18917
19047
|
}
|
|
18918
19048
|
}
|
|
19049
|
+
return [...networkIds];
|
|
18919
19050
|
}
|
|
18920
|
-
async
|
|
19051
|
+
async ensureRequestedEncryptionNetworks() {
|
|
19052
|
+
if (!this.signer || !this.auth) {
|
|
19053
|
+
return;
|
|
19054
|
+
}
|
|
19055
|
+
for (const networkId of this.requestedEncryptionNetworkIds()) {
|
|
19056
|
+
const parsed = parseNetworkId2(networkId);
|
|
19057
|
+
if (!didPrincipalMatches2(parsed.ownerDid, this.did)) {
|
|
19058
|
+
continue;
|
|
19059
|
+
}
|
|
19060
|
+
await this.ensureEncryptionNetwork(networkId);
|
|
19061
|
+
}
|
|
19062
|
+
}
|
|
19063
|
+
async ensureOwnedSpaceHostedById(spaceId) {
|
|
18921
19064
|
if (!this.auth) {
|
|
18922
19065
|
throw new Error("Owned space hosting requires wallet mode");
|
|
18923
19066
|
}
|
|
@@ -18960,7 +19103,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18960
19103
|
* caller is the root authority of their own owned spaces, so no additional
|
|
18961
19104
|
* delegation is required.
|
|
18962
19105
|
*
|
|
18963
|
-
* Unlike {@link
|
|
19106
|
+
* Unlike {@link ensureOwnedSpaceHostedById}, this always submits the host
|
|
18964
19107
|
* delegation rather than inferring hosting from session activation: a space
|
|
18965
19108
|
* the current session has never referenced is reported neither as
|
|
18966
19109
|
* `activated` nor `skipped`, so activation-based detection would wrongly
|
|
@@ -18994,8 +19137,40 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18994
19137
|
`Failed to activate session for owned space ${spaceId}: ${activation.error ?? "space was skipped"}`
|
|
18995
19138
|
);
|
|
18996
19139
|
}
|
|
19140
|
+
void this.account.spaces.register({
|
|
19141
|
+
spaceId,
|
|
19142
|
+
name,
|
|
19143
|
+
ownerDid: this.did,
|
|
19144
|
+
type: "owned",
|
|
19145
|
+
permissions: ["*"],
|
|
19146
|
+
status: "active"
|
|
19147
|
+
}).catch(() => {
|
|
19148
|
+
});
|
|
18997
19149
|
return spaceId;
|
|
18998
19150
|
}
|
|
19151
|
+
/**
|
|
19152
|
+
* Ensure one of this user's owned spaces (e.g. `"secrets"`) is hosted on the
|
|
19153
|
+
* server.
|
|
19154
|
+
*
|
|
19155
|
+
* At sign-in, a full-authority session auto-hosts the owner's `secrets`
|
|
19156
|
+
* space, but a session created with a manifest / capabilityRequest does not.
|
|
19157
|
+
* Such a session can therefore hold valid `tinycloud.kv/*` capabilities for
|
|
19158
|
+
* the owned `secrets` space yet still fail its first scoped
|
|
19159
|
+
* `secrets.put(...)` with `404 Space not found`, because the space was never
|
|
19160
|
+
* registered on the node.
|
|
19161
|
+
*
|
|
19162
|
+
* Calling this resolves `name` to the owner's owned-space URI
|
|
19163
|
+
* (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`) and hosts it via the
|
|
19164
|
+
* host-SIWE delegation flow. The host SIWE is idempotent server-side, so it
|
|
19165
|
+
* is safe to call whether or not the space already exists; do not gate it on
|
|
19166
|
+
* a prior existence check. Must be called after {@link signIn}.
|
|
19167
|
+
*
|
|
19168
|
+
* @param name - The owned space name (e.g. `"secrets"`).
|
|
19169
|
+
* @returns The hosted owned-space URI.
|
|
19170
|
+
*/
|
|
19171
|
+
async ensureOwnedSpaceHosted(name) {
|
|
19172
|
+
return this.hostOwnedSpace(name);
|
|
19173
|
+
}
|
|
18999
19174
|
/**
|
|
19000
19175
|
* Restore a previously established session from stored delegation data.
|
|
19001
19176
|
*
|
|
@@ -19025,6 +19200,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19025
19200
|
if (sessionData.chainId) {
|
|
19026
19201
|
this._chainId = sessionData.chainId;
|
|
19027
19202
|
}
|
|
19203
|
+
const resolvedHost = await this.resolveRestoredHost(
|
|
19204
|
+
sessionData.tinycloudHosts,
|
|
19205
|
+
restoredAddress,
|
|
19206
|
+
sessionData.chainId
|
|
19207
|
+
);
|
|
19208
|
+
if (resolvedHost) {
|
|
19209
|
+
this.config.host = resolvedHost;
|
|
19210
|
+
}
|
|
19028
19211
|
this._serviceContext = new ServiceContext2({
|
|
19029
19212
|
invoke: this.invokeWithRuntimePermissions,
|
|
19030
19213
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
@@ -19070,12 +19253,45 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19070
19253
|
signature: sessionData.signature ?? ""
|
|
19071
19254
|
};
|
|
19072
19255
|
if (this.auth) {
|
|
19073
|
-
this.auth.setRestoredTinyCloudSession(
|
|
19256
|
+
this.auth.setRestoredTinyCloudSession(
|
|
19257
|
+
tcSession,
|
|
19258
|
+
this.config.host ? [this.config.host] : void 0
|
|
19259
|
+
);
|
|
19074
19260
|
} else {
|
|
19075
19261
|
this._restoredTcSession = tcSession;
|
|
19076
19262
|
}
|
|
19077
19263
|
}
|
|
19078
19264
|
}
|
|
19265
|
+
/**
|
|
19266
|
+
* Resolve the host a restored session should target.
|
|
19267
|
+
*
|
|
19268
|
+
* Mirrors fresh sign-in host resolution but for the restore path:
|
|
19269
|
+
* an explicit/pinned host always wins, then the hosts the session was
|
|
19270
|
+
* persisted with, then a lazy registry/fallback resolution for sessions
|
|
19271
|
+
* that predate the persisted `tinycloudHosts` field. Returns `undefined`
|
|
19272
|
+
* only when there's nothing to resolve from (no explicit host, no
|
|
19273
|
+
* persisted hosts, and no address/chainId) — in which case the existing
|
|
19274
|
+
* `config.host` (default) is left in place.
|
|
19275
|
+
*
|
|
19276
|
+
* Resolution failures are surfaced, not swallowed: a genuinely broken
|
|
19277
|
+
* registry lookup throws rather than silently falling back to a wrong host.
|
|
19278
|
+
*/
|
|
19279
|
+
async resolveRestoredHost(persistedHosts, address, chainId) {
|
|
19280
|
+
if (this.explicitHost) {
|
|
19281
|
+
return this.explicitHost;
|
|
19282
|
+
}
|
|
19283
|
+
if (persistedHosts && persistedHosts.length > 0) {
|
|
19284
|
+
return persistedHosts[0];
|
|
19285
|
+
}
|
|
19286
|
+
if (address === void 0 || chainId === void 0) {
|
|
19287
|
+
return void 0;
|
|
19288
|
+
}
|
|
19289
|
+
const resolved = await resolveTinyCloudHosts2(pkhDid2(address, chainId), {
|
|
19290
|
+
registryUrl: this.config.tinycloudRegistryUrl,
|
|
19291
|
+
fallbackHosts: this.config.tinycloudFallbackHosts
|
|
19292
|
+
});
|
|
19293
|
+
return resolved.hosts[0];
|
|
19294
|
+
}
|
|
19079
19295
|
/**
|
|
19080
19296
|
* Resolve the currently-active TinyCloudSession, preferring the auth
|
|
19081
19297
|
* layer's value (wallet mode) and falling back to the node-level
|
|
@@ -19385,7 +19601,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19385
19601
|
const signed2 = await this.signRawNetworkAuthorization({
|
|
19386
19602
|
targetNode: input.targetNode,
|
|
19387
19603
|
networkId: input.networkId,
|
|
19388
|
-
action:
|
|
19604
|
+
action: DECRYPT_ACTION2,
|
|
19389
19605
|
facts: input.facts
|
|
19390
19606
|
});
|
|
19391
19607
|
return {
|
|
@@ -19402,7 +19618,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19402
19618
|
},
|
|
19403
19619
|
wellKnown: {
|
|
19404
19620
|
fetchWellKnown: async (principal, discoveryKey) => {
|
|
19405
|
-
if (!this._address || !
|
|
19621
|
+
if (!this._address || !didPrincipalMatches2(principal, this.did)) {
|
|
19406
19622
|
return null;
|
|
19407
19623
|
}
|
|
19408
19624
|
if (!this.config.host) {
|
|
@@ -19611,6 +19827,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19611
19827
|
}
|
|
19612
19828
|
};
|
|
19613
19829
|
}
|
|
19830
|
+
},
|
|
19831
|
+
onSpaceRegistered: async (space) => {
|
|
19832
|
+
await this.account.spaces.register(space);
|
|
19614
19833
|
}
|
|
19615
19834
|
});
|
|
19616
19835
|
this._sharingService.updateConfig({
|
|
@@ -19909,12 +20128,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19909
20128
|
crypto2.sha256,
|
|
19910
20129
|
body
|
|
19911
20130
|
),
|
|
19912
|
-
action:
|
|
20131
|
+
action: NETWORK_CREATE_ACTION2
|
|
19913
20132
|
};
|
|
19914
20133
|
const signed2 = await this.signRawNetworkAuthorization({
|
|
19915
20134
|
targetNode,
|
|
19916
20135
|
networkId,
|
|
19917
|
-
action:
|
|
20136
|
+
action: NETWORK_CREATE_ACTION2,
|
|
19918
20137
|
facts
|
|
19919
20138
|
});
|
|
19920
20139
|
const response = await fetch(`${this.config.host}/encryption/networks`, {
|
|
@@ -19935,12 +20154,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19935
20154
|
const created = await response.json();
|
|
19936
20155
|
return created.descriptor;
|
|
19937
20156
|
}
|
|
19938
|
-
async ensureEncryptionNetwork(
|
|
19939
|
-
const
|
|
20157
|
+
async ensureEncryptionNetwork(nameOrNetworkId = DEFAULT_ENCRYPTION_NETWORK_NAME) {
|
|
20158
|
+
const networkId = nameOrNetworkId.startsWith("urn:tinycloud:encryption:") ? nameOrNetworkId : this.getDefaultEncryptionNetworkId(nameOrNetworkId);
|
|
20159
|
+
const existing = await this.getEncryptionNetwork(networkId);
|
|
19940
20160
|
if (existing) {
|
|
19941
20161
|
return existing;
|
|
19942
20162
|
}
|
|
19943
|
-
|
|
20163
|
+
const parsed = parseNetworkId2(networkId);
|
|
20164
|
+
if (!didPrincipalMatches2(parsed.ownerDid, this.did)) {
|
|
20165
|
+
throw new Error(
|
|
20166
|
+
`Cannot create encryption network ${networkId}: owner ${parsed.ownerDid} does not match signed-in DID ${this.did}`
|
|
20167
|
+
);
|
|
20168
|
+
}
|
|
20169
|
+
return this.createEncryptionNetwork(parsed.name);
|
|
19944
20170
|
}
|
|
19945
20171
|
/**
|
|
19946
20172
|
* App-facing secrets API backed by the `secrets` space vault.
|
|
@@ -20088,7 +20314,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20088
20314
|
throw new SessionExpiredError(delegation.expiry);
|
|
20089
20315
|
}
|
|
20090
20316
|
const expectedDids = [session.verificationMethod, this.sessionDid];
|
|
20091
|
-
if (!expectedDids.some((did) =>
|
|
20317
|
+
if (!expectedDids.some((did) => didPrincipalMatches2(delegation.delegateDID, did))) {
|
|
20092
20318
|
throw new Error(
|
|
20093
20319
|
`Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
|
|
20094
20320
|
);
|
|
@@ -20617,7 +20843,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20617
20843
|
);
|
|
20618
20844
|
}
|
|
20619
20845
|
const target = request.delegationTargets.find(
|
|
20620
|
-
(entry) =>
|
|
20846
|
+
(entry) => didPrincipalMatches2(entry.did, did)
|
|
20621
20847
|
);
|
|
20622
20848
|
if (!target) {
|
|
20623
20849
|
throw new Error(`No manifest delegation target found for DID ${did}`);
|
|
@@ -21067,7 +21293,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21067
21293
|
if (granted.resource !== void 0 || requested.resource !== void 0) {
|
|
21068
21294
|
return granted.resource !== void 0 && requested.resource !== void 0 && granted.resource === requested.resource && this.pathContains(granted.path, requested.path);
|
|
21069
21295
|
}
|
|
21070
|
-
return granted.spaceId !== void 0 && requested.spaceId !== void 0 && granted.spaceId
|
|
21296
|
+
return granted.spaceId !== void 0 && requested.spaceId !== void 0 && this.spaceIdsEqual(granted.spaceId, requested.spaceId) && this.pathContains(granted.path, requested.path);
|
|
21297
|
+
}
|
|
21298
|
+
// Space IDs are `tinycloud:pkh:eip155:<chain>:<0xADDR>:<name>`. The embedded
|
|
21299
|
+
// EIP-155 address is case-insensitive, but the CLI canonicalizes it to
|
|
21300
|
+
// lowercase when building a space URI while stored runtime delegations keep
|
|
21301
|
+
// the EIP-55 checksummed form — so a byte-for-byte compare spuriously rejects
|
|
21302
|
+
// an otherwise-valid grant. Lowercase ONLY the `eip155:<chain>:0x<addr>`
|
|
21303
|
+
// segment and leave everything else (crucially the case-sensitive space NAME)
|
|
21304
|
+
// byte-exact. Mirrors the CLI's `normalizeSpaceForCompare` (OPENKEY_SCOPE_MISMATCH fix).
|
|
21305
|
+
spaceIdsEqual(a, b) {
|
|
21306
|
+
return this.normalizeSpaceAddress(a) === this.normalizeSpaceAddress(b);
|
|
21307
|
+
}
|
|
21308
|
+
normalizeSpaceAddress(space) {
|
|
21309
|
+
return space.replace(
|
|
21310
|
+
/(eip155:\d+:)(0x[0-9a-fA-F]{40})/,
|
|
21311
|
+
(_match, prefix, addr) => prefix + addr.toLowerCase()
|
|
21312
|
+
);
|
|
21071
21313
|
}
|
|
21072
21314
|
actionContains(grantedAction, requestedAction) {
|
|
21073
21315
|
if (grantedAction === requestedAction) {
|
|
@@ -21331,7 +21573,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21331
21573
|
const targetHost = delegation.host ?? this.config.host;
|
|
21332
21574
|
if (this.isSessionOnly) {
|
|
21333
21575
|
const myDid = this.did;
|
|
21334
|
-
if (!
|
|
21576
|
+
if (!didPrincipalMatches2(delegation.delegateDID, myDid)) {
|
|
21335
21577
|
throw new Error(
|
|
21336
21578
|
`Delegation targets ${delegation.delegateDID} but this user's DID is ${myDid}. The delegation must target this user's DID.`
|
|
21337
21579
|
);
|
|
@@ -21562,7 +21804,7 @@ import {
|
|
|
21562
21804
|
parsePkhDid,
|
|
21563
21805
|
pkhDid as pkhDid3,
|
|
21564
21806
|
principalDid,
|
|
21565
|
-
principalDidEquals as
|
|
21807
|
+
principalDidEquals as principalDidEquals3,
|
|
21566
21808
|
parseCanonicalNetworkId
|
|
21567
21809
|
} from "@tinycloud/sdk-core";
|
|
21568
21810
|
|
|
@@ -21709,6 +21951,32 @@ import {
|
|
|
21709
21951
|
} from "@tinycloud/sdk-core";
|
|
21710
21952
|
|
|
21711
21953
|
// src/delegation.ts
|
|
21954
|
+
async function grantAuthRequest(authority, request, options) {
|
|
21955
|
+
if (request.kind !== "tinycloud.auth.request") {
|
|
21956
|
+
throw new Error(
|
|
21957
|
+
`grantAuthRequest expects a tinycloud.auth.request artifact, got "${request.kind}".`
|
|
21958
|
+
);
|
|
21959
|
+
}
|
|
21960
|
+
if (!Array.isArray(request.requested) || request.requested.length === 0) {
|
|
21961
|
+
throw new Error("grantAuthRequest request has no requested capabilities.");
|
|
21962
|
+
}
|
|
21963
|
+
const expiry = options?.expiry ?? request.requestedExpiry;
|
|
21964
|
+
const result = await authority.delegateTo(
|
|
21965
|
+
request.sessionDid,
|
|
21966
|
+
request.requested,
|
|
21967
|
+
expiry !== void 0 ? { expiry } : void 0
|
|
21968
|
+
);
|
|
21969
|
+
return {
|
|
21970
|
+
kind: "tinycloud.auth.delegation",
|
|
21971
|
+
version: 1,
|
|
21972
|
+
requestId: request.requestId,
|
|
21973
|
+
delegationCid: result.delegation.cid,
|
|
21974
|
+
delegation: result.delegation,
|
|
21975
|
+
permissions: request.requested,
|
|
21976
|
+
expiry: result.delegation.expiry.toISOString(),
|
|
21977
|
+
prompted: result.prompted
|
|
21978
|
+
};
|
|
21979
|
+
}
|
|
21712
21980
|
function serializeDelegation(delegation) {
|
|
21713
21981
|
return JSON.stringify({
|
|
21714
21982
|
...delegation,
|
|
@@ -21749,7 +22017,7 @@ import {
|
|
|
21749
22017
|
} from "@tinycloud/sdk-core";
|
|
21750
22018
|
import {
|
|
21751
22019
|
EncryptionService as EncryptionService2,
|
|
21752
|
-
parseNetworkId,
|
|
22020
|
+
parseNetworkId as parseNetworkId3,
|
|
21753
22021
|
buildNetworkId,
|
|
21754
22022
|
isNetworkId,
|
|
21755
22023
|
networkDiscoveryKey,
|
|
@@ -21784,7 +22052,7 @@ import {
|
|
|
21784
22052
|
DEFAULT_KEY_VERSION,
|
|
21785
22053
|
DECRYPT_FACT_TYPE,
|
|
21786
22054
|
DECRYPT_RESULT_TYPE,
|
|
21787
|
-
DECRYPT_ACTION as
|
|
22055
|
+
DECRYPT_ACTION as DECRYPT_ACTION3,
|
|
21788
22056
|
ENCRYPTION_SERVICE,
|
|
21789
22057
|
ENCRYPTION_SERVICE_SHORT,
|
|
21790
22058
|
encryptionError
|
|
@@ -21820,10 +22088,11 @@ import { ServiceContext as ServiceContext3 } from "@tinycloud/sdk-core";
|
|
|
21820
22088
|
export {
|
|
21821
22089
|
ACCOUNT_REGISTRY_PATH,
|
|
21822
22090
|
ACCOUNT_REGISTRY_SPACE2 as ACCOUNT_REGISTRY_SPACE,
|
|
22091
|
+
AccountService,
|
|
21823
22092
|
AutoApproveSpaceCreationHandler2 as AutoApproveSpaceCreationHandler,
|
|
21824
22093
|
CapabilityKeyRegistry2 as CapabilityKeyRegistry,
|
|
21825
22094
|
CapabilityKeyRegistryErrorCodes,
|
|
21826
|
-
|
|
22095
|
+
DECRYPT_ACTION3 as DECRYPT_ACTION,
|
|
21827
22096
|
DECRYPT_FACT_TYPE,
|
|
21828
22097
|
DECRYPT_RESULT_TYPE,
|
|
21829
22098
|
DEFAULT_ENCRYPTION_ALG,
|
|
@@ -21919,6 +22188,7 @@ export {
|
|
|
21919
22188
|
expandPermissionEntries2 as expandPermissionEntries,
|
|
21920
22189
|
expandPermissionEntry,
|
|
21921
22190
|
generateRandomReceiverKey,
|
|
22191
|
+
grantAuthRequest,
|
|
21922
22192
|
hexDecode,
|
|
21923
22193
|
hexEncode,
|
|
21924
22194
|
isCapabilitySubset2 as isCapabilitySubset,
|
|
@@ -21931,12 +22201,12 @@ export {
|
|
|
21931
22201
|
openWrappedKey,
|
|
21932
22202
|
parseCanonicalNetworkId,
|
|
21933
22203
|
parseExpiry2 as parseExpiry,
|
|
21934
|
-
parseNetworkId,
|
|
22204
|
+
parseNetworkId3 as parseNetworkId,
|
|
21935
22205
|
parsePkhDid,
|
|
21936
22206
|
parseSpaceUri,
|
|
21937
22207
|
pkhDid3 as pkhDid,
|
|
21938
22208
|
principalDid,
|
|
21939
|
-
|
|
22209
|
+
principalDidEquals3 as principalDidEquals,
|
|
21940
22210
|
resolveManifest2 as resolveManifest,
|
|
21941
22211
|
resolveSecretListPrefix2 as resolveSecretListPrefix,
|
|
21942
22212
|
resolveSecretPath2 as resolveSecretPath,
|