@tinycloud/node-sdk 2.11.0-beta.1 → 2.11.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.
@@ -1,4 +1,4 @@
1
- import { ISessionStorage, PersistedSessionData, AutoSignStrategy, AutoRejectStrategy, CallbackStrategy, IUserAuthorization, ISigner, ISpaceCreationHandler, LocalNodeIdentityStore, IWasmBindings, ISessionManager, SiweConfig, Manifest, ComposedManifestRequest, ClientSession, TinyCloudSession, Extension, SignRequest, SignInOptions, Delegation, DelegatedResource, PermissionEntry, TelemetryConfig, IKVService, ISQLService, IDuckDbService, IHooksService, CreateOwnerDelegationParams as CreateOwnerDelegationParams$1, OwnerDelegationReceipt as OwnerDelegationReceipt$1, INotificationHandler, IENSResolver, AccountService, RegisterOwnerSharePolicyParams, OwnerSharePolicyRegistrationReceipt, ShareDeliveryAuthorizationReceipt, IDataVaultService, IEncryptionService, NetworkDescriptor, ISecretsService, ICapabilityKeyRegistry, DelegationManager, ISpaceService, ISpace, ISharingService, CreateDelegationParams, DelegationResult, DelegationRevocationReceipt, DelegationStatus, ResolvedDelegate, KeyProvider, JWK } from '@tinycloud/sdk-core';
1
+ import { ISessionStorage, PersistedSessionData, AutoSignStrategy, AutoRejectStrategy, CallbackStrategy, IUserAuthorization, ISigner, ISpaceCreationHandler, LocalNodeIdentityStore, IWasmBindings, ISessionManager, SiweConfig, Manifest, ComposedManifestRequest, ClientSession, TinyCloudSession, Extension, SignRequest, SignInOptions, CapabilityPresentationEnvelopeV1, Delegation, DelegatedResource, PermissionEntry, TelemetryConfig, IKVService, ISQLService, IDuckDbService, IHooksService, CreateOwnerDelegationParams as CreateOwnerDelegationParams$1, OwnerDelegationReceipt as OwnerDelegationReceipt$1, INotificationHandler, IENSResolver, AccountService, InvokeAnyFunction as InvokeAnyFunction$1, RegisterOwnerSharePolicyParams, OwnerSharePolicyRegistrationReceipt, ShareDeliveryAuthorizationReceipt, IDataVaultService, IEncryptionService, NetworkDescriptor, ISecretsService, ICapabilityKeyRegistry, DelegationManager, ISpaceService, ISpace, ISharingService, CreateDelegationParams, DelegationResult, DelegationRevocationReceipt, DelegationStatus, ResolvedDelegate, KeyProvider, JWK } from '@tinycloud/sdk-core';
2
2
  import { EventEmitter } from 'events';
3
3
  import { InvokeFunction, InvokeAnyFunction } from '@tinycloud/sdk-services';
4
4
 
@@ -195,9 +195,9 @@ interface NodeUserAuthorizationConfig {
195
195
  tinycloudRegistryUrl?: string | null;
196
196
  /** Fallback TinyCloud hosts. Default: hosted TinyCloud node. */
197
197
  tinycloudFallbackHosts?: string[] | null;
198
- /** Probe for a locally-running TinyCloud node before registry/fallback resolution. Default: true. */
198
+ /** Probe configured/registered local nodes before registry/fallback resolution. Default: true. */
199
199
  autoDiscoverLocalNode?: boolean;
200
- /** Local loopback node URL to probe. Default: http://127.0.0.1:8000. */
200
+ /** Local loopback node URL to probe. Omit to avoid probing loopback. */
201
201
  localNodeUrl?: string;
202
202
  /** Known `*.local.tinycloud.link` subdomain name, probed directly. */
203
203
  localLinkName?: string;
@@ -239,7 +239,7 @@ interface NodeUserAuthorizationConfig {
239
239
  manifest?: Manifest | Manifest[];
240
240
  /** Pre-composed manifest request. Takes precedence over `manifest`. */
241
241
  capabilityRequest?: ComposedManifestRequest;
242
- /** Include implicit account registry permissions when composing `manifest`. Default true. */
242
+ /** Include canonical account registry read/create-update/list permissions when composing `manifest` and plain sign-in. Default true. */
243
243
  includeAccountRegistryPermissions?: boolean;
244
244
  }
245
245
  interface CreateBootstrapSessionOptions {
@@ -319,6 +319,12 @@ declare class NodeUserAuthorization implements IUserAuthorization {
319
319
  private _address?;
320
320
  private _chainId?;
321
321
  private _nodeFeatures;
322
+ /**
323
+ * `nodeId` from the `GET /info` performed during sign-in/restore, tagged with
324
+ * the host it came from. Callers that need the node DID (encryption-network
325
+ * admin invocations) reuse this instead of re-fetching `/info`.
326
+ */
327
+ private _nodeInfoIdentity?;
322
328
  private _lastActivationSkippedSpaceIds;
323
329
  constructor(config: NodeUserAuthorizationConfig);
324
330
  /**
@@ -387,6 +393,13 @@ declare class NodeUserAuthorization implements IUserAuthorization {
387
393
  private requireTinyCloudHosts;
388
394
  private get primaryTinyCloudHost();
389
395
  get nodeFeatures(): string[];
396
+ /**
397
+ * The node DID reported by `GET /info` for `host`, if the sign-in (or
398
+ * restore) that populated it targeted that same host. Returns `undefined`
399
+ * for any other host, and for nodes whose `/info` omits `nodeId`, so callers
400
+ * fall back to fetching it themselves rather than using a foreign node's DID.
401
+ */
402
+ nodeIdForHost(host: string): string | undefined;
390
403
  get lastActivationSkippedSpaceIds(): string[];
391
404
  /**
392
405
  * Compute the `abilities` map the WASM `prepareSession` call should
@@ -533,6 +546,153 @@ declare class NodeUserAuthorization implements IUserAuthorization {
533
546
  spaceId: string;
534
547
  verificationMethod: string;
535
548
  }, signature: string, keyId: string, jwk: Record<string, unknown>): Promise<ClientSession>;
549
+ /**
550
+ * End-to-end sign-in via OpenKey `authorizeTinyCloud()` (Sol CRITICAL-4).
551
+ *
552
+ * This is the production entry point that wires
553
+ * {@link prepareSessionForSigning} → OpenKey `authorizeTinyCloud()` →
554
+ * {@link signInWithOpenKeyResult} into one call. Consumers pass in a
555
+ * caller-provided `authorizeFn` (typically a thin wrapper around
556
+ * `openkey.authorizeTinyCloud()`) so this method has no direct
557
+ * dependency on the OpenKey SDK — it works with any transport that
558
+ * conforms to the versioned protocol.
559
+ *
560
+ * The `authorizeFn` MUST:
561
+ * 1. Send the prepared SIWE bytes to OpenKey.
562
+ * 2. Return the exact `TinyCloudAuthorizationResultV1` shape (with
563
+ * `signedMessage` — the bytes the signature actually verifies
564
+ * against — plus `selectedActionKeys` and `permissions`).
565
+ *
566
+ * NodeUserAuthorization then completes the session with `signedMessage`
567
+ * (never the prepared bytes), verifying the signature, the immutable
568
+ * SIWE fields, and every subset invariant enforced by
569
+ * {@link signInWithOpenKeyResult}. This preserves the exact-byte
570
+ * guarantee: if the user did NOT narrow, the returned `signedMessage`
571
+ * equals the prepared SIWE byte-for-byte; if the user narrowed, only
572
+ * the ReCap block differs and every immutable header field survives.
573
+ *
574
+ * Legacy exact-byte {@link signIn} callers are unaffected — this method
575
+ * is opt-in.
576
+ *
577
+ * @param authorizeFn Callback that invokes the versioned OpenKey
578
+ * `authorizeTinyCloud()` protocol and returns the result. Receives
579
+ * the prepared SIWE bytes plus a `host` hint the widget should bind
580
+ * into its /authorize-sign-prepare context.
581
+ * @param options Optional overrides for the OpenKey request.
582
+ */
583
+ signInWithOpenKey(authorizeFn: (input: {
584
+ protocolVersion: 1;
585
+ siwe: string;
586
+ jwk: Record<string, unknown>;
587
+ host?: string;
588
+ /**
589
+ * Sol MAJOR-3: OpenKey key ID (managed or external key) to sign
590
+ * with. When omitted, the OpenKey SDK falls back to the last
591
+ * connected key. Callers who want to bind the flow to a specific
592
+ * OpenKey key can override via options.openkeyKeyId; otherwise the
593
+ * bridge relies on the SDK's connected-key state.
594
+ */
595
+ keyId?: string;
596
+ /**
597
+ * Optional presentation envelope forwarded to the OpenKey widget.
598
+ * Built from this instance's `_manifest` when set. Display-only —
599
+ * the widget/server MUST NOT let it expand authority. The envelope
600
+ * carries `manifests` payloads plus a stable SHA-256 digest so the
601
+ * OpenKey server can origin-bind the browser origin against the
602
+ * app's well-known manifest.
603
+ */
604
+ presentation?: CapabilityPresentationEnvelopeV1;
605
+ }) => Promise<{
606
+ protocolVersion: 1;
607
+ address: string;
608
+ signature: string;
609
+ signedMessage: string;
610
+ selectedActionKeys: string[];
611
+ permissions: Array<{
612
+ service: string;
613
+ space: string;
614
+ path: string;
615
+ actions: string[];
616
+ }>;
617
+ }>, options?: {
618
+ host?: string;
619
+ openkeyKeyId?: string;
620
+ /**
621
+ * Optional caller-supplied reason string forwarded in the
622
+ * presentation envelope. Rendered as caller-supplied (never
623
+ * verified) in the widget.
624
+ */
625
+ reason?: string;
626
+ }): Promise<ClientSession>;
627
+ /**
628
+ * Build a `CapabilityPresentationEnvelopeV1` from `this._manifest`. The
629
+ * envelope is display-only — the OpenKey widget renders it under an
630
+ * honest trust label, and the server /authorize-sign-prepare route
631
+ * decides whether to upgrade the label to `origin-bound` by fetching
632
+ * the well-known manifest and comparing its digest to
633
+ * `manifestDigest`.
634
+ *
635
+ * Returns `undefined` when no manifest is set — the widget renders as
636
+ * "no manifest supplied" (unsigned).
637
+ *
638
+ * The digest is a deterministic SHA-256 over canonical JSON of the
639
+ * first manifest payload; OpenKey parses the fetched well-known manifest
640
+ * and applies the same canonicalization before comparing digests.
641
+ */
642
+ private buildPresentationEnvelope;
643
+ /**
644
+ * Complete sign-in with a versioned OpenKey authorization result.
645
+ *
646
+ * Where `signInWithPreparedSession` completes with a signature over the
647
+ * ORIGINAL prepared SIWE, this method completes with the SIWE bytes the
648
+ * OpenKey widget actually presented and signed (`signedMessage`). It
649
+ * exists because the versioned authorizeTinyCloud protocol lets the user
650
+ * narrow capabilities; the returned bytes may differ from the original
651
+ * request and are the only ones the signature actually verifies against.
652
+ *
653
+ * The `result` parameter is validated at the trust boundary via
654
+ * `validateAuthorizationResultV1` (in sdk-core). Callers should validate
655
+ * BEFORE calling this method so unknown/missing fields are rejected
656
+ * before any session state is created.
657
+ *
658
+ * Validation performed here (defence-in-depth: even a "valid" v1 payload
659
+ * must clear these checks before any session state is created):
660
+ * 1. `result.address` matches the local signer's address.
661
+ * 2. `result.signature` recovers to `result.address` when verified against
662
+ * `result.signedMessage`.
663
+ * 3. Every immutable SIWE header field (domain, address, URI, version,
664
+ * chainId, nonce, issuedAt) in the original prepared SIWE is preserved
665
+ * byte-for-byte in `result.signedMessage`. `statement` is NOT in this
666
+ * list because the WASM renders it from the ReCap contents; it MUST
667
+ * change when the ReCap is narrowed.
668
+ * 4. Every capability in `result.signedMessage`'s ReCap block was present
669
+ * in the original prepared SIWE — narrowing OK, broadening rejected.
670
+ * 5. Every `result.selectedActionKeys` entry corresponds to a
671
+ * (resource, action) pair in the returned SIWE.
672
+ */
673
+ signInWithOpenKeyResult(result: {
674
+ protocolVersion: 1;
675
+ address: string;
676
+ signature: string;
677
+ signedMessage: string;
678
+ selectedActionKeys: string[];
679
+ permissions: Array<{
680
+ service: string;
681
+ space: string;
682
+ path: string;
683
+ actions: string[];
684
+ }>;
685
+ }, prepared: {
686
+ /**
687
+ * The ORIGINAL SIWE the SDK produced via {@link prepareSessionForSigning}.
688
+ * Used as the source-of-truth reference for immutable-header and
689
+ * capability-subset comparison against `result.signedMessage`.
690
+ */
691
+ siwe: string;
692
+ jwk: Record<string, unknown>;
693
+ spaceId: string;
694
+ verificationMethod: string;
695
+ }, keyId: string, jwk: Record<string, unknown>): Promise<ClientSession>;
536
696
  /**
537
697
  * Clear persisted session data.
538
698
  */
@@ -815,6 +975,9 @@ declare class DelegatedAccess {
815
975
  * ```
816
976
  */
817
977
 
978
+ declare const BOOTSTRAP_COMPLETION_MARKER_KEY = "system/bootstrap/complete";
979
+ declare const BOOTSTRAP_COMPLETION_MARKER_VERSION = 1;
980
+ declare const ACCEPTED_MARKER_VERSIONS: readonly number[];
818
981
  /** Input for {@link TinyCloudNode.readSecret}. The target space is required. */
819
982
  interface SecretReadInput {
820
983
  /** Explicit full space URI or an owned-space name. */
@@ -887,9 +1050,9 @@ interface TinyCloudNodeConfig {
887
1050
  tinycloudRegistryUrl?: string | null;
888
1051
  /** Fallback TinyCloud hosts. Default: hosted TinyCloud node. */
889
1052
  tinycloudFallbackHosts?: string[] | null;
890
- /** Probe for a locally-running TinyCloud node before registry/fallback resolution. Default: true. */
1053
+ /** Probe configured/registered local nodes before registry/fallback resolution. Default: true. */
891
1054
  autoDiscoverLocalNode?: boolean;
892
- /** Local loopback node URL to probe. Default: http://127.0.0.1:8000. */
1055
+ /** Local loopback node URL to probe. Omit to avoid probing loopback. */
893
1056
  localNodeUrl?: string;
894
1057
  /** Known `*.local.tinycloud.link` subdomain name, probed directly. */
895
1058
  localLinkName?: string;
@@ -944,7 +1107,7 @@ interface TinyCloudNodeConfig {
944
1107
  manifest?: Manifest | Manifest[];
945
1108
  /** Pre-composed manifest request. Takes precedence over `manifest`. */
946
1109
  capabilityRequest?: ComposedManifestRequest;
947
- /** Include implicit account registry permissions when composing `manifest`. Default true. */
1110
+ /** Include account bootstrap support in plain sessions and implicit manifest permissions. Default true. */
948
1111
  includeAccountRegistryPermissions?: boolean;
949
1112
  /** Run canonical first-account bootstrap when fresh account state is detected. Default true. */
950
1113
  autoBootstrapAccount?: boolean;
@@ -987,6 +1150,21 @@ interface RuntimePermissionGrantOptions {
987
1150
  /** Override expiry. ms-format string ("7d", "1h") or raw milliseconds. */
988
1151
  expiry?: string | number;
989
1152
  }
1153
+ interface EnsureEncryptionNetworkOptions {
1154
+ /**
1155
+ * Skip the `GET /encryption/networks/{id}` existence probe and go straight
1156
+ * to the create.
1157
+ *
1158
+ * The probe pays for itself only when the network already exists. On a
1159
+ * freshly bootstrapped account it is a guaranteed 404, so it costs a round
1160
+ * trip on the cold sign-in path and saves nothing. Creating without it is
1161
+ * safe: the server answers `409 Conflict` if the network is already there,
1162
+ * which {@link TinyCloudNode.createEncryptionNetwork} resolves by reading the
1163
+ * existing descriptor. Set this only when the caller knows the account was
1164
+ * just provisioned.
1165
+ */
1166
+ assumeMissing?: boolean;
1167
+ }
990
1168
  /**
991
1169
  * High-level TinyCloud API for Node.js environments.
992
1170
  *
@@ -998,6 +1176,29 @@ interface NodeDefaults {
998
1176
  createWasmBindings: () => IWasmBindings;
999
1177
  createSigner: (privateKey: string, chainId?: number) => ISigner;
1000
1178
  }
1179
+ /**
1180
+ * A bootstrap step that COMPLETED but did so in a degraded way — e.g. a KV
1181
+ * batch write that failed ambiguously and was recovered by per-space
1182
+ * reconciliation. Structured (not prose) so callers can branch on `kind` and
1183
+ * `code` without parsing messages (TC-361).
1184
+ */
1185
+ interface BootstrapWarning {
1186
+ /** The BootstrapStep.id that degraded, e.g. "account:seed-spaces"
1187
+ * (BootstrapStepBase.id — packages/bootstrap/src/index.ts:642-645). */
1188
+ stepId: string;
1189
+ /** What kind of degradation. Additive union; one member today. */
1190
+ kind: "batch-write-reconciled";
1191
+ /** ServiceError.code of the underlying failure that was recovered from. */
1192
+ code: string;
1193
+ /** Human-readable detail. Diagnostics only — never parse this. */
1194
+ message: string;
1195
+ }
1196
+ /** Durable attestation that the canonical account bootstrap ceremony completed. */
1197
+ interface BootstrapCompletionMarker {
1198
+ v: number;
1199
+ stepIds: string[];
1200
+ completedAt: string;
1201
+ }
1001
1202
  declare class TinyCloudNode {
1002
1203
  /** @internal Registered by importing @tinycloud/node-sdk (not /core) */
1003
1204
  private static nodeDefaults?;
@@ -1044,6 +1245,12 @@ declare class TinyCloudNode {
1044
1245
  * so this avoids re-parsing the recap on every registration.
1045
1246
  */
1046
1247
  private _recapOperationsCache?;
1248
+ /**
1249
+ * Owned space ids this sign-in has already confirmed are hosted. Consulted by
1250
+ * {@link ensureOwnedSpaceHostedById}; cleared on every {@link signIn} because
1251
+ * hosting is confirmed against the session that was active at the time.
1252
+ */
1253
+ private readonly confirmedHostedSpaceIds;
1047
1254
  /**
1048
1255
  * TinyCloudSession captured by {@link restoreSession} when there's no
1049
1256
  * auth-layer signer available (session-only mode used by OpenKey-backed
@@ -1051,6 +1258,7 @@ declare class TinyCloudNode {
1051
1258
  * {@link currentTinyCloudSession} as a fallback for `auth.tinyCloudSession`.
1052
1259
  */
1053
1260
  private _restoredTcSession?;
1261
+ private _activeServiceSession?;
1054
1262
  /**
1055
1263
  * True when the last signIn() detected an interactive signer and skipped
1056
1264
  * client-side bootstrap. Apps can read this to know whether bootstrap was
@@ -1059,9 +1267,15 @@ declare class TinyCloudNode {
1059
1267
  private _bootstrapSkipped;
1060
1268
  /**
1061
1269
  * Outcome of the last signIn()'s account-bootstrap attempt. `skipped` is
1062
- * true when bootstrap did not complete (interactive signer, auto-sign
1063
- * denied, or a bootstrap step failed); `reason` carries the cause so apps
1064
- * can surface a "finish account setup" call-to-action.
1270
+ * true when bootstrap did not complete in this invocation (interactive signer,
1271
+ * auto-bootstrap disabled, already provisioned, or a decision/provisioning
1272
+ * step failed). `already-provisioned` means the bootstrap was not run here;
1273
+ * it does not mean a prior provisioning attempt failed to complete.
1274
+ * `reason` carries the cause so apps can surface a "finish account setup"
1275
+ * call-to-action. `warnings` is
1276
+ * present when bootstrap completed, but one or more steps recovered from
1277
+ * an ambiguous failure (e.g. a KV batch write reconciled via per-space
1278
+ * fallback) — clean vs. recovered runs are otherwise byte-identical.
1065
1279
  */
1066
1280
  private _bootstrapStatus;
1067
1281
  /** Whether the last signIn() skipped client-side bootstrap because the
@@ -1071,6 +1285,7 @@ declare class TinyCloudNode {
1071
1285
  get bootstrapStatus(): {
1072
1286
  skipped: boolean;
1073
1287
  reason?: string;
1288
+ warnings?: BootstrapWarning[];
1074
1289
  };
1075
1290
  private get nodeFeatures();
1076
1291
  /** SIWE domain — uses config override or defaults to app.tinycloud.xyz */
@@ -1193,7 +1408,11 @@ declare class TinyCloudNode {
1193
1408
  signIn(options?: SignInOptions): Promise<void>;
1194
1409
  private ownedSpaceId;
1195
1410
  private bootstrapAccountIfNeeded;
1196
- private isFreshBootstrapAccount;
1411
+ private resolveBootstrapDecision;
1412
+ private readBootstrapCompletionMarker;
1413
+ private writeBootstrapCompletionMarker;
1414
+ private isAcceptedBootstrapCompletionMarker;
1415
+ private markerReadIsUnhostedSpace;
1197
1416
  private runAccountBootstrap;
1198
1417
  private registerBootstrapRuntimeGrant;
1199
1418
  /**
@@ -1252,6 +1471,22 @@ declare class TinyCloudNode {
1252
1471
  private withAccountRegistryRetry;
1253
1472
  private requestedEncryptionNetworkIds;
1254
1473
  private ensureRequestedEncryptionNetworks;
1474
+ /**
1475
+ * Ensure one of this user's owned spaces is hosted, at most once per space
1476
+ * per sign-in.
1477
+ *
1478
+ * Account bootstrap funnels six calls through here (via
1479
+ * `AccountService.ensureAccountSpaceHosted`), and each one re-submits
1480
+ * `activateSessionWithHost` with the *primary* session. That session's recap
1481
+ * covers only `default` and `secrets`, so the account space appears in
1482
+ * neither `activated` nor `skipped` and the guard below returns immediately
1483
+ * — the repeat calls cannot change the outcome, they only cost round trips.
1484
+ *
1485
+ * The memo is per sign-in ({@link confirmedHostedSpaceIds} is cleared in
1486
+ * `signIn`) and only records confirmed successes. A wrong skip is
1487
+ * self-revealing: the next write to the space fails immediately and loudly
1488
+ * with `404 Space not found`.
1489
+ */
1255
1490
  private ensureOwnedSpaceHostedById;
1256
1491
  /**
1257
1492
  * Host one of this user's owned spaces by name (e.g. `"applications"`).
@@ -1399,6 +1634,16 @@ declare class TinyCloudNode {
1399
1634
  * rehydration set by {@link restoreSession} (session-only mode).
1400
1635
  */
1401
1636
  private currentTinyCloudSession;
1637
+ /**
1638
+ * Mint a multi-capability invocation through the established session key.
1639
+ * Callers receive only the signed headers; session key material remains
1640
+ * owned by the session manager and is never part of the caller contract.
1641
+ */
1642
+ invokeAny(entries: Parameters<InvokeAnyFunction$1>[1], facts?: Parameters<InvokeAnyFunction$1>[2]): ReturnType<InvokeAnyFunction$1>;
1643
+ /** Sign protocol bytes with the established in-memory session key. */
1644
+ signSessionBytes(bytes: Uint8Array): Promise<Uint8Array>;
1645
+ /** Bind a session-signed invocation to the canonical service audience. */
1646
+ bindInvocationAudience(authorization: string, audience: string): Promise<string>;
1402
1647
  /**
1403
1648
  * Connect a wallet to upgrade from session-only mode to wallet mode.
1404
1649
  *
@@ -1462,6 +1707,14 @@ declare class TinyCloudNode {
1462
1707
  */
1463
1708
  private requireEncryptionSession;
1464
1709
  private createEncryptionCrypto;
1710
+ /**
1711
+ * The node DID for {@link config.host}.
1712
+ *
1713
+ * Sign-in already performs `GET /info` for the protocol-version check, and
1714
+ * that response carries `nodeId`, so reuse it rather than fetching `/info` a
1715
+ * second time. Only a value recorded for this exact host qualifies; older
1716
+ * nodes that omit `nodeId` fall through to the fetch.
1717
+ */
1465
1718
  private fetchNodeId;
1466
1719
  private signRawNetworkAuthorization;
1467
1720
  private fetchEncryptionNetworkAt;
@@ -1518,6 +1771,7 @@ declare class TinyCloudNode {
1518
1771
  readonly recipientEmail: string;
1519
1772
  readonly shareUrl: string;
1520
1773
  readonly documentName: string;
1774
+ readonly idempotencyKey: string;
1521
1775
  readonly expiresAt: string;
1522
1776
  /** The enrolled receipt key from the node trust bundle. */
1523
1777
  readonly nodeProof: {
@@ -1586,7 +1840,13 @@ declare class TinyCloudNode {
1586
1840
  get encryption(): IEncryptionService;
1587
1841
  getEncryptionNetwork(nameOrNetworkId?: string): Promise<NetworkDescriptor | null>;
1588
1842
  createEncryptionNetwork(name?: string): Promise<NetworkDescriptor>;
1589
- ensureEncryptionNetwork(nameOrNetworkId?: string): Promise<NetworkDescriptor>;
1843
+ /**
1844
+ * Ensure an encryption network exists, creating it if necessary.
1845
+ *
1846
+ * @param nameOrNetworkId - Network name or full `urn:tinycloud:encryption:` id.
1847
+ * @param options - See {@link EnsureEncryptionNetworkOptions}.
1848
+ */
1849
+ ensureEncryptionNetwork(nameOrNetworkId?: string, options?: EnsureEncryptionNetworkOptions): Promise<NetworkDescriptor>;
1590
1850
  /**
1591
1851
  * App-facing secrets API backed by the `secrets` space vault.
1592
1852
  */
@@ -2057,6 +2317,13 @@ declare class TinyCloudNode {
2057
2317
  disableSubDelegation?: boolean;
2058
2318
  /** Expiration time in milliseconds from now (must be before parent's expiry) */
2059
2319
  expiryMs?: number;
2320
+ /** Explicit multi-resource projection, including encryption networks. */
2321
+ resources?: Array<{
2322
+ service: string;
2323
+ space?: string;
2324
+ path: string;
2325
+ actions: string[];
2326
+ }>;
2060
2327
  }): Promise<PortableDelegation>;
2061
2328
  }
2062
2329
 
@@ -2168,4 +2435,4 @@ declare class WasmKeyProvider implements KeyProvider {
2168
2435
  */
2169
2436
  declare function createWasmKeyProvider(sessionManager: SessionManagerWithListing): WasmKeyProvider;
2170
2437
 
2171
- export { type AuthDelegationArtifact as A, type CreateOwnerDelegationParams as C, type DelegateToOptions as D, FileSessionStorage as F, MemorySessionStorage as M, type NodeEventEmitterStrategy as N, type OwnerDelegationReceipt as O, type PortableDelegation as P, type RestorableSession as R, type SecretPermissionHint as S, TinyCloudNode as T, UnsupportedSessionRestoreError as U, type ValidatedRuntimeDelegation as V, WasmKeyProvider as W, type AuthRequestArtifact as a, type DelegateToResult as b, DelegatedAccess as c, type DelegationAuthority as d, NodeUserAuthorization as e, type NodeUserAuthorizationConfig as f, type RuntimeDelegationActivator as g, type RuntimePermissionGrantOptions as h, type SecretReadInput as i, type SecretReadResult as j, type SignStrategy as k, type TinyCloudNodeConfig as l, type WasmKeyProviderConfig as m, activateValidatedRuntimeDelegation as n, createWasmKeyProvider as o, defaultSignStrategy as p, deserializeDelegation as q, grantAuthRequest as r, serializeDelegation as s };
2438
+ export { ACCEPTED_MARKER_VERSIONS as A, BOOTSTRAP_COMPLETION_MARKER_KEY as B, type CreateOwnerDelegationParams as C, type DelegateToOptions as D, type EnsureEncryptionNetworkOptions as E, FileSessionStorage as F, MemorySessionStorage as M, type NodeEventEmitterStrategy as N, type OwnerDelegationReceipt as O, type PortableDelegation as P, type RestorableSession as R, type SecretPermissionHint as S, TinyCloudNode as T, UnsupportedSessionRestoreError as U, type ValidatedRuntimeDelegation as V, WasmKeyProvider as W, type AuthDelegationArtifact as a, type AuthRequestArtifact as b, BOOTSTRAP_COMPLETION_MARKER_VERSION as c, type BootstrapCompletionMarker as d, type BootstrapWarning as e, type DelegateToResult as f, DelegatedAccess as g, type DelegationAuthority as h, NodeUserAuthorization as i, type NodeUserAuthorizationConfig as j, type RuntimeDelegationActivator as k, type RuntimePermissionGrantOptions as l, type SecretReadInput as m, type SecretReadResult as n, type SignStrategy as o, type TinyCloudNodeConfig as p, type WasmKeyProviderConfig as q, activateValidatedRuntimeDelegation as r, createWasmKeyProvider as s, defaultSignStrategy as t, deserializeDelegation as u, grantAuthRequest as v, serializeDelegation as w };