@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.
package/dist/index.cjs CHANGED
@@ -19961,16 +19961,26 @@ var _TinyCloudNode = class _TinyCloudNode {
19961
19961
  */
19962
19962
  getVerifiedSessionCapabilities() {
19963
19963
  const session = this.currentTinyCloudSession();
19964
- if (!session || !session.siwe) return [];
19965
- return (0, import_sdk_core7.parseRecapCapabilities)(
19966
- (siwe) => this.parseRecapWithCaveats(siwe),
19967
- session.siwe
19968
- ).map((entry) => entry.service === "tinycloud.encryption" ? {
19969
- service: entry.service,
19970
- path: entry.path,
19971
- actions: [...entry.actions],
19972
- ...entry.caveats === void 0 ? {} : { caveats: entry.caveats }
19973
- } : entry);
19964
+ return session?.siwe ? this.projectSignedRecapCapabilities(session.siwe) : [];
19965
+ }
19966
+ /** Normalize signed capabilities without collapsing nested encryption into raw authority. */
19967
+ projectSignedRecapCapabilities(siwe) {
19968
+ const projected = this.parseRecapWithCaveats(siwe).map((entry) => {
19969
+ const normalized = (0, import_sdk_core7.parseRecapCapabilities)(() => [entry], siwe)[0];
19970
+ if (normalized.service !== "tinycloud.encryption") return normalized;
19971
+ if (!this.isEncryptionNetworkOperation("encryption", entry.path, entry.space)) {
19972
+ return { ...normalized, space: entry.space };
19973
+ }
19974
+ return {
19975
+ service: normalized.service,
19976
+ path: normalized.path,
19977
+ actions: normalized.actions,
19978
+ ...normalized.caveats === void 0 ? {} : { caveats: normalized.caveats }
19979
+ };
19980
+ });
19981
+ return projected.sort(
19982
+ (left, right) => (left.space ?? "").localeCompare(right.space ?? "") || left.service.localeCompare(right.service) || left.path.localeCompare(right.path)
19983
+ );
19974
19984
  }
19975
19985
  /**
19976
19986
  * Get the Ethereum address for this user.
@@ -20425,9 +20435,9 @@ var _TinyCloudNode = class _TinyCloudNode {
20425
20435
  * We must keep the full owner-scoped URI so a synthetic primary grant can
20426
20436
  * never cover an operation on a different owner's space.
20427
20437
  *
20428
- * Mirrors {@link operationsFromDelegation}'s op shape: encryption network
20429
- * entries (`urn:tinycloud:encryption:` paths) become `resource` ops; every
20430
- * other entry becomes a `spaceId` op carrying the raw recap `space` URI.
20438
+ * Only top-level encryption network entries (`space: "encryption"` or
20439
+ * absent) become `resource` ops. A network-shaped path nested under a
20440
+ * data space remains a `spaceId` op, not raw network authority.
20431
20441
  * One op per action.
20432
20442
  *
20433
20443
  * Returns `[]` for session-only / restored-without-siwe modes and for any
@@ -20448,7 +20458,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20448
20458
  operations = entries.flatMap((entry) => {
20449
20459
  const service = this.invocationServiceName(entry.service);
20450
20460
  return entry.actions.map((action) => ({
20451
- ...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId: entry.space },
20461
+ ...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId: entry.space },
20452
20462
  service,
20453
20463
  path: entry.path,
20454
20464
  action,
@@ -21062,7 +21072,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21062
21072
  operations = recap.flatMap((entry) => {
21063
21073
  const service = this.invocationServiceName(entry.service);
21064
21074
  return entry.actions.map((action) => ({
21065
- ...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId: entry.space },
21075
+ ...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId: entry.space },
21066
21076
  service,
21067
21077
  path: entry.path,
21068
21078
  action,
@@ -21848,16 +21858,11 @@ var _TinyCloudNode = class _TinyCloudNode {
21848
21858
  );
21849
21859
  graph.assertActive();
21850
21860
  if (!response.ok) {
21851
- let permissionHint;
21852
- if (response.status === 401 || response.status === 403) {
21853
- try {
21854
- const body = await response.json();
21855
- const record = typeof body === "object" && body !== null ? body : void 0;
21856
- const nested = typeof record?.error === "object" && record.error !== null ? record.error : void 0;
21857
- permissionHint = (0, import_sdk_services.parsePermissionHint)(record?.permissionHint) ?? (0, import_sdk_services.parsePermissionHint)(nested?.permissionHint);
21858
- } catch {
21859
- }
21860
- }
21861
+ const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services.parsePermissionHint)({
21862
+ service: "tinycloud.encryption",
21863
+ path: networkId,
21864
+ actions: ["tinycloud.encryption/decrypt"]
21865
+ }) : void 0;
21861
21866
  throw new import_sdk_core7.DecryptTransportResponseError(response.status, permissionHint);
21862
21867
  }
21863
21868
  return await response.json();
@@ -22792,7 +22797,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22792
22797
  continue;
22793
22798
  }
22794
22799
  let space;
22795
- if (service !== "tinycloud.encryption") {
22800
+ if (service !== "tinycloud.encryption" || operation.resource === void 0) {
22796
22801
  if (typeof operation.spaceId !== "string") continue;
22797
22802
  try {
22798
22803
  space = this.resolvePermissionSpace(operation.spaceId, session);
@@ -23337,11 +23342,8 @@ var _TinyCloudNode = class _TinyCloudNode {
23337
23342
  );
23338
23343
  return { delegation: delegation2, prompted: true };
23339
23344
  }
23340
- const granted = (0, import_sdk_core7.parseRecapCapabilities)(
23341
- (siwe) => this.parseRecapWithCaveats(siwe),
23342
- session.siwe
23343
- );
23344
- const { subset, missing } = (0, import_sdk_core7.isCapabilitySubset)(expandedEntries, granted);
23345
+ const granted = this.projectSignedRecapCapabilities(session.siwe);
23346
+ const { subset, missing } = this.signedCapabilitySubset(expandedEntries, granted);
23345
23347
  if (!subset) {
23346
23348
  const runtimeOperations = this.permissionEntriesToOperations(expandedEntries, session);
23347
23349
  const runtimeGrant = this.findGrantForOperations(
@@ -23661,7 +23663,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23661
23663
  return abilities;
23662
23664
  }
23663
23665
  isEncryptionPermissionEntry(entry) {
23664
- return entry.service === import_sdk_core7.ENCRYPTION_PERMISSION_SERVICE && entry.path.startsWith("urn:tinycloud:encryption:");
23666
+ return entry.service === import_sdk_core7.ENCRYPTION_PERMISSION_SERVICE && this.isEncryptionNetworkOperation("encryption", entry.path, entry.space);
23665
23667
  }
23666
23668
  permissionsToRawAbilities(entries) {
23667
23669
  const rawAbilities = {};
@@ -23685,7 +23687,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23685
23687
  return entries.flatMap((entry) => {
23686
23688
  const service = this.shortServiceName(entry.service);
23687
23689
  return entry.actions.map((action) => ({
23688
- ...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
23690
+ ...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
23689
23691
  service,
23690
23692
  path: entry.path,
23691
23693
  action,
@@ -23693,13 +23695,21 @@ var _TinyCloudNode = class _TinyCloudNode {
23693
23695
  }));
23694
23696
  });
23695
23697
  }
23698
+ /** Raw network authority cannot be covered by a nested encryption space. */
23699
+ signedCapabilitySubset(requested, granted) {
23700
+ const rawGranted = granted.filter((entry) => this.isEncryptionPermissionEntry(entry)).map((entry) => ({ ...entry, space: "encryption" }));
23701
+ const spaceGranted = granted.filter((entry) => !this.isEncryptionPermissionEntry(entry));
23702
+ const missing = requested.filter((entry) => {
23703
+ const raw = this.isEncryptionPermissionEntry(entry);
23704
+ const comparable = raw ? { ...entry, space: "encryption" } : entry;
23705
+ return !(0, import_sdk_core7.isCapabilitySubset)([comparable], raw ? rawGranted : spaceGranted).subset;
23706
+ });
23707
+ return { subset: missing.length === 0, missing };
23708
+ }
23696
23709
  sessionCoversPermissionEntries(session, entries) {
23697
23710
  try {
23698
- const granted = (0, import_sdk_core7.parseRecapCapabilities)(
23699
- (siwe) => this.parseRecapWithCaveats(siwe),
23700
- session.siwe
23701
- );
23702
- return (0, import_sdk_core7.isCapabilitySubset)(entries, granted).subset;
23711
+ const granted = this.projectSignedRecapCapabilities(session.siwe);
23712
+ return this.signedCapabilitySubset(entries, granted).subset;
23703
23713
  } catch {
23704
23714
  return false;
23705
23715
  }
@@ -23709,7 +23719,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23709
23719
  const spaceId = this.resolvePermissionSpace(entry.space, session);
23710
23720
  const service = this.shortServiceName(entry.service);
23711
23721
  return entry.actions.map((action) => ({
23712
- ...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
23722
+ ...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
23713
23723
  service,
23714
23724
  path: entry.path,
23715
23725
  action,
@@ -23798,7 +23808,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23798
23808
  return resources.flatMap((resource) => {
23799
23809
  const service = this.invocationServiceName(resource.service);
23800
23810
  return resource.actions.map((action) => ({
23801
- ...this.isEncryptionNetworkOperation(service, resource.path) ? { resource: resource.path } : { spaceId: resource.space },
23811
+ ...this.isEncryptionNetworkOperation(service, resource.path, resource.space) ? { resource: resource.path } : { spaceId: resource.space },
23802
23812
  service,
23803
23813
  path: resource.path,
23804
23814
  action,
@@ -23859,7 +23869,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23859
23869
  };
23860
23870
  for (const resource of resources) {
23861
23871
  const service = this.invocationServiceName(resource.service);
23862
- if (this.isEncryptionNetworkOperation(service, resource.path)) {
23872
+ if (this.isEncryptionNetworkOperation(service, resource.path, resource.space)) {
23863
23873
  rawAbilities[_a = resource.path] ?? (rawAbilities[_a] = []);
23864
23874
  addActions(rawAbilities[resource.path], resource.actions);
23865
23875
  continue;
@@ -23956,8 +23966,8 @@ var _TinyCloudNode = class _TinyCloudNode {
23956
23966
  const verified = this.wasmBindings.parseVerifiedRecapFromSiwe?.(siwe);
23957
23967
  return verified == null ? this.wasmBindings.parseRecapFromSiwe(siwe) : verifierRecapEntries(verified);
23958
23968
  }
23959
- isEncryptionNetworkOperation(service, path) {
23960
- return service === "encryption" && path.startsWith("urn:tinycloud:encryption:");
23969
+ isEncryptionNetworkOperation(service, path, space) {
23970
+ return service === "encryption" && (space === void 0 || space === "encryption") && path.startsWith("urn:tinycloud:encryption:");
23961
23971
  }
23962
23972
  operationFromInvokeAnyEntry(entry) {
23963
23973
  const service = this.invocationServiceName(entry.service);
@@ -23970,7 +23980,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23970
23980
  ...entry.caveats === void 0 ? {} : { caveats: cloneRecapCaveats(entry.caveats) }
23971
23981
  };
23972
23982
  }
23973
- if (this.isEncryptionNetworkOperation(service, entry.path)) {
23983
+ if (entry.spaceId === void 0 && this.isEncryptionNetworkOperation(service, entry.path)) {
23974
23984
  return {
23975
23985
  resource: entry.path,
23976
23986
  service,