@tinycloud/node-sdk 3.3.0-beta.18 → 3.3.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
@@ -18835,6 +18835,11 @@ var NodeUserAuthorization = class {
18835
18835
  this.tinycloudHosts = config.tinycloudHosts;
18836
18836
  this.tinycloudRegistryUrl = config.tinycloudRegistryUrl;
18837
18837
  this.tinycloudFallbackHosts = config.tinycloudFallbackHosts;
18838
+ this.registryPolicy = config.registryPolicy;
18839
+ this.newUserHost = config.newUserHost;
18840
+ this.registryChainId = config.registryChainId;
18841
+ this.registrySequenceStore = config.registrySequenceStore ?? (0, import_sdk_core4.createInMemoryRegistrySequenceStore)();
18842
+ this.onNodeNotFound = config.onNodeNotFound;
18838
18843
  this.autoDiscoverLocalNode = config.autoDiscoverLocalNode;
18839
18844
  this.localNodeUrl = config.localNodeUrl;
18840
18845
  this.localLinkName = config.localLinkName;
@@ -18946,6 +18951,7 @@ var NodeUserAuthorization = class {
18946
18951
  this._nodeFeaturesKnown = nodeFeatures !== void 0;
18947
18952
  this._nodeInfoIdentity = void 0;
18948
18953
  this.tinycloudHosts = hosts && hosts.length > 0 ? [...hosts] : void 0;
18954
+ this.registryVerdict = void 0;
18949
18955
  this._lastActivationSkippedSpaceIds = [];
18950
18956
  this._lastActivationActivatedSpaceIds = [];
18951
18957
  if (!session) {
@@ -18996,6 +19002,23 @@ var NodeUserAuthorization = class {
18996
19002
  if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
18997
19003
  return;
18998
19004
  }
19005
+ if (this.registryPolicy === "fail-closed") {
19006
+ const resolved2 = await (0, import_sdk_core4.resolveFailClosedTinyCloudHosts)(address, {
19007
+ registryUrl: this.tinycloudRegistryUrl,
19008
+ registryChainId: this.registryChainId,
19009
+ newUserHost: this.newUserHost,
19010
+ sequenceStore: this.registrySequenceStore,
19011
+ onNodeNotFound: this.onNodeNotFound,
19012
+ autoDiscoverLocalNode: this.autoDiscoverLocalNode,
19013
+ localNodeUrl: this.localNodeUrl,
19014
+ localLinkName: this.localLinkName,
19015
+ expectedNodeDid: this.expectedNodeDid,
19016
+ localNodeIdentityStore: this.localNodeIdentityStore
19017
+ });
19018
+ this.tinycloudHosts = resolved2.hosts;
19019
+ this.registryVerdict = resolved2.verdict;
19020
+ return;
19021
+ }
18999
19022
  const subject = (0, import_sdk_core4.pkhDid)(address, chainId);
19000
19023
  const resolved = await (0, import_sdk_core4.resolveTinyCloudHosts)(subject, {
19001
19024
  registryUrl: this.tinycloudRegistryUrl,
@@ -19008,6 +19031,32 @@ var NodeUserAuthorization = class {
19008
19031
  });
19009
19032
  this.tinycloudHosts = resolved.hosts;
19010
19033
  }
19034
+ /**
19035
+ * Space-creation guard (TC-1443). Under `registryPolicy: "fail-closed"`,
19036
+ * throws unless the owner's registry verdict allows a space on the primary
19037
+ * host: `NodeRegistryEntryExistsError` when the owner's record does not
19038
+ * list it, `RegistryUnavailableError` when the registry gives no
19039
+ * verdict. Reuses this session's sign-in verdict unless it was
19040
+ * `unavailable`, else looks it up now (explicit-host apps). Under the
19041
+ * default policy it returns at once and performs no lookup.
19042
+ */
19043
+ async assertMayCreateSpace() {
19044
+ if (this.registryPolicy !== "fail-closed") return;
19045
+ if (this._address === void 0) {
19046
+ throw new Error("Must be signed in to create a space");
19047
+ }
19048
+ await this.ensureTinyCloudHosts();
19049
+ const subject = (0, import_sdk_core4.registryOwnerSubjectV1)(this._address, this.registryChainId);
19050
+ let verdict = this.registryVerdict;
19051
+ if (verdict?.subject !== subject || verdict.status === "unavailable") {
19052
+ verdict = await (0, import_sdk_core4.lookupOwnerRegistryVerdict)(subject, {
19053
+ registryUrl: this.tinycloudRegistryUrl,
19054
+ sequenceStore: this.registrySequenceStore
19055
+ });
19056
+ this.registryVerdict = verdict;
19057
+ }
19058
+ (0, import_sdk_core4.assertSpaceCreationAllowed)(verdict, this.primaryTinyCloudHost);
19059
+ }
19011
19060
  requireTinyCloudHosts() {
19012
19061
  if (!this.tinycloudHosts || this.tinycloudHosts.length === 0) {
19013
19062
  throw new Error("TinyCloud hosts have not been resolved. Call signIn() first.");
@@ -19456,6 +19505,7 @@ var NodeUserAuthorization = class {
19456
19505
  if (!handler) {
19457
19506
  return;
19458
19507
  }
19508
+ await this.guardSpaceCreation(handler, creationContext);
19459
19509
  const confirmed = await handler.confirmSpaceCreation(creationContext);
19460
19510
  if (!confirmed) {
19461
19511
  return;
@@ -19496,6 +19546,7 @@ var NodeUserAuthorization = class {
19496
19546
  if (!handler) {
19497
19547
  return;
19498
19548
  }
19549
+ await this.guardSpaceCreation(handler, creationContext);
19499
19550
  const confirmed = await handler.confirmSpaceCreation(creationContext);
19500
19551
  if (!confirmed) {
19501
19552
  return;
@@ -19537,6 +19588,16 @@ var NodeUserAuthorization = class {
19537
19588
  { cause: result }
19538
19589
  );
19539
19590
  }
19591
+ /** {@link assertMayCreateSpace}, reporting a refusal to the creation handler before rethrowing it. */
19592
+ async guardSpaceCreation(handler, context) {
19593
+ try {
19594
+ await this.assertMayCreateSpace();
19595
+ } catch (error) {
19596
+ const failure = error instanceof Error ? error : new Error(String(error));
19597
+ handler.onSpaceCreationFailed?.(context, failure);
19598
+ throw failure;
19599
+ }
19600
+ }
19540
19601
  recordActivationSkippedSpaces(result, primarySpaceId) {
19541
19602
  if (result.success) {
19542
19603
  this._lastActivationSkippedSpaceIds = result.skipped ?? [];
@@ -21489,7 +21550,9 @@ var _TinyCloudNode = class _TinyCloudNode {
21489
21550
  this.explicitHost = config.host;
21490
21551
  this.config = {
21491
21552
  ...config,
21492
- host: config.host ?? DEFAULT_HOST
21553
+ host: config.host ?? DEFAULT_HOST,
21554
+ // One store for every authorization this client creates.
21555
+ registrySequenceStore: config.registrySequenceStore ?? (0, import_sdk_core9.createInMemoryRegistrySequenceStore)()
21493
21556
  };
21494
21557
  if (this.config.replication?.enabled) {
21495
21558
  const runtime = getNodeReplicationLoaders().runtime().then(({ ReplicationRuntime: ReplicationRuntime2 }) => {
@@ -21759,6 +21822,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21759
21822
  tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
21760
21823
  tinycloudRegistryUrl: config.tinycloudRegistryUrl,
21761
21824
  tinycloudFallbackHosts: config.tinycloudFallbackHosts,
21825
+ ...this.registryPolicyConfig(),
21762
21826
  autoDiscoverLocalNode: config.autoDiscoverLocalNode,
21763
21827
  localNodeUrl: config.localNodeUrl,
21764
21828
  localLinkName: config.localLinkName,
@@ -22464,6 +22528,9 @@ var _TinyCloudNode = class _TinyCloudNode {
22464
22528
  const primarySession = auth.tinyCloudSession;
22465
22529
  const defaultSpaceId = this.ownedSpaceId("default");
22466
22530
  const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default;
22531
+ if (steps.some((step) => step.kind === "host")) {
22532
+ await this.assertMayCreateSpace();
22533
+ }
22467
22534
  for (const step of steps) {
22468
22535
  if (step.kind !== "session") continue;
22469
22536
  graph.assertActive();
@@ -23105,6 +23172,8 @@ var _TinyCloudNode = class _TinyCloudNode {
23105
23172
  { cause: activation }
23106
23173
  );
23107
23174
  }
23175
+ await this.assertMayCreateSpace();
23176
+ if (signal?.aborted) throw signal.reason;
23108
23177
  const created = await this.hostOwnedSpaceOnce(spaceId, signal);
23109
23178
  if (!created.success) {
23110
23179
  throw Object.assign(
@@ -23218,6 +23287,12 @@ var _TinyCloudNode = class _TinyCloudNode {
23218
23287
  * session's recap doesn't cover it and the registry has no record; the host
23219
23288
  * SIWE is idempotent server-side. Must be called after {@link signIn}.
23220
23289
  *
23290
+ * Under `registryPolicy: "fail-closed"`, hosting is refused with
23291
+ * `NodeRegistryEntryExistsError` when the owner's registry record does not
23292
+ * list the host, or `RegistryUnavailableError` when the registry gives no
23293
+ * verdict. {@link hostOwnedSpace} itself is an explicit action and is not
23294
+ * guarded.
23295
+ *
23221
23296
  * @param name - The owned space name (e.g. `"secrets"`).
23222
23297
  * @returns The hosted owned-space URI.
23223
23298
  */
@@ -23229,8 +23304,25 @@ var _TinyCloudNode = class _TinyCloudNode {
23229
23304
  if (this.hostedOwnedSpaceIds.has(spaceId) || await this.isOwnedSpaceRegistered(spaceId)) {
23230
23305
  return spaceId;
23231
23306
  }
23307
+ await this.assertMayCreateSpace();
23232
23308
  return this.hostOwnedSpace(name);
23233
23309
  }
23310
+ /**
23311
+ * Space-creation guard (TC-1443) for the automatic hosting paths: sign-in's
23312
+ * owned spaces, account bootstrap, {@link ensureOwnedSpaceHosted} and
23313
+ * {@link ensurePublicSpace}. Only `registryPolicy: "fail-closed"` consults
23314
+ * the registry ({@link NodeUserAuthorization.assertMayCreateSpace}); the
23315
+ * default policy performs no lookup.
23316
+ */
23317
+ async assertMayCreateSpace() {
23318
+ if (this.config.registryPolicy !== "fail-closed") return;
23319
+ await this.auth.assertMayCreateSpace();
23320
+ }
23321
+ /** Registry-policy settings shared by every authorization this client creates. */
23322
+ registryPolicyConfig() {
23323
+ const { registryPolicy, newUserHost, registryChainId, registrySequenceStore, onNodeNotFound } = this.config;
23324
+ return { registryPolicy, newUserHost, registryChainId, registrySequenceStore, onNodeNotFound };
23325
+ }
23234
23326
  /**
23235
23327
  * Submit the host delegation for an owned space, sharing one in-flight
23236
23328
  * request (and so one approval) between concurrent callers in this session,
@@ -23908,6 +24000,21 @@ var _TinyCloudNode = class _TinyCloudNode {
23908
24000
  if (address === void 0 || chainId === void 0) {
23909
24001
  return void 0;
23910
24002
  }
24003
+ if (this.config.registryPolicy === "fail-closed") {
24004
+ const resolved2 = await (0, import_sdk_core9.resolveFailClosedTinyCloudHosts)(address, {
24005
+ registryUrl: this.config.tinycloudRegistryUrl,
24006
+ registryChainId: this.config.registryChainId,
24007
+ newUserHost: this.config.newUserHost,
24008
+ sequenceStore: this.config.registrySequenceStore,
24009
+ onNodeNotFound: this.config.onNodeNotFound,
24010
+ autoDiscoverLocalNode: this.config.autoDiscoverLocalNode,
24011
+ localNodeUrl: this.config.localNodeUrl,
24012
+ localLinkName: this.config.localLinkName,
24013
+ expectedNodeDid: this.config.expectedNodeDid,
24014
+ localNodeIdentityStore: this.config.localNodeIdentityStore
24015
+ });
24016
+ return resolved2.hosts[0];
24017
+ }
23911
24018
  const resolved = await (0, import_sdk_core9.resolveTinyCloudHosts)((0, import_sdk_core9.pkhDid)(address, chainId), {
23912
24019
  registryUrl: this.config.tinycloudRegistryUrl,
23913
24020
  fallbackHosts: this.config.tinycloudFallbackHosts,
@@ -24100,6 +24207,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24100
24207
  tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
24101
24208
  tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
24102
24209
  tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
24210
+ ...this.registryPolicyConfig(),
24103
24211
  autoDiscoverLocalNode: this.config.autoDiscoverLocalNode,
24104
24212
  localNodeUrl: this.config.localNodeUrl,
24105
24213
  localLinkName: this.config.localLinkName,
@@ -24159,6 +24267,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24159
24267
  tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
24160
24268
  tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
24161
24269
  tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
24270
+ ...this.registryPolicyConfig(),
24162
24271
  autoDiscoverLocalNode: this.config.autoDiscoverLocalNode,
24163
24272
  localNodeUrl: this.config.localNodeUrl,
24164
24273
  localLinkName: this.config.localLinkName,
@@ -25796,7 +25905,9 @@ var _TinyCloudNode = class _TinyCloudNode {
25796
25905
  * Ensure the user's public space exists and is accessible.
25797
25906
  * Creates the space and activates a session delegation for it.
25798
25907
  * This is the trigger for lazy public space creation — call it
25799
- * before writing to spaces.get('public').kv.
25908
+ * before writing to spaces.get('public').kv. The vault calls it on unlock.
25909
+ * Under `registryPolicy: "fail-closed"` creation goes through the
25910
+ * space-creation guard.
25800
25911
  */
25801
25912
  async ensurePublicSpace() {
25802
25913
  if (!this.auth || !this.session || !this.signer) {
@@ -25806,6 +25917,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25806
25917
  if (!publicSpaceId) {
25807
25918
  throw new Error("Public space not enabled. Set enablePublicSpace: true in config.");
25808
25919
  }
25920
+ await this.assertMayCreateSpace();
25809
25921
  await this.auth.hostPublicSpace(publicSpaceId);
25810
25922
  const kvActions = [import_sdk_core9.KV.PUT, import_sdk_core9.KV.GET, import_sdk_core9.KV.DEL, import_sdk_core9.KV.LIST, import_sdk_core9.KV.METADATA];
25811
25923
  const abilities = { kv: { "": kvActions } };