@tinycloud/node-sdk 3.2.0-beta.7 → 3.2.0-beta.9

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.
@@ -2583,6 +2583,15 @@ declare class TinyCloudNode {
2583
2583
  */
2584
2584
  private buildActivationAbilities;
2585
2585
  private selectInvocationSession;
2586
+ /**
2587
+ * A non-primary grant's session, aimed at `spaceId`. The grant's delegation
2588
+ * may span spaces (the widened default bootstrap session also carries
2589
+ * account-space entries, TC-957); its session's own `spaceId` is the space
2590
+ * it was minted for, so an op on another covered space must keep the grant's
2591
+ * key and proof but target that space. A grant on the target space itself is
2592
+ * returned unchanged, keeping its own spelling of the space id.
2593
+ */
2594
+ private grantSessionForSpace;
2586
2595
  private findGrantForOperations;
2587
2596
  private findGrantForOperation;
2588
2597
  private pruneExpiredRuntimePermissionGrants;
@@ -2583,6 +2583,15 @@ declare class TinyCloudNode {
2583
2583
  */
2584
2584
  private buildActivationAbilities;
2585
2585
  private selectInvocationSession;
2586
+ /**
2587
+ * A non-primary grant's session, aimed at `spaceId`. The grant's delegation
2588
+ * may span spaces (the widened default bootstrap session also carries
2589
+ * account-space entries, TC-957); its session's own `spaceId` is the space
2590
+ * it was minted for, so an op on another covered space must keep the grant's
2591
+ * key and proof but target that space. A grant on the target space itself is
2592
+ * returned unchanged, keeping its own spelling of the space id.
2593
+ */
2594
+ private grantSessionForSpace;
2586
2595
  private findGrantForOperations;
2587
2596
  private findGrantForOperation;
2588
2597
  private pruneExpiredRuntimePermissionGrants;
package/dist/core.cjs CHANGED
@@ -397,6 +397,10 @@ var import_sdk_core3 = require("@tinycloud/sdk-core");
397
397
  var defaultSignStrategy = { type: "auto-sign" };
398
398
 
399
399
  // src/authorization/NodeUserAuthorization.ts
400
+ function pkhSpaceIdentity(spaceId) {
401
+ const match = /^(tinycloud:pkh:eip155:\d+:)(0x[0-9a-fA-F]{40})(:.+)$/.exec(spaceId);
402
+ return match === null ? spaceId : `${match[1]}${match[2].toLowerCase()}${match[3]}`;
403
+ }
400
404
  var DECRYPT_ACTION = import_sdk_core4.ENCRYPTION.DECRYPT;
401
405
  var NETWORK_CREATE_ACTION = import_sdk_core4.ENCRYPTION.NETWORK_CREATE;
402
406
  function describeHostFailure(result) {
@@ -1195,11 +1199,26 @@ var NodeUserAuthorization = class {
1195
1199
  const jwk = JSON.parse(jwkString);
1196
1200
  const now = /* @__PURE__ */ new Date();
1197
1201
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
1198
- const abilities = (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)(
1199
- options.capabilityRequest.resources
1200
- );
1202
+ const primaryIdentity = pkhSpaceIdentity(options.spaceId);
1203
+ const resourcesBySpace = /* @__PURE__ */ new Map();
1204
+ for (const resource of options.capabilityRequest.resources) {
1205
+ const resolved = this.resolveSpaceName(resource.space, address, chainId);
1206
+ const identity = pkhSpaceIdentity(resolved);
1207
+ const group = resourcesBySpace.get(identity) ?? {
1208
+ spaceId: identity === primaryIdentity ? options.spaceId : resolved,
1209
+ resources: []
1210
+ };
1211
+ group.resources.push(resource);
1212
+ resourcesBySpace.set(identity, group);
1213
+ }
1214
+ const spaceAbilities = {};
1215
+ for (const { spaceId, resources } of resourcesBySpace.values()) {
1216
+ spaceAbilities[spaceId] = (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)(resources);
1217
+ }
1218
+ const abilities = spaceAbilities[options.spaceId] ?? (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)([]);
1201
1219
  const prepared = this.wasm.prepareSession({
1202
1220
  abilities,
1221
+ spaceAbilities,
1203
1222
  ...options.rawAbilities !== void 0 ? { rawAbilities: options.rawAbilities } : {},
1204
1223
  address,
1205
1224
  chainId,
@@ -3349,6 +3368,32 @@ function authorizationHeader(headers) {
3349
3368
  }
3350
3369
  return value;
3351
3370
  }
3371
+ function accountIndexWarningDiagnostic(error) {
3372
+ const diagnostic = {};
3373
+ let current = error;
3374
+ for (let depth = 0; depth < 8 && current !== null && typeof current === "object"; depth += 1) {
3375
+ const record = current;
3376
+ if (diagnostic.status === void 0) {
3377
+ if (typeof record.status === "number" && Number.isFinite(record.status)) {
3378
+ diagnostic.status = record.status;
3379
+ } else if (typeof record.statusCode === "number" && Number.isFinite(record.statusCode)) {
3380
+ diagnostic.status = record.statusCode;
3381
+ } else {
3382
+ const meta = record.meta;
3383
+ if (meta !== null && typeof meta === "object") {
3384
+ const status = meta.status;
3385
+ if (typeof status === "number" && Number.isFinite(status)) diagnostic.status = status;
3386
+ }
3387
+ }
3388
+ }
3389
+ if (diagnostic.code === void 0 && typeof record.code === "string" && /^[A-Z][A-Z0-9_]*$/.test(record.code)) {
3390
+ diagnostic.code = record.code;
3391
+ }
3392
+ if (diagnostic.status !== void 0 && diagnostic.code !== void 0) break;
3393
+ current = record.cause;
3394
+ }
3395
+ return diagnostic;
3396
+ }
3352
3397
  var _TinyCloudNode = class _TinyCloudNode {
3353
3398
  /**
3354
3399
  * Create a new TinyCloudNode instance.
@@ -3430,7 +3475,7 @@ var _TinyCloudNode = class _TinyCloudNode {
3430
3475
  const grantedOperation = grant?.operations.find(
3431
3476
  (candidate) => this.operationCovers(candidate, operation)
3432
3477
  );
3433
- const invocationSession = !grant || grant.provenance === "primary" ? session : grant.session;
3478
+ const invocationSession = !grant || grant.provenance === "primary" ? session : this.grantSessionForSpace(grant, session.spaceId);
3434
3479
  if ((grantedOperation?.caveats?.length ?? 0) > 0) {
3435
3480
  if (!this.wasmBindings.invokeAny) {
3436
3481
  throw new Error("WASM binding does not support caveat-preserving invocation");
@@ -4592,13 +4637,27 @@ var _TinyCloudNode = class _TinyCloudNode {
4592
4637
  jwk: current.jwk
4593
4638
  });
4594
4639
  const registry = this.createAccountRegistryServices(context, controller.signal);
4640
+ let indexWarningLogged = false;
4595
4641
  try {
4596
4642
  await this.withAccountRegistryRetry(async () => {
4597
4643
  if (controller.signal.aborted) throw controller.signal.reason;
4598
4644
  if (this.currentTinyCloudSession() !== session || this.ownStorageFull) return;
4599
- await registry.account.index.ensure();
4645
+ let indexFailure;
4646
+ try {
4647
+ const index = await registry.account.index.ensure();
4648
+ if (!index.ok) indexFailure = index.error;
4649
+ } catch (error) {
4650
+ indexFailure = error;
4651
+ }
4600
4652
  if (controller.signal.aborted) throw controller.signal.reason;
4601
4653
  if (this.currentTinyCloudSession() !== session || this.ownStorageFull) return;
4654
+ if (indexFailure !== void 0 && !indexWarningLogged) {
4655
+ indexWarningLogged = true;
4656
+ console.warn(
4657
+ "TinyCloud account index initialization failed; continuing registry sync",
4658
+ accountIndexWarningDiagnostic(indexFailure)
4659
+ );
4660
+ }
4602
4661
  await this.writeManifestRegistryRecords(registry.account, controller.signal);
4603
4662
  if (controller.signal.aborted) throw controller.signal.reason;
4604
4663
  if (this.currentTinyCloudSession() !== session || this.ownStorageFull) return;
@@ -4684,7 +4743,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4684
4743
  }
4685
4744
  const verdict = (0, import_sdk_core10.authorizationVerdictOf)(error);
4686
4745
  const message = error instanceof Error ? error.message : String(error);
4687
- const isAuthorizationVerdict = verdict === void 0 ? /Unauthorized Action|\b(?:401|403)\b/.test(message) : verdict !== "other";
4746
+ const isAuthorizationVerdict = verdict === void 0 ? /^(?:Unauthorized Action\b|(?:(?:request failed|HTTP request failed|status(?: code)?|response status)\s*:\s*)?(?:HTTP\s*)?(?:401|403)\b)/i.test(message) : verdict !== "other";
4688
4747
  if (isAuthorizationVerdict) {
4689
4748
  console.warn(
4690
4749
  "TinyCloud account registry sync stopped: authorization verdict is not retryable",
@@ -8332,7 +8391,18 @@ var _TinyCloudNode = class _TinyCloudNode {
8332
8391
  if (!grant) {
8333
8392
  return fallback;
8334
8393
  }
8335
- return grant.provenance === "primary" ? fallback : grant.session;
8394
+ return grant.provenance === "primary" ? fallback : this.grantSessionForSpace(grant, fallback.spaceId);
8395
+ }
8396
+ /**
8397
+ * A non-primary grant's session, aimed at `spaceId`. The grant's delegation
8398
+ * may span spaces (the widened default bootstrap session also carries
8399
+ * account-space entries, TC-957); its session's own `spaceId` is the space
8400
+ * it was minted for, so an op on another covered space must keep the grant's
8401
+ * key and proof but target that space. A grant on the target space itself is
8402
+ * returned unchanged, keeping its own spelling of the space id.
8403
+ */
8404
+ grantSessionForSpace(grant, spaceId) {
8405
+ return this.spaceIdsEqual(grant.session.spaceId, spaceId) ? grant.session : { ...grant.session, spaceId };
8336
8406
  }
8337
8407
  findGrantForOperations(operations, options) {
8338
8408
  if (operations.length === 0) {