@tinycloud/node-sdk 3.0.0-beta.19 → 3.0.0-beta.20

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.
@@ -1390,6 +1390,8 @@ declare class TinyCloudNode {
1390
1390
  * rather than treating a malformed session as unrestricted authority.
1391
1391
  */
1392
1392
  getVerifiedSessionCapabilities(): PermissionEntry[];
1393
+ /** Normalize signed capabilities without collapsing nested encryption into raw authority. */
1394
+ private projectSignedRecapCapabilities;
1393
1395
  /**
1394
1396
  * Get the Ethereum address for this user.
1395
1397
  */
@@ -1450,9 +1452,9 @@ declare class TinyCloudNode {
1450
1452
  * We must keep the full owner-scoped URI so a synthetic primary grant can
1451
1453
  * never cover an operation on a different owner's space.
1452
1454
  *
1453
- * Mirrors {@link operationsFromDelegation}'s op shape: encryption network
1454
- * entries (`urn:tinycloud:encryption:` paths) become `resource` ops; every
1455
- * other entry becomes a `spaceId` op carrying the raw recap `space` URI.
1455
+ * Only top-level encryption network entries (`space: "encryption"` or
1456
+ * absent) become `resource` ops. A network-shaped path nested under a
1457
+ * data space remains a `spaceId` op, not raw network authority.
1456
1458
  * One op per action.
1457
1459
  *
1458
1460
  * Returns `[]` for session-only / restored-without-siwe modes and for any
@@ -2223,6 +2225,8 @@ declare class TinyCloudNode {
2223
2225
  private isEncryptionPermissionEntry;
2224
2226
  private permissionsToRawAbilities;
2225
2227
  private permissionOperations;
2228
+ /** Raw network authority cannot be covered by a nested encryption space. */
2229
+ private signedCapabilitySubset;
2226
2230
  private sessionCoversPermissionEntries;
2227
2231
  private permissionEntriesToOperations;
2228
2232
  private findRuntimeGrantsForPermissionEntries;
@@ -1390,6 +1390,8 @@ declare class TinyCloudNode {
1390
1390
  * rather than treating a malformed session as unrestricted authority.
1391
1391
  */
1392
1392
  getVerifiedSessionCapabilities(): PermissionEntry[];
1393
+ /** Normalize signed capabilities without collapsing nested encryption into raw authority. */
1394
+ private projectSignedRecapCapabilities;
1393
1395
  /**
1394
1396
  * Get the Ethereum address for this user.
1395
1397
  */
@@ -1450,9 +1452,9 @@ declare class TinyCloudNode {
1450
1452
  * We must keep the full owner-scoped URI so a synthetic primary grant can
1451
1453
  * never cover an operation on a different owner's space.
1452
1454
  *
1453
- * Mirrors {@link operationsFromDelegation}'s op shape: encryption network
1454
- * entries (`urn:tinycloud:encryption:` paths) become `resource` ops; every
1455
- * other entry becomes a `spaceId` op carrying the raw recap `space` URI.
1455
+ * Only top-level encryption network entries (`space: "encryption"` or
1456
+ * absent) become `resource` ops. A network-shaped path nested under a
1457
+ * data space remains a `spaceId` op, not raw network authority.
1456
1458
  * One op per action.
1457
1459
  *
1458
1460
  * Returns `[]` for session-only / restored-without-siwe modes and for any
@@ -2223,6 +2225,8 @@ declare class TinyCloudNode {
2223
2225
  private isEncryptionPermissionEntry;
2224
2226
  private permissionsToRawAbilities;
2225
2227
  private permissionOperations;
2228
+ /** Raw network authority cannot be covered by a nested encryption space. */
2229
+ private signedCapabilitySubset;
2226
2230
  private sessionCoversPermissionEntries;
2227
2231
  private permissionEntriesToOperations;
2228
2232
  private findRuntimeGrantsForPermissionEntries;
package/dist/core.cjs CHANGED
@@ -2933,16 +2933,26 @@ var _TinyCloudNode = class _TinyCloudNode {
2933
2933
  */
2934
2934
  getVerifiedSessionCapabilities() {
2935
2935
  const session = this.currentTinyCloudSession();
2936
- if (!session || !session.siwe) return [];
2937
- return (0, import_sdk_core8.parseRecapCapabilities)(
2938
- (siwe) => this.parseRecapWithCaveats(siwe),
2939
- session.siwe
2940
- ).map((entry) => entry.service === "tinycloud.encryption" ? {
2941
- service: entry.service,
2942
- path: entry.path,
2943
- actions: [...entry.actions],
2944
- ...entry.caveats === void 0 ? {} : { caveats: entry.caveats }
2945
- } : entry);
2936
+ return session?.siwe ? this.projectSignedRecapCapabilities(session.siwe) : [];
2937
+ }
2938
+ /** Normalize signed capabilities without collapsing nested encryption into raw authority. */
2939
+ projectSignedRecapCapabilities(siwe) {
2940
+ const projected = this.parseRecapWithCaveats(siwe).map((entry) => {
2941
+ const normalized = (0, import_sdk_core8.parseRecapCapabilities)(() => [entry], siwe)[0];
2942
+ if (normalized.service !== "tinycloud.encryption") return normalized;
2943
+ if (!this.isEncryptionNetworkOperation("encryption", entry.path, entry.space)) {
2944
+ return { ...normalized, space: entry.space };
2945
+ }
2946
+ return {
2947
+ service: normalized.service,
2948
+ path: normalized.path,
2949
+ actions: normalized.actions,
2950
+ ...normalized.caveats === void 0 ? {} : { caveats: normalized.caveats }
2951
+ };
2952
+ });
2953
+ return projected.sort(
2954
+ (left, right) => (left.space ?? "").localeCompare(right.space ?? "") || left.service.localeCompare(right.service) || left.path.localeCompare(right.path)
2955
+ );
2946
2956
  }
2947
2957
  /**
2948
2958
  * Get the Ethereum address for this user.
@@ -3397,9 +3407,9 @@ var _TinyCloudNode = class _TinyCloudNode {
3397
3407
  * We must keep the full owner-scoped URI so a synthetic primary grant can
3398
3408
  * never cover an operation on a different owner's space.
3399
3409
  *
3400
- * Mirrors {@link operationsFromDelegation}'s op shape: encryption network
3401
- * entries (`urn:tinycloud:encryption:` paths) become `resource` ops; every
3402
- * other entry becomes a `spaceId` op carrying the raw recap `space` URI.
3410
+ * Only top-level encryption network entries (`space: "encryption"` or
3411
+ * absent) become `resource` ops. A network-shaped path nested under a
3412
+ * data space remains a `spaceId` op, not raw network authority.
3403
3413
  * One op per action.
3404
3414
  *
3405
3415
  * Returns `[]` for session-only / restored-without-siwe modes and for any
@@ -3420,7 +3430,7 @@ var _TinyCloudNode = class _TinyCloudNode {
3420
3430
  operations = entries.flatMap((entry) => {
3421
3431
  const service = this.invocationServiceName(entry.service);
3422
3432
  return entry.actions.map((action) => ({
3423
- ...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId: entry.space },
3433
+ ...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId: entry.space },
3424
3434
  service,
3425
3435
  path: entry.path,
3426
3436
  action,
@@ -4034,7 +4044,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4034
4044
  operations = recap.flatMap((entry) => {
4035
4045
  const service = this.invocationServiceName(entry.service);
4036
4046
  return entry.actions.map((action) => ({
4037
- ...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId: entry.space },
4047
+ ...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId: entry.space },
4038
4048
  service,
4039
4049
  path: entry.path,
4040
4050
  action,
@@ -4820,16 +4830,11 @@ var _TinyCloudNode = class _TinyCloudNode {
4820
4830
  );
4821
4831
  graph.assertActive();
4822
4832
  if (!response.ok) {
4823
- let permissionHint;
4824
- if (response.status === 401 || response.status === 403) {
4825
- try {
4826
- const body = await response.json();
4827
- const record = typeof body === "object" && body !== null ? body : void 0;
4828
- const nested = typeof record?.error === "object" && record.error !== null ? record.error : void 0;
4829
- permissionHint = (0, import_sdk_services.parsePermissionHint)(record?.permissionHint) ?? (0, import_sdk_services.parsePermissionHint)(nested?.permissionHint);
4830
- } catch {
4831
- }
4832
- }
4833
+ const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services.parsePermissionHint)({
4834
+ service: "tinycloud.encryption",
4835
+ path: networkId,
4836
+ actions: ["tinycloud.encryption/decrypt"]
4837
+ }) : void 0;
4833
4838
  throw new import_sdk_core8.DecryptTransportResponseError(response.status, permissionHint);
4834
4839
  }
4835
4840
  return await response.json();
@@ -5764,7 +5769,7 @@ var _TinyCloudNode = class _TinyCloudNode {
5764
5769
  continue;
5765
5770
  }
5766
5771
  let space;
5767
- if (service !== "tinycloud.encryption") {
5772
+ if (service !== "tinycloud.encryption" || operation.resource === void 0) {
5768
5773
  if (typeof operation.spaceId !== "string") continue;
5769
5774
  try {
5770
5775
  space = this.resolvePermissionSpace(operation.spaceId, session);
@@ -6309,11 +6314,8 @@ var _TinyCloudNode = class _TinyCloudNode {
6309
6314
  );
6310
6315
  return { delegation: delegation2, prompted: true };
6311
6316
  }
6312
- const granted = (0, import_sdk_core8.parseRecapCapabilities)(
6313
- (siwe) => this.parseRecapWithCaveats(siwe),
6314
- session.siwe
6315
- );
6316
- const { subset, missing } = (0, import_sdk_core8.isCapabilitySubset)(expandedEntries, granted);
6317
+ const granted = this.projectSignedRecapCapabilities(session.siwe);
6318
+ const { subset, missing } = this.signedCapabilitySubset(expandedEntries, granted);
6317
6319
  if (!subset) {
6318
6320
  const runtimeOperations = this.permissionEntriesToOperations(expandedEntries, session);
6319
6321
  const runtimeGrant = this.findGrantForOperations(
@@ -6633,7 +6635,7 @@ var _TinyCloudNode = class _TinyCloudNode {
6633
6635
  return abilities;
6634
6636
  }
6635
6637
  isEncryptionPermissionEntry(entry) {
6636
- return entry.service === import_sdk_core8.ENCRYPTION_PERMISSION_SERVICE && entry.path.startsWith("urn:tinycloud:encryption:");
6638
+ return entry.service === import_sdk_core8.ENCRYPTION_PERMISSION_SERVICE && this.isEncryptionNetworkOperation("encryption", entry.path, entry.space);
6637
6639
  }
6638
6640
  permissionsToRawAbilities(entries) {
6639
6641
  const rawAbilities = {};
@@ -6657,7 +6659,7 @@ var _TinyCloudNode = class _TinyCloudNode {
6657
6659
  return entries.flatMap((entry) => {
6658
6660
  const service = this.shortServiceName(entry.service);
6659
6661
  return entry.actions.map((action) => ({
6660
- ...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
6662
+ ...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
6661
6663
  service,
6662
6664
  path: entry.path,
6663
6665
  action,
@@ -6665,13 +6667,21 @@ var _TinyCloudNode = class _TinyCloudNode {
6665
6667
  }));
6666
6668
  });
6667
6669
  }
6670
+ /** Raw network authority cannot be covered by a nested encryption space. */
6671
+ signedCapabilitySubset(requested, granted) {
6672
+ const rawGranted = granted.filter((entry) => this.isEncryptionPermissionEntry(entry)).map((entry) => ({ ...entry, space: "encryption" }));
6673
+ const spaceGranted = granted.filter((entry) => !this.isEncryptionPermissionEntry(entry));
6674
+ const missing = requested.filter((entry) => {
6675
+ const raw = this.isEncryptionPermissionEntry(entry);
6676
+ const comparable = raw ? { ...entry, space: "encryption" } : entry;
6677
+ return !(0, import_sdk_core8.isCapabilitySubset)([comparable], raw ? rawGranted : spaceGranted).subset;
6678
+ });
6679
+ return { subset: missing.length === 0, missing };
6680
+ }
6668
6681
  sessionCoversPermissionEntries(session, entries) {
6669
6682
  try {
6670
- const granted = (0, import_sdk_core8.parseRecapCapabilities)(
6671
- (siwe) => this.parseRecapWithCaveats(siwe),
6672
- session.siwe
6673
- );
6674
- return (0, import_sdk_core8.isCapabilitySubset)(entries, granted).subset;
6683
+ const granted = this.projectSignedRecapCapabilities(session.siwe);
6684
+ return this.signedCapabilitySubset(entries, granted).subset;
6675
6685
  } catch {
6676
6686
  return false;
6677
6687
  }
@@ -6681,7 +6691,7 @@ var _TinyCloudNode = class _TinyCloudNode {
6681
6691
  const spaceId = this.resolvePermissionSpace(entry.space, session);
6682
6692
  const service = this.shortServiceName(entry.service);
6683
6693
  return entry.actions.map((action) => ({
6684
- ...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
6694
+ ...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
6685
6695
  service,
6686
6696
  path: entry.path,
6687
6697
  action,
@@ -6770,7 +6780,7 @@ var _TinyCloudNode = class _TinyCloudNode {
6770
6780
  return resources.flatMap((resource) => {
6771
6781
  const service = this.invocationServiceName(resource.service);
6772
6782
  return resource.actions.map((action) => ({
6773
- ...this.isEncryptionNetworkOperation(service, resource.path) ? { resource: resource.path } : { spaceId: resource.space },
6783
+ ...this.isEncryptionNetworkOperation(service, resource.path, resource.space) ? { resource: resource.path } : { spaceId: resource.space },
6774
6784
  service,
6775
6785
  path: resource.path,
6776
6786
  action,
@@ -6831,7 +6841,7 @@ var _TinyCloudNode = class _TinyCloudNode {
6831
6841
  };
6832
6842
  for (const resource of resources) {
6833
6843
  const service = this.invocationServiceName(resource.service);
6834
- if (this.isEncryptionNetworkOperation(service, resource.path)) {
6844
+ if (this.isEncryptionNetworkOperation(service, resource.path, resource.space)) {
6835
6845
  rawAbilities[_a = resource.path] ?? (rawAbilities[_a] = []);
6836
6846
  addActions(rawAbilities[resource.path], resource.actions);
6837
6847
  continue;
@@ -6928,8 +6938,8 @@ var _TinyCloudNode = class _TinyCloudNode {
6928
6938
  const verified = this.wasmBindings.parseVerifiedRecapFromSiwe?.(siwe);
6929
6939
  return verified == null ? this.wasmBindings.parseRecapFromSiwe(siwe) : verifierRecapEntries(verified);
6930
6940
  }
6931
- isEncryptionNetworkOperation(service, path) {
6932
- return service === "encryption" && path.startsWith("urn:tinycloud:encryption:");
6941
+ isEncryptionNetworkOperation(service, path, space) {
6942
+ return service === "encryption" && (space === void 0 || space === "encryption") && path.startsWith("urn:tinycloud:encryption:");
6933
6943
  }
6934
6944
  operationFromInvokeAnyEntry(entry) {
6935
6945
  const service = this.invocationServiceName(entry.service);
@@ -6942,7 +6952,7 @@ var _TinyCloudNode = class _TinyCloudNode {
6942
6952
  ...entry.caveats === void 0 ? {} : { caveats: cloneRecapCaveats(entry.caveats) }
6943
6953
  };
6944
6954
  }
6945
- if (this.isEncryptionNetworkOperation(service, entry.path)) {
6955
+ if (entry.spaceId === void 0 && this.isEncryptionNetworkOperation(service, entry.path)) {
6946
6956
  return {
6947
6957
  resource: entry.path,
6948
6958
  service,