@tinycloud/node-sdk 2.3.0 → 2.4.0-beta.1

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.
@@ -914,6 +914,27 @@ declare class TinyCloudNode {
914
914
  private ownedSpaceId;
915
915
  private writeManifestRegistryRecords;
916
916
  private ensureOwnedSpaceHosted;
917
+ /**
918
+ * Host one of this user's owned spaces by name (e.g. `"applications"`).
919
+ *
920
+ * Resolves the name to the owned space URI
921
+ * (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`) and registers it on the
922
+ * server via the host-SIWE delegation flow, so subsequent KV/SQL writes to
923
+ * that space succeed instead of returning `404 - Space not found`. The
924
+ * caller is the root authority of their own owned spaces, so no additional
925
+ * delegation is required.
926
+ *
927
+ * Unlike {@link ensureOwnedSpaceHosted}, this always submits the host
928
+ * delegation rather than inferring hosting from session activation: a space
929
+ * the current session has never referenced is reported neither as
930
+ * `activated` nor `skipped`, so activation-based detection would wrongly
931
+ * skip the host. The host SIWE is idempotent server-side, so re-hosting an
932
+ * existing space is a safe no-op. Must be called after {@link signIn}.
933
+ *
934
+ * @param name - The owned space name (e.g. `"applications"`).
935
+ * @returns The hosted space URI.
936
+ */
937
+ hostOwnedSpace(name: string): Promise<string>;
917
938
  /**
918
939
  * Restore a previously established session from stored delegation data.
919
940
  *
@@ -1427,6 +1448,28 @@ declare class TinyCloudNode {
1427
1448
  private delegatedResourcesForEntries;
1428
1449
  private operationsFromDelegation;
1429
1450
  private flatDelegationResources;
1451
+ /**
1452
+ * Build the abilities/rawAbilities maps for a wallet-mode activation
1453
+ * sub-delegation from the FULL resource set of a received delegation.
1454
+ *
1455
+ * Each entry in `delegation.resources[]` is one `(service, space, path,
1456
+ * actions)` grant; the flat top-level `path`/`actions` mirror only the
1457
+ * first resource. We must reconstruct every grant so the activated
1458
+ * session carries all of them (e.g. both `tinycloud.kv/get` and
1459
+ * `tinycloud.encryption/decrypt`) — not just the primary one.
1460
+ *
1461
+ * Encryption resources are raw network URNs (space-independent) and go
1462
+ * into `rawAbilities`. All other resources are space-scoped and go into
1463
+ * `abilities` keyed by short service name. The activation `prepareSession`
1464
+ * call uses a single `spaceId` (`delegation.spaceId`), so every
1465
+ * non-encryption resource must target that same space — which is exactly
1466
+ * what the multi-resource issuance path enforces. A resource targeting a
1467
+ * different space cannot be activated in one call, so we fail loudly
1468
+ * rather than silently dropping it.
1469
+ *
1470
+ * @internal
1471
+ */
1472
+ private buildActivationAbilities;
1430
1473
  private selectInvocationSession;
1431
1474
  private findGrantForOperations;
1432
1475
  private findGrantForOperation;
@@ -914,6 +914,27 @@ declare class TinyCloudNode {
914
914
  private ownedSpaceId;
915
915
  private writeManifestRegistryRecords;
916
916
  private ensureOwnedSpaceHosted;
917
+ /**
918
+ * Host one of this user's owned spaces by name (e.g. `"applications"`).
919
+ *
920
+ * Resolves the name to the owned space URI
921
+ * (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`) and registers it on the
922
+ * server via the host-SIWE delegation flow, so subsequent KV/SQL writes to
923
+ * that space succeed instead of returning `404 - Space not found`. The
924
+ * caller is the root authority of their own owned spaces, so no additional
925
+ * delegation is required.
926
+ *
927
+ * Unlike {@link ensureOwnedSpaceHosted}, this always submits the host
928
+ * delegation rather than inferring hosting from session activation: a space
929
+ * the current session has never referenced is reported neither as
930
+ * `activated` nor `skipped`, so activation-based detection would wrongly
931
+ * skip the host. The host SIWE is idempotent server-side, so re-hosting an
932
+ * existing space is a safe no-op. Must be called after {@link signIn}.
933
+ *
934
+ * @param name - The owned space name (e.g. `"applications"`).
935
+ * @returns The hosted space URI.
936
+ */
937
+ hostOwnedSpace(name: string): Promise<string>;
917
938
  /**
918
939
  * Restore a previously established session from stored delegation data.
919
940
  *
@@ -1427,6 +1448,28 @@ declare class TinyCloudNode {
1427
1448
  private delegatedResourcesForEntries;
1428
1449
  private operationsFromDelegation;
1429
1450
  private flatDelegationResources;
1451
+ /**
1452
+ * Build the abilities/rawAbilities maps for a wallet-mode activation
1453
+ * sub-delegation from the FULL resource set of a received delegation.
1454
+ *
1455
+ * Each entry in `delegation.resources[]` is one `(service, space, path,
1456
+ * actions)` grant; the flat top-level `path`/`actions` mirror only the
1457
+ * first resource. We must reconstruct every grant so the activated
1458
+ * session carries all of them (e.g. both `tinycloud.kv/get` and
1459
+ * `tinycloud.encryption/decrypt`) — not just the primary one.
1460
+ *
1461
+ * Encryption resources are raw network URNs (space-independent) and go
1462
+ * into `rawAbilities`. All other resources are space-scoped and go into
1463
+ * `abilities` keyed by short service name. The activation `prepareSession`
1464
+ * call uses a single `spaceId` (`delegation.spaceId`), so every
1465
+ * non-encryption resource must target that same space — which is exactly
1466
+ * what the multi-resource issuance path enforces. A resource targeting a
1467
+ * different space cannot be activated in one call, so we fail loudly
1468
+ * rather than silently dropping it.
1469
+ *
1470
+ * @internal
1471
+ */
1472
+ private buildActivationAbilities;
1430
1473
  private selectInvocationSession;
1431
1474
  private findGrantForOperations;
1432
1475
  private findGrantForOperation;
package/dist/core.cjs CHANGED
@@ -1971,6 +1971,52 @@ var _TinyCloudNode = class _TinyCloudNode {
1971
1971
  );
1972
1972
  }
1973
1973
  }
1974
+ /**
1975
+ * Host one of this user's owned spaces by name (e.g. `"applications"`).
1976
+ *
1977
+ * Resolves the name to the owned space URI
1978
+ * (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`) and registers it on the
1979
+ * server via the host-SIWE delegation flow, so subsequent KV/SQL writes to
1980
+ * that space succeed instead of returning `404 - Space not found`. The
1981
+ * caller is the root authority of their own owned spaces, so no additional
1982
+ * delegation is required.
1983
+ *
1984
+ * Unlike {@link ensureOwnedSpaceHosted}, this always submits the host
1985
+ * delegation rather than inferring hosting from session activation: a space
1986
+ * the current session has never referenced is reported neither as
1987
+ * `activated` nor `skipped`, so activation-based detection would wrongly
1988
+ * skip the host. The host SIWE is idempotent server-side, so re-hosting an
1989
+ * existing space is a safe no-op. Must be called after {@link signIn}.
1990
+ *
1991
+ * @param name - The owned space name (e.g. `"applications"`).
1992
+ * @returns The hosted space URI.
1993
+ */
1994
+ async hostOwnedSpace(name) {
1995
+ if (!this.auth || !this.auth.tinyCloudSession) {
1996
+ throw new Error("Not signed in. Call signIn() first.");
1997
+ }
1998
+ const spaceId = this.ownedSpaceId(name);
1999
+ const host = this.hosts[0] ?? this.config.host;
2000
+ if (!host) {
2001
+ throw new Error("Owned space hosting requires a TinyCloud host");
2002
+ }
2003
+ const hosted = await this.auth.hostOwnedSpace(
2004
+ spaceId
2005
+ );
2006
+ if (!hosted) {
2007
+ throw new Error(`Failed to host owned space: ${spaceId}`);
2008
+ }
2009
+ const activation = await (0, import_sdk_core6.activateSessionWithHost)(
2010
+ host,
2011
+ this.auth.tinyCloudSession.delegationHeader
2012
+ );
2013
+ if (!activation.success || activation.skipped?.includes(spaceId)) {
2014
+ throw new Error(
2015
+ `Failed to activate session for owned space ${spaceId}: ${activation.error ?? "space was skipped"}`
2016
+ );
2017
+ }
2018
+ return spaceId;
2019
+ }
1974
2020
  /**
1975
2021
  * Restore a previously established session from stored delegation data.
1976
2022
  *
@@ -3951,6 +3997,59 @@ var _TinyCloudNode = class _TinyCloudNode {
3951
3997
  actions
3952
3998
  }));
3953
3999
  }
4000
+ /**
4001
+ * Build the abilities/rawAbilities maps for a wallet-mode activation
4002
+ * sub-delegation from the FULL resource set of a received delegation.
4003
+ *
4004
+ * Each entry in `delegation.resources[]` is one `(service, space, path,
4005
+ * actions)` grant; the flat top-level `path`/`actions` mirror only the
4006
+ * first resource. We must reconstruct every grant so the activated
4007
+ * session carries all of them (e.g. both `tinycloud.kv/get` and
4008
+ * `tinycloud.encryption/decrypt`) — not just the primary one.
4009
+ *
4010
+ * Encryption resources are raw network URNs (space-independent) and go
4011
+ * into `rawAbilities`. All other resources are space-scoped and go into
4012
+ * `abilities` keyed by short service name. The activation `prepareSession`
4013
+ * call uses a single `spaceId` (`delegation.spaceId`), so every
4014
+ * non-encryption resource must target that same space — which is exactly
4015
+ * what the multi-resource issuance path enforces. A resource targeting a
4016
+ * different space cannot be activated in one call, so we fail loudly
4017
+ * rather than silently dropping it.
4018
+ *
4019
+ * @internal
4020
+ */
4021
+ buildActivationAbilities(delegation) {
4022
+ var _a, _b, _c;
4023
+ const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
4024
+ const abilities = {};
4025
+ const rawAbilities = {};
4026
+ const addActions = (target, actions) => {
4027
+ const seen = new Set(target);
4028
+ for (const action of actions) {
4029
+ if (!seen.has(action)) {
4030
+ target.push(action);
4031
+ seen.add(action);
4032
+ }
4033
+ }
4034
+ };
4035
+ for (const resource of resources) {
4036
+ const service = this.invocationServiceName(resource.service);
4037
+ if (this.isEncryptionNetworkOperation(service, resource.path)) {
4038
+ rawAbilities[_a = resource.path] ?? (rawAbilities[_a] = []);
4039
+ addActions(rawAbilities[resource.path], resource.actions);
4040
+ continue;
4041
+ }
4042
+ if (resource.space !== delegation.spaceId) {
4043
+ throw new Error(
4044
+ `useDelegation: resource targets space '${resource.space}' but the delegation activates space '${delegation.spaceId}'. Multi-space delegations cannot be activated in a single useDelegation call.`
4045
+ );
4046
+ }
4047
+ abilities[service] ?? (abilities[service] = {});
4048
+ (_b = abilities[service])[_c = resource.path] ?? (_b[_c] = []);
4049
+ addActions(abilities[service][resource.path], resource.actions);
4050
+ }
4051
+ return { abilities, rawAbilities };
4052
+ }
3954
4053
  selectInvocationSession(fallback, service, path, action) {
3955
4054
  const grant = this.findGrantForOperation({
3956
4055
  spaceId: fallback.spaceId,
@@ -4297,26 +4396,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4297
4396
  throw new Error("Not signed in. Call signIn() first.");
4298
4397
  }
4299
4398
  const jwk = mySession.jwk;
4300
- const abilities = {};
4301
- const kvActions = delegation.actions.filter((a) => a.startsWith("tinycloud.kv/"));
4302
- const sqlActions = delegation.actions.filter((a) => a.startsWith("tinycloud.sql/"));
4303
- const duckdbActions = delegation.actions.filter((a) => a.startsWith("tinycloud.duckdb/"));
4304
- const encryptionActions = delegation.actions.filter(
4305
- (a) => a.startsWith("tinycloud.encryption/")
4306
- );
4307
- const rawAbilities = {};
4308
- if (kvActions.length > 0) {
4309
- abilities.kv = { [delegation.path]: kvActions };
4310
- }
4311
- if (sqlActions.length > 0) {
4312
- abilities.sql = { [delegation.path]: sqlActions };
4313
- }
4314
- if (duckdbActions.length > 0) {
4315
- abilities.duckdb = { [delegation.path]: duckdbActions };
4316
- }
4317
- if (encryptionActions.length > 0 && delegation.path.startsWith("urn:tinycloud:encryption:")) {
4318
- rawAbilities[delegation.path] = encryptionActions;
4319
- }
4399
+ const { abilities, rawAbilities } = this.buildActivationAbilities(delegation);
4320
4400
  const now = /* @__PURE__ */ new Date();
4321
4401
  const maxExpiry = new Date(now.getTime() + 60 * 60 * 1e3);
4322
4402
  const expirationTime = delegation.expiry < maxExpiry ? delegation.expiry : maxExpiry;