@hsuite/smart-engines-sdk 3.0.1 → 3.0.3

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.js CHANGED
@@ -1,22 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var zod = require('zod');
4
- var common = require('@nestjs/common');
5
4
 
6
5
  var __defProp = Object.defineProperty;
7
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
10
8
  __defProp(target, name, { get: all[name], enumerable: true });
11
9
  };
12
- var __decorateClass = (decorators, target, key, kind) => {
13
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
14
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
15
- if (decorator = decorators[i])
16
- result = (decorator(result)) || result;
17
- return result;
18
- };
19
- var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
20
10
 
21
11
  // src/_vendor/circuit-breaker.ts
22
12
  var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
@@ -1735,14 +1725,14 @@ function createHttpClient(config) {
1735
1725
  throw new SdkHttpError(`Network error: ${err.message}`, 0, error);
1736
1726
  }
1737
1727
  }
1738
- async function upload(path, file, filename, metadata) {
1728
+ async function upload(path, file, filename, metadata, fieldName = "file") {
1739
1729
  const url = `${config.baseUrl}${path}`;
1740
1730
  const controller = new AbortController();
1741
1731
  const timeoutId = setTimeout(() => controller.abort(), timeout * 2);
1742
1732
  try {
1743
1733
  const formData = new FormData();
1744
1734
  const blob = file instanceof Blob ? file : new Blob([new Uint8Array(file)]);
1745
- formData.append("file", blob, filename);
1735
+ formData.append(fieldName, blob, filename);
1746
1736
  if (metadata) {
1747
1737
  for (const [key, value] of Object.entries(metadata)) {
1748
1738
  formData.append(key, value);
@@ -1786,7 +1776,7 @@ function createHttpClient(config) {
1786
1776
  get: (path) => request("GET", path),
1787
1777
  put: (path, body) => request("PUT", path, body),
1788
1778
  delete: (path) => request("DELETE", path),
1789
- upload,
1779
+ upload: ((path, file, filename, metadata, fieldName) => upload(path, file, filename, metadata, fieldName)),
1790
1780
  setAuthToken
1791
1781
  };
1792
1782
  return client;
@@ -3629,49 +3619,101 @@ var DeploymentClient = class {
3629
3619
  }
3630
3620
  http;
3631
3621
  /**
3632
- * Create (deploy) a new app
3622
+ * Step 1 allocate appId + receive ephemeral push credentials for
3623
+ * the cluster's per-tenant Harbor project.
3624
+ *
3625
+ * Each app gets its own Harbor project (`hsuite-customers-<appId>`)
3626
+ * isolated by Harbor's RBAC. The push robot returned in
3627
+ * `registry.{username, password}` is scoped to that project only —
3628
+ * it cannot read or write any other tenant's images.
3629
+ *
3630
+ * **Single-use secret discipline:** `registry.password` is returned
3631
+ * exactly once and is NOT persisted server-side. Store it locally
3632
+ * for the `docker push` and discard. To rotate, call `init` again
3633
+ * (issues a new robot under the same project).
3634
+ *
3635
+ * Use the credentials to `docker login` + `docker push`, then call
3636
+ * {@link deploy} with the pushed image tag.
3633
3637
  */
3634
- async create(request) {
3635
- return this.http.post("/api/deployment/apps", request);
3638
+ async init(request) {
3639
+ return this.http.post("/api/deployment/apps/init", request);
3636
3640
  }
3637
3641
  /**
3638
- * List all deployed apps
3642
+ * Step 3 (optional) — upload the SPA tarball.
3643
+ *
3644
+ * The tarball is content-addressed (SHA-256) and mounted read-only
3645
+ * into the customer's pod alongside the backend container. Returns
3646
+ * the hash + size so the caller can verify the upload.
3647
+ */
3648
+ async uploadFrontend(appId, bundle, filename = "bundle.tar.gz") {
3649
+ return this.http.upload(
3650
+ `/api/deployment/apps/${encodeURIComponent(appId)}/frontend`,
3651
+ bundle,
3652
+ filename,
3653
+ void 0,
3654
+ "bundle"
3655
+ );
3656
+ }
3657
+ /**
3658
+ * Step 4 — reconcile the runtime to k8s.
3659
+ *
3660
+ * Returns immediately with `status: 'deploying'`. Poll {@link status}
3661
+ * until `runtime.runtimeState === 'RUNNING'` for the URL to be live.
3662
+ */
3663
+ async deploy(appId, request) {
3664
+ return this.http.post(`/api/deployment/apps/${encodeURIComponent(appId)}/deploy`, request);
3665
+ }
3666
+ /**
3667
+ * Roll back to a previously-deployed image tag (must exist in
3668
+ * `runtime.deploymentHistory[]`).
3669
+ */
3670
+ async rollback(appId, request) {
3671
+ return this.http.post(`/api/deployment/apps/${encodeURIComponent(appId)}/rollback`, request);
3672
+ }
3673
+ /**
3674
+ * Live combined lifecycle + runtime status of an app.
3675
+ */
3676
+ async status(appId) {
3677
+ return this.http.get(`/api/deployment/apps/${encodeURIComponent(appId)}/status`);
3678
+ }
3679
+ /**
3680
+ * List all deployed apps for the authenticated developer.
3639
3681
  */
3640
3682
  async list() {
3641
3683
  return this.http.get("/api/deployment/apps");
3642
3684
  }
3643
3685
  /**
3644
- * Get app details
3686
+ * Get app details.
3645
3687
  */
3646
3688
  async get(appId) {
3647
3689
  return this.http.get(`/api/deployment/apps/${encodeURIComponent(appId)}`);
3648
3690
  }
3649
3691
  /**
3650
- * Update app configuration
3692
+ * Update app configuration. Runtime effect lands in PR-H.
3651
3693
  */
3652
3694
  async update(appId, updates) {
3653
3695
  return this.http.put(`/api/deployment/apps/${encodeURIComponent(appId)}`, updates);
3654
3696
  }
3655
3697
  /**
3656
- * Delete an app
3698
+ * Delete an app. Runtime effect (namespace teardown) lands in PR-H.
3657
3699
  */
3658
3700
  async delete(appId) {
3659
3701
  return this.http.delete(`/api/deployment/apps/${encodeURIComponent(appId)}`);
3660
3702
  }
3661
3703
  /**
3662
- * Suspend an app
3704
+ * Suspend an app. Runtime effect (scale to zero) lands in PR-H.
3663
3705
  */
3664
3706
  async suspend(appId) {
3665
3707
  return this.http.post(`/api/deployment/apps/${encodeURIComponent(appId)}/suspend`, {});
3666
3708
  }
3667
3709
  /**
3668
- * Resume a suspended app
3710
+ * Resume a suspended app. Runtime effect (scale back up) lands in PR-H.
3669
3711
  */
3670
3712
  async resume(appId) {
3671
3713
  return this.http.post(`/api/deployment/apps/${encodeURIComponent(appId)}/resume`, {});
3672
3714
  }
3673
3715
  /**
3674
- * Get deployment statistics
3716
+ * Get deployment statistics.
3675
3717
  */
3676
3718
  async getStats() {
3677
3719
  return this.http.get("/api/deployment/stats");
@@ -3801,6 +3843,78 @@ var AgentsClient = class {
3801
3843
  }
3802
3844
  };
3803
3845
 
3846
+ // src/baas/customer-session/index.ts
3847
+ var CustomerSessionClient = class {
3848
+ constructor(baseUrl, timeoutMs = 3e4) {
3849
+ this.baseUrl = baseUrl;
3850
+ this.timeoutMs = timeoutMs;
3851
+ }
3852
+ baseUrl;
3853
+ timeoutMs;
3854
+ /**
3855
+ * Step 1: ask the host to issue a fresh challenge for the customer to sign.
3856
+ */
3857
+ async challenge(input) {
3858
+ return this.fetch("POST", "/api/customer-session/challenge", input);
3859
+ }
3860
+ /**
3861
+ * Step 2: submit the customer's signed challenge. On success returns a
3862
+ * short-lived bearer JWT scoped to {appId, chain, address}.
3863
+ */
3864
+ async verify(req) {
3865
+ return this.fetch("POST", "/api/customer-session/verify", req);
3866
+ }
3867
+ /**
3868
+ * Validate a customer bearer + return the decoded session info. Used by
3869
+ * smart-app backends to authorise incoming customer requests.
3870
+ */
3871
+ async validate(bearer) {
3872
+ return this.fetch("GET", "/api/customer-session/validate", void 0, bearer);
3873
+ }
3874
+ /**
3875
+ * Revoke a customer session. Idempotent.
3876
+ */
3877
+ async end(bearer) {
3878
+ return this.fetch(
3879
+ "POST",
3880
+ "/api/customer-session/end",
3881
+ void 0,
3882
+ bearer
3883
+ );
3884
+ }
3885
+ async fetch(method, path, body, bearer) {
3886
+ const url = `${this.baseUrl}${path}`;
3887
+ const controller = new AbortController();
3888
+ const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
3889
+ try {
3890
+ const headers = { "Content-Type": "application/json" };
3891
+ if (bearer) headers["Authorization"] = `Bearer ${bearer}`;
3892
+ const init = { method, headers, signal: controller.signal };
3893
+ if (body !== void 0) init.body = JSON.stringify(body);
3894
+ const response = await fetch(url, init);
3895
+ clearTimeout(timeoutId);
3896
+ if (!response.ok) {
3897
+ const errBody = await response.json().catch(() => ({}));
3898
+ const err = new Error(
3899
+ errBody.message ?? `customer-session ${path} failed: ${response.status} ${response.statusText}`
3900
+ );
3901
+ err.status = response.status;
3902
+ throw err;
3903
+ }
3904
+ const text = await response.text();
3905
+ if (!text) return void 0;
3906
+ return JSON.parse(text);
3907
+ } catch (error) {
3908
+ clearTimeout(timeoutId);
3909
+ const e = error;
3910
+ if (e.name === "AbortError") {
3911
+ throw new Error(`customer-session ${path} timeout`);
3912
+ }
3913
+ throw error;
3914
+ }
3915
+ }
3916
+ };
3917
+
3804
3918
  // src/baas/client.ts
3805
3919
  var BaasClient = class {
3806
3920
  hostUrl;
@@ -3825,6 +3939,8 @@ var BaasClient = class {
3825
3939
  deployment;
3826
3940
  /** Autonomous smart agent management */
3827
3941
  agents;
3942
+ /** Customer→smart-app session bridge (TokenGate Face B). */
3943
+ customerSession;
3828
3944
  constructor(config) {
3829
3945
  this.allowInsecure = config.allowInsecure ?? false;
3830
3946
  this.hostUrl = validateUrl2(config.hostUrl, this.allowInsecure);
@@ -3844,6 +3960,7 @@ var BaasClient = class {
3844
3960
  this.messaging = new MessagingClient(this.http, getAppId);
3845
3961
  this.deployment = new DeploymentClient(this.http);
3846
3962
  this.agents = new AgentsClient(this.http);
3963
+ this.customerSession = new CustomerSessionClient(baseUrlWithPrefix, this.timeout);
3847
3964
  }
3848
3965
  /** Set the app ID (for newly registered apps) */
3849
3966
  setAppId(appId) {
@@ -3870,7 +3987,7 @@ var BaasClient = class {
3870
3987
  requireAppId() {
3871
3988
  if (!this.appId) {
3872
3989
  throw new BaasError(
3873
- "App ID required. Either provide appId in config or call register() first.",
3990
+ "App ID required. Provide appId in config (e.g. from a prior deployment.init() call).",
3874
3991
  400
3875
3992
  );
3876
3993
  }
@@ -3917,12 +4034,6 @@ var BaasClient = class {
3917
4034
  }
3918
4035
  this.authToken = null;
3919
4036
  }
3920
- // ========== App Registration ==========
3921
- /** Register a new app on the BaaS host */
3922
- async register(request) {
3923
- this.requireAuth();
3924
- return this.post("/api/deployment/apps", request);
3925
- }
3926
4037
  // ========== HTTP Helpers ==========
3927
4038
  requireAuth() {
3928
4039
  if (!this.authToken) {
@@ -4010,293 +4121,6 @@ function validateUrl2(url, allowInsecure = false) {
4010
4121
  }
4011
4122
  }
4012
4123
 
4013
- // src/nestjs/index.ts
4014
- var nestjs_exports = {};
4015
- __export(nestjs_exports, {
4016
- SMART_ENGINE_CONFIG: () => SMART_ENGINE_CONFIG,
4017
- SmartEngineModule: () => exports.SmartEngineModule,
4018
- SmartEngineService: () => exports.SmartEngineService
4019
- });
4020
- var SMART_ENGINE_CONFIG = "SMART_ENGINE_CONFIG";
4021
- exports.SmartEngineService = class SmartEngineService {
4022
- constructor(config) {
4023
- this.config = config;
4024
- }
4025
- config;
4026
- logger = new common.Logger(exports.SmartEngineService.name);
4027
- client = null;
4028
- baasClient = null;
4029
- connected = false;
4030
- reconnectTimer = null;
4031
- reconnectAttempts = 0;
4032
- /**
4033
- * Initialize the service when the module starts
4034
- */
4035
- async onModuleInit() {
4036
- if (!this.config) {
4037
- this.logger.warn(
4038
- "SmartEngineService initialized without configuration. Call configure() before using."
4039
- );
4040
- return;
4041
- }
4042
- await this.initialize(this.config);
4043
- }
4044
- /**
4045
- * Clean up resources when the module is destroyed
4046
- */
4047
- async onModuleDestroy() {
4048
- await this.shutdown();
4049
- }
4050
- /**
4051
- * Initialize the service with configuration
4052
- *
4053
- * Can be called manually if not using DI configuration
4054
- */
4055
- async initialize(config) {
4056
- this.logger.log(`Initializing SmartEngineService for ${config.baseUrl}`);
4057
- try {
4058
- this.client = new SmartEngineClient({
4059
- baseUrl: config.baseUrl,
4060
- apiKey: config.apiKey,
4061
- authToken: config.authToken,
4062
- timeout: config.timeout,
4063
- allowInsecure: config.allowInsecure
4064
- });
4065
- this.baasClient = this.createBaasClient(this.client);
4066
- if (config.testConnection !== false) {
4067
- await this.testConnection();
4068
- }
4069
- this.connected = true;
4070
- this.reconnectAttempts = 0;
4071
- this.logger.log("SmartEngineService initialized successfully");
4072
- } catch (error) {
4073
- const err = error;
4074
- this.logger.error(`Failed to initialize SmartEngineService: ${err.message}`);
4075
- if (config.autoReconnect) {
4076
- this.scheduleReconnect(config);
4077
- } else {
4078
- throw error;
4079
- }
4080
- }
4081
- }
4082
- /**
4083
- * Gracefully shutdown the service
4084
- */
4085
- async shutdown() {
4086
- this.logger.log("Shutting down SmartEngineService");
4087
- if (this.reconnectTimer) {
4088
- clearTimeout(this.reconnectTimer);
4089
- this.reconnectTimer = null;
4090
- }
4091
- this.client = null;
4092
- this.baasClient = null;
4093
- this.connected = false;
4094
- this.logger.log("SmartEngineService shutdown complete");
4095
- }
4096
- /**
4097
- * Get the SmartEngineClient instance
4098
- *
4099
- * @throws SmartEngineError if client is not initialized
4100
- */
4101
- getClient() {
4102
- if (!this.client) {
4103
- throw new SmartEngineError2(
4104
- "SmartEngineClient not initialized. Ensure SmartEngineService is configured properly.",
4105
- 500
4106
- );
4107
- }
4108
- return this.client;
4109
- }
4110
- /**
4111
- * Get the BaaS client for simplified blockchain access
4112
- *
4113
- * The BaaS client provides a simplified interface for applications
4114
- * that need managed blockchain infrastructure access.
4115
- *
4116
- * @throws SmartEngineError if client is not initialized
4117
- */
4118
- getBaasClient() {
4119
- if (!this.baasClient) {
4120
- throw new SmartEngineError2(
4121
- "BaasClient not initialized. Ensure SmartEngineService is configured properly.",
4122
- 500
4123
- );
4124
- }
4125
- return this.baasClient;
4126
- }
4127
- /**
4128
- * Check if the service is connected and healthy
4129
- */
4130
- isConnected() {
4131
- return this.connected;
4132
- }
4133
- /**
4134
- * Test the connection to the validator
4135
- */
4136
- async testConnection() {
4137
- if (!this.client) {
4138
- return false;
4139
- }
4140
- try {
4141
- const health = await this.client.getHealth();
4142
- this.connected = health.status === "healthy" || health.status === "ok";
4143
- return this.connected;
4144
- } catch (error) {
4145
- const err = error;
4146
- this.logger.warn(`Connection test failed: ${err.message}`);
4147
- this.connected = false;
4148
- return false;
4149
- }
4150
- }
4151
- /**
4152
- * Get the current connection status
4153
- */
4154
- getStatus() {
4155
- return {
4156
- connected: this.connected,
4157
- baseUrl: this.client?.getBaseUrl() ?? null,
4158
- authenticated: this.client?.isAuthenticated() ?? false,
4159
- reconnectAttempts: this.reconnectAttempts
4160
- };
4161
- }
4162
- /**
4163
- * Create a SmartGatewayClient for gateway operations
4164
- */
4165
- createGatewayClient(config) {
4166
- return new SmartGatewayClient(config);
4167
- }
4168
- /**
4169
- * Create a BaaS client for host operations
4170
- */
4171
- createHostClient(config) {
4172
- return new BaasClient(config);
4173
- }
4174
- /**
4175
- * Create a BaaS client wrapper around the SmartEngineClient
4176
- */
4177
- createBaasClient(client) {
4178
- return {
4179
- client,
4180
- isHealthy: async () => {
4181
- try {
4182
- const health = await client.getHealth();
4183
- return health.status === "healthy" || health.status === "ok";
4184
- } catch {
4185
- return false;
4186
- }
4187
- },
4188
- getBaseUrl: () => client.getBaseUrl()
4189
- };
4190
- }
4191
- /**
4192
- * Schedule a reconnection attempt
4193
- */
4194
- scheduleReconnect(config) {
4195
- const maxAttempts = config.maxReconnectAttempts ?? 0;
4196
- const interval = config.reconnectInterval ?? 5e3;
4197
- if (maxAttempts > 0 && this.reconnectAttempts >= maxAttempts) {
4198
- this.logger.error(`Max reconnection attempts (${maxAttempts}) reached. Giving up.`);
4199
- return;
4200
- }
4201
- this.reconnectAttempts++;
4202
- this.logger.log(`Scheduling reconnection attempt ${this.reconnectAttempts} in ${interval}ms`);
4203
- this.reconnectTimer = setTimeout(async () => {
4204
- try {
4205
- await this.initialize(config);
4206
- } catch {
4207
- }
4208
- }, interval);
4209
- }
4210
- };
4211
- exports.SmartEngineService = __decorateClass([
4212
- common.Injectable(),
4213
- __decorateParam(0, common.Optional()),
4214
- __decorateParam(0, common.Inject(SMART_ENGINE_CONFIG))
4215
- ], exports.SmartEngineService);
4216
-
4217
- // src/nestjs/smart-engine.module.ts
4218
- exports.SmartEngineModule = class SmartEngineModule {
4219
- /**
4220
- * Configure the module with static configuration
4221
- *
4222
- * @param config - SmartEngine service configuration
4223
- * @param isGlobal - Whether to make the module global (default: true)
4224
- */
4225
- static forRoot(config, isGlobal = true) {
4226
- return {
4227
- module: exports.SmartEngineModule,
4228
- global: isGlobal,
4229
- providers: [
4230
- {
4231
- provide: SMART_ENGINE_CONFIG,
4232
- useValue: config
4233
- },
4234
- exports.SmartEngineService
4235
- ],
4236
- exports: [exports.SmartEngineService]
4237
- };
4238
- }
4239
- /**
4240
- * Configure the module with async configuration
4241
- *
4242
- * Supports factory functions, configuration classes, and existing providers.
4243
- *
4244
- * @param options - Async configuration options
4245
- */
4246
- static forRootAsync(options) {
4247
- const asyncProviders = this.createAsyncProviders(options);
4248
- return {
4249
- module: exports.SmartEngineModule,
4250
- global: options.isGlobal ?? true,
4251
- imports: options.imports || [],
4252
- providers: [...asyncProviders, exports.SmartEngineService],
4253
- exports: [exports.SmartEngineService]
4254
- };
4255
- }
4256
- /**
4257
- * Create async providers based on configuration options
4258
- */
4259
- static createAsyncProviders(options) {
4260
- if (options.useFactory) {
4261
- return [
4262
- {
4263
- provide: SMART_ENGINE_CONFIG,
4264
- useFactory: options.useFactory,
4265
- inject: options.inject || []
4266
- }
4267
- ];
4268
- }
4269
- if (options.useClass) {
4270
- return [
4271
- {
4272
- provide: options.useClass,
4273
- useClass: options.useClass
4274
- },
4275
- {
4276
- provide: SMART_ENGINE_CONFIG,
4277
- useFactory: async (optionsFactory) => optionsFactory.createSmartEngineOptions(),
4278
- inject: [options.useClass]
4279
- }
4280
- ];
4281
- }
4282
- if (options.useExisting) {
4283
- return [
4284
- {
4285
- provide: SMART_ENGINE_CONFIG,
4286
- useFactory: async (optionsFactory) => optionsFactory.createSmartEngineOptions(),
4287
- inject: [options.useExisting]
4288
- }
4289
- ];
4290
- }
4291
- throw new Error(
4292
- "Invalid SmartEngineModuleAsyncOptions: must provide useFactory, useClass, or useExisting"
4293
- );
4294
- }
4295
- };
4296
- exports.SmartEngineModule = __decorateClass([
4297
- common.Module({})
4298
- ], exports.SmartEngineModule);
4299
-
4300
4124
  exports.AgentsClient = AgentsClient;
4301
4125
  exports.BaasClient = BaasClient;
4302
4126
  exports.BaasError = BaasError;
@@ -4304,6 +4128,7 @@ exports.CapabilityNotEnabledError = CapabilityNotEnabledError;
4304
4128
  exports.CapabilityValidationError = CapabilityValidationError;
4305
4129
  exports.CircuitBreaker = CircuitBreaker;
4306
4130
  exports.CircuitBreakerOpenError = CircuitBreakerOpenError;
4131
+ exports.CustomerSessionClient = CustomerSessionClient;
4307
4132
  exports.DEFAULT_CIRCUIT_BREAKER_CONFIG = DEFAULT_CIRCUIT_BREAKER_CONFIG;
4308
4133
  exports.DEFAULT_RETRY_CONFIG = DEFAULT_RETRY_CONFIG;
4309
4134
  exports.DatabaseClient = DatabaseClient;
@@ -4319,7 +4144,6 @@ exports.MirrorNodeClient = MirrorNodeClient;
4319
4144
  exports.MirrorNodeError = MirrorNodeError;
4320
4145
  exports.RateLimiter = RateLimiter;
4321
4146
  exports.RoutingClient = RoutingClient;
4322
- exports.SMART_ENGINE_CONFIG = SMART_ENGINE_CONFIG;
4323
4147
  exports.SdkHttpError = SdkHttpError;
4324
4148
  exports.SettlementClient = SettlementClient;
4325
4149
  exports.SmartEngineClient = SmartEngineClient;
@@ -4341,7 +4165,6 @@ exports.createHttpClient = createHttpClient;
4341
4165
  exports.createResilientFetchWithBreaker = createResilientFetchWithBreaker;
4342
4166
  exports.discovery = discovery_exports;
4343
4167
  exports.encodePathParam = encodePathParam;
4344
- exports.nestjs = nestjs_exports;
4345
4168
  exports.resilientFetch = resilientFetch;
4346
4169
  exports.settlement = settlement_exports;
4347
4170
  exports.subscription = subscription_exports;