@tinycloud/node-sdk 2.4.0 → 2.4.1-beta.0

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.
@@ -893,8 +893,8 @@ declare class TinyCloudNode {
893
893
  private _hooks?;
894
894
  private _vault?;
895
895
  private _encryption?;
896
- private _baseSecrets?;
897
- private _secrets?;
896
+ private _baseSecrets;
897
+ private _secrets;
898
898
  private _account?;
899
899
  /** Cached public KV with proper delegation (set by ensurePublicSpace) */
900
900
  private _publicKV?;
@@ -1013,6 +1013,11 @@ declare class TinyCloudNode {
1013
1013
  * Available after signIn().
1014
1014
  */
1015
1015
  get session(): TinyCloudSession | undefined;
1016
+ /**
1017
+ * Get the currently active session in the shape callers can persist and later
1018
+ * pass back to {@link restoreSession}.
1019
+ */
1020
+ get restorableSession(): TinyCloudSession | undefined;
1016
1021
  /**
1017
1022
  * Sign in and create a new session.
1018
1023
  * This creates the user's space if it doesn't exist.
@@ -1222,6 +1227,8 @@ declare class TinyCloudNode {
1222
1227
  private initializeServices;
1223
1228
  private createSpaceScopedKVService;
1224
1229
  getDefaultEncryptionNetworkId(name?: string): string;
1230
+ getEncryptionNetworkIdForSpace(spaceId: string, name?: string): string;
1231
+ private ownerDidFromSpaceId;
1225
1232
  private requireServiceSession;
1226
1233
  private createEncryptionCrypto;
1227
1234
  private fetchNodeId;
@@ -1327,6 +1334,10 @@ declare class TinyCloudNode {
1327
1334
  * App-facing secrets API backed by the `secrets` space vault.
1328
1335
  */
1329
1336
  get secrets(): ISecretsService;
1337
+ /**
1338
+ * App-facing secrets API backed by the requested space's vault.
1339
+ */
1340
+ secretsForSpace(spaceId: string): ISecretsService;
1330
1341
  private getBaseSecrets;
1331
1342
  /**
1332
1343
  * Hooks write stream subscription API.
@@ -893,8 +893,8 @@ declare class TinyCloudNode {
893
893
  private _hooks?;
894
894
  private _vault?;
895
895
  private _encryption?;
896
- private _baseSecrets?;
897
- private _secrets?;
896
+ private _baseSecrets;
897
+ private _secrets;
898
898
  private _account?;
899
899
  /** Cached public KV with proper delegation (set by ensurePublicSpace) */
900
900
  private _publicKV?;
@@ -1013,6 +1013,11 @@ declare class TinyCloudNode {
1013
1013
  * Available after signIn().
1014
1014
  */
1015
1015
  get session(): TinyCloudSession | undefined;
1016
+ /**
1017
+ * Get the currently active session in the shape callers can persist and later
1018
+ * pass back to {@link restoreSession}.
1019
+ */
1020
+ get restorableSession(): TinyCloudSession | undefined;
1016
1021
  /**
1017
1022
  * Sign in and create a new session.
1018
1023
  * This creates the user's space if it doesn't exist.
@@ -1222,6 +1227,8 @@ declare class TinyCloudNode {
1222
1227
  private initializeServices;
1223
1228
  private createSpaceScopedKVService;
1224
1229
  getDefaultEncryptionNetworkId(name?: string): string;
1230
+ getEncryptionNetworkIdForSpace(spaceId: string, name?: string): string;
1231
+ private ownerDidFromSpaceId;
1225
1232
  private requireServiceSession;
1226
1233
  private createEncryptionCrypto;
1227
1234
  private fetchNodeId;
@@ -1327,6 +1334,10 @@ declare class TinyCloudNode {
1327
1334
  * App-facing secrets API backed by the `secrets` space vault.
1328
1335
  */
1329
1336
  get secrets(): ISecretsService;
1337
+ /**
1338
+ * App-facing secrets API backed by the requested space's vault.
1339
+ */
1340
+ secretsForSpace(spaceId: string): ISecretsService;
1330
1341
  private getBaseSecrets;
1331
1342
  /**
1332
1343
  * Hooks write stream subscription API.
package/dist/core.cjs CHANGED
@@ -1523,12 +1523,12 @@ function displayActionUrn(action) {
1523
1523
  function secretActionName(action) {
1524
1524
  return action;
1525
1525
  }
1526
- function secretPermissionEntries(name, options, action, encryptionNetworkId) {
1526
+ function secretPermissionEntries(name, options, action, space, encryptionNetworkId) {
1527
1527
  const entries = [];
1528
1528
  const path = action === "list" ? (0, import_sdk_core7.resolveSecretListPrefix)(options) : (0, import_sdk_core7.resolveSecretPath)(name, options).permissionPaths.vault;
1529
1529
  entries.push({
1530
1530
  service: "tinycloud.kv",
1531
- space: SECRETS_SPACE,
1531
+ space,
1532
1532
  path,
1533
1533
  actions: [secretActionName(action)],
1534
1534
  skipPrefix: true
@@ -1543,11 +1543,23 @@ function secretPermissionEntries(name, options, action, encryptionNetworkId) {
1543
1543
  }
1544
1544
  return entries;
1545
1545
  }
1546
+ function normalizeSpace(space, resolveSpace) {
1547
+ if (!space) return void 0;
1548
+ if (space.startsWith("tinycloud:")) return space;
1549
+ return resolveSpace?.(space) ?? space;
1550
+ }
1551
+ function spaceMatches(granted, requested, resolveSpace) {
1552
+ if (!granted || !requested) return false;
1553
+ return normalizeSpace(granted, resolveSpace) === normalizeSpace(requested, resolveSpace);
1554
+ }
1546
1555
  var NodeSecretsService = class {
1547
1556
  constructor(config) {
1548
1557
  this.config = config;
1549
1558
  this.shouldRestoreUnlock = false;
1550
1559
  }
1560
+ get space() {
1561
+ return this.config.space ?? SECRETS_SPACE;
1562
+ }
1551
1563
  get vault() {
1552
1564
  return this.service.vault;
1553
1565
  }
@@ -1600,6 +1612,7 @@ var NodeSecretsService = class {
1600
1612
  name,
1601
1613
  options,
1602
1614
  action,
1615
+ this.space,
1603
1616
  action === "get" ? this.config.getEncryptionNetworkId?.() : void 0
1604
1617
  );
1605
1618
  } catch (error) {
@@ -1649,7 +1662,7 @@ var NodeSecretsService = class {
1649
1662
  (entry) => manifests.some((candidate) => {
1650
1663
  const resolved = (0, import_sdk_core7.resolveManifest)(candidate);
1651
1664
  return resolved.resources.some(
1652
- (resource) => resource.service === entry.service && resource.space === entry.space && resource.path === entry.path && entry.actions.every((action) => resource.actions.includes(action))
1665
+ (resource) => resource.service === entry.service && spaceMatches(resource.space, entry.space, this.config.resolveSpace) && resource.path === entry.path && entry.actions.every((action) => resource.actions.includes(action))
1653
1666
  );
1654
1667
  })
1655
1668
  );
@@ -1673,6 +1686,20 @@ function didPrincipalMatches2(actual, expected) {
1673
1686
  return actual === expected;
1674
1687
  }
1675
1688
  }
1689
+ function sharingActionsToAbilities(path, actions) {
1690
+ var _a;
1691
+ const abilities = {};
1692
+ for (const action of actions) {
1693
+ const slash = action.indexOf("/");
1694
+ if (slash === -1) return void 0;
1695
+ const shortService = import_sdk_core8.SERVICE_LONG_TO_SHORT[action.slice(0, slash)];
1696
+ if (shortService === void 0) return void 0;
1697
+ abilities[shortService] ?? (abilities[shortService] = {});
1698
+ (_a = abilities[shortService])[path] ?? (_a[path] = []);
1699
+ abilities[shortService][path].push(action);
1700
+ }
1701
+ return Object.keys(abilities).length > 0 ? abilities : void 0;
1702
+ }
1676
1703
  function base64UrlEncode(bytes) {
1677
1704
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
1678
1705
  let output = "";
@@ -1785,6 +1812,8 @@ var _TinyCloudNode = class _TinyCloudNode {
1785
1812
  this.auth = null;
1786
1813
  this.tc = null;
1787
1814
  this._chainId = 1;
1815
+ this._baseSecrets = /* @__PURE__ */ new Map();
1816
+ this._secrets = /* @__PURE__ */ new Map();
1788
1817
  this.runtimePermissionGrants = [];
1789
1818
  this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
1790
1819
  return this.wasmBindings.invoke(
@@ -2047,6 +2076,13 @@ var _TinyCloudNode = class _TinyCloudNode {
2047
2076
  get session() {
2048
2077
  return this.auth?.tinyCloudSession;
2049
2078
  }
2079
+ /**
2080
+ * Get the currently active session in the shape callers can persist and later
2081
+ * pass back to {@link restoreSession}.
2082
+ */
2083
+ get restorableSession() {
2084
+ return this.currentTinyCloudSession();
2085
+ }
2050
2086
  /**
2051
2087
  * Sign in and create a new session.
2052
2088
  * This creates the user's space if it doesn't exist.
@@ -2069,8 +2105,8 @@ var _TinyCloudNode = class _TinyCloudNode {
2069
2105
  this._hooks = void 0;
2070
2106
  this._vault = void 0;
2071
2107
  this._encryption = void 0;
2072
- this._baseSecrets = void 0;
2073
- this._secrets = void 0;
2108
+ this._baseSecrets.clear();
2109
+ this._secrets.clear();
2074
2110
  this._spaceService = void 0;
2075
2111
  this._serviceContext = void 0;
2076
2112
  this.runtimePermissionGrants = [];
@@ -2556,8 +2592,8 @@ var _TinyCloudNode = class _TinyCloudNode {
2556
2592
  this._hooks = void 0;
2557
2593
  this._vault = void 0;
2558
2594
  this._encryption = void 0;
2559
- this._baseSecrets = void 0;
2560
- this._secrets = void 0;
2595
+ this._baseSecrets.clear();
2596
+ this._secrets.clear();
2561
2597
  this._spaceService = void 0;
2562
2598
  this._serviceContext = void 0;
2563
2599
  this.runtimePermissionGrants = [];
@@ -2847,6 +2883,20 @@ var _TinyCloudNode = class _TinyCloudNode {
2847
2883
  getDefaultEncryptionNetworkId(name = DEFAULT_ENCRYPTION_NETWORK_NAME) {
2848
2884
  return `urn:tinycloud:encryption:${this.did}:${name}`;
2849
2885
  }
2886
+ getEncryptionNetworkIdForSpace(spaceId, name = DEFAULT_ENCRYPTION_NETWORK_NAME) {
2887
+ const ownerDid = this.ownerDidFromSpaceId(spaceId) ?? this.did;
2888
+ return `urn:tinycloud:encryption:${ownerDid}:${name}`;
2889
+ }
2890
+ ownerDidFromSpaceId(spaceId) {
2891
+ if (!spaceId.startsWith("tinycloud:")) return void 0;
2892
+ const body = spaceId.slice("tinycloud:".length);
2893
+ const lastSeparator = body.lastIndexOf(":");
2894
+ if (lastSeparator <= 0) return void 0;
2895
+ const owner = body.slice(0, lastSeparator);
2896
+ if (owner.startsWith("did:")) return owner;
2897
+ if (!owner.includes(":")) return void 0;
2898
+ return `did:${owner}`;
2899
+ }
2850
2900
  requireServiceSession() {
2851
2901
  const session = this._serviceContext?.session;
2852
2902
  if (!session) {
@@ -3034,7 +3084,7 @@ var _TinyCloudNode = class _TinyCloudNode {
3034
3084
  spaceId,
3035
3085
  crypto: vaultCrypto,
3036
3086
  encryption: {
3037
- networkId: this.getDefaultEncryptionNetworkId(),
3087
+ networkId: this.getEncryptionNetworkIdForSpace(spaceId),
3038
3088
  service: this.getEncryptionService(),
3039
3089
  decryptCapabilityProof: () => ({
3040
3090
  proofs: [this.requireServiceSession().delegationCid]
@@ -3165,6 +3215,9 @@ var _TinyCloudNode = class _TinyCloudNode {
3165
3215
  }
3166
3216
  return vaultService;
3167
3217
  },
3218
+ createSecretsService: (spaceId) => {
3219
+ return this.secretsForSpace(spaceId);
3220
+ },
3168
3221
  // Enable space.delegations.create() via SIWE-based delegation
3169
3222
  createDelegation: async (params) => {
3170
3223
  try {
@@ -3287,11 +3340,10 @@ var _TinyCloudNode = class _TinyCloudNode {
3287
3340
  try {
3288
3341
  const host = this.config.host;
3289
3342
  const now = /* @__PURE__ */ new Date();
3290
- const abilities = {
3291
- kv: {
3292
- [params.path]: params.actions
3293
- }
3294
- };
3343
+ const abilities = sharingActionsToAbilities(params.path, params.actions);
3344
+ if (!abilities) {
3345
+ return void 0;
3346
+ }
3295
3347
  const prepared = this.wasmBindings.prepareSession({
3296
3348
  abilities,
3297
3349
  address: this.wasmBindings.ensureEip55(session.address),
@@ -3547,27 +3599,49 @@ var _TinyCloudNode = class _TinyCloudNode {
3547
3599
  if (!this._spaceService) {
3548
3600
  throw new Error("Not signed in. Call signIn() first.");
3549
3601
  }
3550
- if (!this._secrets) {
3551
- this._secrets = new NodeSecretsService({
3552
- getService: () => this.getBaseSecrets(),
3602
+ return this.secretsForSpace("secrets");
3603
+ }
3604
+ /**
3605
+ * App-facing secrets API backed by the requested space's vault.
3606
+ */
3607
+ secretsForSpace(spaceId) {
3608
+ if (!this._spaceService) {
3609
+ throw new Error("Not signed in. Call signIn() first.");
3610
+ }
3611
+ const resolvedSpace = spaceId.startsWith("tinycloud:") ? spaceId : this.ownedSpaceId(spaceId);
3612
+ let secrets = this._secrets.get(resolvedSpace);
3613
+ if (!secrets) {
3614
+ secrets = new NodeSecretsService({
3615
+ getService: () => this.getBaseSecrets(resolvedSpace),
3616
+ space: resolvedSpace,
3553
3617
  getManifest: () => this.manifest,
3554
3618
  hasPermissions: (permissions) => this.hasRuntimePermissions(permissions),
3555
3619
  grantPermissions: (additional) => this.grantRuntimePermissions(additional),
3556
3620
  canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
3557
- getEncryptionNetworkId: () => this.getDefaultEncryptionNetworkId(),
3621
+ getEncryptionNetworkId: () => this.getEncryptionNetworkIdForSpace(resolvedSpace),
3622
+ resolveSpace: (space) => space.startsWith("tinycloud:") ? space : this.ownedSpaceId(space),
3558
3623
  getUnlockSigner: () => this.signer ?? void 0
3559
3624
  });
3625
+ this._secrets.set(resolvedSpace, secrets);
3560
3626
  }
3561
- return this._secrets;
3627
+ return secrets;
3562
3628
  }
3563
- getBaseSecrets() {
3629
+ getBaseSecrets(spaceId) {
3564
3630
  if (!this._spaceService) {
3565
3631
  throw new Error("Not signed in. Call signIn() first.");
3566
3632
  }
3567
- if (!this._baseSecrets) {
3568
- this._baseSecrets = new import_sdk_core8.SecretsService(() => this.space("secrets").vault);
3633
+ const resolvedSpace = spaceId.startsWith("tinycloud:") ? spaceId : this.ownedSpaceId(spaceId);
3634
+ let secrets = this._baseSecrets.get(resolvedSpace);
3635
+ if (!secrets) {
3636
+ const kvService = this.createSpaceScopedKVService(resolvedSpace);
3637
+ const vaultService = this.createVaultService(resolvedSpace, kvService);
3638
+ if (this._serviceContext) {
3639
+ vaultService.initialize(this._serviceContext);
3640
+ }
3641
+ secrets = new import_sdk_core8.SecretsService(() => vaultService);
3642
+ this._baseSecrets.set(resolvedSpace, secrets);
3569
3643
  }
3570
- return this._baseSecrets;
3644
+ return secrets;
3571
3645
  }
3572
3646
  /**
3573
3647
  * Hooks write stream subscription API.