@hsuite/smart-engines-sdk 3.5.0 → 3.6.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.
@@ -230,7 +230,7 @@ var CreateAccountRequestSchema = zod.z.object({
230
230
  * Smart node security mode for the account key structure.
231
231
  * - 'partial': threshold(2, [appOwnerKey, tssKeyList]) — co-control
232
232
  * - 'full': TSS KeyList only — full validator network control
233
- * Default: 'full' (Arc 5 §7.5.2: 'none' removed).
233
+ * @defaultValue 'full'
234
234
  */
235
235
  securityMode: zod.z.enum(["partial", "full"]).default("full"),
236
236
  /**
@@ -1244,14 +1244,34 @@ function createHttpClient(config) {
1244
1244
  throw new SdkHttpError(`Upload error: ${err.message}`, 0, error);
1245
1245
  }
1246
1246
  }
1247
+ let reauthInFlight = null;
1248
+ async function withAuthRetry(path, op) {
1249
+ try {
1250
+ return await op();
1251
+ } catch (error) {
1252
+ const refreshable = !!config.onUnauthorized && !path.startsWith("/api/auth/") && error instanceof SdkHttpError && error.statusCode === 401;
1253
+ if (!refreshable) throw error;
1254
+ if (!reauthInFlight) {
1255
+ reauthInFlight = Promise.resolve(config.onUnauthorized()).finally(() => {
1256
+ reauthInFlight = null;
1257
+ });
1258
+ }
1259
+ try {
1260
+ await reauthInFlight;
1261
+ } catch {
1262
+ throw error;
1263
+ }
1264
+ return await op();
1265
+ }
1266
+ }
1247
1267
  const client = {
1248
- post: (path, body) => request("POST", path, body),
1249
- get: (path) => request("GET", path),
1250
- put: (path, body) => request("PUT", path, body),
1251
- patch: (path, body) => request("PATCH", path, body),
1252
- delete: (path) => request("DELETE", path),
1253
- getText,
1254
- upload: ((path, file, filename, metadata, fieldName) => upload(path, file, filename, metadata, fieldName)),
1268
+ post: (path, body) => withAuthRetry(path, () => request("POST", path, body)),
1269
+ get: (path) => withAuthRetry(path, () => request("GET", path)),
1270
+ put: (path, body) => withAuthRetry(path, () => request("PUT", path, body)),
1271
+ patch: (path, body) => withAuthRetry(path, () => request("PATCH", path, body)),
1272
+ delete: (path) => withAuthRetry(path, () => request("DELETE", path)),
1273
+ getText: (path) => withAuthRetry(path, () => getText(path)),
1274
+ upload: ((path, file, filename, metadata, fieldName) => withAuthRetry(path, () => upload(path, file, filename, metadata, fieldName))),
1255
1275
  setAuthToken,
1256
1276
  getAuthToken
1257
1277
  };
@@ -1637,8 +1657,8 @@ var ValidatorAuthClient = class {
1637
1657
  *
1638
1658
  * Structurally typed against the surface of xrpl's `Wallet` — see the
1639
1659
  * comment on {@link HederaSigner} for the "no direct import" rationale.
1640
- * Accepts both the modern `{ signedTransaction }` envelope and the
1641
- * legacy bare-string return shape.
1660
+ * Accepts both the `{ signedTransaction }` envelope and the bare-string
1661
+ * return shapes that xrpl signer libraries expose.
1642
1662
  *
1643
1663
  * @param challenge - Challenge string from validator
1644
1664
  * @param wallet - XRPL Wallet instance (or compatible signer)
@@ -1863,6 +1883,40 @@ var SubscriptionClient = class {
1863
1883
  }
1864
1884
  };
1865
1885
 
1886
+ // src/faucet/index.ts
1887
+ var FaucetClient = class {
1888
+ constructor(http) {
1889
+ this.http = http;
1890
+ }
1891
+ http;
1892
+ /**
1893
+ * Request a signing challenge for a recipient address. The returned
1894
+ * `message` must be signed by the key controlling `recipientAddress`.
1895
+ */
1896
+ async requestChallenge(chain, recipientAddress) {
1897
+ return this.http.post("/faucet/hsuite/challenge", { chain, recipientAddress });
1898
+ }
1899
+ /**
1900
+ * Submit a signed challenge to dispense HST. The result is a discriminated
1901
+ * union on `status` — branch on `'dispensed' | 'trustline_required' |
1902
+ * 'rate_limited'`. On `'trustline_required'`, set the returned trust line on
1903
+ * the recipient and re-dispense with a fresh challenge.
1904
+ */
1905
+ async dispense(req) {
1906
+ return this.http.post("/faucet/hsuite", req);
1907
+ }
1908
+ /**
1909
+ * Get today's dispense status for a recipient (e.g. amount already
1910
+ * dispensed today).
1911
+ */
1912
+ async getStatus(chain, recipientAddress) {
1913
+ const params = new URLSearchParams();
1914
+ params.append("chain", chain);
1915
+ params.append("recipientAddress", recipientAddress);
1916
+ return this.http.get(`/faucet/hsuite/status?${params.toString()}`);
1917
+ }
1918
+ };
1919
+
1866
1920
  // src/tss/index.ts
1867
1921
  var TSSClient = class {
1868
1922
  constructor(http) {
@@ -1870,20 +1924,29 @@ var TSSClient = class {
1870
1924
  }
1871
1925
  http;
1872
1926
  /**
1873
- * Create a multi-sig entity with TSS
1927
+ * Create a multi-sig entity via a synchronous DKG ceremony.
1928
+ *
1929
+ * @param options Entity-creation parameters (chain, threshold, participants).
1930
+ * @returns The created entity's identity (ids + group public keys).
1874
1931
  */
1875
1932
  async createEntity(options) {
1876
1933
  return this.http.post("/tss/entity/create", options);
1877
1934
  }
1878
1935
  /**
1879
- * Reshare keys when cluster membership changes.
1880
- * Redistributes secret shares WITHOUT changing public keys.
1936
+ * Reshare keys when cluster membership changes. Redistributes secret shares
1937
+ * WITHOUT changing public keys.
1938
+ *
1939
+ * @param request The new membership / threshold to reshare to.
1940
+ * @returns The reshare outcome.
1881
1941
  */
1882
1942
  async reshareCluster(request) {
1883
1943
  return this.http.post("/tss/cluster/reshare", request);
1884
1944
  }
1885
1945
  /**
1886
- * Get entity details by ID
1946
+ * Get entity details by id.
1947
+ *
1948
+ * @param entityId The entity id to look up.
1949
+ * @returns The entity's details.
1887
1950
  */
1888
1951
  async getEntity(entityId) {
1889
1952
  return this.http.get(`/tss/entity/${encodePathParam(entityId)}`);
@@ -1892,55 +1955,71 @@ var TSSClient = class {
1892
1955
  * Sign a transaction using MPC.
1893
1956
  *
1894
1957
  * Routes to `POST /api/v3/tss/hedera/sign-mpc`. Only `'hedera'` is wired
1895
- * server-side today (see
1896
- * `apps/smart-validator/src/tss/tss.controller.ts:279`); other chain
1897
- * signing paths run via their own controllers (XRPL multisig, Polkadot
1898
- * MPC) and are not exposed through this sub-client. The `chain` field is
1899
- * carried into the request body so the validator can log + route, but
1900
- * any non-`'hedera'` value will 404.
1958
+ * server-side; other chain signing paths run via their own controllers (XRPL
1959
+ * multisig, Polkadot MPC) and are not exposed through this sub-client. The
1960
+ * `chain` field is carried into the request body so the validator can log +
1961
+ * route, but any non-`'hedera'` value will 404.
1962
+ *
1963
+ * @param request The MPC signing request; `chain` is forced to `'hedera'`.
1964
+ * @returns The MPC signing result.
1901
1965
  */
1902
1966
  async signMPC(request) {
1903
1967
  const chain = "hedera";
1904
1968
  return this.http.post(`/tss/${chain}/sign-mpc`, { ...request, chain });
1905
1969
  }
1906
1970
  /**
1907
- * Get known validators and their public keys
1971
+ * Get known validators and their public keys.
1972
+ *
1973
+ * @returns The validator list with public keys.
1908
1974
  */
1909
1975
  async getValidators() {
1910
1976
  return this.http.get("/tss/validators");
1911
1977
  }
1912
1978
  /**
1913
- * Force announcement of this node's public key
1979
+ * Force announcement of this node's public key.
1980
+ *
1981
+ * @returns Whether the announcement was accepted, plus a status message.
1914
1982
  */
1915
1983
  async announceKey() {
1916
1984
  return this.http.post("/tss/announce", {});
1917
1985
  }
1918
1986
  /**
1919
- * Get TSS statistics
1987
+ * Get TSS statistics.
1988
+ *
1989
+ * @returns Aggregate TSS statistics.
1920
1990
  */
1921
1991
  async getStats() {
1922
1992
  return this.http.get("/tss/stats");
1923
1993
  }
1924
1994
  /**
1925
- * List all TSS entities
1995
+ * List all TSS entities.
1996
+ *
1997
+ * @returns The full entity list.
1926
1998
  */
1927
1999
  async listEntities() {
1928
2000
  return this.http.get("/tss/entities");
1929
2001
  }
1930
2002
  /**
1931
- * TSS health check
2003
+ * TSS health check.
2004
+ *
2005
+ * @returns The TSS subsystem health report.
1932
2006
  */
1933
2007
  async getHealth() {
1934
2008
  return this.http.get("/tss/health");
1935
2009
  }
1936
2010
  /**
1937
- * List DKG ceremonies and their statistics
2011
+ * List DKG ceremonies and their statistics.
2012
+ *
2013
+ * @returns The ceremony list.
1938
2014
  */
1939
2015
  async listCeremonies() {
1940
2016
  return this.http.get("/tss/multisig/ceremonies");
1941
2017
  }
1942
2018
  /**
1943
- * Get multi-sig transaction status by transaction ID
2019
+ * Get multi-sig transaction status by transaction id.
2020
+ *
2021
+ * @param txId The multi-sig transaction id.
2022
+ * @returns The current status of that transaction.
1944
2023
  */
1945
2024
  async getMultiSigStatus(txId) {
1946
2025
  return this.http.get(`/tss/multisig/transactions/${encodePathParam(txId)}`);
@@ -1951,6 +2030,9 @@ var TSSClient = class {
1951
2030
  * Server returns 202 + `{ jobId, statusUrl, status: 'pending' }` immediately;
1952
2031
  * the DKG ceremony runs in the background. Poll {@link getJob} until the
1953
2032
  * status reaches `'success'` or `'failed'`.
2033
+ *
2034
+ * @param options Entity-creation parameters.
2035
+ * @returns A job descriptor (`jobId`, `statusUrl`, initial status).
1954
2036
  */
1955
2037
  async createEntityAsync(options) {
1956
2038
  return this.http.post("/tss/entity/create/async", options);
@@ -1958,6 +2040,9 @@ var TSSClient = class {
1958
2040
  /**
1959
2041
  * Async-job variant of {@link reshareCluster}. Returns 202 + a polling
1960
2042
  * descriptor; resharing runs in the background.
2043
+ *
2044
+ * @param request The new membership / threshold to reshare to.
2045
+ * @returns A job descriptor to poll via {@link getJob}.
1961
2046
  */
1962
2047
  async reshareClusterAsync(request) {
1963
2048
  return this.http.post("/tss/cluster/reshare/async", request);
@@ -1965,6 +2050,9 @@ var TSSClient = class {
1965
2050
  /**
1966
2051
  * Poll the status of an async TSS-ceremony job kicked off via
1967
2052
  * {@link createEntityAsync} or {@link reshareClusterAsync}.
2053
+ *
2054
+ * @param jobId The job id returned by the async kickoff call.
2055
+ * @returns The job's current status (and result once terminal).
1968
2056
  */
1969
2057
  async getJob(jobId) {
1970
2058
  return this.http.get(`/tss/jobs/${encodePathParam(jobId)}`);
@@ -1977,6 +2065,10 @@ var TSSClient = class {
1977
2065
  * Payload constraints (enforced server-side):
1978
2066
  * - even-length lowercase hex
1979
2067
  * - ≥32 bytes, ≤8KB
2068
+ *
2069
+ * @param appId The smart-app entity id to sign as.
2070
+ * @param request The hex payload to sign.
2071
+ * @returns The aggregate signature over the payload.
1980
2072
  */
1981
2073
  async signForApp(appId, request) {
1982
2074
  return this.http.post(`/tss/entity/${encodePathParam(appId)}/sign`, request);
@@ -2957,25 +3049,29 @@ var DeploymentClient = class {
2957
3049
  return this.http.get(`/api/deployment/apps/${encodePathParam(appId)}`);
2958
3050
  }
2959
3051
  /**
2960
- * Update app configuration. Runtime effect lands in PR-H.
3052
+ * Update app configuration.
3053
+ *
3054
+ * @param appId - The app to update.
3055
+ * @param updates - Partial deploy-request fields to apply.
3056
+ * @returns The updated app info.
2961
3057
  */
2962
3058
  async update(appId, updates) {
2963
3059
  return this.http.put(`/api/deployment/apps/${encodePathParam(appId)}`, updates);
2964
3060
  }
2965
3061
  /**
2966
- * Delete an app. Runtime effect (namespace teardown) lands in PR-H.
3062
+ * Delete an app (runtime effect: namespace teardown).
2967
3063
  */
2968
3064
  async delete(appId) {
2969
3065
  return this.http.delete(`/api/deployment/apps/${encodePathParam(appId)}`);
2970
3066
  }
2971
3067
  /**
2972
- * Suspend an app. Runtime effect (scale to zero) lands in PR-H.
3068
+ * Suspend an app (runtime effect: scale to zero).
2973
3069
  */
2974
3070
  async suspend(appId) {
2975
3071
  return this.http.post(`/api/deployment/apps/${encodePathParam(appId)}/suspend`, {});
2976
3072
  }
2977
3073
  /**
2978
- * Resume a suspended app. Runtime effect (scale back up) lands in PR-H.
3074
+ * Resume a suspended app (runtime effect: scale back up).
2979
3075
  */
2980
3076
  async resume(appId) {
2981
3077
  return this.http.post(`/api/deployment/apps/${encodePathParam(appId)}/resume`, {});
@@ -3024,7 +3120,7 @@ var DeploymentClient = class {
3024
3120
  return this.http.getText(`/api/deployment/apps/${encodePathParam(appId)}/metrics`);
3025
3121
  }
3026
3122
  /**
3027
- * Rotate the smart-app's tenant-secret KEK (ADR-011 Phase 6).
3123
+ * Rotate the smart-app's tenant-secret KEK.
3028
3124
  *
3029
3125
  * Re-encrypts every `runtime.env` envelope at the new KEK version
3030
3126
  * transparently. Previous versions remain valid until explicitly
@@ -3037,7 +3133,7 @@ var DeploymentClient = class {
3037
3133
  );
3038
3134
  }
3039
3135
  /**
3040
- * Revoke a tenant-secret KEK version (ADR-011 Phase 6 emergency burn).
3136
+ * Revoke a tenant-secret KEK version (emergency burn).
3041
3137
  *
3042
3138
  * Envelopes at the revoked version become operationally dead —
3043
3139
  * decryption inside the smart-app pod fails. Owner-only and
@@ -3260,6 +3356,8 @@ var SmartEngineClient = class _SmartEngineClient {
3260
3356
  // ========== Sub-Clients ==========
3261
3357
  /** Application subscription management */
3262
3358
  subscription;
3359
+ /** Testnet HST faucet (challenge -> sign -> dispense) */
3360
+ faucet;
3263
3361
  /** Threshold Signature Scheme — chain-agnostic MPC operations */
3264
3362
  tss;
3265
3363
  /** IPFS decentralized file storage */
@@ -3318,6 +3416,7 @@ var SmartEngineClient = class _SmartEngineClient {
3318
3416
  timeout: config.timeout
3319
3417
  });
3320
3418
  this.subscription = new SubscriptionClient(this.http);
3419
+ this.faucet = new FaucetClient(this.http);
3321
3420
  this.tss = new TSSClient(this.http);
3322
3421
  this.ipfs = new IPFSClient(this.http);
3323
3422
  this.transactions = new TransactionsClient(this.txHttp);
@@ -3373,13 +3472,17 @@ var SmartEngineClient = class _SmartEngineClient {
3373
3472
  });
3374
3473
  }
3375
3474
  /**
3376
- * Connect to the smart-engines network with auto-discovery and authentication
3475
+ * Connect to the smart-engines network with auto-discovery and authentication.
3476
+ *
3477
+ * Steps:
3478
+ * 1. Discovers validators via the HCS registry topic.
3479
+ * 2. Selects a random validator with an API endpoint.
3480
+ * 3. Authenticates with Web3-style challenge-response.
3481
+ * 4. Returns a configured client ready to use.
3377
3482
  *
3378
- * This method:
3379
- * 1. Discovers validators via HCS registry topic
3380
- * 2. Selects a random validator with API endpoint
3381
- * 3. Authenticates with Web3-style challenge-response
3382
- * 4. Returns a configured client ready to use
3483
+ * @param config - Network, registry topic, and auth signer config.
3484
+ * @returns The configured client, the chosen validator, and the auth session.
3485
+ * @throws SmartEngineError 503 if no validator with an API endpoint is found.
3383
3486
  */
3384
3487
  static async connectToNetwork(config) {
3385
3488
  const allowInsecure = config.allowInsecure ?? false;
@@ -3416,18 +3519,22 @@ var SmartEngineClient = class _SmartEngineClient {
3416
3519
  return { client, validator, session };
3417
3520
  }
3418
3521
  /**
3419
- * Connect to the smart-engines network via the **service-registry**
3420
- * (PR-1 of the cluster-discovery arc). Preferred over
3421
- * {@link connectToNetwork} once the validator pods in the target network
3422
- * have published their cluster endpoints the SDK auto-balances across
3423
- * the active cluster set and rides permissionless cluster join/leave
3424
- * without code edits.
3522
+ * Connect to the smart-engines network via the **service-registry**.
3523
+ * Preferred over {@link connectToNetwork} once the validator pods in the
3524
+ * target network have published their cluster endpoints the SDK
3525
+ * auto-balances across the active cluster set and rides permissionless
3526
+ * cluster join/leave without code edits.
3425
3527
  *
3426
- * Fallback ladder (per `docs/ops/HANDOFF-service-registry-distribution-layer.md` §6):
3528
+ * Resolution ladder:
3427
3529
  * 1. HTTP fetch `/api/v3/discovery/clusters` from each bootstrap seed.
3428
3530
  * 2. (Optional) HCS trust-anchor membership cross-check.
3429
3531
  * 3. Random-pick over the verified set.
3430
3532
  *
3533
+ * @param config - Seed + auth config. See {@link ClusterConnectionConfig}.
3534
+ * @returns The configured client, the selected cluster, and the auth session.
3535
+ * @throws SmartEngineError 400 if neither `bootstrap` nor `network` is given.
3536
+ * @throws SmartEngineError 503 if no active cluster can be reached.
3537
+ *
3431
3538
  * @example Zero-config (recommended for smart-app callers)
3432
3539
  * ```ts
3433
3540
  * const { client, cluster, session } = await SmartEngineClient.connectToCluster({
@@ -3556,17 +3663,11 @@ var SmartEngineClient = class _SmartEngineClient {
3556
3663
  return this.http.post("/tokens/mint", validated);
3557
3664
  }
3558
3665
  /**
3559
- * Get token information.
3666
+ * Get token information for a token on the given chain.
3560
3667
  *
3561
- * Route `GET /api/v3/tokens/:chain/:tokenId` is registered twice on the
3562
- * validator: by `ValidatorController` at
3563
- * `apps/smart-validator/src/validator.controller.ts:497` and by
3564
- * `TokenMigrationController` at
3565
- * `apps/smart-validator/src/token-migration/token-migration.controller.ts:173`.
3566
- * Nest resolves routes in `controllers: [...]` order — `ValidatorController`
3567
- * is registered first (`apps/smart-validator/src/smart-validator.module.ts:1222`),
3568
- * so `multiChain.getTokenInfo(chain, tokenId)` wins and the
3569
- * token-migration handler is unreachable via this path.
3668
+ * @param chain - Chain identifier (e.g. `'hedera'`, `'xrpl'`).
3669
+ * @param tokenId - Chain-native token identifier.
3670
+ * @returns Token metadata and supply information.
3570
3671
  */
3571
3672
  async getTokenInfo(chain, tokenId) {
3572
3673
  return this.http.get(`/tokens/${encodePathParam(chain)}/${encodePathParam(tokenId)}`);
@@ -3795,8 +3896,7 @@ var DomainsClient = class {
3795
3896
  }
3796
3897
  /**
3797
3898
  * Generate a verification token. Server accepts one of `dns-txt`,
3798
- * `dns-cname`, `http-file`, `email` (see controller Swagger enum at
3799
- * `apps/smart-gateway/src/domains/domains.controller.ts:226-234`).
3899
+ * `dns-cname`, `http-file`, `email`.
3800
3900
  */
3801
3901
  async generateVerificationToken(domain, method) {
3802
3902
  return this.http.post(`/domains/${encodePathParam(domain)}/verification`, { method });
@@ -3920,10 +4020,8 @@ var HealthClient = class {
3920
4020
  }
3921
4021
  http;
3922
4022
  /**
3923
- * Per-cluster aggregate health probe. Wraps
3924
- * `GET /api/v3/cluster/health` see
3925
- * `apps/smart-gateway/src/health/health.controller.ts:213-263`. Returns
3926
- * local validator + host + genesis state in a single payload.
4023
+ * Per-cluster aggregate health probe. Wraps `GET /api/v3/cluster/health`.
4024
+ * Returns local validator + host + genesis state in a single payload.
3927
4025
  */
3928
4026
  async getCluster() {
3929
4027
  return this.http.get("/cluster/health");
@@ -4156,23 +4254,11 @@ var StorageClient = class {
4156
4254
  return this.http.delete(`/api/storage/${encodePathParam(appId)}/${encodePathParam(cid)}`);
4157
4255
  }
4158
4256
  /**
4159
- * Get file info.
4257
+ * List all files for the app.
4160
4258
  *
4161
- * @deprecated The smart-host storage controller does not expose a
4162
- * bare-CID metadata route — every metadata lookup must go through
4163
- * `getMetadata(cid)` (`/api/storage/:appId/metadata/:cid`) or the
4164
- * stream body via `download(cid)`. This alias forwards to `download`
4165
- * for back-compat; **scheduled for removal in 4.0.0**.
4166
- */
4167
- async getFile(cid) {
4168
- return this.download(cid);
4169
- }
4170
- /**
4171
- * List all files for the app
4172
- *
4173
- * @param pagination.offset Server reads `offset`; the legacy `skip`
4174
- * option was a client-only synonym that the server silently ignored.
4175
- * Use `offset` going forward.
4259
+ * @param pagination - Optional `limit` and `offset` (the server reads
4260
+ * `offset` for pagination).
4261
+ * @returns The file list and total count.
4176
4262
  */
4177
4263
  async listFiles(pagination) {
4178
4264
  const appId = this.getAppId();
@@ -4553,6 +4639,13 @@ var BaasClient = class _BaasClient {
4553
4639
  http;
4554
4640
  /** Last HTTP error (for getHttpHealth) */
4555
4641
  lastHttpError;
4642
+ /**
4643
+ * Auth options from the last {@link authenticate} call, retained so the
4644
+ * client can transparently re-authenticate when the session token expires
4645
+ * (the http client invokes {@link reauthenticate} on a 401). Undefined until
4646
+ * the first successful authenticate.
4647
+ */
4648
+ authContext;
4556
4649
  // ========== Sub-Clients ==========
4557
4650
  /** Trustless database with state proofs and Merkle verification */
4558
4651
  db;
@@ -4582,7 +4675,11 @@ var BaasClient = class _BaasClient {
4582
4675
  const baseUrlWithPrefix = this.pathPrefix ? this.hostUrl.replace(/\/$/, "") + this.pathPrefix : this.hostUrl;
4583
4676
  this.http = createHttpClient({
4584
4677
  baseUrl: baseUrlWithPrefix,
4585
- timeout: this.timeout
4678
+ timeout: this.timeout,
4679
+ // Transparent session refresh: on a 401, re-run the challenge-response
4680
+ // with the retained signer and retry once. No-op until authenticate() has
4681
+ // been called (authContext set). Excludes /api/auth/* (see http client).
4682
+ onUnauthorized: () => this.reauthenticate()
4586
4683
  });
4587
4684
  const getAppId = () => this.requireAppId();
4588
4685
  this.db = new DatabaseClient(this.http, getAppId);
@@ -4718,6 +4815,7 @@ var BaasClient = class _BaasClient {
4718
4815
  */
4719
4816
  async authenticate(options) {
4720
4817
  const { chain, walletAddress, publicKey, signFn } = options;
4818
+ this.authContext = options;
4721
4819
  let challenge;
4722
4820
  try {
4723
4821
  challenge = await this.http.post("/api/auth/challenge", {
@@ -4742,6 +4840,30 @@ var BaasClient = class _BaasClient {
4742
4840
  this.http.setAuthToken(result.token);
4743
4841
  return result;
4744
4842
  }
4843
+ /**
4844
+ * Re-run the challenge-response with the retained signer to mint a fresh
4845
+ * session token. Invoked by the http client's `onUnauthorized` hook when a
4846
+ * request 401s because the token expired — so long-lived clients keep working
4847
+ * without the caller re-implementing refresh. No-op if {@link authenticate}
4848
+ * was never called. The `/api/auth/*` calls below are excluded from the http
4849
+ * client's 401-retry path, so this can never recurse.
4850
+ */
4851
+ async reauthenticate() {
4852
+ const ctx = this.authContext;
4853
+ if (!ctx) return;
4854
+ const challenge = await this.http.post("/api/auth/challenge", {
4855
+ chain: ctx.chain,
4856
+ walletAddress: ctx.walletAddress,
4857
+ appId: this.appId
4858
+ });
4859
+ const signature = await ctx.signFn(challenge.message);
4860
+ const result = await this.http.post("/api/auth/verify", {
4861
+ challengeId: challenge.challengeId,
4862
+ signature,
4863
+ publicKey: ctx.publicKey
4864
+ });
4865
+ this.http.setAuthToken(result.token);
4866
+ }
4745
4867
  /** Validate the current session */
4746
4868
  async validateSession() {
4747
4869
  this.requireAuth();
@@ -5012,10 +5134,12 @@ exports.SmartEngineService = __decorateClass([
5012
5134
  // src/nestjs/smart-engine.module.ts
5013
5135
  exports.SmartEngineModule = class SmartEngineModule {
5014
5136
  /**
5015
- * Configure the module with static configuration
5137
+ * Configure the module with static configuration.
5016
5138
  *
5017
- * @param config - SmartEngine service configuration
5018
- * @param isGlobal - Whether to make the module global (default: true)
5139
+ * @param config - SmartEngine service configuration.
5140
+ * @param isGlobal - Whether to make the module global. @defaultValue true
5141
+ * @returns A `DynamicModule` exporting {@link SmartEngineService} plus the
5142
+ * BaaS / rules / entities clients.
5019
5143
  */
5020
5144
  static forRoot(config, isGlobal = true) {
5021
5145
  return {
@@ -5038,11 +5162,15 @@ exports.SmartEngineModule = class SmartEngineModule {
5038
5162
  };
5039
5163
  }
5040
5164
  /**
5041
- * Configure the module with async configuration
5165
+ * Configure the module with async configuration.
5042
5166
  *
5043
5167
  * Supports factory functions, configuration classes, and existing providers.
5044
5168
  *
5045
- * @param options - Async configuration options
5169
+ * @param options - Async configuration options.
5170
+ * @returns A `DynamicModule` exporting {@link SmartEngineService} plus the
5171
+ * BaaS / rules / entities clients.
5172
+ * @throws Error if `options` provides none of `useFactory`, `useClass`, or
5173
+ * `useExisting`.
5046
5174
  */
5047
5175
  static forRootAsync(options) {
5048
5176
  const asyncProviders = this.createAsyncProviders(options);