@tinycloud/node-sdk 2.1.0-beta.1 → 2.1.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.cjs +205 -62
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +162 -23
- package/dist/core.d.ts +162 -23
- package/dist/core.js +212 -66
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +203 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +210 -64
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -17327,8 +17327,25 @@ var NodeUserAuthorization = class {
|
|
|
17327
17327
|
this.enablePublicSpace = config.enablePublicSpace ?? true;
|
|
17328
17328
|
this.nonce = config.nonce;
|
|
17329
17329
|
this.siweConfig = config.siweConfig;
|
|
17330
|
+
this._manifest = config.manifest;
|
|
17330
17331
|
this.sessionManager = this.wasm.createSessionManager();
|
|
17331
17332
|
}
|
|
17333
|
+
/**
|
|
17334
|
+
* Return the manifest currently driving sign-in behavior, or
|
|
17335
|
+
* `undefined` if none is set. Used by TinyCloudWeb/TinyCloudNode
|
|
17336
|
+
* internals to surface the manifest for requestPermissions flows
|
|
17337
|
+
* without forcing the caller to track it separately.
|
|
17338
|
+
*/
|
|
17339
|
+
get manifest() {
|
|
17340
|
+
return this._manifest;
|
|
17341
|
+
}
|
|
17342
|
+
/**
|
|
17343
|
+
* Install or replace the stored manifest. Takes effect on the next
|
|
17344
|
+
* `signIn()` call — the current session (if any) is not touched.
|
|
17345
|
+
*/
|
|
17346
|
+
setManifest(manifest) {
|
|
17347
|
+
this._manifest = manifest;
|
|
17348
|
+
}
|
|
17332
17349
|
/**
|
|
17333
17350
|
* The current active session (web-core compatible).
|
|
17334
17351
|
*/
|
|
@@ -17345,6 +17362,39 @@ var NodeUserAuthorization = class {
|
|
|
17345
17362
|
get nodeFeatures() {
|
|
17346
17363
|
return this._nodeFeatures;
|
|
17347
17364
|
}
|
|
17365
|
+
/**
|
|
17366
|
+
* Compute the `abilities` map the WASM `prepareSession` call should
|
|
17367
|
+
* see at sign-in time.
|
|
17368
|
+
*
|
|
17369
|
+
* When a manifest is installed, we resolve it and union together:
|
|
17370
|
+
* - the app's own `resources` (what it needs at runtime)
|
|
17371
|
+
* - every `additionalDelegates[*].permissions` list (what it will
|
|
17372
|
+
* re-delegate to other DIDs post sign-in)
|
|
17373
|
+
*
|
|
17374
|
+
* into the short-service / path / full-URN-actions shape the WASM
|
|
17375
|
+
* layer expects. This is the key invariant that lets
|
|
17376
|
+
* {@link TinyCloudNode.delegateTo} issue manifest-declared
|
|
17377
|
+
* delegations via the session key (no wallet prompt): the session's
|
|
17378
|
+
* own recap already covers every action those delegations need.
|
|
17379
|
+
*
|
|
17380
|
+
* When no manifest is installed, we fall back to the
|
|
17381
|
+
* {@link defaultActions} table so existing callers see no change.
|
|
17382
|
+
*
|
|
17383
|
+
* This is a pure function of `this._manifest` + `this.defaultActions`
|
|
17384
|
+
* — the manifest resolution performs no I/O and throws a
|
|
17385
|
+
* {@link ManifestValidationError} on structural problems (missing
|
|
17386
|
+
* id/name, unparseable expiry, etc), which will surface at sign-in
|
|
17387
|
+
* rather than being silently swallowed.
|
|
17388
|
+
*
|
|
17389
|
+
* @internal
|
|
17390
|
+
*/
|
|
17391
|
+
resolveSignInAbilities() {
|
|
17392
|
+
if (this._manifest === void 0) {
|
|
17393
|
+
return this.defaultActions;
|
|
17394
|
+
}
|
|
17395
|
+
const resolved = (0, import_sdk_core.resolveManifest)(this._manifest);
|
|
17396
|
+
return (0, import_sdk_core.manifestAbilitiesUnion)(resolved);
|
|
17397
|
+
}
|
|
17348
17398
|
/**
|
|
17349
17399
|
* Build SIWE overrides from the top-level nonce and siweConfig.
|
|
17350
17400
|
* - Top-level `nonce` is seeded first so `siweConfig.nonce` wins if both are set.
|
|
@@ -17548,7 +17598,7 @@ var NodeUserAuthorization = class {
|
|
|
17548
17598
|
const now = /* @__PURE__ */ new Date();
|
|
17549
17599
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
17550
17600
|
const prepared = this.wasm.prepareSession({
|
|
17551
|
-
abilities: this.
|
|
17601
|
+
abilities: this.resolveSignInAbilities(),
|
|
17552
17602
|
address,
|
|
17553
17603
|
chainId,
|
|
17554
17604
|
domain: this.domain,
|
|
@@ -17691,7 +17741,7 @@ var NodeUserAuthorization = class {
|
|
|
17691
17741
|
const now = /* @__PURE__ */ new Date();
|
|
17692
17742
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
17693
17743
|
const prepared = this.wasm.prepareSession({
|
|
17694
|
-
abilities: this.
|
|
17744
|
+
abilities: this.resolveSignInAbilities(),
|
|
17695
17745
|
address,
|
|
17696
17746
|
chainId,
|
|
17697
17747
|
domain: this.domain,
|
|
@@ -18197,12 +18247,35 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18197
18247
|
enablePublicSpace: config.enablePublicSpace ?? true,
|
|
18198
18248
|
spaceCreationHandler: config.spaceCreationHandler,
|
|
18199
18249
|
nonce: config.nonce,
|
|
18200
|
-
siweConfig: config.siweConfig
|
|
18250
|
+
siweConfig: config.siweConfig,
|
|
18251
|
+
manifest: config.manifest
|
|
18201
18252
|
});
|
|
18202
18253
|
this.tc = new import_sdk_core4.TinyCloud(this.auth, {
|
|
18203
18254
|
invokeAny: this.wasmBindings.invokeAny
|
|
18204
18255
|
});
|
|
18205
18256
|
}
|
|
18257
|
+
/**
|
|
18258
|
+
* Install or replace the manifest that drives the SIWE recap at
|
|
18259
|
+
* sign-in. Takes effect on the next `signIn()` call — the current
|
|
18260
|
+
* session (if any) is not touched. Wire this up from a higher
|
|
18261
|
+
* layer (e.g. TinyCloudWeb.setManifest) so the manifest is kept
|
|
18262
|
+
* in sync across the stack.
|
|
18263
|
+
*/
|
|
18264
|
+
setManifest(manifest) {
|
|
18265
|
+
if (!this.auth) {
|
|
18266
|
+
throw new Error(
|
|
18267
|
+
"setManifest requires wallet mode. Provide a signer or privateKey in the TinyCloudNode config."
|
|
18268
|
+
);
|
|
18269
|
+
}
|
|
18270
|
+
this.auth.setManifest(manifest);
|
|
18271
|
+
}
|
|
18272
|
+
/**
|
|
18273
|
+
* Return the manifest currently installed on the auth handler,
|
|
18274
|
+
* or `undefined` if none is set.
|
|
18275
|
+
*/
|
|
18276
|
+
get manifest() {
|
|
18277
|
+
return this.auth?.manifest;
|
|
18278
|
+
}
|
|
18206
18279
|
/**
|
|
18207
18280
|
* Get the primary identity DID for this user.
|
|
18208
18281
|
* - If wallet connected and signed in: returns PKH DID (did:pkh:eip155:{chainId}:{address})
|
|
@@ -18709,7 +18782,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18709
18782
|
}
|
|
18710
18783
|
/**
|
|
18711
18784
|
* Wrapper for the WASM createDelegation function.
|
|
18712
|
-
*
|
|
18785
|
+
*
|
|
18786
|
+
* The WASM call now takes a multi-resource `abilities` map
|
|
18787
|
+
* (matching `prepareSession`'s shape) and emits ONE UCAN that
|
|
18788
|
+
* covers every `(service, path, actions)` entry. We mirror the raw
|
|
18789
|
+
* result back through `CreateDelegationWasmResult`, converting the
|
|
18790
|
+
* seconds-since-epoch `expiry` to a Date and normalizing the
|
|
18791
|
+
* `delegateDid` → `delegateDID` case.
|
|
18792
|
+
*
|
|
18793
|
+
* Both SharingService (single-entry) and
|
|
18794
|
+
* {@link TinyCloudNode.delegateTo} (multi-entry) drive this through
|
|
18795
|
+
* the same code path so there's exactly one place that touches the
|
|
18796
|
+
* WASM boundary.
|
|
18797
|
+
*
|
|
18713
18798
|
* @internal
|
|
18714
18799
|
*/
|
|
18715
18800
|
createDelegationWrapper(params) {
|
|
@@ -18724,18 +18809,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18724
18809
|
wasmSession,
|
|
18725
18810
|
params.delegateDID,
|
|
18726
18811
|
params.spaceId,
|
|
18727
|
-
params.
|
|
18728
|
-
params.actions,
|
|
18812
|
+
params.abilities,
|
|
18729
18813
|
params.expirationSecs,
|
|
18730
18814
|
params.notBeforeSecs
|
|
18731
18815
|
);
|
|
18732
18816
|
return {
|
|
18733
18817
|
delegation: result.delegation,
|
|
18734
18818
|
cid: result.cid,
|
|
18735
|
-
|
|
18736
|
-
|
|
18737
|
-
|
|
18738
|
-
|
|
18819
|
+
// Rust serde `rename_all = "camelCase"` emits `delegateDid`
|
|
18820
|
+
// (lowercase d); the TypeScript interface uses `delegateDID`
|
|
18821
|
+
// (historical, matches Delegation.delegateDID). Normalize here.
|
|
18822
|
+
delegateDID: result.delegateDid ?? result.delegateDID,
|
|
18823
|
+
expiry: new Date(result.expiry * 1e3),
|
|
18824
|
+
resources: result.resources
|
|
18739
18825
|
};
|
|
18740
18826
|
}
|
|
18741
18827
|
/**
|
|
@@ -19210,24 +19296,38 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19210
19296
|
/**
|
|
19211
19297
|
* Issue a delegation using the capability-chain flow.
|
|
19212
19298
|
*
|
|
19213
|
-
* When
|
|
19214
|
-
* recap, the delegation is signed by the session key via
|
|
19215
|
-
* prompt. When
|
|
19216
|
-
*
|
|
19217
|
-
*
|
|
19218
|
-
*
|
|
19219
|
-
*
|
|
19220
|
-
*
|
|
19299
|
+
* When every requested permission is a subset of the current
|
|
19300
|
+
* session's recap, the delegation is signed by the session key via
|
|
19301
|
+
* WASM — no wallet prompt. When at least one is NOT derivable, a
|
|
19302
|
+
* {@link PermissionNotInManifestError} is raised (carrying the
|
|
19303
|
+
* missing entries) so the caller can trigger an escalation flow
|
|
19304
|
+
* (e.g. `TinyCloudWeb.requestPermissions`). Passing
|
|
19305
|
+
* `forceWalletSign: true` bypasses the derivability check and
|
|
19306
|
+
* always uses the wallet-signed SIWE path — used by the legacy
|
|
19307
|
+
* `createDelegation` fallback and by callers that want explicit
|
|
19308
|
+
* wallet confirmation.
|
|
19221
19309
|
*
|
|
19222
|
-
*
|
|
19223
|
-
*
|
|
19224
|
-
*
|
|
19225
|
-
*
|
|
19310
|
+
* Multi-entry delegations are now emitted as **one** signed UCAN:
|
|
19311
|
+
* the underlying WASM `createDelegation` takes a full
|
|
19312
|
+
* `HashMap<Service, HashMap<Path, Vec<Ability>>>` abilities map
|
|
19313
|
+
* and produces a single attenuation carrying every
|
|
19314
|
+
* `(service, path, actions)` entry. The returned
|
|
19315
|
+
* {@link DelegateToResult.delegation} is that single blob, and
|
|
19316
|
+
* apps can POST it to their backend exactly like a single-entry
|
|
19317
|
+
* delegation (the server verifies all granted resources from one
|
|
19318
|
+
* UCAN).
|
|
19226
19319
|
*
|
|
19227
|
-
*
|
|
19228
|
-
*
|
|
19229
|
-
*
|
|
19230
|
-
*
|
|
19320
|
+
* For single-entry requests the `PortableDelegation.path` and
|
|
19321
|
+
* `.actions` fields mirror the one granted entry. For
|
|
19322
|
+
* multi-entry requests they mirror the **first** entry (stable
|
|
19323
|
+
* lexicographic order from the Rust side); consumers that need
|
|
19324
|
+
* the full picture read `PortableDelegation.resources`.
|
|
19325
|
+
*
|
|
19326
|
+
* @throws {@link SessionExpiredError} when there is no session or
|
|
19327
|
+
* the current session has expired (or will within the 60s
|
|
19328
|
+
* safety margin).
|
|
19329
|
+
* @throws {@link PermissionNotInManifestError} when any requested
|
|
19330
|
+
* entry is not a subset of the granted session capabilities and
|
|
19231
19331
|
* `forceWalletSign` is not set.
|
|
19232
19332
|
*/
|
|
19233
19333
|
async delegateTo(did, permissions, options) {
|
|
@@ -19248,16 +19348,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19248
19348
|
"delegateTo requires a non-empty permissions array"
|
|
19249
19349
|
);
|
|
19250
19350
|
}
|
|
19251
|
-
|
|
19252
|
-
throw new Error(
|
|
19253
|
-
"delegateTo currently supports one permission entry per call. Call delegateTo multiple times for multi-resource delegation."
|
|
19254
|
-
);
|
|
19255
|
-
}
|
|
19256
|
-
const entry = permissions[0];
|
|
19257
|
-
const expandedEntry = {
|
|
19351
|
+
const expandedEntries = permissions.map((entry) => ({
|
|
19258
19352
|
...entry,
|
|
19259
19353
|
actions: (0, import_sdk_core4.expandActionShortNames)(entry.service, entry.actions)
|
|
19260
|
-
};
|
|
19354
|
+
}));
|
|
19261
19355
|
const now = /* @__PURE__ */ new Date();
|
|
19262
19356
|
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
19263
19357
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
@@ -19266,9 +19360,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19266
19360
|
effectiveExpiration = sessionExpiry;
|
|
19267
19361
|
}
|
|
19268
19362
|
if (options?.forceWalletSign) {
|
|
19363
|
+
if (expandedEntries.length > 1) {
|
|
19364
|
+
throw new Error(
|
|
19365
|
+
"delegateTo with forceWalletSign=true supports at most one PermissionEntry. Multi-entry requests must go through the session-key UCAN path (drop forceWalletSign) or the legacy createDelegation method."
|
|
19366
|
+
);
|
|
19367
|
+
}
|
|
19269
19368
|
const delegation2 = await this.createDelegationLegacyWalletPath(
|
|
19270
19369
|
did,
|
|
19271
|
-
|
|
19370
|
+
expandedEntries[0],
|
|
19272
19371
|
effectiveExpiration
|
|
19273
19372
|
);
|
|
19274
19373
|
return { delegation: delegation2, prompted: true };
|
|
@@ -19277,14 +19376,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19277
19376
|
(siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
|
|
19278
19377
|
session.siwe
|
|
19279
19378
|
);
|
|
19280
|
-
const
|
|
19281
|
-
const { subset, missing } = (0, import_sdk_core4.isCapabilitySubset)(requested, granted);
|
|
19379
|
+
const { subset, missing } = (0, import_sdk_core4.isCapabilitySubset)(expandedEntries, granted);
|
|
19282
19380
|
if (!subset) {
|
|
19283
19381
|
throw new import_sdk_core4.PermissionNotInManifestError(missing, granted);
|
|
19284
19382
|
}
|
|
19285
19383
|
const delegation = await this.createDelegationViaWasmPath(
|
|
19286
19384
|
did,
|
|
19287
|
-
|
|
19385
|
+
expandedEntries,
|
|
19288
19386
|
effectiveExpiration,
|
|
19289
19387
|
session
|
|
19290
19388
|
);
|
|
@@ -19293,14 +19391,60 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19293
19391
|
/**
|
|
19294
19392
|
* Issue a delegation via the session-key UCAN WASM path.
|
|
19295
19393
|
*
|
|
19296
|
-
* The caller has already verified
|
|
19297
|
-
* current session; we
|
|
19298
|
-
*
|
|
19394
|
+
* The caller has already verified every entry is derivable from
|
|
19395
|
+
* the current session; we build one multi-resource abilities map
|
|
19396
|
+
* and emit one signed UCAN covering them all.
|
|
19397
|
+
*
|
|
19398
|
+
* All entries must share the same target space (the UCAN is
|
|
19399
|
+
* scoped to a single space). If they don't, this throws — mixing
|
|
19400
|
+
* spaces in a single delegation is not supported by the underlying
|
|
19401
|
+
* Rust create_delegation call and the resulting UCAN would be
|
|
19402
|
+
* under-specified.
|
|
19299
19403
|
*
|
|
19300
19404
|
* @internal
|
|
19301
19405
|
*/
|
|
19302
|
-
async createDelegationViaWasmPath(did,
|
|
19303
|
-
|
|
19406
|
+
async createDelegationViaWasmPath(did, entries, expirationTime, session) {
|
|
19407
|
+
if (entries.length === 0) {
|
|
19408
|
+
throw new Error(
|
|
19409
|
+
"createDelegationViaWasmPath requires a non-empty entries array"
|
|
19410
|
+
);
|
|
19411
|
+
}
|
|
19412
|
+
const resolvedSpaces = /* @__PURE__ */ new Set();
|
|
19413
|
+
for (const entry of entries) {
|
|
19414
|
+
const spaceId2 = entry.space === "default" ? session.spaceId : entry.space;
|
|
19415
|
+
resolvedSpaces.add(spaceId2);
|
|
19416
|
+
}
|
|
19417
|
+
if (resolvedSpaces.size !== 1) {
|
|
19418
|
+
throw new Error(
|
|
19419
|
+
`delegateTo: all permission entries must target the same space, got ${resolvedSpaces.size}: ${JSON.stringify([...resolvedSpaces])}`
|
|
19420
|
+
);
|
|
19421
|
+
}
|
|
19422
|
+
const spaceId = [...resolvedSpaces][0];
|
|
19423
|
+
const abilities = {};
|
|
19424
|
+
for (const entry of entries) {
|
|
19425
|
+
const shortService = import_sdk_core4.SERVICE_LONG_TO_SHORT[entry.service];
|
|
19426
|
+
if (shortService === void 0) {
|
|
19427
|
+
throw new Error(
|
|
19428
|
+
`delegateTo: unknown service '${entry.service}' \u2014 no short-form mapping`
|
|
19429
|
+
);
|
|
19430
|
+
}
|
|
19431
|
+
if (abilities[shortService] === void 0) {
|
|
19432
|
+
abilities[shortService] = {};
|
|
19433
|
+
}
|
|
19434
|
+
const pathsMap = abilities[shortService];
|
|
19435
|
+
const existing = pathsMap[entry.path];
|
|
19436
|
+
if (existing === void 0) {
|
|
19437
|
+
pathsMap[entry.path] = [...entry.actions];
|
|
19438
|
+
} else {
|
|
19439
|
+
const seen = new Set(existing);
|
|
19440
|
+
for (const action of entry.actions) {
|
|
19441
|
+
if (!seen.has(action)) {
|
|
19442
|
+
existing.push(action);
|
|
19443
|
+
seen.add(action);
|
|
19444
|
+
}
|
|
19445
|
+
}
|
|
19446
|
+
}
|
|
19447
|
+
}
|
|
19304
19448
|
const serviceSession = {
|
|
19305
19449
|
delegationHeader: session.delegationHeader,
|
|
19306
19450
|
delegationCid: session.delegationCid,
|
|
@@ -19313,16 +19457,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19313
19457
|
session: serviceSession,
|
|
19314
19458
|
delegateDID: did,
|
|
19315
19459
|
spaceId,
|
|
19316
|
-
|
|
19317
|
-
actions: entry.actions,
|
|
19460
|
+
abilities,
|
|
19318
19461
|
expirationSecs
|
|
19319
19462
|
});
|
|
19463
|
+
const primary = result.resources[0];
|
|
19320
19464
|
return {
|
|
19321
19465
|
cid: result.cid,
|
|
19322
19466
|
delegationHeader: { Authorization: `Bearer ${result.delegation}` },
|
|
19323
19467
|
spaceId,
|
|
19324
|
-
path:
|
|
19325
|
-
actions:
|
|
19468
|
+
path: primary.path,
|
|
19469
|
+
actions: primary.actions,
|
|
19470
|
+
resources: result.resources,
|
|
19326
19471
|
disableSubDelegation: false,
|
|
19327
19472
|
expiry: result.expiry,
|
|
19328
19473
|
delegateDID: did,
|
|
@@ -19378,19 +19523,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19378
19523
|
params.path,
|
|
19379
19524
|
params.spaceIdOverride
|
|
19380
19525
|
);
|
|
19381
|
-
|
|
19382
|
-
|
|
19383
|
-
|
|
19384
|
-
|
|
19385
|
-
|
|
19386
|
-
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
throw err;
|
|
19393
|
-
}
|
|
19526
|
+
try {
|
|
19527
|
+
const result = await this.delegateTo(
|
|
19528
|
+
resolvedDelegateDID,
|
|
19529
|
+
entries,
|
|
19530
|
+
params.expiryMs !== void 0 ? { expiry: params.expiryMs } : void 0
|
|
19531
|
+
);
|
|
19532
|
+
return result.delegation;
|
|
19533
|
+
} catch (err) {
|
|
19534
|
+
if (err instanceof import_sdk_core4.PermissionNotInManifestError) {
|
|
19535
|
+
} else {
|
|
19536
|
+
throw err;
|
|
19394
19537
|
}
|
|
19395
19538
|
}
|
|
19396
19539
|
return this.createDelegationWalletPath({
|