@tinycloud/node-sdk 2.4.1-beta.0 → 2.5.0

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
@@ -17722,7 +17722,7 @@ var NodeUserAuthorization = class {
17722
17722
  * Create the space on the TinyCloud server (host delegation).
17723
17723
  * This registers the user as the owner of the space.
17724
17724
  */
17725
- async hostSpace(targetSpaceId) {
17725
+ async hostSpace(targetSpaceId, purpose) {
17726
17726
  if (!this._tinyCloudSession || !this._address || !this._chainId) {
17727
17727
  throw new Error("Must be signed in to host space");
17728
17728
  }
@@ -17738,7 +17738,7 @@ var NodeUserAuthorization = class {
17738
17738
  spaceId,
17739
17739
  peerId
17740
17740
  });
17741
- const signature2 = await this.signMessage(siwe);
17741
+ const signature2 = await this.signMessage(siwe, purpose);
17742
17742
  const headers = this.wasm.siweToDelegationHeaders({ siwe, signature: signature2 });
17743
17743
  const result = await (0, import_sdk_core2.submitHostDelegation)(host, headers);
17744
17744
  return result.success;
@@ -17754,8 +17754,8 @@ var NodeUserAuthorization = class {
17754
17754
  * Create a specific owned space on the server via host delegation.
17755
17755
  * Used by manifest registry setup for the account space.
17756
17756
  */
17757
- async hostOwnedSpace(spaceId) {
17758
- return this.hostSpace(spaceId);
17757
+ async hostOwnedSpace(spaceId, purpose) {
17758
+ return this.hostSpace(spaceId, purpose);
17759
17759
  }
17760
17760
  /**
17761
17761
  * Ensure the user's space exists on the TinyCloud server.
@@ -17905,7 +17905,8 @@ var NodeUserAuthorization = class {
17905
17905
  address,
17906
17906
  chainId,
17907
17907
  message: prepared.siwe,
17908
- type: "siwe"
17908
+ type: "siwe",
17909
+ purpose: "bootstrap-session"
17909
17910
  });
17910
17911
  const session = this.wasm.completeSessionSetup({
17911
17912
  ...prepared,
@@ -17969,7 +17970,8 @@ var NodeUserAuthorization = class {
17969
17970
  address,
17970
17971
  chainId,
17971
17972
  message: prepared.siwe,
17972
- type: "siwe"
17973
+ type: "siwe",
17974
+ purpose: "sign-in"
17973
17975
  });
17974
17976
  const session = this.wasm.completeSessionSetup({
17975
17977
  ...prepared,
@@ -18057,7 +18059,7 @@ var NodeUserAuthorization = class {
18057
18059
  /**
18058
18060
  * Sign a message with the connected signer.
18059
18061
  */
18060
- async signMessage(message) {
18062
+ async signMessage(message, purpose) {
18061
18063
  if (!this._address) {
18062
18064
  this._address = (0, import_sdk_core2.canonicalizeAddress)(await this.signer.getAddress());
18063
18065
  }
@@ -18068,7 +18070,8 @@ var NodeUserAuthorization = class {
18068
18070
  address: this._address,
18069
18071
  chainId: this._chainId,
18070
18072
  message,
18071
- type: "message"
18073
+ type: "message",
18074
+ ...purpose ? { purpose } : {}
18072
18075
  });
18073
18076
  }
18074
18077
  /**
@@ -18696,6 +18699,15 @@ var DEFAULT_SESSION_EXPIRATION_MS = import_sdk_core7.EXPIRY.SESSION_MS;
18696
18699
  function isOpenKeyAutoSignStrategy(strategy) {
18697
18700
  return strategy?.openKeyAutoSign === true;
18698
18701
  }
18702
+ function isInteractiveSigner(config) {
18703
+ if (config.privateKey) {
18704
+ return false;
18705
+ }
18706
+ if (isOpenKeyAutoSignStrategy(config.signStrategy)) {
18707
+ return false;
18708
+ }
18709
+ return config.signer !== void 0;
18710
+ }
18699
18711
  function didPrincipalMatches2(actual, expected) {
18700
18712
  try {
18701
18713
  return (0, import_sdk_core7.principalDidEquals)(actual, expected);
@@ -18832,6 +18844,21 @@ var _TinyCloudNode = class _TinyCloudNode {
18832
18844
  this._baseSecrets = /* @__PURE__ */ new Map();
18833
18845
  this._secrets = /* @__PURE__ */ new Map();
18834
18846
  this.runtimePermissionGrants = [];
18847
+ /**
18848
+ * True when the last signIn() detected an interactive signer and skipped
18849
+ * client-side bootstrap. Apps can read this to know whether bootstrap was
18850
+ * deferred to the server (OpenKey) or requires a separate user action.
18851
+ */
18852
+ this._bootstrapSkipped = false;
18853
+ /**
18854
+ * Outcome of the last signIn()'s account-bootstrap attempt. `skipped` is
18855
+ * true when bootstrap did not complete (interactive signer, auto-sign
18856
+ * denied, or a bootstrap step failed); `reason` carries the cause so apps
18857
+ * can surface a "finish account setup" call-to-action.
18858
+ */
18859
+ this._bootstrapStatus = {
18860
+ skipped: false
18861
+ };
18835
18862
  this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
18836
18863
  return this.wasmBindings.invoke(
18837
18864
  this.selectInvocationSession(session, service, path, action),
@@ -18924,6 +18951,15 @@ var _TinyCloudNode = class _TinyCloudNode {
18924
18951
  static registerNodeDefaults(defaults) {
18925
18952
  _TinyCloudNode.nodeDefaults = defaults;
18926
18953
  }
18954
+ /** Whether the last signIn() skipped client-side bootstrap because the
18955
+ * signer is interactive (browser wallet / EIP-1193 provider). */
18956
+ get bootstrapSkipped() {
18957
+ return this._bootstrapSkipped;
18958
+ }
18959
+ /** Outcome of the last signIn()'s account-bootstrap attempt. */
18960
+ get bootstrapStatus() {
18961
+ return this._bootstrapStatus;
18962
+ }
18927
18963
  get nodeFeatures() {
18928
18964
  return this.auth?.nodeFeatures ?? [];
18929
18965
  }
@@ -19147,17 +19183,38 @@ var _TinyCloudNode = class _TinyCloudNode {
19147
19183
  return this.wasmBindings.makeSpaceId(this._address, this._chainId, name);
19148
19184
  }
19149
19185
  async bootstrapAccountIfNeeded() {
19186
+ this._bootstrapSkipped = false;
19187
+ this._bootstrapStatus = { skipped: false };
19150
19188
  if (this.config.autoBootstrapAccount === false) {
19151
19189
  return false;
19152
19190
  }
19153
19191
  if (!this.auth || !this._address) {
19154
19192
  return false;
19155
19193
  }
19194
+ if (isInteractiveSigner(this.config)) {
19195
+ console.debug(
19196
+ "[TinyCloudNode] bootstrap skipped: interactive signer detected. Server-side bootstrap (OpenKey) is expected to have provisioned the account."
19197
+ );
19198
+ this._bootstrapSkipped = true;
19199
+ this._bootstrapStatus = { skipped: true, reason: "interactive-signer" };
19200
+ return false;
19201
+ }
19156
19202
  const steps = (0, import_sdk_core7.bootstrapSteps)(this._address, this._chainId);
19157
19203
  if (!await this.isFreshBootstrapAccount(steps)) {
19158
19204
  return false;
19159
19205
  }
19160
- await this.runAccountBootstrap(steps);
19206
+ try {
19207
+ await this.runAccountBootstrap(steps);
19208
+ } catch (err) {
19209
+ const reason = err instanceof Error ? err.message : String(err);
19210
+ this._bootstrapSkipped = true;
19211
+ this._bootstrapStatus = { skipped: true, reason };
19212
+ this.notificationHandler.warning(
19213
+ `Account bootstrap did not complete: ${reason}`
19214
+ );
19215
+ console.warn(`[TinyCloudNode] account bootstrap failed: ${reason}`);
19216
+ return false;
19217
+ }
19161
19218
  return true;
19162
19219
  }
19163
19220
  async isFreshBootstrapAccount(steps) {
@@ -19209,16 +19266,23 @@ var _TinyCloudNode = class _TinyCloudNode {
19209
19266
  if (rawAbilities) {
19210
19267
  rawAbilitiesBySpace.set(step.space, rawAbilities);
19211
19268
  }
19212
- const session = await auth.createBootstrapSession({
19213
- spaceId: step.spaceId,
19214
- capabilityRequest: step.request ?? import_sdk_core7.BOOTSTRAP_SESSION_REQUESTS[step.space],
19215
- rawAbilities
19216
- });
19269
+ let session;
19270
+ try {
19271
+ session = await auth.createBootstrapSession({
19272
+ spaceId: step.spaceId,
19273
+ capabilityRequest: step.request ?? import_sdk_core7.BOOTSTRAP_SESSION_REQUESTS[step.space],
19274
+ rawAbilities
19275
+ });
19276
+ } catch (err) {
19277
+ throw new Error(
19278
+ `Account bootstrap aborted: signature rejected for space "${step.space}". Cause: ${err instanceof Error ? err.message : String(err)}`
19279
+ );
19280
+ }
19217
19281
  sessions.set(step.space, session);
19218
19282
  }
19219
19283
  for (const step of steps) {
19220
19284
  if (step.kind !== "host") continue;
19221
- const hosted = await auth.hostOwnedSpace(step.spaceId);
19285
+ const hosted = await auth.hostOwnedSpace(step.spaceId, "bootstrap-host");
19222
19286
  if (!hosted) {
19223
19287
  throw new Error(`Failed to host bootstrap space: ${step.spaceId}`);
19224
19288
  }