@hsuite/smart-engines-sdk 3.5.0 → 3.6.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.
@@ -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.
3377
3476
  *
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
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.
3482
+ *
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");
@@ -3967,11 +4065,28 @@ var SmartGatewayClient = class {
3967
4065
  return this.http.get("/status");
3968
4066
  }
3969
4067
  /**
3970
- * Check gateway readiness. Returns either `{ status: 'ready', ... }` with
3971
- * a verified host count or `{ status: 'not_ready', reason, ... }`.
4068
+ * Check gateway readiness. Resolves to either `{ status: 'ready', ... }`
4069
+ * with a verified host count or `{ status: 'not_ready', reason, ... }`.
4070
+ *
4071
+ * NOTE: `/api/v3/ready` returns **HTTP 503** when not ready (so load
4072
+ * balancers / k8s probes drain the origin). This method unwraps that 503's
4073
+ * body and still RESOLVES to a `GatewayReadinessResponse` — it does not
4074
+ * throw for a not-ready gateway. Genuine errors (non-readiness 503s, 5xx,
4075
+ * network) still throw.
3972
4076
  */
3973
4077
  async getReadiness() {
3974
- return this.http.get("/ready");
4078
+ try {
4079
+ return await this.http.get("/ready");
4080
+ } catch (err) {
4081
+ if (err instanceof SdkHttpError && err.statusCode === 503) {
4082
+ const d = err.details;
4083
+ const body = d?.context ?? d;
4084
+ if (body?.status === "not_ready") {
4085
+ return body;
4086
+ }
4087
+ }
4088
+ throw err;
4089
+ }
3975
4090
  }
3976
4091
  /** Check gateway liveness. */
3977
4092
  async getLiveness() {
@@ -4156,23 +4271,11 @@ var StorageClient = class {
4156
4271
  return this.http.delete(`/api/storage/${encodePathParam(appId)}/${encodePathParam(cid)}`);
4157
4272
  }
4158
4273
  /**
4159
- * Get file info.
4160
- *
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
4274
+ * List all files for the app.
4172
4275
  *
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.
4276
+ * @param pagination - Optional `limit` and `offset` (the server reads
4277
+ * `offset` for pagination).
4278
+ * @returns The file list and total count.
4176
4279
  */
4177
4280
  async listFiles(pagination) {
4178
4281
  const appId = this.getAppId();
@@ -4553,6 +4656,13 @@ var BaasClient = class _BaasClient {
4553
4656
  http;
4554
4657
  /** Last HTTP error (for getHttpHealth) */
4555
4658
  lastHttpError;
4659
+ /**
4660
+ * Auth options from the last {@link authenticate} call, retained so the
4661
+ * client can transparently re-authenticate when the session token expires
4662
+ * (the http client invokes {@link reauthenticate} on a 401). Undefined until
4663
+ * the first successful authenticate.
4664
+ */
4665
+ authContext;
4556
4666
  // ========== Sub-Clients ==========
4557
4667
  /** Trustless database with state proofs and Merkle verification */
4558
4668
  db;
@@ -4582,7 +4692,11 @@ var BaasClient = class _BaasClient {
4582
4692
  const baseUrlWithPrefix = this.pathPrefix ? this.hostUrl.replace(/\/$/, "") + this.pathPrefix : this.hostUrl;
4583
4693
  this.http = createHttpClient({
4584
4694
  baseUrl: baseUrlWithPrefix,
4585
- timeout: this.timeout
4695
+ timeout: this.timeout,
4696
+ // Transparent session refresh: on a 401, re-run the challenge-response
4697
+ // with the retained signer and retry once. No-op until authenticate() has
4698
+ // been called (authContext set). Excludes /api/auth/* (see http client).
4699
+ onUnauthorized: () => this.reauthenticate()
4586
4700
  });
4587
4701
  const getAppId = () => this.requireAppId();
4588
4702
  this.db = new DatabaseClient(this.http, getAppId);
@@ -4718,6 +4832,7 @@ var BaasClient = class _BaasClient {
4718
4832
  */
4719
4833
  async authenticate(options) {
4720
4834
  const { chain, walletAddress, publicKey, signFn } = options;
4835
+ this.authContext = options;
4721
4836
  let challenge;
4722
4837
  try {
4723
4838
  challenge = await this.http.post("/api/auth/challenge", {
@@ -4742,6 +4857,30 @@ var BaasClient = class _BaasClient {
4742
4857
  this.http.setAuthToken(result.token);
4743
4858
  return result;
4744
4859
  }
4860
+ /**
4861
+ * Re-run the challenge-response with the retained signer to mint a fresh
4862
+ * session token. Invoked by the http client's `onUnauthorized` hook when a
4863
+ * request 401s because the token expired — so long-lived clients keep working
4864
+ * without the caller re-implementing refresh. No-op if {@link authenticate}
4865
+ * was never called. The `/api/auth/*` calls below are excluded from the http
4866
+ * client's 401-retry path, so this can never recurse.
4867
+ */
4868
+ async reauthenticate() {
4869
+ const ctx = this.authContext;
4870
+ if (!ctx) return;
4871
+ const challenge = await this.http.post("/api/auth/challenge", {
4872
+ chain: ctx.chain,
4873
+ walletAddress: ctx.walletAddress,
4874
+ appId: this.appId
4875
+ });
4876
+ const signature = await ctx.signFn(challenge.message);
4877
+ const result = await this.http.post("/api/auth/verify", {
4878
+ challengeId: challenge.challengeId,
4879
+ signature,
4880
+ publicKey: ctx.publicKey
4881
+ });
4882
+ this.http.setAuthToken(result.token);
4883
+ }
4745
4884
  /** Validate the current session */
4746
4885
  async validateSession() {
4747
4886
  this.requireAuth();
@@ -5012,10 +5151,12 @@ exports.SmartEngineService = __decorateClass([
5012
5151
  // src/nestjs/smart-engine.module.ts
5013
5152
  exports.SmartEngineModule = class SmartEngineModule {
5014
5153
  /**
5015
- * Configure the module with static configuration
5154
+ * Configure the module with static configuration.
5016
5155
  *
5017
- * @param config - SmartEngine service configuration
5018
- * @param isGlobal - Whether to make the module global (default: true)
5156
+ * @param config - SmartEngine service configuration.
5157
+ * @param isGlobal - Whether to make the module global. @defaultValue true
5158
+ * @returns A `DynamicModule` exporting {@link SmartEngineService} plus the
5159
+ * BaaS / rules / entities clients.
5019
5160
  */
5020
5161
  static forRoot(config, isGlobal = true) {
5021
5162
  return {
@@ -5038,11 +5179,15 @@ exports.SmartEngineModule = class SmartEngineModule {
5038
5179
  };
5039
5180
  }
5040
5181
  /**
5041
- * Configure the module with async configuration
5182
+ * Configure the module with async configuration.
5042
5183
  *
5043
5184
  * Supports factory functions, configuration classes, and existing providers.
5044
5185
  *
5045
- * @param options - Async configuration options
5186
+ * @param options - Async configuration options.
5187
+ * @returns A `DynamicModule` exporting {@link SmartEngineService} plus the
5188
+ * BaaS / rules / entities clients.
5189
+ * @throws Error if `options` provides none of `useFactory`, `useClass`, or
5190
+ * `useExisting`.
5046
5191
  */
5047
5192
  static forRootAsync(options) {
5048
5193
  const asyncProviders = this.createAsyncProviders(options);