@hsuite/smart-engines-sdk 3.0.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.js ADDED
@@ -0,0 +1,4350 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+ var common = require('@nestjs/common');
5
+
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
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
+
21
+ // src/_vendor/circuit-breaker.ts
22
+ var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
23
+ failureThreshold: 5,
24
+ rollingWindowMs: 6e4,
25
+ cooldownMs: 3e4,
26
+ name: "circuit"
27
+ };
28
+ var CircuitBreakerOpenError = class extends Error {
29
+ constructor(name, nextProbeAt) {
30
+ super(`Circuit breaker '${name}' is open until ${new Date(nextProbeAt).toISOString()}`);
31
+ this.nextProbeAt = nextProbeAt;
32
+ this.name = "CircuitBreakerOpenError";
33
+ }
34
+ nextProbeAt;
35
+ code = "CIRCUIT_BREAKER_OPEN";
36
+ };
37
+ var CircuitBreaker = class {
38
+ state = "closed";
39
+ failureTimestamps = [];
40
+ successCount = 0;
41
+ openedAt;
42
+ config;
43
+ constructor(config = {}) {
44
+ const merged = { ...DEFAULT_CIRCUIT_BREAKER_CONFIG, ...config };
45
+ if (merged.failureThreshold < 1) {
46
+ throw new Error("failureThreshold must be >= 1");
47
+ }
48
+ if (merged.rollingWindowMs <= 0) {
49
+ throw new Error("rollingWindowMs must be > 0");
50
+ }
51
+ if (merged.cooldownMs <= 0) {
52
+ throw new Error("cooldownMs must be > 0");
53
+ }
54
+ this.config = merged;
55
+ }
56
+ /**
57
+ * Execute an operation through the breaker.
58
+ * @throws CircuitBreakerOpenError if the breaker is open
59
+ */
60
+ async execute(operation) {
61
+ this.evaluateState();
62
+ if (this.state === "open") {
63
+ throw new CircuitBreakerOpenError(this.config.name ?? "circuit", this.nextProbeTime());
64
+ }
65
+ try {
66
+ const result = await operation();
67
+ this.recordSuccess();
68
+ return result;
69
+ } catch (err) {
70
+ this.recordFailure(err);
71
+ throw err;
72
+ }
73
+ }
74
+ /** Allow probing without executing (e.g. for health endpoints) */
75
+ canExecute() {
76
+ this.evaluateState();
77
+ return this.state !== "open";
78
+ }
79
+ getState() {
80
+ this.evaluateState();
81
+ return this.state;
82
+ }
83
+ snapshot() {
84
+ this.evaluateState();
85
+ return {
86
+ state: this.state,
87
+ failureCount: this.failureTimestamps.length,
88
+ successCount: this.successCount,
89
+ lastFailureAt: this.failureTimestamps[this.failureTimestamps.length - 1],
90
+ openedAt: this.openedAt,
91
+ nextProbeAt: this.state === "open" ? this.nextProbeTime() : void 0
92
+ };
93
+ }
94
+ /** Force the breaker back to CLOSED. Use sparingly (e.g. on operator override). */
95
+ reset() {
96
+ this.state = "closed";
97
+ this.failureTimestamps = [];
98
+ this.successCount = 0;
99
+ this.openedAt = void 0;
100
+ }
101
+ evaluateState() {
102
+ if (this.state === "open" && this.openedAt !== void 0) {
103
+ if (Date.now() - this.openedAt >= this.config.cooldownMs) {
104
+ this.state = "half_open";
105
+ }
106
+ }
107
+ this.pruneOldFailures();
108
+ }
109
+ nextProbeTime() {
110
+ return (this.openedAt ?? Date.now()) + this.config.cooldownMs;
111
+ }
112
+ pruneOldFailures() {
113
+ const cutoff = Date.now() - this.config.rollingWindowMs;
114
+ if (this.failureTimestamps.length === 0 || this.failureTimestamps[0] >= cutoff) {
115
+ return;
116
+ }
117
+ this.failureTimestamps = this.failureTimestamps.filter((ts) => ts >= cutoff);
118
+ }
119
+ recordSuccess() {
120
+ this.successCount += 1;
121
+ if (this.state === "half_open") {
122
+ this.state = "closed";
123
+ this.failureTimestamps = [];
124
+ this.openedAt = void 0;
125
+ } else if (this.state === "closed") {
126
+ this.failureTimestamps.shift();
127
+ }
128
+ }
129
+ recordFailure(err) {
130
+ if (!this.shouldCountFailure(err)) {
131
+ return;
132
+ }
133
+ const now = Date.now();
134
+ this.failureTimestamps.push(now);
135
+ this.pruneOldFailures();
136
+ if (this.state === "half_open") {
137
+ this.openedAt = now;
138
+ this.state = "open";
139
+ return;
140
+ }
141
+ if (this.state === "closed" && this.failureTimestamps.length >= this.config.failureThreshold) {
142
+ this.openedAt = now;
143
+ this.state = "open";
144
+ }
145
+ }
146
+ shouldCountFailure(err) {
147
+ const filter = this.config.failureFilter;
148
+ if (!filter || filter.length === 0) return true;
149
+ const message = (err.message || "").toLowerCase();
150
+ const name = (err.name || "").toLowerCase();
151
+ return filter.some((pattern) => {
152
+ const p = pattern.toLowerCase();
153
+ return message.includes(p) || name.includes(p);
154
+ });
155
+ }
156
+ };
157
+
158
+ // src/_vendor/rate-limiter.ts
159
+ var DEFAULT_CONFIG = {
160
+ maxRequests: 60,
161
+ windowMs: 6e4
162
+ // 1 minute
163
+ };
164
+ var RateLimiter = class {
165
+ // Lightweight logger stub (no @nestjs/common dependency). Replace via constructor injection if needed.
166
+ logger = { debug: (..._args) => {
167
+ }, warn: (..._args) => {
168
+ } };
169
+ limits = /* @__PURE__ */ new Map();
170
+ config;
171
+ constructor(config) {
172
+ this.config = {
173
+ ...DEFAULT_CONFIG,
174
+ ...config
175
+ };
176
+ }
177
+ /**
178
+ * Check if request is allowed under rate limit
179
+ *
180
+ * @param key - Unique identifier for rate limit bucket
181
+ * @returns True if request is allowed
182
+ */
183
+ isAllowed(key) {
184
+ const now = Date.now();
185
+ const entry = this.limits.get(key);
186
+ if (!entry || now - entry.windowStart >= this.config.windowMs) {
187
+ this.limits.set(key, { count: 1, windowStart: now });
188
+ return true;
189
+ }
190
+ if (entry.count >= this.config.maxRequests) {
191
+ this.logger.debug(`Rate limit exceeded for key: ${key.substring(0, 20)}...`);
192
+ return false;
193
+ }
194
+ entry.count++;
195
+ return true;
196
+ }
197
+ /**
198
+ * Reset rate limit for a specific key
199
+ *
200
+ * @param key - Key to reset
201
+ */
202
+ reset(key) {
203
+ this.limits.delete(key);
204
+ }
205
+ /**
206
+ * Clear all rate limits
207
+ */
208
+ clear() {
209
+ this.limits.clear();
210
+ }
211
+ /**
212
+ * Clean up expired entries
213
+ */
214
+ cleanup() {
215
+ const now = Date.now();
216
+ const expiredThreshold = this.config.windowMs * 2;
217
+ for (const [key, entry] of this.limits.entries()) {
218
+ if (now - entry.windowStart > expiredThreshold) {
219
+ this.limits.delete(key);
220
+ }
221
+ }
222
+ }
223
+ /**
224
+ * Get current count for a key
225
+ *
226
+ * @param key - Key to check
227
+ * @returns Current request count or 0
228
+ */
229
+ getCount(key) {
230
+ const entry = this.limits.get(key);
231
+ if (!entry) return 0;
232
+ if (Date.now() - entry.windowStart >= this.config.windowMs) {
233
+ return 0;
234
+ }
235
+ return entry.count;
236
+ }
237
+ /**
238
+ * Get remaining requests for a key
239
+ *
240
+ * @param key - Key to check
241
+ * @returns Remaining requests in current window
242
+ */
243
+ getRemaining(key) {
244
+ return Math.max(0, this.config.maxRequests - this.getCount(key));
245
+ }
246
+ /**
247
+ * Get configuration
248
+ */
249
+ getConfig() {
250
+ return Object.freeze({ ...this.config });
251
+ }
252
+ };
253
+
254
+ // src/_vendor/smart-engine.error.ts
255
+ var ErrorCode = {
256
+ // General errors
257
+ UNKNOWN_ERROR: "UNKNOWN_ERROR",
258
+ VALIDATION_ERROR: "VALIDATION_ERROR",
259
+ NOT_FOUND: "NOT_FOUND",
260
+ UNAUTHORIZED: "UNAUTHORIZED",
261
+ FORBIDDEN: "FORBIDDEN",
262
+ RATE_LIMIT_EXCEEDED: "RATE_LIMIT_EXCEEDED",
263
+ PAYLOAD_TOO_LARGE: "PAYLOAD_TOO_LARGE",
264
+ // Chain-specific errors
265
+ CHAIN_NOT_SUPPORTED: "CHAIN_NOT_SUPPORTED",
266
+ CHAIN_CONNECTION_ERROR: "CHAIN_CONNECTION_ERROR",
267
+ CHAIN_TIMEOUT: "CHAIN_TIMEOUT",
268
+ // Transaction errors
269
+ TRANSACTION_FAILED: "TRANSACTION_FAILED",
270
+ TRANSACTION_TIMEOUT: "TRANSACTION_TIMEOUT",
271
+ INSUFFICIENT_BALANCE: "INSUFFICIENT_BALANCE",
272
+ INVALID_TRANSACTION: "INVALID_TRANSACTION",
273
+ // Account errors
274
+ ACCOUNT_NOT_FOUND: "ACCOUNT_NOT_FOUND",
275
+ ACCOUNT_CREATION_FAILED: "ACCOUNT_CREATION_FAILED",
276
+ INVALID_ACCOUNT_ID: "INVALID_ACCOUNT_ID",
277
+ // Wallet errors
278
+ WALLET_NOT_FOUND: "WALLET_NOT_FOUND",
279
+ WALLET_ENCRYPTION_ERROR: "WALLET_ENCRYPTION_ERROR",
280
+ WALLET_DECRYPTION_ERROR: "WALLET_DECRYPTION_ERROR",
281
+ INVALID_PRIVATE_KEY: "INVALID_PRIVATE_KEY",
282
+ // Token errors
283
+ TOKEN_NOT_FOUND: "TOKEN_NOT_FOUND",
284
+ TOKEN_CREATION_FAILED: "TOKEN_CREATION_FAILED",
285
+ INSUFFICIENT_TOKEN_BALANCE: "INSUFFICIENT_TOKEN_BALANCE",
286
+ TRUST_LINE_REQUIRED: "TRUST_LINE_REQUIRED",
287
+ TOKEN_NOT_ASSOCIATED: "TOKEN_NOT_ASSOCIATED",
288
+ TOKEN_PAUSED: "TOKEN_PAUSED",
289
+ ACCOUNT_FROZEN: "ACCOUNT_FROZEN",
290
+ KYC_NOT_GRANTED: "KYC_NOT_GRANTED",
291
+ // Signature/Auth errors
292
+ INVALID_SIGNATURE: "INVALID_SIGNATURE",
293
+ NONCE_MISMATCH: "NONCE_MISMATCH",
294
+ // Contract errors
295
+ CONTRACT_REVERT: "CONTRACT_REVERT",
296
+ CONTRACT_NOT_FOUND: "CONTRACT_NOT_FOUND",
297
+ GAS_ERROR: "GAS_ERROR",
298
+ // Infrastructure errors
299
+ DATABASE_ERROR: "DATABASE_ERROR",
300
+ CACHE_ERROR: "CACHE_ERROR",
301
+ EVENT_BUS_ERROR: "EVENT_BUS_ERROR",
302
+ EXTERNAL_SERVICE_ERROR: "EXTERNAL_SERVICE_ERROR"
303
+ };
304
+ var SmartEngineError = class extends Error {
305
+ constructor(message, code, statusCode = 500, context, isRetryable = false) {
306
+ super(message);
307
+ this.code = code;
308
+ this.statusCode = statusCode;
309
+ this.context = context;
310
+ this.isRetryable = isRetryable;
311
+ this.name = "SmartEngineError";
312
+ Error.captureStackTrace(this, this.constructor);
313
+ }
314
+ code;
315
+ statusCode;
316
+ context;
317
+ isRetryable;
318
+ toJSON() {
319
+ return {
320
+ error: {
321
+ name: this.name,
322
+ message: this.message,
323
+ code: this.code,
324
+ statusCode: this.statusCode,
325
+ context: this.context,
326
+ isRetryable: this.isRetryable
327
+ }
328
+ };
329
+ }
330
+ };
331
+
332
+ // src/_vendor/capability.error.ts
333
+ var UnsupportedCapabilityError = class extends SmartEngineError {
334
+ constructor(chain, capability, alternatives) {
335
+ const message = `Capability '${capability}' is not supported on chain '${chain}'`;
336
+ const context = {
337
+ chain,
338
+ capability,
339
+ alternatives
340
+ };
341
+ super(message, ErrorCode.VALIDATION_ERROR, 400, context, false);
342
+ this.chain = chain;
343
+ this.capability = capability;
344
+ this.alternatives = alternatives;
345
+ this.name = "UnsupportedCapabilityError";
346
+ }
347
+ chain;
348
+ capability;
349
+ alternatives;
350
+ };
351
+ var CapabilityNotEnabledError = class extends SmartEngineError {
352
+ constructor(tokenId, capability) {
353
+ const message = `Capability '${capability}' was not enabled for token '${tokenId}'`;
354
+ const context = {
355
+ tokenId,
356
+ capability
357
+ };
358
+ super(message, ErrorCode.VALIDATION_ERROR, 400, context, false);
359
+ this.tokenId = tokenId;
360
+ this.capability = capability;
361
+ this.name = "CapabilityNotEnabledError";
362
+ }
363
+ tokenId;
364
+ capability;
365
+ };
366
+ var CapabilityValidationError = class extends SmartEngineError {
367
+ constructor(message, capabilities, chain) {
368
+ const context = {
369
+ capabilities,
370
+ chain
371
+ };
372
+ super(message, ErrorCode.VALIDATION_ERROR, 400, context, false);
373
+ this.capabilities = capabilities;
374
+ this.chain = chain;
375
+ this.name = "CapabilityValidationError";
376
+ }
377
+ capabilities;
378
+ chain;
379
+ };
380
+ var ChainTypeSchema = zod.z.enum([
381
+ "hedera",
382
+ "xrpl",
383
+ "polkadot",
384
+ "solana",
385
+ "stellar",
386
+ "ethereum",
387
+ "polygon",
388
+ "bitcoin",
389
+ "cardano"
390
+ ]);
391
+ var NetworkTypeSchema = zod.z.enum(["mainnet", "testnet", "devnet", "local"]);
392
+ zod.z.object({
393
+ chain: ChainTypeSchema,
394
+ network: NetworkTypeSchema,
395
+ nativeCurrency: zod.z.object({
396
+ name: zod.z.string(),
397
+ symbol: zod.z.string(),
398
+ decimals: zod.z.number().int().min(0)
399
+ }),
400
+ blockTime: zod.z.number().optional(),
401
+ rpcEndpoint: zod.z.string().url().optional()
402
+ });
403
+ var NetworkMembershipTypeSchema = zod.z.enum(["validator", "host", "gateway"]);
404
+ var MembershipStatusSchema = zod.z.enum(["pending", "active", "exiting", "exited", "banned"]);
405
+ zod.z.object({
406
+ nodeId: zod.z.string().min(1),
407
+ networkType: NetworkMembershipTypeSchema,
408
+ chain: zod.z.enum(["hedera", "xrpl", "polkadot", "solana"]),
409
+ endpoint: zod.z.string().url(),
410
+ publicKey: zod.z.string().min(1),
411
+ joinedAt: zod.z.string().datetime(),
412
+ depositTxId: zod.z.string().min(1),
413
+ status: MembershipStatusSchema,
414
+ networkConfig: zod.z.record(zod.z.unknown()).optional()
415
+ });
416
+ var NetworkDepositRequirementsSchema = zod.z.object({
417
+ depositAmount: zod.z.string().min(1),
418
+ lockDurationDays: zod.z.number().int().positive(),
419
+ renewalWindowDays: zod.z.number().int().positive().optional()
420
+ });
421
+ zod.z.object({
422
+ validator: NetworkDepositRequirementsSchema,
423
+ host: NetworkDepositRequirementsSchema,
424
+ gateway: NetworkDepositRequirementsSchema
425
+ });
426
+ var TokenCapabilitiesSchema = zod.z.object({
427
+ /**
428
+ * Pause all token operations globally
429
+ * - Hedera: Adds pauseKey to token
430
+ * - XRPL: Enables GlobalFreeze flag on issuer account
431
+ */
432
+ pausable: zod.z.boolean().default(false),
433
+ /**
434
+ * Freeze/restrict specific accounts from transacting
435
+ * - Hedera: Adds freezeKey to token
436
+ * - XRPL: Enables trust line freeze capability
437
+ */
438
+ restrictable: zod.z.boolean().default(false),
439
+ /**
440
+ * KYC/compliance controls for accounts
441
+ * - Hedera: Adds kycKey to token
442
+ * - XRPL: Requires authorized trust lines (RequireAuth)
443
+ */
444
+ compliant: zod.z.boolean().default(false),
445
+ /**
446
+ * Force remove tokens from accounts (compliance wipe)
447
+ * - Hedera: Adds wipeKey to token
448
+ * - XRPL: Enables clawback (lsfAllowTrustLineClawback)
449
+ */
450
+ wipeable: zod.z.boolean().default(false),
451
+ /**
452
+ * Mint additional supply after creation
453
+ * - Hedera: Adds supplyKey to token
454
+ * - XRPL: Issuer can always issue more via Payment
455
+ */
456
+ mintable: zod.z.boolean().default(true),
457
+ /**
458
+ * Burn tokens (reduce supply)
459
+ * - Hedera: Requires supplyKey
460
+ * - XRPL: Send back to issuer (reduces supply)
461
+ */
462
+ burnable: zod.z.boolean().default(true),
463
+ /**
464
+ * Allow transfers between accounts
465
+ * - All chains: Generally always supported
466
+ */
467
+ transferable: zod.z.boolean().default(true)
468
+ });
469
+ var AccountIdSchema = zod.z.string().min(1);
470
+ zod.z.object({
471
+ accountId: AccountIdSchema,
472
+ balance: zod.z.string(),
473
+ // String to handle large numbers and decimals
474
+ chain: ChainTypeSchema,
475
+ publicKey: zod.z.string().optional(),
476
+ metadata: zod.z.record(zod.z.any()).optional(),
477
+ createdAt: zod.z.date().optional(),
478
+ updatedAt: zod.z.date().optional()
479
+ });
480
+ zod.z.object({
481
+ accountId: AccountIdSchema,
482
+ chain: ChainTypeSchema,
483
+ nativeBalance: zod.z.string(),
484
+ tokens: zod.z.array(
485
+ zod.z.object({
486
+ tokenId: zod.z.string(),
487
+ balance: zod.z.string(),
488
+ decimals: zod.z.number().int().min(0),
489
+ symbol: zod.z.string().optional()
490
+ })
491
+ ).optional(),
492
+ timestamp: zod.z.date()
493
+ });
494
+ var SecurityModeSchema = zod.z.enum(["none", "partial", "full"]);
495
+ var sovereigntyRefinePredicate = (v) => {
496
+ if (v.securityMode === "partial") {
497
+ return !!v.entityId && !!v.appOwnerPublicKey;
498
+ }
499
+ if (v.securityMode === "full") {
500
+ return !!v.entityId;
501
+ }
502
+ return true;
503
+ };
504
+ var SOVEREIGNTY_REFINE_MESSAGE = "securityMode='partial' requires entityId+appOwnerPublicKey; 'full' requires entityId";
505
+ var SovereigntyFieldsRawSchema = zod.z.object({
506
+ securityMode: SecurityModeSchema.default("none"),
507
+ entityId: zod.z.string().optional(),
508
+ appOwnerPublicKey: zod.z.string().optional()
509
+ });
510
+ SovereigntyFieldsRawSchema.refine(sovereigntyRefinePredicate, { message: SOVEREIGNTY_REFINE_MESSAGE });
511
+ var HederaKeyShapeSchema = zod.z.lazy(
512
+ () => zod.z.union([
513
+ zod.z.object({ type: zod.z.literal("ed25519"), key: zod.z.string() }),
514
+ zod.z.object({
515
+ type: zod.z.literal("keyList"),
516
+ threshold: zod.z.number().int().nonnegative(),
517
+ keys: zod.z.array(HederaKeyShapeSchema)
518
+ })
519
+ ])
520
+ );
521
+ var HederaAuthorizationSetShapeSchema = zod.z.object({
522
+ chain: zod.z.literal("hedera"),
523
+ adminKey: HederaKeyShapeSchema,
524
+ supplyKey: HederaKeyShapeSchema.optional(),
525
+ freezeKey: HederaKeyShapeSchema.optional(),
526
+ wipeKey: HederaKeyShapeSchema.optional(),
527
+ pauseKey: HederaKeyShapeSchema.optional(),
528
+ kycKey: HederaKeyShapeSchema.optional()
529
+ });
530
+ var XrplAuthorizationSetShapeSchema = zod.z.object({
531
+ chain: zod.z.literal("xrpl"),
532
+ signerEntries: zod.z.array(
533
+ zod.z.object({
534
+ account: zod.z.string(),
535
+ weight: zod.z.number().int().nonnegative()
536
+ })
537
+ ),
538
+ signerQuorum: zod.z.number().int().nonnegative(),
539
+ masterDisabled: zod.z.boolean()
540
+ });
541
+ var StellarAuthorizationSetShapeSchema = zod.z.object({
542
+ chain: zod.z.literal("stellar"),
543
+ signers: zod.z.array(
544
+ zod.z.object({
545
+ key: zod.z.string(),
546
+ weight: zod.z.number().int().nonnegative()
547
+ })
548
+ ),
549
+ thresholds: zod.z.object({
550
+ low: zod.z.number().int().nonnegative(),
551
+ med: zod.z.number().int().nonnegative(),
552
+ high: zod.z.number().int().nonnegative()
553
+ }),
554
+ masterWeight: zod.z.number().int().nonnegative()
555
+ });
556
+ var PolkadotSignatoryShapeSchema = zod.z.lazy(
557
+ () => zod.z.union([
558
+ zod.z.object({ type: zod.z.literal("account"), address: zod.z.string() }),
559
+ zod.z.object({
560
+ type: zod.z.literal("multisig"),
561
+ address: zod.z.string(),
562
+ threshold: zod.z.number().int().positive(),
563
+ signatories: zod.z.array(PolkadotSignatoryShapeSchema)
564
+ })
565
+ ])
566
+ );
567
+ var PolkadotAuthorizationSetShapeSchema = zod.z.object({
568
+ chain: zod.z.literal("polkadot"),
569
+ address: zod.z.string(),
570
+ signatory: PolkadotSignatoryShapeSchema,
571
+ ss58Format: zod.z.number().int().nonnegative()
572
+ });
573
+ var PreparedTransactionAuthorizationSetSchema = zod.z.discriminatedUnion("chain", [
574
+ HederaAuthorizationSetShapeSchema,
575
+ XrplAuthorizationSetShapeSchema,
576
+ StellarAuthorizationSetShapeSchema,
577
+ PolkadotAuthorizationSetShapeSchema
578
+ ]);
579
+ var PreparedTransactionSovereigntySchema = zod.z.discriminatedUnion("mode", [
580
+ zod.z.object({ mode: zod.z.literal("none") }),
581
+ zod.z.object({
582
+ mode: zod.z.literal("partial"),
583
+ entityId: zod.z.string(),
584
+ validatorPublicKeys: zod.z.array(zod.z.string()),
585
+ authorizationSet: PreparedTransactionAuthorizationSetSchema.optional()
586
+ }),
587
+ zod.z.object({
588
+ mode: zod.z.literal("full"),
589
+ entityId: zod.z.string(),
590
+ validatorPublicKeys: zod.z.array(zod.z.string()),
591
+ authorizationSet: PreparedTransactionAuthorizationSetSchema.optional()
592
+ })
593
+ ]);
594
+ var TransactionStatusSchema = zod.z.enum(["pending", "success", "failed", "expired"]);
595
+ var TransactionTypeSchema = zod.z.enum([
596
+ "transfer",
597
+ "token_transfer",
598
+ "account_create",
599
+ "token_create",
600
+ "token_mint",
601
+ "token_burn",
602
+ "contract_call",
603
+ "contract_create",
604
+ "topic_message",
605
+ "other"
606
+ ]);
607
+ zod.z.object({
608
+ id: zod.z.string(),
609
+ chain: ChainTypeSchema,
610
+ type: TransactionTypeSchema,
611
+ status: TransactionStatusSchema,
612
+ timestamp: zod.z.date(),
613
+ from: AccountIdSchema,
614
+ to: AccountIdSchema.optional(),
615
+ amount: zod.z.string().optional(),
616
+ fee: zod.z.string(),
617
+ memo: zod.z.string().optional(),
618
+ metadata: zod.z.record(zod.z.any()).optional()
619
+ });
620
+ zod.z.object({
621
+ transactionId: zod.z.string(),
622
+ chain: ChainTypeSchema,
623
+ status: TransactionStatusSchema,
624
+ blockNumber: zod.z.number().optional(),
625
+ blockHash: zod.z.string().optional(),
626
+ timestamp: zod.z.date(),
627
+ gasUsed: zod.z.string().optional(),
628
+ effectiveFee: zod.z.string(),
629
+ logs: zod.z.array(zod.z.any()).optional(),
630
+ metadata: zod.z.record(zod.z.any()).optional()
631
+ });
632
+ var TokenTypeSchema = zod.z.enum(["fungible", "nft", "semi_fungible"]);
633
+ var TokenSchema = zod.z.object({
634
+ tokenId: zod.z.string(),
635
+ chain: ChainTypeSchema,
636
+ name: zod.z.string(),
637
+ symbol: zod.z.string(),
638
+ decimals: zod.z.number().int().min(0),
639
+ totalSupply: zod.z.string(),
640
+ type: TokenTypeSchema,
641
+ creator: AccountIdSchema.optional(),
642
+ metadata: zod.z.record(zod.z.any()).optional(),
643
+ createdAt: zod.z.date().optional()
644
+ });
645
+ zod.z.object({
646
+ name: zod.z.string(),
647
+ description: zod.z.string().optional(),
648
+ image: zod.z.string().url().optional(),
649
+ attributes: zod.z.array(
650
+ zod.z.object({
651
+ trait_type: zod.z.string(),
652
+ value: zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean()])
653
+ })
654
+ ).optional(),
655
+ external_url: zod.z.string().url().optional()
656
+ });
657
+ TokenSchema.extend({
658
+ holders: zod.z.number().optional(),
659
+ transferCount: zod.z.number().optional(),
660
+ circulatingSupply: zod.z.string().optional()
661
+ });
662
+ var CreateAccountRequestSchema = zod.z.object({
663
+ chain: ChainTypeSchema,
664
+ initialBalance: zod.z.string(),
665
+ publicKey: zod.z.string().optional(),
666
+ memo: zod.z.string().optional(),
667
+ /**
668
+ * Who pays the chain fee for this transaction. Resolution happens in the
669
+ * controller layer (`resolvePayerAccountId`): explicit `payerAccountId`
670
+ * wins, else the JWT-authenticated smart-app's wallet address, else the
671
+ * request is rejected with 400. The validator **never** silently falls
672
+ * back to its own operator account.
673
+ */
674
+ payerAccountId: zod.z.string().optional(),
675
+ /**
676
+ * HCS consensus timestamp of the validator rules (REQUIRED).
677
+ * Format: "1766490325.123456789"
678
+ */
679
+ validatorTimestamp: zod.z.string().min(1, "validatorTimestamp is required"),
680
+ /**
681
+ * HCS topic ID where validator rules are stored (REQUIRED).
682
+ */
683
+ validatorTopicId: zod.z.string().min(1, "validatorTopicId is required"),
684
+ /**
685
+ * Whether to remove admin key after creation (makes entity immutable).
686
+ * Default: true for production-grade immutability.
687
+ */
688
+ immutable: zod.z.boolean().default(true),
689
+ /**
690
+ * Smart node security mode for the account key structure.
691
+ * - 'none': Owner-only key (no validator involvement)
692
+ * - 'partial': threshold(2, [appOwnerKey, tssKeyList]) — co-control
693
+ * - 'full': TSS KeyList only — full validator network control
694
+ * Default: 'none' for basic account creation via SDK.
695
+ */
696
+ securityMode: zod.z.enum(["none", "partial", "full"]).default("none"),
697
+ /**
698
+ * App owner's public key (required for 'partial' security mode).
699
+ * The owner key + TSS network key form a threshold-2 multi-sig.
700
+ */
701
+ appOwnerPublicKey: zod.z.string().optional(),
702
+ metadata: zod.z.record(zod.z.any()).optional()
703
+ });
704
+ zod.z.object({
705
+ accountId: AccountIdSchema,
706
+ publicKey: zod.z.string().optional(),
707
+ privateKey: zod.z.string().optional(),
708
+ // Only returned on creation, store securely!
709
+ transactionId: zod.z.string(),
710
+ chain: ChainTypeSchema,
711
+ timestamp: zod.z.date().optional()
712
+ });
713
+ var TransferRequestSchema = zod.z.object({
714
+ chain: ChainTypeSchema,
715
+ from: AccountIdSchema,
716
+ to: AccountIdSchema,
717
+ amount: zod.z.string(),
718
+ tokenId: zod.z.string().optional(),
719
+ // undefined = native token
720
+ memo: zod.z.string().optional(),
721
+ /** See CreateAccountRequestSchema.payerAccountId — same resolution rules. */
722
+ payerAccountId: zod.z.string().optional(),
723
+ metadata: zod.z.record(zod.z.any()).optional()
724
+ });
725
+ zod.z.object({
726
+ transactionId: zod.z.string(),
727
+ status: zod.z.enum(["pending", "success", "failed"]),
728
+ chain: ChainTypeSchema,
729
+ fee: zod.z.string().optional(),
730
+ timestamp: zod.z.date().optional()
731
+ });
732
+ zod.z.object({
733
+ chain: ChainTypeSchema,
734
+ accountId: AccountIdSchema
735
+ });
736
+ zod.z.object({
737
+ chain: ChainTypeSchema,
738
+ transactionId: zod.z.string()
739
+ });
740
+ var CreateTokenRequestSchema = zod.z.object({
741
+ chain: ChainTypeSchema,
742
+ name: zod.z.string().min(1).max(100),
743
+ symbol: zod.z.string().min(1).max(10),
744
+ decimals: zod.z.number().int().min(0).max(18),
745
+ initialSupply: zod.z.string(),
746
+ type: zod.z.enum(["fungible", "nft"]),
747
+ treasury: AccountIdSchema.optional(),
748
+ /**
749
+ * Token capabilities define what operations the token supports.
750
+ * These are validated against chain support and translated to native implementations.
751
+ *
752
+ * @example
753
+ * ```typescript
754
+ * capabilities: {
755
+ * pausable: true, // Hedera: pauseKey, XRPL: GlobalFreeze
756
+ * restrictable: true, // Hedera: freezeKey, XRPL: TrustLineFreeze
757
+ * compliant: true, // Hedera: kycKey, XRPL: RequireAuth
758
+ * wipeable: true, // Hedera: wipeKey, XRPL: Clawback
759
+ * mintable: true, // Allow additional minting
760
+ * burnable: true, // Allow burning
761
+ * }
762
+ * ```
763
+ */
764
+ capabilities: TokenCapabilitiesSchema.optional().default({
765
+ pausable: false,
766
+ restrictable: false,
767
+ compliant: false,
768
+ wipeable: false,
769
+ mintable: true,
770
+ burnable: true,
771
+ transferable: true
772
+ }),
773
+ /**
774
+ * HCS consensus timestamp of the validator rules (REQUIRED).
775
+ * Format: "1766490325.123456789"
776
+ */
777
+ validatorTimestamp: zod.z.string().min(1, "validatorTimestamp is required"),
778
+ /**
779
+ * HCS topic ID where validator rules are stored (REQUIRED).
780
+ */
781
+ validatorTopicId: zod.z.string().min(1, "validatorTopicId is required"),
782
+ /**
783
+ * Whether to remove admin key after creation (makes entity immutable).
784
+ * Default: true for production-grade immutability.
785
+ */
786
+ immutable: zod.z.boolean().default(true),
787
+ /** See CreateAccountRequestSchema.payerAccountId — same resolution rules. */
788
+ payerAccountId: zod.z.string().optional(),
789
+ metadata: zod.z.record(zod.z.any()).optional()
790
+ });
791
+ zod.z.object({
792
+ tokenId: zod.z.string(),
793
+ transactionId: zod.z.string(),
794
+ chain: ChainTypeSchema,
795
+ timestamp: zod.z.date().optional()
796
+ });
797
+ var MintTokenRequestSchema = zod.z.object({
798
+ chain: ChainTypeSchema,
799
+ tokenId: zod.z.string(),
800
+ /** Amount to mint (fungible tokens). Ignored for NFTs. */
801
+ amount: zod.z.string().optional(),
802
+ /** Recipient account (fungible: transfer after mint; NFT: Hedera mints to treasury). */
803
+ recipient: AccountIdSchema.optional(),
804
+ /**
805
+ * NFT metadata entries — one per NFT to mint.
806
+ * Each entry becomes on-chain metadata (e.g. IPFS CID, encoded memo).
807
+ * On Hedera: passed to TokenMintTransaction.setMetadata().
808
+ * On XRPL: used as URI in NFTokenMint.
809
+ */
810
+ nftMetadata: zod.z.array(zod.z.string()).optional(),
811
+ /** Additional chain-specific options. */
812
+ metadata: zod.z.record(zod.z.any()).optional(),
813
+ /** See CreateAccountRequestSchema.payerAccountId — same resolution rules. */
814
+ payerAccountId: zod.z.string().optional()
815
+ });
816
+ var BurnTokenRequestSchema = zod.z.object({
817
+ chain: ChainTypeSchema,
818
+ tokenId: zod.z.string(),
819
+ amount: zod.z.string(),
820
+ /** See CreateAccountRequestSchema.payerAccountId — same resolution rules. */
821
+ payerAccountId: zod.z.string().optional(),
822
+ metadata: zod.z.record(zod.z.any()).optional()
823
+ });
824
+ var TokenActionRequestSchema = zod.z.object({
825
+ chain: ChainTypeSchema,
826
+ tokenId: zod.z.string(),
827
+ accountId: AccountIdSchema.optional(),
828
+ // Required for account-specific actions
829
+ amount: zod.z.string().optional(),
830
+ // Required for wipe action
831
+ /** See CreateAccountRequestSchema.payerAccountId — same resolution rules. */
832
+ payerAccountId: zod.z.string().optional(),
833
+ metadata: zod.z.record(zod.z.any()).optional()
834
+ });
835
+ var ActionResultSchema = zod.z.object({
836
+ success: zod.z.boolean(),
837
+ transactionId: zod.z.string(),
838
+ chain: ChainTypeSchema,
839
+ /** The native chain operation that was executed */
840
+ chainOperation: zod.z.string(),
841
+ /** Additional context or notes about the operation */
842
+ notes: zod.z.array(zod.z.string()).optional(),
843
+ /** Timestamp of the operation */
844
+ timestamp: zod.z.date().optional()
845
+ });
846
+ ActionResultSchema.extend({
847
+ tokenId: zod.z.string(),
848
+ /** The capabilities that were enabled for this token */
849
+ enabledCapabilities: zod.z.array(zod.z.string())
850
+ });
851
+ var ValidatorSignatureSchema = zod.z.object({
852
+ /** Validator's node ID */
853
+ validatorId: zod.z.string(),
854
+ /** Validator's public key (hex-encoded) */
855
+ publicKey: zod.z.string(),
856
+ /** Signature over the transaction bytes (hex-encoded) */
857
+ signature: zod.z.string(),
858
+ /** When this signature was created */
859
+ signedAt: zod.z.date(),
860
+ /** Signature algorithm used */
861
+ algorithm: zod.z.enum(["ed25519", "ecdsa-secp256k1", "bls12-381"]).optional()
862
+ });
863
+ var HederaPreparedMetadataSchema = zod.z.object({
864
+ /** Hedera node account IDs that will process this transaction */
865
+ nodeAccountIds: zod.z.array(zod.z.string()).optional(),
866
+ /** Maximum transaction fee in tinybars */
867
+ maxTransactionFee: zod.z.string().optional(),
868
+ /** Transaction memo */
869
+ memo: zod.z.string().optional(),
870
+ /** Schedule info if this is a scheduled transaction */
871
+ scheduleInfo: zod.z.object({
872
+ scheduleId: zod.z.string(),
873
+ adminKey: zod.z.string().optional()
874
+ }).optional()
875
+ });
876
+ var XRPLPreparedMetadataSchema = zod.z.object({
877
+ /** Sequence number for this transaction */
878
+ sequence: zod.z.number().optional(),
879
+ /** Last ledger sequence for expiration */
880
+ lastLedgerSequence: zod.z.number().optional(),
881
+ /** Signer list info for multi-sig */
882
+ signerList: zod.z.array(
883
+ zod.z.object({
884
+ account: zod.z.string(),
885
+ signerWeight: zod.z.number()
886
+ })
887
+ ).optional(),
888
+ /** Quorum weight required */
889
+ signerQuorum: zod.z.number().optional()
890
+ });
891
+ var SolanaPreparedMetadataSchema = zod.z.object({
892
+ /** Recent blockhash for transaction validity */
893
+ recentBlockhash: zod.z.string().optional(),
894
+ /** Fee payer account */
895
+ feePayer: zod.z.string().optional(),
896
+ /** Program IDs involved */
897
+ programIds: zod.z.array(zod.z.string()).optional(),
898
+ /** Squads v4 multisig PDA address (partial/full modes) */
899
+ squadsMultisigPda: zod.z.string().optional(),
900
+ /** Squads v4 vault PDA address (partial/full modes) */
901
+ squadsVaultPda: zod.z.string().optional(),
902
+ /** Index of the vault transaction proposal */
903
+ squadsTransactionIndex: zod.z.number().optional(),
904
+ /** Proposal PDA address */
905
+ squadsProposalAddress: zod.z.string().optional(),
906
+ /** Whether the multisig was created in this call (vs already existed) */
907
+ multisigCreated: zod.z.boolean().optional(),
908
+ /** Security mode used to prepare this transaction */
909
+ securityMode: zod.z.enum(["none", "partial", "full"]).optional(),
910
+ /** SPL Token mint address (token-create and all SPL operations) */
911
+ splMint: zod.z.string().optional()
912
+ });
913
+ var PolkadotPreparedMetadataSchema = zod.z.object({
914
+ /** Era for transaction mortality */
915
+ era: zod.z.string().optional(),
916
+ /** Nonce for the sender */
917
+ nonce: zod.z.number().optional(),
918
+ /** Tip for priority */
919
+ tip: zod.z.string().optional(),
920
+ /** Spec version for runtime */
921
+ specVersion: zod.z.number().optional()
922
+ });
923
+ var ChainPreparedMetadataSchema = zod.z.union([
924
+ HederaPreparedMetadataSchema,
925
+ XRPLPreparedMetadataSchema,
926
+ SolanaPreparedMetadataSchema,
927
+ PolkadotPreparedMetadataSchema,
928
+ zod.z.record(zod.z.any())
929
+ // Allow extension for future chains
930
+ ]);
931
+ zod.z.object({
932
+ /** The blockchain this transaction is for */
933
+ chain: ChainTypeSchema,
934
+ /** Type of transaction (e.g., 'TokenCreate', 'Payment', 'NFTMint') */
935
+ transactionType: zod.z.string(),
936
+ /** Pre-assigned transaction ID for tracking */
937
+ transactionId: zod.z.string(),
938
+ /** Base64-encoded frozen transaction bytes ready for submission */
939
+ transactionBytes: zod.z.string(),
940
+ /** When this prepared transaction expires */
941
+ expiresAt: zod.z.date(),
942
+ /** Validator signatures collected for this transaction */
943
+ validatorSignatures: zod.z.array(ValidatorSignatureSchema),
944
+ /** Required payer account ID (caller must fund this account) */
945
+ payerAccountId: zod.z.string().optional(),
946
+ /** Estimated network fee */
947
+ estimatedFee: zod.z.string().optional(),
948
+ /** Number of signatures required for submission */
949
+ requiredSignatures: zod.z.number().optional(),
950
+ /** Whether the transaction has enough signatures to submit */
951
+ readyToSubmit: zod.z.boolean().default(false),
952
+ /** Chain-specific metadata */
953
+ metadata: ChainPreparedMetadataSchema.optional(),
954
+ /**
955
+ * Sovereignty metadata: the mode and (for partial/full) the on-chain
956
+ * authorization set the validator is binding to. Lets smart-apps and tests
957
+ * inspect the authorization topology without decoding chain-native bytes.
958
+ */
959
+ sovereignty: PreparedTransactionSovereigntySchema.optional()
960
+ });
961
+ zod.z.object({
962
+ /** The original transaction ID */
963
+ transactionId: zod.z.string(),
964
+ /** The blockchain */
965
+ chain: ChainTypeSchema,
966
+ /** Whether submission was successful */
967
+ success: zod.z.boolean(),
968
+ /** Consensus timestamp (Hedera) or ledger/block info */
969
+ consensusTimestamp: zod.z.string().optional(),
970
+ /** Block or ledger number */
971
+ blockNumber: zod.z.number().optional(),
972
+ /** Actual fee paid */
973
+ actualFee: zod.z.string().optional(),
974
+ /** Receipt or confirmation data */
975
+ receipt: zod.z.record(zod.z.any()).optional(),
976
+ /** Error message if submission failed */
977
+ error: zod.z.string().optional()
978
+ });
979
+ zod.z.object({
980
+ chain: zod.z.literal("hedera"),
981
+ payerAccountId: zod.z.string().optional(),
982
+ name: zod.z.string().min(1).max(100),
983
+ symbol: zod.z.string().min(1).max(10),
984
+ decimals: zod.z.number().int().min(0).max(18),
985
+ initialSupply: zod.z.string(),
986
+ treasuryAccountId: zod.z.string().min(1, "treasuryAccountId is required"),
987
+ memo: zod.z.string().optional(),
988
+ tokenType: zod.z.enum(["FUNGIBLE_COMMON", "NON_FUNGIBLE_UNIQUE"]).default("FUNGIBLE_COMMON"),
989
+ supplyKey: zod.z.string().optional(),
990
+ adminKey: zod.z.string().optional(),
991
+ pauseKey: zod.z.string().optional(),
992
+ freezeKey: zod.z.string().optional(),
993
+ kycKey: zod.z.string().optional(),
994
+ wipeKey: zod.z.string().optional(),
995
+ validatorTimestamp: zod.z.string().min(1),
996
+ validatorTopicId: zod.z.string().min(1)
997
+ }).merge(SovereigntyFieldsRawSchema).refine(sovereigntyRefinePredicate, { message: SOVEREIGNTY_REFINE_MESSAGE });
998
+ zod.z.object({
999
+ chain: zod.z.literal("xrpl"),
1000
+ payerAccountId: zod.z.string().optional(),
1001
+ // User's XRPL account whose authorization we're configuring.
1002
+ accountAddress: zod.z.string().min(25).max(34),
1003
+ validatorTimestamp: zod.z.string().min(1),
1004
+ validatorTopicId: zod.z.string().min(1)
1005
+ }).merge(SovereigntyFieldsRawSchema).refine(sovereigntyRefinePredicate, { message: SOVEREIGNTY_REFINE_MESSAGE });
1006
+ zod.z.object({
1007
+ chain: zod.z.literal("stellar"),
1008
+ payerAccountId: zod.z.string().optional(),
1009
+ // The master public key of the new Stellar account.
1010
+ publicKey: zod.z.string().min(56).max(56),
1011
+ startingBalance: zod.z.string().regex(/^\d+(\.\d+)?$/),
1012
+ validatorTimestamp: zod.z.string().min(1),
1013
+ validatorTopicId: zod.z.string().min(1)
1014
+ }).merge(SovereigntyFieldsRawSchema).refine(
1015
+ (v) => {
1016
+ if (v.securityMode === "partial" || v.securityMode === "full") {
1017
+ return !!v.entityId;
1018
+ }
1019
+ return true;
1020
+ },
1021
+ { message: "securityMode='partial'/'full' requires entityId" }
1022
+ );
1023
+
1024
+ // src/discovery/index.ts
1025
+ var discovery_exports = {};
1026
+ __export(discovery_exports, {
1027
+ MIRROR_NODE_URLS: () => MIRROR_NODE_URLS,
1028
+ MirrorNodeClient: () => MirrorNodeClient,
1029
+ MirrorNodeError: () => MirrorNodeError,
1030
+ ValidatorDiscoveryClient: () => ValidatorDiscoveryClient
1031
+ });
1032
+
1033
+ // src/discovery/mirror-node.ts
1034
+ function validateUrl(url, allowInsecure = false) {
1035
+ try {
1036
+ const parsed = new URL(url);
1037
+ if (!["http:", "https:"].includes(parsed.protocol)) {
1038
+ throw new Error(`Invalid protocol: ${parsed.protocol}`);
1039
+ }
1040
+ if (!allowInsecure && parsed.protocol !== "https:") {
1041
+ throw new Error(
1042
+ "HTTPS is required for secure connections. Set allowInsecure=true to override."
1043
+ );
1044
+ }
1045
+ const hostname = parsed.hostname.toLowerCase();
1046
+ const blockedPatterns = [
1047
+ /^localhost$/i,
1048
+ /^127\./,
1049
+ /^10\./,
1050
+ /^172\.(1[6-9]|2[0-9]|3[01])\./,
1051
+ /^192\.168\./,
1052
+ /^169\.254\./,
1053
+ /^::1$/,
1054
+ /^fe80:/i,
1055
+ /^fc00:/i,
1056
+ /^fd00:/i
1057
+ ];
1058
+ const isPrivate = blockedPatterns.some((pattern) => pattern.test(hostname));
1059
+ if (isPrivate && !allowInsecure) {
1060
+ throw new Error(
1061
+ "Private/internal URLs are blocked. Set allowInsecure=true for local development."
1062
+ );
1063
+ }
1064
+ return parsed;
1065
+ } catch (error) {
1066
+ if (error instanceof Error && error.message.includes("Invalid URL")) {
1067
+ throw new MirrorNodeError(`Invalid URL format: ${url}`, 400);
1068
+ }
1069
+ throw error;
1070
+ }
1071
+ }
1072
+ function validateTopicId(topicId) {
1073
+ if (!/^\d+\.\d+\.\d+$/.test(topicId)) {
1074
+ throw new MirrorNodeError(
1075
+ `Invalid topic ID format: ${topicId}. Expected format: 0.0.123456`,
1076
+ 400
1077
+ );
1078
+ }
1079
+ }
1080
+ var MIRROR_NODE_URLS = {
1081
+ mainnet: "https://mainnet-public.mirrornode.hedera.com",
1082
+ testnet: "https://testnet.mirrornode.hedera.com",
1083
+ previewnet: "https://previewnet.mirrornode.hedera.com"
1084
+ };
1085
+ var MirrorNodeClient = class _MirrorNodeClient {
1086
+ baseUrl;
1087
+ timeout;
1088
+ allowInsecure;
1089
+ constructor(config) {
1090
+ this.allowInsecure = config.allowInsecure ?? false;
1091
+ const validatedUrl = validateUrl(config.baseUrl, this.allowInsecure);
1092
+ this.baseUrl = validatedUrl.origin;
1093
+ this.timeout = config.timeout || 3e4;
1094
+ }
1095
+ /**
1096
+ * Create client for a specific network
1097
+ */
1098
+ static forNetwork(network) {
1099
+ const baseUrl = MIRROR_NODE_URLS[network];
1100
+ if (!baseUrl) {
1101
+ throw new Error(`Unknown network: ${network}`);
1102
+ }
1103
+ return new _MirrorNodeClient({ baseUrl });
1104
+ }
1105
+ /**
1106
+ * Get topic messages from mirror node
1107
+ *
1108
+ * @param topicId - HCS topic ID (e.g., '0.0.123456')
1109
+ * @param options - Query options
1110
+ * @returns Topic messages
1111
+ */
1112
+ async getTopicMessages(topicId, options) {
1113
+ validateTopicId(topicId);
1114
+ const params = new URLSearchParams();
1115
+ if (options?.limit) {
1116
+ params.set("limit", options.limit.toString());
1117
+ }
1118
+ if (options?.order) {
1119
+ params.set("order", options.order);
1120
+ }
1121
+ if (options?.timestampStart) {
1122
+ params.set("timestamp", `gte:${options.timestampStart}`);
1123
+ }
1124
+ if (options?.timestampEnd) {
1125
+ params.set("timestamp", `lte:${options.timestampEnd}`);
1126
+ }
1127
+ if (options?.sequenceNumberStart) {
1128
+ params.set("sequencenumber", `gte:${options.sequenceNumberStart}`);
1129
+ }
1130
+ const url = `${this.baseUrl}/api/v1/topics/${topicId}/messages?${params.toString()}`;
1131
+ const controller = new AbortController();
1132
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1133
+ try {
1134
+ const response = await fetch(url, {
1135
+ method: "GET",
1136
+ headers: {
1137
+ Accept: "application/json"
1138
+ },
1139
+ signal: controller.signal
1140
+ });
1141
+ clearTimeout(timeoutId);
1142
+ if (!response.ok) {
1143
+ throw new MirrorNodeError(
1144
+ `Mirror node error: ${response.status} ${response.statusText}`,
1145
+ response.status
1146
+ );
1147
+ }
1148
+ const data = await response.json();
1149
+ return data.messages;
1150
+ } catch (error) {
1151
+ clearTimeout(timeoutId);
1152
+ if (error instanceof MirrorNodeError) {
1153
+ throw error;
1154
+ }
1155
+ const err = error;
1156
+ if (err.name === "AbortError") {
1157
+ throw new MirrorNodeError("Mirror node request timeout", 408);
1158
+ }
1159
+ throw new MirrorNodeError(`Mirror node network error: ${err.message}`, 0);
1160
+ }
1161
+ }
1162
+ /**
1163
+ * Get all topic messages with pagination
1164
+ *
1165
+ * @param topicId - HCS topic ID
1166
+ * @param maxMessages - Maximum messages to fetch (default: 1000)
1167
+ * @returns All topic messages
1168
+ */
1169
+ async getAllTopicMessages(topicId, maxMessages = 1e3) {
1170
+ validateTopicId(topicId);
1171
+ const safeMaxMessages = Math.min(maxMessages, 1e4);
1172
+ const allMessages = [];
1173
+ let nextPath = `/api/v1/topics/${topicId}/messages?limit=100&order=desc`;
1174
+ while (nextPath && allMessages.length < safeMaxMessages) {
1175
+ const controller = new AbortController();
1176
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1177
+ try {
1178
+ const fullUrl = `${this.baseUrl}${nextPath}`;
1179
+ const response = await fetch(fullUrl, {
1180
+ method: "GET",
1181
+ headers: { Accept: "application/json" },
1182
+ signal: controller.signal
1183
+ });
1184
+ clearTimeout(timeoutId);
1185
+ if (!response.ok) {
1186
+ throw new MirrorNodeError(
1187
+ `Mirror node error: ${response.status} ${response.statusText}`,
1188
+ response.status
1189
+ );
1190
+ }
1191
+ const data = await response.json();
1192
+ allMessages.push(...data.messages);
1193
+ if (data.links.next) {
1194
+ const nextLink = data.links.next;
1195
+ if (nextLink.startsWith("/api/v1/topics/")) {
1196
+ nextPath = nextLink;
1197
+ } else {
1198
+ nextPath = void 0;
1199
+ }
1200
+ } else {
1201
+ nextPath = void 0;
1202
+ }
1203
+ } catch (error) {
1204
+ clearTimeout(timeoutId);
1205
+ if (error instanceof MirrorNodeError) {
1206
+ throw error;
1207
+ }
1208
+ const err = error;
1209
+ throw new MirrorNodeError(`Mirror node error: ${err.message}`, 0);
1210
+ }
1211
+ }
1212
+ return allMessages.slice(0, safeMaxMessages);
1213
+ }
1214
+ /**
1215
+ * Decode base64 message content
1216
+ */
1217
+ static decodeMessage(base64Message) {
1218
+ if (typeof Buffer !== "undefined") {
1219
+ return Buffer.from(base64Message, "base64").toString("utf-8");
1220
+ }
1221
+ return atob(base64Message);
1222
+ }
1223
+ };
1224
+ var MirrorNodeError = class extends Error {
1225
+ constructor(message, statusCode) {
1226
+ super(message);
1227
+ this.statusCode = statusCode;
1228
+ this.name = "MirrorNodeError";
1229
+ }
1230
+ statusCode;
1231
+ };
1232
+
1233
+ // src/discovery/validator-discovery.ts
1234
+ var ValidatorDiscoveryClient = class {
1235
+ mirrorNode;
1236
+ registryTopicId;
1237
+ cacheTtlMs;
1238
+ cache = null;
1239
+ constructor(config) {
1240
+ const mirrorNodeUrl = config.mirrorNodeUrl || MIRROR_NODE_URLS[config.network];
1241
+ if (!mirrorNodeUrl) {
1242
+ throw new Error(`Unknown network: ${config.network}`);
1243
+ }
1244
+ this.mirrorNode = new MirrorNodeClient({
1245
+ baseUrl: mirrorNodeUrl,
1246
+ allowInsecure: config.allowInsecure
1247
+ });
1248
+ this.registryTopicId = config.registryTopicId;
1249
+ this.cacheTtlMs = config.cacheTtlMs ?? 6e4;
1250
+ }
1251
+ /**
1252
+ * Get all active validators from the registry
1253
+ *
1254
+ * Results are cached for efficiency. Use `forceRefresh` to bypass cache.
1255
+ *
1256
+ * @param forceRefresh - Force refresh from mirror node
1257
+ * @returns List of active validators
1258
+ */
1259
+ async getValidators(forceRefresh = false) {
1260
+ if (!forceRefresh && this.cache && this.isCacheValid()) {
1261
+ return this.cache.validators;
1262
+ }
1263
+ const messages = await this.mirrorNode.getAllTopicMessages(
1264
+ this.registryTopicId,
1265
+ 500
1266
+ // Max messages to fetch
1267
+ );
1268
+ const validatorMap = /* @__PURE__ */ new Map();
1269
+ const leftValidators = /* @__PURE__ */ new Set();
1270
+ for (const msg of messages) {
1271
+ try {
1272
+ const content = MirrorNodeClient.decodeMessage(msg.message);
1273
+ const raw = JSON.parse(content);
1274
+ const entry = normalizeRegistryEntry(raw);
1275
+ if (!entry) continue;
1276
+ if (entry.messageType === "validator.leave") {
1277
+ leftValidators.add(entry.nodeId);
1278
+ continue;
1279
+ }
1280
+ if (leftValidators.has(entry.nodeId)) {
1281
+ continue;
1282
+ }
1283
+ if (!validatorMap.has(entry.nodeId)) {
1284
+ validatorMap.set(entry.nodeId, entry);
1285
+ }
1286
+ } catch {
1287
+ continue;
1288
+ }
1289
+ }
1290
+ const validators = Array.from(validatorMap.values());
1291
+ this.cache = {
1292
+ validators,
1293
+ lastUpdated: Date.now()
1294
+ };
1295
+ return validators;
1296
+ }
1297
+ /**
1298
+ * Get validators with API endpoints available
1299
+ *
1300
+ * @param forceRefresh - Force refresh from mirror node
1301
+ * @returns Validators with apiEndpoint configured
1302
+ */
1303
+ async getValidatorsWithEndpoints(forceRefresh = false) {
1304
+ const validators = await this.getValidators(forceRefresh);
1305
+ return validators.filter((v) => v.networkEndpoints?.apiEndpoint);
1306
+ }
1307
+ /**
1308
+ * Get a random validator from the registry
1309
+ *
1310
+ * @param forceRefresh - Force refresh from mirror node
1311
+ * @returns Random validator info or null if none available
1312
+ */
1313
+ async getRandomValidator(forceRefresh = false) {
1314
+ const validators = await this.getValidatorsWithEndpoints(forceRefresh);
1315
+ if (validators.length === 0) {
1316
+ return null;
1317
+ }
1318
+ const randomBytes = new Uint32Array(1);
1319
+ crypto.getRandomValues(randomBytes);
1320
+ const randomIndex = randomBytes[0] % validators.length;
1321
+ return validators[randomIndex];
1322
+ }
1323
+ /**
1324
+ * Get a random validator API endpoint URL
1325
+ *
1326
+ * @param forceRefresh - Force refresh from mirror node
1327
+ * @returns Random validator API URL or null if none available
1328
+ */
1329
+ async getRandomValidatorUrl(forceRefresh = false) {
1330
+ const validator = await this.getRandomValidator(forceRefresh);
1331
+ return validator?.networkEndpoints?.apiEndpoint ?? null;
1332
+ }
1333
+ /**
1334
+ * Get validator by node ID
1335
+ *
1336
+ * @param nodeId - Validator node ID (e.g., 'validator-1')
1337
+ * @param forceRefresh - Force refresh from mirror node
1338
+ * @returns Validator info or null if not found
1339
+ */
1340
+ async getValidatorByNodeId(nodeId, forceRefresh = false) {
1341
+ const validators = await this.getValidators(forceRefresh);
1342
+ return validators.find((v) => v.nodeId === nodeId) ?? null;
1343
+ }
1344
+ /**
1345
+ * Get validators by capability
1346
+ *
1347
+ * @param capability - Required capability (e.g., 'hedera', 'xrpl', 'dkg')
1348
+ * @param forceRefresh - Force refresh from mirror node
1349
+ * @returns Validators with the specified capability
1350
+ */
1351
+ async getValidatorsByCapability(capability, forceRefresh = false) {
1352
+ const validators = await this.getValidatorsWithEndpoints(forceRefresh);
1353
+ return validators.filter((v) => v.capabilities?.includes(capability));
1354
+ }
1355
+ /**
1356
+ * Clear the validator cache
1357
+ */
1358
+ clearCache() {
1359
+ this.cache = null;
1360
+ }
1361
+ /**
1362
+ * Check if cache is still valid
1363
+ */
1364
+ isCacheValid() {
1365
+ if (!this.cache) return false;
1366
+ return Date.now() - this.cache.lastUpdated < this.cacheTtlMs;
1367
+ }
1368
+ };
1369
+ function normalizeRegistryEntry(raw) {
1370
+ if (raw.messageType && typeof raw.nodeId === "string") {
1371
+ return raw;
1372
+ }
1373
+ if (raw.type === "validator.register") {
1374
+ if (raw.validatorType && raw.validatorType !== void 0 && raw.validatorType !== null) {
1375
+ if (typeof raw.validatorType === "string" && raw.validatorType !== "node") {
1376
+ return null;
1377
+ }
1378
+ }
1379
+ const nodeId = typeof raw.validatorId === "string" && raw.validatorId || typeof raw.nodeId === "string" && raw.nodeId || null;
1380
+ if (!nodeId) return null;
1381
+ const endpoint = typeof raw.endpoint === "string" ? raw.endpoint : void 0;
1382
+ if (!endpoint) return null;
1383
+ const capabilities = Array.isArray(raw.capabilities) ? raw.capabilities.filter((c) => typeof c === "string") : void 0;
1384
+ return {
1385
+ validatorTimestamp: typeof raw.timestamp === "string" ? raw.timestamp : "",
1386
+ nodeId,
1387
+ type: "consensus",
1388
+ networkEndpoints: { apiEndpoint: endpoint },
1389
+ publicKey: typeof raw.publicKey === "string" ? raw.publicKey : void 0,
1390
+ capabilities,
1391
+ metadata: {},
1392
+ registeredAt: typeof raw.timestamp === "string" ? raw.timestamp : "",
1393
+ messageType: "validator.join"
1394
+ };
1395
+ }
1396
+ return null;
1397
+ }
1398
+
1399
+ // src/auth/index.ts
1400
+ var auth_exports = {};
1401
+ __export(auth_exports, {
1402
+ ValidatorAuthClient: () => ValidatorAuthClient,
1403
+ ValidatorAuthError: () => ValidatorAuthError
1404
+ });
1405
+
1406
+ // src/auth/validator-auth.ts
1407
+ var SUPPORTED_AUTH_CHAINS = [
1408
+ "hedera",
1409
+ "xrpl",
1410
+ "polkadot",
1411
+ "stellar",
1412
+ "solana"
1413
+ ];
1414
+ function validateValidatorUrl(url, allowInsecure = false) {
1415
+ try {
1416
+ const parsed = new URL(url);
1417
+ if (!["http:", "https:"].includes(parsed.protocol)) {
1418
+ throw new ValidatorAuthError(`Invalid protocol: ${parsed.protocol}`, 400);
1419
+ }
1420
+ if (!allowInsecure && parsed.protocol !== "https:") {
1421
+ throw new ValidatorAuthError(
1422
+ "HTTPS is required for validator connections. Set allowInsecure=true for local development.",
1423
+ 400
1424
+ );
1425
+ }
1426
+ const hostname = parsed.hostname.toLowerCase();
1427
+ const isLocalhost = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
1428
+ if (isLocalhost && !allowInsecure) {
1429
+ throw new ValidatorAuthError(
1430
+ "Localhost connections blocked in secure mode. Set allowInsecure=true for local development.",
1431
+ 400
1432
+ );
1433
+ }
1434
+ return parsed.origin;
1435
+ } catch (error) {
1436
+ if (error instanceof ValidatorAuthError) {
1437
+ throw error;
1438
+ }
1439
+ throw new ValidatorAuthError(`Invalid validator URL: ${url}`, 400);
1440
+ }
1441
+ }
1442
+ function sanitizeInput(input, fieldName, maxLength = 256) {
1443
+ if (typeof input !== "string") {
1444
+ throw new ValidatorAuthError(`${fieldName} must be a string`, 400);
1445
+ }
1446
+ if (input.length > maxLength) {
1447
+ throw new ValidatorAuthError(`${fieldName} exceeds maximum length of ${maxLength}`, 400);
1448
+ }
1449
+ return input.replace(/[\x00-\x1F\x7F]/g, "");
1450
+ }
1451
+ var ValidatorAuthClient = class {
1452
+ timeout;
1453
+ allowInsecure;
1454
+ constructor(config) {
1455
+ this.timeout = config?.timeout ?? 3e4;
1456
+ this.allowInsecure = config?.security?.allowInsecure ?? false;
1457
+ }
1458
+ /**
1459
+ * Request authentication challenge from validator
1460
+ *
1461
+ * @param validatorUrl - Validator API base URL
1462
+ * @param chain - Blockchain type
1463
+ * @param address - Wallet address
1464
+ * @returns Challenge to sign
1465
+ */
1466
+ async requestChallenge(validatorUrl, chain, address) {
1467
+ const safeUrl = validateValidatorUrl(validatorUrl, this.allowInsecure);
1468
+ const safeAddress = sanitizeInput(address, "address", 128);
1469
+ if (!SUPPORTED_AUTH_CHAINS.includes(chain)) {
1470
+ throw new ValidatorAuthError(`Invalid chain type: ${chain}`, 400);
1471
+ }
1472
+ const url = `${safeUrl}/auth/validator/challenge`;
1473
+ const controller = new AbortController();
1474
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1475
+ try {
1476
+ const response = await fetch(url, {
1477
+ method: "POST",
1478
+ headers: {
1479
+ "Content-Type": "application/json"
1480
+ },
1481
+ body: JSON.stringify({ chain, address: safeAddress }),
1482
+ signal: controller.signal
1483
+ });
1484
+ clearTimeout(timeoutId);
1485
+ if (!response.ok) {
1486
+ const error = await response.json().catch(() => ({}));
1487
+ throw new ValidatorAuthError(
1488
+ `Challenge request failed: ${response.status} ${response.statusText}`,
1489
+ response.status,
1490
+ error
1491
+ );
1492
+ }
1493
+ return await response.json();
1494
+ } catch (error) {
1495
+ clearTimeout(timeoutId);
1496
+ if (error instanceof ValidatorAuthError) {
1497
+ throw error;
1498
+ }
1499
+ const err = error;
1500
+ if (err.name === "AbortError") {
1501
+ throw new ValidatorAuthError("Challenge request timeout", 408);
1502
+ }
1503
+ throw new ValidatorAuthError(`Challenge request failed: ${err.message}`, 0);
1504
+ }
1505
+ }
1506
+ /**
1507
+ * Authenticate with signed challenge
1508
+ *
1509
+ * @param validatorUrl - Validator API base URL
1510
+ * @param request - Authentication request with signature
1511
+ * @returns Session token and info
1512
+ */
1513
+ async authenticate(validatorUrl, request) {
1514
+ const safeUrl = validateValidatorUrl(validatorUrl, this.allowInsecure);
1515
+ const sanitizedRequest = {
1516
+ chain: request.chain,
1517
+ address: sanitizeInput(request.address, "address", 128),
1518
+ publicKey: sanitizeInput(request.publicKey, "publicKey", 512),
1519
+ signature: sanitizeInput(request.signature, "signature", 1024),
1520
+ challenge: sanitizeInput(request.challenge, "challenge", 512),
1521
+ metadata: request.metadata ? {
1522
+ nodeId: request.metadata.nodeId ? sanitizeInput(request.metadata.nodeId, "nodeId", 64) : void 0,
1523
+ endpoint: request.metadata.endpoint ? sanitizeInput(request.metadata.endpoint, "endpoint", 256) : void 0,
1524
+ capabilities: request.metadata.capabilities,
1525
+ appId: request.metadata.appId ? sanitizeInput(request.metadata.appId, "appId", 64) : void 0,
1526
+ appName: request.metadata.appName ? sanitizeInput(request.metadata.appName, "appName", 128) : void 0
1527
+ } : void 0
1528
+ };
1529
+ if (!SUPPORTED_AUTH_CHAINS.includes(sanitizedRequest.chain)) {
1530
+ throw new ValidatorAuthError(`Invalid chain type: ${sanitizedRequest.chain}`, 400);
1531
+ }
1532
+ if (!/^[0-9a-fA-F]+$/.test(sanitizedRequest.signature.replace(/_.*$/, ""))) {
1533
+ throw new ValidatorAuthError("Invalid signature format: must be hex encoded", 400);
1534
+ }
1535
+ const url = `${safeUrl}/auth/validator/authenticate`;
1536
+ const controller = new AbortController();
1537
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1538
+ try {
1539
+ const response = await fetch(url, {
1540
+ method: "POST",
1541
+ headers: {
1542
+ "Content-Type": "application/json"
1543
+ },
1544
+ body: JSON.stringify(sanitizedRequest),
1545
+ signal: controller.signal
1546
+ });
1547
+ clearTimeout(timeoutId);
1548
+ if (!response.ok) {
1549
+ const error = await response.json().catch(() => ({}));
1550
+ throw new ValidatorAuthError(
1551
+ `Authentication failed: ${response.status} ${response.statusText}`,
1552
+ response.status,
1553
+ error
1554
+ );
1555
+ }
1556
+ return await response.json();
1557
+ } catch (error) {
1558
+ clearTimeout(timeoutId);
1559
+ if (error instanceof ValidatorAuthError) {
1560
+ throw error;
1561
+ }
1562
+ const err = error;
1563
+ if (err.name === "AbortError") {
1564
+ throw new ValidatorAuthError("Authentication request timeout", 408);
1565
+ }
1566
+ throw new ValidatorAuthError(`Authentication failed: ${err.message}`, 0);
1567
+ }
1568
+ }
1569
+ /**
1570
+ * Get current session info
1571
+ *
1572
+ * @param validatorUrl - Validator API base URL
1573
+ * @param token - Session token
1574
+ * @returns Session information
1575
+ */
1576
+ async getSession(validatorUrl, token) {
1577
+ const safeUrl = validateValidatorUrl(validatorUrl, this.allowInsecure);
1578
+ const safeToken = sanitizeInput(token, "token", 2048);
1579
+ const url = `${safeUrl}/auth/validator/session`;
1580
+ const controller = new AbortController();
1581
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1582
+ try {
1583
+ const response = await fetch(url, {
1584
+ method: "GET",
1585
+ headers: {
1586
+ Authorization: `Bearer ${safeToken}`
1587
+ },
1588
+ signal: controller.signal
1589
+ });
1590
+ clearTimeout(timeoutId);
1591
+ if (!response.ok) {
1592
+ const error = await response.json().catch(() => ({}));
1593
+ throw new ValidatorAuthError(
1594
+ `Session request failed: ${response.status} ${response.statusText}`,
1595
+ response.status,
1596
+ error
1597
+ );
1598
+ }
1599
+ return await response.json();
1600
+ } catch (error) {
1601
+ clearTimeout(timeoutId);
1602
+ if (error instanceof ValidatorAuthError) {
1603
+ throw error;
1604
+ }
1605
+ const err = error;
1606
+ if (err.name === "AbortError") {
1607
+ throw new ValidatorAuthError("Session request timeout", 408);
1608
+ }
1609
+ throw new ValidatorAuthError(`Session request failed: ${err.message}`, 0);
1610
+ }
1611
+ }
1612
+ /**
1613
+ * Sign challenge with Hedera private key
1614
+ *
1615
+ * @param challenge - Challenge string from validator
1616
+ * @param privateKey - Hedera PrivateKey instance from @hashgraph/sdk
1617
+ * @returns Hex-encoded signature
1618
+ */
1619
+ signChallengeHedera(challenge, privateKey) {
1620
+ const messageBytes = Buffer.from(challenge, "utf-8");
1621
+ const signature = privateKey.sign(messageBytes);
1622
+ return Buffer.from(signature).toString("hex");
1623
+ }
1624
+ /**
1625
+ * Sign challenge with XRPL wallet
1626
+ *
1627
+ * @param challenge - Challenge string from validator
1628
+ * @param wallet - XRPL Wallet instance from xrpl library
1629
+ * @returns Hex-encoded signature
1630
+ */
1631
+ signChallengeXRPL(challenge, wallet) {
1632
+ const signature = wallet.sign(challenge);
1633
+ if (typeof signature === "string" && /^[0-9A-Fa-f]+$/.test(signature)) {
1634
+ return signature;
1635
+ }
1636
+ return Buffer.from(signature).toString("hex");
1637
+ }
1638
+ /**
1639
+ * Complete authentication flow in one call
1640
+ *
1641
+ * @param validatorUrl - Validator API base URL
1642
+ * @param chain - Blockchain type
1643
+ * @param address - Wallet address
1644
+ * @param publicKey - Public key (hex)
1645
+ * @param signFn - Function to sign the challenge
1646
+ * @param metadata - Optional metadata
1647
+ * @returns Session token and info
1648
+ */
1649
+ async authenticateWithSigner(validatorUrl, chain, address, publicKey, signFn, metadata) {
1650
+ const challengeResponse = await this.requestChallenge(validatorUrl, chain, address);
1651
+ const signature = await signFn(challengeResponse.challenge);
1652
+ return this.authenticate(validatorUrl, {
1653
+ chain,
1654
+ address,
1655
+ publicKey,
1656
+ signature,
1657
+ challenge: challengeResponse.challenge,
1658
+ metadata
1659
+ });
1660
+ }
1661
+ };
1662
+ var ValidatorAuthError = class extends Error {
1663
+ constructor(message, statusCode, details) {
1664
+ super(message);
1665
+ this.statusCode = statusCode;
1666
+ this.details = details;
1667
+ this.name = "ValidatorAuthError";
1668
+ }
1669
+ statusCode;
1670
+ details;
1671
+ };
1672
+
1673
+ // src/http/index.ts
1674
+ var SdkHttpError = class extends Error {
1675
+ constructor(message, statusCode, details) {
1676
+ super(message);
1677
+ this.statusCode = statusCode;
1678
+ this.details = details;
1679
+ this.name = "SdkHttpError";
1680
+ }
1681
+ statusCode;
1682
+ details;
1683
+ };
1684
+ function createHttpClient(config) {
1685
+ const timeout = config.timeout ?? 3e4;
1686
+ function getHeaders(contentType) {
1687
+ const headers = {};
1688
+ {
1689
+ headers["Content-Type"] = contentType;
1690
+ }
1691
+ if (config.authToken) {
1692
+ headers["Authorization"] = `Bearer ${config.authToken}`;
1693
+ }
1694
+ if (config.apiKey) {
1695
+ headers["X-API-Key"] = config.apiKey;
1696
+ }
1697
+ return headers;
1698
+ }
1699
+ function setAuthToken(token) {
1700
+ config.authToken = token;
1701
+ }
1702
+ async function request(method, path, body) {
1703
+ const url = `${config.baseUrl}${path}`;
1704
+ const controller = new AbortController();
1705
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1706
+ try {
1707
+ const init = {
1708
+ method,
1709
+ headers: getHeaders("application/json"),
1710
+ signal: controller.signal
1711
+ };
1712
+ if (body !== void 0) {
1713
+ init.body = JSON.stringify(body);
1714
+ }
1715
+ const response = await fetch(url, init);
1716
+ clearTimeout(timeoutId);
1717
+ if (!response.ok) {
1718
+ const errorData = await response.json().catch(() => ({}));
1719
+ throw new SdkHttpError(
1720
+ errorData.message || `API error: ${response.status} ${response.statusText}`,
1721
+ response.status,
1722
+ errorData
1723
+ );
1724
+ }
1725
+ const text = await response.text();
1726
+ if (!text) return void 0;
1727
+ return JSON.parse(text);
1728
+ } catch (error) {
1729
+ clearTimeout(timeoutId);
1730
+ if (error instanceof SdkHttpError) throw error;
1731
+ const err = error;
1732
+ if (err.name === "AbortError") {
1733
+ throw new SdkHttpError("Request timeout", 408);
1734
+ }
1735
+ throw new SdkHttpError(`Network error: ${err.message}`, 0, error);
1736
+ }
1737
+ }
1738
+ async function upload(path, file, filename, metadata) {
1739
+ const url = `${config.baseUrl}${path}`;
1740
+ const controller = new AbortController();
1741
+ const timeoutId = setTimeout(() => controller.abort(), timeout * 2);
1742
+ try {
1743
+ const formData = new FormData();
1744
+ const blob = file instanceof Blob ? file : new Blob([new Uint8Array(file)]);
1745
+ formData.append("file", blob, filename);
1746
+ if (metadata) {
1747
+ for (const [key, value] of Object.entries(metadata)) {
1748
+ formData.append(key, value);
1749
+ }
1750
+ }
1751
+ const headers = {};
1752
+ if (config.authToken) {
1753
+ headers["Authorization"] = `Bearer ${config.authToken}`;
1754
+ }
1755
+ if (config.apiKey) {
1756
+ headers["X-API-Key"] = config.apiKey;
1757
+ }
1758
+ const response = await fetch(url, {
1759
+ method: "POST",
1760
+ headers,
1761
+ body: formData,
1762
+ signal: controller.signal
1763
+ });
1764
+ clearTimeout(timeoutId);
1765
+ if (!response.ok) {
1766
+ const errorData = await response.json().catch(() => ({}));
1767
+ throw new SdkHttpError(
1768
+ errorData.message || `Upload error: ${response.status} ${response.statusText}`,
1769
+ response.status,
1770
+ errorData
1771
+ );
1772
+ }
1773
+ return response.json();
1774
+ } catch (error) {
1775
+ clearTimeout(timeoutId);
1776
+ if (error instanceof SdkHttpError) throw error;
1777
+ const err = error;
1778
+ if (err.name === "AbortError") {
1779
+ throw new SdkHttpError("Upload timeout", 408);
1780
+ }
1781
+ throw new SdkHttpError(`Upload error: ${err.message}`, 0, error);
1782
+ }
1783
+ }
1784
+ const client = {
1785
+ post: (path, body) => request("POST", path, body),
1786
+ get: (path) => request("GET", path),
1787
+ put: (path, body) => request("PUT", path, body),
1788
+ delete: (path) => request("DELETE", path),
1789
+ upload,
1790
+ setAuthToken
1791
+ };
1792
+ return client;
1793
+ }
1794
+ function encodePathParam(param) {
1795
+ return encodeURIComponent(param).replace(/%2F/gi, "");
1796
+ }
1797
+
1798
+ // src/subscription/index.ts
1799
+ var subscription_exports = {};
1800
+ __export(subscription_exports, {
1801
+ SubscriptionClient: () => SubscriptionClient
1802
+ });
1803
+ var SubscriptionClient = class {
1804
+ constructor(http) {
1805
+ this.http = http;
1806
+ }
1807
+ http;
1808
+ /**
1809
+ * Request a new subscription.
1810
+ * Creates a deposit wallet and returns deposit instructions.
1811
+ */
1812
+ async request(request) {
1813
+ return this.http.post("/subscription/request", request);
1814
+ }
1815
+ /**
1816
+ * Get subscription status by app ID
1817
+ */
1818
+ async getStatus(appId) {
1819
+ return this.http.get(`/subscription/status/${encodeURIComponent(appId)}`);
1820
+ }
1821
+ /**
1822
+ * Mint subscription NFT after deposit is confirmed
1823
+ */
1824
+ async mintNft(appId) {
1825
+ return this.http.post(`/subscription/mint/${encodeURIComponent(appId)}`, {});
1826
+ }
1827
+ /**
1828
+ * Renew subscription by extending period
1829
+ */
1830
+ async renew(request) {
1831
+ return this.http.post("/subscription/renew", request);
1832
+ }
1833
+ /**
1834
+ * Fetch available subscription tiers from the network.
1835
+ *
1836
+ * Use this instead of hard-coding tier names -- the validator returns the
1837
+ * canonical list of tiers together with pricing, limits, and features.
1838
+ *
1839
+ * @returns Array of {@link SubscriptionTierInfo} objects.
1840
+ *
1841
+ * @example
1842
+ * ```typescript
1843
+ * const tiers = await subscription.getTiers();
1844
+ * console.log(tiers.map(t => `${t.name}: $${t.priceUsd}/mo`));
1845
+ * ```
1846
+ */
1847
+ async getTiers() {
1848
+ try {
1849
+ return await this.http.get("/subscription/tiers");
1850
+ } catch (err) {
1851
+ const isNotFound = err != null && typeof err === "object" && "statusCode" in err && err.statusCode === 404;
1852
+ if (!isNotFound) throw err;
1853
+ const cfg = await this.http.get("/subscription/config");
1854
+ return (cfg.availableTiers || []).map((raw) => {
1855
+ const tier = raw.tier ?? raw.name;
1856
+ const displayName = raw.name ?? raw.displayName ?? String(tier);
1857
+ const monthlyPriceHsuite = Number(
1858
+ raw.monthlyPriceHsuite ?? raw.depositAmount ?? 0
1859
+ );
1860
+ const apiCallsPerDay = Number(raw.apiCallsPerDay ?? 0);
1861
+ const rawNetworks = raw.allowedNetworks ?? raw.supportedNetworks ?? [];
1862
+ const supportedNetworks = rawNetworks.some(
1863
+ (n) => n === "mainnet"
1864
+ ) ? ["hedera", "xrpl"] : ["hedera"];
1865
+ return {
1866
+ name: tier,
1867
+ displayName,
1868
+ description: raw.description ?? `${displayName} tier`,
1869
+ priceUsd: Number(raw.priceUsd ?? 0),
1870
+ depositAmount: String(monthlyPriceHsuite),
1871
+ apiCallsPerDay: Number.isFinite(apiCallsPerDay) ? apiCallsPerDay : Number.MAX_SAFE_INTEGER,
1872
+ supportedNetworks,
1873
+ features: raw.features ?? []
1874
+ };
1875
+ });
1876
+ }
1877
+ }
1878
+ /**
1879
+ * Get subscription configuration
1880
+ */
1881
+ async getConfig() {
1882
+ return this.http.get("/subscription/config");
1883
+ }
1884
+ /**
1885
+ * List all subscriptions
1886
+ */
1887
+ async list() {
1888
+ return this.http.get("/subscription/list");
1889
+ }
1890
+ /**
1891
+ * List subscriptions by status
1892
+ */
1893
+ async listByStatus(status) {
1894
+ return this.http.get(`/subscription/list/status/${encodeURIComponent(status)}`);
1895
+ }
1896
+ /**
1897
+ * Get subscription balance
1898
+ */
1899
+ async getBalance(appId) {
1900
+ return this.http.get(`/subscription/balance/${encodeURIComponent(appId)}`);
1901
+ }
1902
+ };
1903
+
1904
+ // src/tss/index.ts
1905
+ var TSSClient = class {
1906
+ constructor(http) {
1907
+ this.http = http;
1908
+ }
1909
+ http;
1910
+ /**
1911
+ * Create a multi-sig entity with TSS
1912
+ */
1913
+ async createEntity(options) {
1914
+ return this.http.post("/tss/entity/create", options);
1915
+ }
1916
+ /**
1917
+ * Reshare keys when cluster membership changes.
1918
+ * Redistributes secret shares WITHOUT changing public keys.
1919
+ */
1920
+ async reshareCluster(request) {
1921
+ return this.http.post("/tss/cluster/reshare", request);
1922
+ }
1923
+ /**
1924
+ * Get entity details by ID
1925
+ */
1926
+ async getEntity(entityId) {
1927
+ return this.http.get(`/tss/entity/${encodeURIComponent(entityId)}`);
1928
+ }
1929
+ /**
1930
+ * Sign a transaction using MPC — chain-agnostic.
1931
+ * Routes to the correct chain backend based on the `chain` parameter.
1932
+ *
1933
+ * @param request - MPC signing request with chain, entityId, and transaction bytes
1934
+ */
1935
+ async signMPC(request) {
1936
+ const chain = request.chain || "hedera";
1937
+ return this.http.post(`/tss/${encodeURIComponent(chain)}/sign-mpc`, request);
1938
+ }
1939
+ /**
1940
+ * Get known validators and their public keys
1941
+ */
1942
+ async getValidators() {
1943
+ return this.http.get("/tss/validators");
1944
+ }
1945
+ /**
1946
+ * Force announcement of this node's public key
1947
+ */
1948
+ async announceKey() {
1949
+ return this.http.post("/tss/announce", {});
1950
+ }
1951
+ /**
1952
+ * Get TSS statistics
1953
+ */
1954
+ async getStats() {
1955
+ return this.http.get("/tss/stats");
1956
+ }
1957
+ /**
1958
+ * List all TSS entities
1959
+ */
1960
+ async listEntities() {
1961
+ return this.http.get("/tss/entities");
1962
+ }
1963
+ /**
1964
+ * TSS health check
1965
+ */
1966
+ async getHealth() {
1967
+ return this.http.get("/tss/health");
1968
+ }
1969
+ /**
1970
+ * List DKG ceremonies and their statistics
1971
+ */
1972
+ async listCeremonies() {
1973
+ return this.http.get("/tss/multisig/ceremonies");
1974
+ }
1975
+ /**
1976
+ * Get multi-sig transaction status by transaction ID
1977
+ */
1978
+ async getMultiSigStatus(txId) {
1979
+ return this.http.get(`/tss/multisig/transactions/${encodeURIComponent(txId)}`);
1980
+ }
1981
+ };
1982
+
1983
+ // src/ipfs/index.ts
1984
+ var IPFSClient = class {
1985
+ constructor(http) {
1986
+ this.http = http;
1987
+ }
1988
+ http;
1989
+ /**
1990
+ * Upload a file to IPFS
1991
+ *
1992
+ * @param file - File data as Blob or Buffer
1993
+ * @param filename - Name of the file
1994
+ * @param metadata - Optional metadata key-value pairs
1995
+ * @returns Upload result with CID
1996
+ */
1997
+ async upload(file, filename, metadata) {
1998
+ return this.http.upload("/ipfs/upload", file, filename, metadata);
1999
+ }
2000
+ /**
2001
+ * Pin content by CID to ensure it persists
2002
+ */
2003
+ async pin(cid) {
2004
+ return this.http.post(`/ipfs/pin/${encodeURIComponent(cid)}`, {});
2005
+ }
2006
+ /**
2007
+ * Unpin content by CID
2008
+ */
2009
+ async unpin(cid) {
2010
+ return this.http.delete(`/ipfs/unpin/${encodeURIComponent(cid)}`);
2011
+ }
2012
+ /**
2013
+ * Get a file by CID
2014
+ */
2015
+ async getFile(cid) {
2016
+ return this.http.get(`/ipfs/file/${encodeURIComponent(cid)}`);
2017
+ }
2018
+ /**
2019
+ * Get raw content by CID
2020
+ */
2021
+ async getContent(cid) {
2022
+ return this.http.get(`/ipfs/${encodeURIComponent(cid)}`);
2023
+ }
2024
+ /**
2025
+ * Get file metadata by CID
2026
+ */
2027
+ async getMetadata(cid) {
2028
+ return this.http.get(`/ipfs/metadata/${encodeURIComponent(cid)}`);
2029
+ }
2030
+ /**
2031
+ * List all pinned content
2032
+ */
2033
+ async listPins() {
2034
+ return this.http.get("/ipfs/pins");
2035
+ }
2036
+ /**
2037
+ * Get IPFS node status
2038
+ */
2039
+ async getStatus() {
2040
+ return this.http.get("/ipfs/status");
2041
+ }
2042
+ /**
2043
+ * Get storage usage information
2044
+ */
2045
+ async getStorageUsage() {
2046
+ return this.http.get("/ipfs/storage");
2047
+ }
2048
+ };
2049
+
2050
+ // src/transactions/index.ts
2051
+ var TransactionsClient = class {
2052
+ constructor(http) {
2053
+ this.http = http;
2054
+ }
2055
+ http;
2056
+ /**
2057
+ * Get transaction preparation service info
2058
+ */
2059
+ async getInfo() {
2060
+ return this.http.get("/info");
2061
+ }
2062
+ /**
2063
+ * Prepare a transfer transaction for local signing
2064
+ */
2065
+ async prepareTransfer(request) {
2066
+ return this.http.post("/transfer/prepare", request);
2067
+ }
2068
+ /**
2069
+ * Prepare an NFT mint transaction
2070
+ */
2071
+ async prepareNftMint(request) {
2072
+ return this.http.post("/nft/mint/prepare", request);
2073
+ }
2074
+ /**
2075
+ * Prepare an NFT burn transaction
2076
+ */
2077
+ async prepareNftBurn(request) {
2078
+ return this.http.post("/nft/burn/prepare", request);
2079
+ }
2080
+ /**
2081
+ * Prepare an NFT transfer transaction
2082
+ */
2083
+ async prepareNftTransfer(request) {
2084
+ return this.http.post("/nft/transfer/prepare", request);
2085
+ }
2086
+ /**
2087
+ * Prepare a token creation transaction
2088
+ */
2089
+ async prepareTokenCreate(request) {
2090
+ return this.http.post("/token/create/prepare", request);
2091
+ }
2092
+ /**
2093
+ * Prepare a token mint transaction
2094
+ */
2095
+ async prepareTokenMint(request) {
2096
+ return this.http.post("/token/mint/prepare", request);
2097
+ }
2098
+ /**
2099
+ * Prepare a fungible token burn transaction (Hedera).
2100
+ *
2101
+ * For NFT burn use `prepareNftBurn` with a serialNumber.
2102
+ */
2103
+ async prepareTokenBurn(request) {
2104
+ return this.http.post("/token/burn/prepare", request);
2105
+ }
2106
+ /**
2107
+ * Prepare a token association transaction
2108
+ */
2109
+ async prepareTokenAssociation(request) {
2110
+ return this.http.post("/token/associate/prepare", request);
2111
+ }
2112
+ // ── Capability actions (Hedera) ──────────────────────────────────────
2113
+ /** Prepare a token pause transaction (capability: pausable). */
2114
+ async prepareTokenPause(request) {
2115
+ return this.http.post("/token/pause/prepare", request);
2116
+ }
2117
+ /** Prepare a token unpause transaction (capability: pausable). */
2118
+ async prepareTokenUnpause(request) {
2119
+ return this.http.post("/token/unpause/prepare", request);
2120
+ }
2121
+ /**
2122
+ * Prepare a token restrict (freeze account) transaction (capability:
2123
+ * restrictable). Freezes `accountId` from transacting `tokenId`.
2124
+ */
2125
+ async prepareTokenRestrict(request) {
2126
+ return this.http.post("/token/restrict/prepare", request);
2127
+ }
2128
+ /** Prepare a token unrestrict (unfreeze account) transaction. */
2129
+ async prepareTokenUnrestrict(request) {
2130
+ return this.http.post("/token/unrestrict/prepare", request);
2131
+ }
2132
+ /**
2133
+ * Prepare a token compliance-enable (grant KYC) transaction (capability:
2134
+ * compliant).
2135
+ */
2136
+ async prepareTokenComplianceEnable(request) {
2137
+ return this.http.post("/token/compliance/enable/prepare", request);
2138
+ }
2139
+ /** Prepare a token compliance-disable (revoke KYC) transaction. */
2140
+ async prepareTokenComplianceDisable(request) {
2141
+ return this.http.post("/token/compliance/disable/prepare", request);
2142
+ }
2143
+ /**
2144
+ * Prepare a token wipe transaction (capability: wipeable). Force-removes
2145
+ * `amount` of `tokenId` from `accountId`.
2146
+ */
2147
+ async prepareTokenWipe(request) {
2148
+ return this.http.post("/token/wipe/prepare", request);
2149
+ }
2150
+ /**
2151
+ * Prepare a topic creation transaction
2152
+ */
2153
+ async prepareTopicCreate(request) {
2154
+ return this.http.post("/topic/create/prepare", request);
2155
+ }
2156
+ /**
2157
+ * Prepare a topic message submission transaction
2158
+ */
2159
+ async prepareTopicMessage(request) {
2160
+ return this.http.post("/topic/message/prepare", request);
2161
+ }
2162
+ /**
2163
+ * Prepare a trust line transaction (e.g. XRPL trust lines)
2164
+ */
2165
+ async prepareTrustLine(request) {
2166
+ return this.http.post("/trustline/prepare", request);
2167
+ }
2168
+ };
2169
+
2170
+ // src/snapshots/index.ts
2171
+ var SnapshotsClient = class {
2172
+ constructor(http) {
2173
+ this.http = http;
2174
+ }
2175
+ http;
2176
+ /**
2177
+ * Generate a new snapshot for a token
2178
+ *
2179
+ * @param tokenId - Token identifier
2180
+ * @param options - Generation options (format, filters)
2181
+ */
2182
+ async generate(tokenId, options) {
2183
+ return this.http.post(
2184
+ `/snapshots/generate/${encodeURIComponent(tokenId)}`,
2185
+ options || {}
2186
+ );
2187
+ }
2188
+ /**
2189
+ * Get snapshot details by ID
2190
+ */
2191
+ async get(snapshotId) {
2192
+ return this.http.get(`/snapshots/${encodeURIComponent(snapshotId)}`);
2193
+ }
2194
+ /**
2195
+ * List snapshots for a token
2196
+ */
2197
+ async listByToken(tokenId, pagination) {
2198
+ const params = new URLSearchParams();
2199
+ if (pagination?.page !== void 0) params.set("page", String(pagination.page));
2200
+ if (pagination?.limit !== void 0) params.set("limit", String(pagination.limit));
2201
+ const qs = params.toString();
2202
+ return this.http.get(
2203
+ `/snapshots/token/${encodeURIComponent(tokenId)}${qs ? `?${qs}` : ""}`
2204
+ );
2205
+ }
2206
+ /**
2207
+ * Download snapshot data
2208
+ *
2209
+ * @param snapshotId - Snapshot ID
2210
+ * @param format - Output format (json or csv)
2211
+ */
2212
+ async download(snapshotId, format) {
2213
+ const params = format ? `?format=${encodeURIComponent(format)}` : "";
2214
+ return this.http.get(
2215
+ `/snapshots/${encodeURIComponent(snapshotId)}/download${params}`
2216
+ );
2217
+ }
2218
+ };
2219
+
2220
+ // src/settlement/index.ts
2221
+ var settlement_exports = {};
2222
+ __export(settlement_exports, {
2223
+ SettlementClient: () => SettlementClient
2224
+ });
2225
+ var SettlementClient = class {
2226
+ constructor(http) {
2227
+ this.http = http;
2228
+ }
2229
+ http;
2230
+ /**
2231
+ * Initiate a new settlement operation.
2232
+ * Submits source-chain payment details and begins the conversion pipeline.
2233
+ */
2234
+ async initiate(request) {
2235
+ return this.http.post("/settlement/initiate", request);
2236
+ }
2237
+ /**
2238
+ * Get the current status of a settlement by ID.
2239
+ */
2240
+ async getStatus(settlementId) {
2241
+ return this.http.get(`/settlement/${encodeURIComponent(settlementId)}/status`);
2242
+ }
2243
+ /**
2244
+ * Confirm that XRP has landed on the destination address.
2245
+ * Advances the settlement to the next processing step.
2246
+ */
2247
+ async confirmXrpLanded(settlementId) {
2248
+ return this.http.post(`/settlement/${encodeURIComponent(settlementId)}/confirm-xrp`, {});
2249
+ }
2250
+ /**
2251
+ * Get settlement history for a given entity.
2252
+ */
2253
+ async getHistory(entityId) {
2254
+ return this.http.get(`/settlement/history/${encodeURIComponent(entityId)}`);
2255
+ }
2256
+ };
2257
+
2258
+ // src/client.ts
2259
+ var SmartEngineClient = class _SmartEngineClient {
2260
+ baseUrl;
2261
+ allowInsecure;
2262
+ http;
2263
+ /** Separate HTTP client for /api/transactions (non-v3 base path) */
2264
+ txHttp;
2265
+ /** Last HTTP error (for getHttpHealth) */
2266
+ lastHttpError;
2267
+ // ========== Sub-Clients ==========
2268
+ /** Application subscription management */
2269
+ subscription;
2270
+ /** Threshold Signature Scheme — chain-agnostic MPC operations */
2271
+ tss;
2272
+ /** IPFS decentralized file storage */
2273
+ ipfs;
2274
+ /** Transaction preparation for local signing (sovereignty model) */
2275
+ transactions;
2276
+ /** Token holder snapshot generation and retrieval */
2277
+ snapshots;
2278
+ /** Cross-chain settlement operations */
2279
+ settlement;
2280
+ constructor(config) {
2281
+ this.allowInsecure = config.allowInsecure ?? false;
2282
+ this.baseUrl = validateClientUrl(config.baseUrl, this.allowInsecure);
2283
+ this.http = createHttpClient({
2284
+ baseUrl: `${this.baseUrl}/api/v3`,
2285
+ apiKey: config.apiKey,
2286
+ authToken: config.authToken,
2287
+ timeout: config.timeout
2288
+ });
2289
+ this.txHttp = createHttpClient({
2290
+ baseUrl: `${this.baseUrl}/api/transactions`,
2291
+ apiKey: config.apiKey,
2292
+ authToken: config.authToken,
2293
+ timeout: config.timeout
2294
+ });
2295
+ this.subscription = new SubscriptionClient(this.http);
2296
+ this.tss = new TSSClient(this.http);
2297
+ this.ipfs = new IPFSClient(this.http);
2298
+ this.transactions = new TransactionsClient(this.txHttp);
2299
+ this.snapshots = new SnapshotsClient(this.http);
2300
+ this.settlement = new SettlementClient(this.http);
2301
+ }
2302
+ /**
2303
+ * Connect to the smart-engines network with auto-discovery and authentication
2304
+ *
2305
+ * This method:
2306
+ * 1. Discovers validators via HCS registry topic
2307
+ * 2. Selects a random validator with API endpoint
2308
+ * 3. Authenticates with Web3-style challenge-response
2309
+ * 4. Returns a configured client ready to use
2310
+ */
2311
+ static async connectToNetwork(config) {
2312
+ const allowInsecure = config.allowInsecure ?? false;
2313
+ const discovery = new ValidatorDiscoveryClient({
2314
+ network: config.network,
2315
+ registryTopicId: config.registryTopicId,
2316
+ mirrorNodeUrl: config.mirrorNodeUrl
2317
+ });
2318
+ const validator = await discovery.getRandomValidator();
2319
+ if (!validator || !validator.networkEndpoints?.apiEndpoint) {
2320
+ throw new SmartEngineError2(
2321
+ "No validators available. Check registry topic and network configuration.",
2322
+ 503
2323
+ );
2324
+ }
2325
+ const validatorUrl = validator.networkEndpoints.apiEndpoint;
2326
+ validateClientUrl(validatorUrl, allowInsecure);
2327
+ const auth = new ValidatorAuthClient({
2328
+ security: { allowInsecure }
2329
+ });
2330
+ const session = await auth.authenticateWithSigner(
2331
+ validatorUrl,
2332
+ config.chain,
2333
+ config.address,
2334
+ config.publicKey,
2335
+ config.signFn,
2336
+ config.metadata
2337
+ );
2338
+ const client = new _SmartEngineClient({
2339
+ baseUrl: validatorUrl,
2340
+ authToken: session.token,
2341
+ allowInsecure
2342
+ });
2343
+ return { client, validator, session };
2344
+ }
2345
+ /** Get the current validator URL */
2346
+ getBaseUrl() {
2347
+ return this.baseUrl;
2348
+ }
2349
+ /** Check if client has an auth token */
2350
+ isAuthenticated() {
2351
+ return !!this.http.authToken;
2352
+ }
2353
+ /**
2354
+ * Get HTTP resilience health information
2355
+ * @returns Object with circuit breaker state and last error (if any)
2356
+ */
2357
+ getHttpHealth() {
2358
+ return {
2359
+ breaker: null,
2360
+ lastError: this.lastHttpError
2361
+ };
2362
+ }
2363
+ // ========== Health & Info ==========
2364
+ /** Get health status of the validator */
2365
+ async getHealth() {
2366
+ return this.http.get("/health");
2367
+ }
2368
+ /** Get list of supported chains */
2369
+ async getSupportedChains() {
2370
+ return this.http.get("/chains");
2371
+ }
2372
+ // ========== Account Operations ==========
2373
+ /** Create a new account on the specified chain */
2374
+ async createAccount(request) {
2375
+ const validated = CreateAccountRequestSchema.parse(request);
2376
+ return this.http.post("/accounts", validated);
2377
+ }
2378
+ /** Get account information */
2379
+ async getAccountInfo(chain, accountId) {
2380
+ return this.http.get(`/accounts/${encodePathParam(chain)}/${encodePathParam(accountId)}`);
2381
+ }
2382
+ /** Get account balance */
2383
+ async getBalance(chain, accountId) {
2384
+ return this.http.get(`/accounts/${encodePathParam(chain)}/${encodePathParam(accountId)}/balance`);
2385
+ }
2386
+ // ========== Transaction Operations ==========
2387
+ /** Execute a transfer transaction */
2388
+ async transfer(request) {
2389
+ const validated = TransferRequestSchema.parse(request);
2390
+ return this.http.post("/transfer", validated);
2391
+ }
2392
+ /** Get transaction details */
2393
+ async getTransaction(chain, txId) {
2394
+ return this.http.get(`/transactions/${encodePathParam(chain)}/${encodePathParam(txId)}`);
2395
+ }
2396
+ /** Get transaction receipt */
2397
+ async getTransactionReceipt(chain, txId) {
2398
+ return this.http.get(`/transactions/${encodePathParam(chain)}/${encodePathParam(txId)}/receipt`);
2399
+ }
2400
+ // ========== Token Operations ==========
2401
+ /** Create a new token */
2402
+ async createToken(request) {
2403
+ const validated = CreateTokenRequestSchema.parse(request);
2404
+ return this.http.post("/tokens", validated);
2405
+ }
2406
+ /** Mint tokens */
2407
+ async mintToken(request) {
2408
+ const validated = MintTokenRequestSchema.parse(request);
2409
+ return this.http.post("/tokens/mint", validated);
2410
+ }
2411
+ /** Get token information */
2412
+ async getTokenInfo(chain, tokenId) {
2413
+ return this.http.get(`/tokens/${encodePathParam(chain)}/${encodePathParam(tokenId)}`);
2414
+ }
2415
+ /** Burn tokens to reduce supply */
2416
+ async burnToken(request) {
2417
+ const validated = BurnTokenRequestSchema.parse(request);
2418
+ return this.http.post("/tokens/burn", validated);
2419
+ }
2420
+ /** Pause all token operations globally */
2421
+ async pauseToken(request) {
2422
+ const validated = TokenActionRequestSchema.parse(request);
2423
+ return this.http.post("/tokens/pause", validated);
2424
+ }
2425
+ /** Unpause token operations */
2426
+ async unpauseToken(request) {
2427
+ const validated = TokenActionRequestSchema.parse(request);
2428
+ return this.http.post("/tokens/unpause", validated);
2429
+ }
2430
+ /** Freeze/restrict an account from transacting the token */
2431
+ async restrictAccount(request) {
2432
+ const validated = TokenActionRequestSchema.parse(request);
2433
+ if (!validated.accountId) {
2434
+ throw new SmartEngineError2("accountId is required for restrictAccount", 400);
2435
+ }
2436
+ return this.http.post("/tokens/restrict", validated);
2437
+ }
2438
+ /** Unfreeze an account */
2439
+ async unrestrictAccount(request) {
2440
+ const validated = TokenActionRequestSchema.parse(request);
2441
+ if (!validated.accountId) {
2442
+ throw new SmartEngineError2("accountId is required for unrestrictAccount", 400);
2443
+ }
2444
+ return this.http.post("/tokens/unrestrict", validated);
2445
+ }
2446
+ /** Grant KYC/compliance approval to an account */
2447
+ async enableCompliance(request) {
2448
+ const validated = TokenActionRequestSchema.parse(request);
2449
+ if (!validated.accountId) {
2450
+ throw new SmartEngineError2("accountId is required for enableCompliance", 400);
2451
+ }
2452
+ return this.http.post("/tokens/compliance/enable", validated);
2453
+ }
2454
+ /** Revoke KYC/compliance approval from an account */
2455
+ async disableCompliance(request) {
2456
+ const validated = TokenActionRequestSchema.parse(request);
2457
+ if (!validated.accountId) {
2458
+ throw new SmartEngineError2("accountId is required for disableCompliance", 400);
2459
+ }
2460
+ return this.http.post("/tokens/compliance/disable", validated);
2461
+ }
2462
+ /** Force remove tokens from an account (compliance action) */
2463
+ async wipeFromAccount(request) {
2464
+ const validated = TokenActionRequestSchema.parse(request);
2465
+ if (!validated.accountId) {
2466
+ throw new SmartEngineError2("accountId is required for wipeFromAccount", 400);
2467
+ }
2468
+ if (!validated.amount) {
2469
+ throw new SmartEngineError2("amount is required for wipeFromAccount", 400);
2470
+ }
2471
+ return this.http.post("/tokens/wipe", validated);
2472
+ }
2473
+ // ========== Capabilities Discovery ==========
2474
+ /** Get capability support matrix for all chains */
2475
+ async getAllCapabilities() {
2476
+ return this.http.get("/capabilities");
2477
+ }
2478
+ /** Get capability support for a specific chain */
2479
+ async getChainCapabilities(chain) {
2480
+ return this.http.get(`/capabilities/${encodePathParam(chain)}`);
2481
+ }
2482
+ /** Get comprehensive system status */
2483
+ async getSystemStatus() {
2484
+ return this.http.get("/status");
2485
+ }
2486
+ // ========== Messaging Operations ==========
2487
+ /** Submit a message to consensus */
2488
+ async submitMessage(chain, topicId, message) {
2489
+ if (message.length > 1024 * 1024) {
2490
+ throw new SmartEngineError2("Message too large (max 1MB)", 400);
2491
+ }
2492
+ return this.http.post(`/messages/${encodePathParam(chain)}/${encodePathParam(topicId)}`, {
2493
+ message
2494
+ });
2495
+ }
2496
+ // ========== Cluster Operations ==========
2497
+ /** Get cluster health status */
2498
+ async getClusterHealth() {
2499
+ return this.http.get("/cluster/health");
2500
+ }
2501
+ /** Get cluster status including node details */
2502
+ async getClusterStatus() {
2503
+ return this.http.get("/cluster/status");
2504
+ }
2505
+ // ========== Metrics & Monitoring ==========
2506
+ /** Get Prometheus-format metrics */
2507
+ async getMetrics() {
2508
+ return this.http.get("/metrics");
2509
+ }
2510
+ /** Get queue statistics for monitoring */
2511
+ async getQueueStats() {
2512
+ return this.http.get("/monitoring/queue");
2513
+ }
2514
+ /** Get circuit breaker status for all services */
2515
+ async getCircuitBreakerStatus() {
2516
+ return this.http.get("/monitoring/circuit-breakers");
2517
+ }
2518
+ // ========== Signature Verification ==========
2519
+ /** Verify an arbitrary signature */
2520
+ async verifySignature(request) {
2521
+ return this.http.post("/auth/verify-signature", request);
2522
+ }
2523
+ };
2524
+ var SmartEngineError2 = class extends Error {
2525
+ constructor(message, statusCode, details) {
2526
+ super(message);
2527
+ this.statusCode = statusCode;
2528
+ this.details = details;
2529
+ this.name = "SmartEngineError";
2530
+ }
2531
+ statusCode;
2532
+ details;
2533
+ };
2534
+ function validateClientUrl(url, allowInsecure = false) {
2535
+ try {
2536
+ const parsed = new URL(url);
2537
+ if (!["http:", "https:"].includes(parsed.protocol)) {
2538
+ throw new SmartEngineError2(`Invalid protocol: ${parsed.protocol}`, 400);
2539
+ }
2540
+ if (!allowInsecure && parsed.protocol !== "https:") {
2541
+ throw new SmartEngineError2(
2542
+ "HTTPS is required for secure connections. Set allowInsecure=true for local development.",
2543
+ 400
2544
+ );
2545
+ }
2546
+ return parsed.origin;
2547
+ } catch (error) {
2548
+ if (error instanceof SmartEngineError2) throw error;
2549
+ throw new SmartEngineError2(`Invalid URL: ${url}`, 400);
2550
+ }
2551
+ }
2552
+
2553
+ // src/gateway/routing/index.ts
2554
+ var RoutingClient = class {
2555
+ constructor(http) {
2556
+ this.http = http;
2557
+ }
2558
+ http;
2559
+ /** Register a new host */
2560
+ async registerHost(request) {
2561
+ return this.http.post("/routing/hosts", request);
2562
+ }
2563
+ /** Unregister a host */
2564
+ async unregisterHost(hostId) {
2565
+ return this.http.delete(`/routing/hosts/${encodeURIComponent(hostId)}`);
2566
+ }
2567
+ /** Get all registered hosts */
2568
+ async getAllHosts() {
2569
+ return this.http.get("/routing/hosts");
2570
+ }
2571
+ /** Get only verified hosts */
2572
+ async getVerifiedHosts() {
2573
+ return this.http.get("/routing/hosts/verified");
2574
+ }
2575
+ /** Get a specific host by ID */
2576
+ async getHost(hostId) {
2577
+ return this.http.get(`/routing/hosts/${encodeURIComponent(hostId)}`);
2578
+ }
2579
+ /** Verify a host */
2580
+ async verifyHost(hostId) {
2581
+ return this.http.post(`/routing/hosts/${encodeURIComponent(hostId)}/verify`, {});
2582
+ }
2583
+ /** Set routing configuration for an app */
2584
+ async setRoutingConfig(appId, config) {
2585
+ return this.http.put(`/routing/config/${encodeURIComponent(appId)}`, config);
2586
+ }
2587
+ /** Get routing configuration for an app */
2588
+ async getRoutingConfig(appId) {
2589
+ return this.http.get(`/routing/config/${encodeURIComponent(appId)}`);
2590
+ }
2591
+ /** Proxy a request through the gateway */
2592
+ async proxyRequest(request) {
2593
+ return this.http.post("/routing/proxy", request);
2594
+ }
2595
+ /** Get routing statistics */
2596
+ async getStats() {
2597
+ return this.http.get("/routing/stats");
2598
+ }
2599
+ /** Map a domain to an application */
2600
+ async mapDomainToApp(domain, appId) {
2601
+ return this.http.post(`/routing/domains/${encodeURIComponent(domain)}/map`, { appId });
2602
+ }
2603
+ };
2604
+
2605
+ // src/gateway/domains/index.ts
2606
+ var DomainsClient = class {
2607
+ constructor(http) {
2608
+ this.http = http;
2609
+ }
2610
+ http;
2611
+ /** Register a new domain */
2612
+ async register(request) {
2613
+ return this.http.post("/domains", request);
2614
+ }
2615
+ /** Check domain availability */
2616
+ async checkAvailability(domain) {
2617
+ return this.http.get(`/domains/check/${encodeURIComponent(domain)}`);
2618
+ }
2619
+ /** Get domain information */
2620
+ async getInfo(domain) {
2621
+ return this.http.get(`/domains/${encodeURIComponent(domain)}`);
2622
+ }
2623
+ /** List domains, optionally filtered by owner */
2624
+ async list(owner) {
2625
+ const params = owner ? `?owner=${encodeURIComponent(owner)}` : "";
2626
+ return this.http.get(`/domains${params}`);
2627
+ }
2628
+ /** Generate a verification token */
2629
+ async generateVerificationToken(domain, method) {
2630
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/verification`, { method });
2631
+ }
2632
+ /** Verify domain ownership */
2633
+ async verifyOwnership(domain, token) {
2634
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/verify`, { token });
2635
+ }
2636
+ /** Configure DNS records for a domain */
2637
+ async configureDns(domain, records) {
2638
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/dns`, { records });
2639
+ }
2640
+ /** Enable DNSSEC for a domain */
2641
+ async enableDnssec(domain) {
2642
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/dnssec/enable`, {});
2643
+ }
2644
+ /** Disable DNSSEC for a domain */
2645
+ async disableDnssec(domain) {
2646
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/dnssec/disable`, {});
2647
+ }
2648
+ /** Renew a domain */
2649
+ async renew(domain, years) {
2650
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/renew`, { years: years ?? 1 });
2651
+ }
2652
+ /** Initiate a domain transfer */
2653
+ async transfer(domain, request) {
2654
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/transfer`, request);
2655
+ }
2656
+ /** Approve a pending domain transfer */
2657
+ async approveTransfer(domain) {
2658
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/transfer/approve`, {});
2659
+ }
2660
+ /** Reject a pending domain transfer */
2661
+ async rejectTransfer(domain) {
2662
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/transfer/reject`, {});
2663
+ }
2664
+ /** Suspend a domain */
2665
+ async suspend(domain, reason) {
2666
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/suspend`, { reason });
2667
+ }
2668
+ /** Unsuspend a domain */
2669
+ async unsuspend(domain) {
2670
+ return this.http.post(`/domains/${encodeURIComponent(domain)}/unsuspend`, {});
2671
+ }
2672
+ };
2673
+
2674
+ // src/gateway/dns/index.ts
2675
+ var DnsClient = class {
2676
+ constructor(http) {
2677
+ this.http = http;
2678
+ }
2679
+ http;
2680
+ /** Resolve a DNS name */
2681
+ async resolve(name, type, dnssec) {
2682
+ const params = new URLSearchParams({ name });
2683
+ if (type) params.set("type", type);
2684
+ if (dnssec !== void 0) params.set("dnssec", String(dnssec));
2685
+ return this.http.get(`/dns/resolve?${params.toString()}`);
2686
+ }
2687
+ /** Batch resolve multiple DNS queries */
2688
+ async resolveBatch(queries) {
2689
+ return this.http.post("/dns/resolve/batch", { queries });
2690
+ }
2691
+ /** List all DNS zones */
2692
+ async listZones() {
2693
+ return this.http.get("/dns/zones");
2694
+ }
2695
+ /** Get a specific zone */
2696
+ async getZone(zoneName) {
2697
+ return this.http.get(`/dns/zones/${encodeURIComponent(zoneName)}`);
2698
+ }
2699
+ /** Create a new DNS zone */
2700
+ async createZone(request) {
2701
+ return this.http.post("/dns/zones", request);
2702
+ }
2703
+ /** Delete a DNS zone */
2704
+ async deleteZone(zoneName) {
2705
+ return this.http.delete(`/dns/zones/${encodeURIComponent(zoneName)}`);
2706
+ }
2707
+ /** Add a record to a zone */
2708
+ async addRecord(zoneName, record) {
2709
+ return this.http.post(`/dns/zones/${encodeURIComponent(zoneName)}/records`, record);
2710
+ }
2711
+ /** Update a record in a zone */
2712
+ async updateRecord(zoneName, recordId, updates) {
2713
+ return this.http.put(
2714
+ `/dns/zones/${encodeURIComponent(zoneName)}/records/${encodeURIComponent(recordId)}`,
2715
+ updates
2716
+ );
2717
+ }
2718
+ /** Delete a record from a zone */
2719
+ async deleteRecord(zoneName, recordId) {
2720
+ return this.http.delete(
2721
+ `/dns/zones/${encodeURIComponent(zoneName)}/records/${encodeURIComponent(recordId)}`
2722
+ );
2723
+ }
2724
+ /** Generate DNSSEC keys for a zone */
2725
+ async generateDnssecKeys(zoneName, algorithm) {
2726
+ return this.http.post(`/dns/zones/${encodeURIComponent(zoneName)}/dnssec/keys`, {
2727
+ algorithm
2728
+ });
2729
+ }
2730
+ /** Get DNSSEC keys for a zone */
2731
+ async getDnssecKeys(zoneName) {
2732
+ return this.http.get(`/dns/zones/${encodeURIComponent(zoneName)}/dnssec/keys`);
2733
+ }
2734
+ /** Get DS record for a zone (for registrar configuration) */
2735
+ async getDsRecord(zoneName) {
2736
+ return this.http.get(`/dns/zones/${encodeURIComponent(zoneName)}/dnssec/ds`);
2737
+ }
2738
+ /** Clear DNS cache */
2739
+ async clearCache() {
2740
+ return this.http.post("/dns/cache/clear", {});
2741
+ }
2742
+ };
2743
+
2744
+ // src/gateway/client.ts
2745
+ var SmartGatewayClient = class {
2746
+ http;
2747
+ /** Host routing and proxy management */
2748
+ routing;
2749
+ /** Domain registration and management */
2750
+ domains;
2751
+ /** DNS resolution and zone management */
2752
+ dns;
2753
+ constructor(config) {
2754
+ const baseUrl = config.baseUrl.replace(/\/+$/, "");
2755
+ this.http = createHttpClient({
2756
+ baseUrl: `${baseUrl}/api/v3`,
2757
+ apiKey: config.apiKey,
2758
+ authToken: config.authToken,
2759
+ timeout: config.timeout
2760
+ });
2761
+ this.routing = new RoutingClient(this.http);
2762
+ this.domains = new DomainsClient(this.http);
2763
+ this.dns = new DnsClient(this.http);
2764
+ }
2765
+ // ========== Health & Metrics ==========
2766
+ /** Get gateway health status */
2767
+ async getHealth() {
2768
+ return this.http.get("/health");
2769
+ }
2770
+ /** Get gateway status with host and domain counts */
2771
+ async getStatus() {
2772
+ return this.http.get("/status");
2773
+ }
2774
+ /** Check gateway readiness */
2775
+ async getReadiness() {
2776
+ return this.http.get("/ready");
2777
+ }
2778
+ /** Check gateway liveness */
2779
+ async getLiveness() {
2780
+ return this.http.get("/live");
2781
+ }
2782
+ /** Get detailed gateway metrics */
2783
+ async getMetrics(refresh) {
2784
+ const params = refresh ? "?refresh=true" : "";
2785
+ return this.http.get(`/metrics${params}`);
2786
+ }
2787
+ /** Get metrics summary */
2788
+ async getMetricsSummary() {
2789
+ return this.http.get("/metrics/summary");
2790
+ }
2791
+ };
2792
+
2793
+ // src/http/resilient-http.ts
2794
+ var DEFAULT_RETRY_CONFIG = {
2795
+ maxRetries: 3,
2796
+ initialDelayMs: 1e3,
2797
+ maxDelayMs: 3e4,
2798
+ backoffMultiplier: 2,
2799
+ jitterFactor: 0.1
2800
+ };
2801
+ function calculateBackoffDelay(attempt, config) {
2802
+ const exponentialDelay = config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt);
2803
+ const cappedDelay = Math.min(exponentialDelay, config.maxDelayMs);
2804
+ if (config.jitterFactor && config.jitterFactor > 0) {
2805
+ const jitter = cappedDelay * config.jitterFactor * Math.random();
2806
+ return Math.floor(cappedDelay + jitter);
2807
+ }
2808
+ return Math.floor(cappedDelay);
2809
+ }
2810
+ function parseRetryAfter(retryAfter) {
2811
+ if (!retryAfter) return 0;
2812
+ const seconds = parseInt(retryAfter, 10);
2813
+ if (!isNaN(seconds)) {
2814
+ return seconds * 1e3;
2815
+ }
2816
+ const date = new Date(retryAfter);
2817
+ if (!isNaN(date.getTime())) {
2818
+ return Math.max(0, date.getTime() - Date.now());
2819
+ }
2820
+ return 0;
2821
+ }
2822
+ function sleep(ms) {
2823
+ return new Promise((resolve) => setTimeout(resolve, ms));
2824
+ }
2825
+ function isIdempotent(method) {
2826
+ const m = (method || "GET").toUpperCase();
2827
+ return m === "GET" || m === "HEAD" || m === "OPTIONS";
2828
+ }
2829
+ async function resilientFetch(url, init, config) {
2830
+ const timeoutMs = config?.timeoutMs ?? 3e4;
2831
+ const retryConfig = { ...DEFAULT_RETRY_CONFIG, ...config?.retry };
2832
+ const method = (init?.method || "GET").toUpperCase();
2833
+ const shouldUseCircuitBreaker = config?.circuitBreaker !== false;
2834
+ const breaker = shouldUseCircuitBreaker ? new CircuitBreaker({
2835
+ failureThreshold: 5,
2836
+ rollingWindowMs: 6e4,
2837
+ cooldownMs: 3e4,
2838
+ name: `http-${method}`,
2839
+ ...config?.circuitBreaker || {}
2840
+ }) : null;
2841
+ let lastError;
2842
+ let lastStatus;
2843
+ for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
2844
+ try {
2845
+ if (breaker) {
2846
+ if (!breaker.canExecute()) {
2847
+ const state = breaker.getState();
2848
+ if (config?.onCircuitBreakerStateChange) {
2849
+ config.onCircuitBreakerStateChange(state);
2850
+ }
2851
+ const snapshot = breaker.snapshot();
2852
+ throw new Error(
2853
+ `Circuit breaker is ${state}. Next probe at ${new Date(snapshot.nextProbeAt || 0).toISOString()}`
2854
+ );
2855
+ }
2856
+ }
2857
+ const controller = new AbortController();
2858
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
2859
+ let response;
2860
+ try {
2861
+ response = await fetch(url, { ...init, signal: controller.signal });
2862
+ clearTimeout(timeoutId);
2863
+ } catch (fetchError) {
2864
+ clearTimeout(timeoutId);
2865
+ throw fetchError;
2866
+ }
2867
+ if ((response.status === 429 || response.status === 503) && isIdempotent(method)) {
2868
+ if (attempt < retryConfig.maxRetries) {
2869
+ const retryAfterMs = parseRetryAfter(response.headers.get("Retry-After"));
2870
+ const delay = retryAfterMs > 0 ? retryAfterMs : calculateBackoffDelay(attempt, retryConfig);
2871
+ lastStatus = response.status;
2872
+ if (config?.onRetry) {
2873
+ config.onRetry(attempt + 1, delay, response.status);
2874
+ }
2875
+ const statusError = new Error(`HTTP ${response.status}`);
2876
+ if (breaker) {
2877
+ try {
2878
+ await breaker.execute(async () => {
2879
+ await sleep(delay);
2880
+ throw statusError;
2881
+ });
2882
+ } catch {
2883
+ }
2884
+ } else {
2885
+ await sleep(delay);
2886
+ }
2887
+ continue;
2888
+ }
2889
+ }
2890
+ return response;
2891
+ } catch (error) {
2892
+ lastError = error;
2893
+ if (attempt >= retryConfig.maxRetries) {
2894
+ break;
2895
+ }
2896
+ if (!isIdempotent(method)) {
2897
+ break;
2898
+ }
2899
+ const delay = calculateBackoffDelay(attempt, retryConfig);
2900
+ if (config?.onRetry) {
2901
+ config.onRetry(attempt + 1, delay, lastStatus);
2902
+ }
2903
+ await sleep(delay);
2904
+ }
2905
+ }
2906
+ if (lastError) {
2907
+ throw lastError;
2908
+ }
2909
+ throw new Error(`Failed to fetch ${url} after ${retryConfig.maxRetries} retries`);
2910
+ }
2911
+ function createResilientFetchWithBreaker(config) {
2912
+ const shouldUseCircuitBreaker = config?.circuitBreaker !== false;
2913
+ const breaker = shouldUseCircuitBreaker ? new CircuitBreaker({
2914
+ failureThreshold: 5,
2915
+ rollingWindowMs: 6e4,
2916
+ cooldownMs: 3e4,
2917
+ name: "http-breaker",
2918
+ ...config?.circuitBreaker || {}
2919
+ }) : null;
2920
+ const boundFetch = async (url, init) => {
2921
+ const timeoutMs = config?.timeoutMs ?? 3e4;
2922
+ const retryConfig = { ...DEFAULT_RETRY_CONFIG, ...config?.retry };
2923
+ const method = (init?.method || "GET").toUpperCase();
2924
+ let lastError;
2925
+ let lastStatus;
2926
+ for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
2927
+ try {
2928
+ if (breaker) {
2929
+ const response = await breaker.execute(async () => {
2930
+ const controller = new AbortController();
2931
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
2932
+ try {
2933
+ const resp = await fetch(url, { ...init, signal: controller.signal });
2934
+ clearTimeout(timeoutId);
2935
+ return resp;
2936
+ } catch (fetchError) {
2937
+ clearTimeout(timeoutId);
2938
+ throw fetchError;
2939
+ }
2940
+ });
2941
+ if ((response.status === 429 || response.status === 503) && isIdempotent(method)) {
2942
+ if (attempt < retryConfig.maxRetries) {
2943
+ const retryAfterMs = parseRetryAfter(response.headers.get("Retry-After"));
2944
+ const delay = retryAfterMs > 0 ? retryAfterMs : calculateBackoffDelay(attempt, retryConfig);
2945
+ lastStatus = response.status;
2946
+ if (config?.onRetry) {
2947
+ config.onRetry(attempt + 1, delay, response.status);
2948
+ }
2949
+ await sleep(delay);
2950
+ continue;
2951
+ }
2952
+ }
2953
+ return response;
2954
+ } else {
2955
+ const controller = new AbortController();
2956
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
2957
+ try {
2958
+ const response = await fetch(url, { ...init, signal: controller.signal });
2959
+ clearTimeout(timeoutId);
2960
+ if ((response.status === 429 || response.status === 503) && isIdempotent(method)) {
2961
+ if (attempt < retryConfig.maxRetries) {
2962
+ const retryAfterMs = parseRetryAfter(response.headers.get("Retry-After"));
2963
+ const delay = retryAfterMs > 0 ? retryAfterMs : calculateBackoffDelay(attempt, retryConfig);
2964
+ lastStatus = response.status;
2965
+ if (config?.onRetry) {
2966
+ config.onRetry(attempt + 1, delay, response.status);
2967
+ }
2968
+ await sleep(delay);
2969
+ continue;
2970
+ }
2971
+ }
2972
+ return response;
2973
+ } catch (fetchError) {
2974
+ clearTimeout(timeoutId);
2975
+ throw fetchError;
2976
+ }
2977
+ }
2978
+ } catch (error) {
2979
+ lastError = error;
2980
+ if (attempt >= retryConfig.maxRetries) {
2981
+ break;
2982
+ }
2983
+ if (!isIdempotent(method)) {
2984
+ break;
2985
+ }
2986
+ const delay = calculateBackoffDelay(attempt, retryConfig);
2987
+ if (config?.onRetry) {
2988
+ config.onRetry(attempt + 1, delay, lastStatus);
2989
+ }
2990
+ await sleep(delay);
2991
+ }
2992
+ }
2993
+ if (lastError) {
2994
+ throw lastError;
2995
+ }
2996
+ throw new Error(`Failed to fetch ${url} after ${retryConfig.maxRetries} retries`);
2997
+ };
2998
+ return {
2999
+ fetch: boundFetch,
3000
+ getCircuitBreakerSnapshot: () => breaker ? breaker.snapshot() : null
3001
+ };
3002
+ }
3003
+
3004
+ // src/chains/index.ts
3005
+ var chains_exports = {};
3006
+ __export(chains_exports, {
3007
+ bitcoin: () => bitcoin_exports,
3008
+ hedera: () => hedera_exports,
3009
+ polkadot: () => polkadot_exports,
3010
+ solana: () => solana_exports,
3011
+ stellar: () => stellar_exports,
3012
+ xrpl: () => xrpl_exports
3013
+ });
3014
+
3015
+ // src/chains/hedera.ts
3016
+ var hedera_exports = {};
3017
+ __export(hedera_exports, {
3018
+ formatHederaAccountId: () => formatHederaAccountId,
3019
+ formatHederaTokenId: () => formatHederaTokenId,
3020
+ formatHederaTopicId: () => formatHederaTopicId,
3021
+ hbarToTinybars: () => hbarToTinybars,
3022
+ parseHbar: () => parseHbar,
3023
+ tinybarsToHbar: () => tinybarsToHbar
3024
+ });
3025
+ function formatHederaAccountId(id) {
3026
+ if (!/^\d+\.\d+\.\d+$/.test(id)) {
3027
+ throw new Error(`Invalid Hedera account ID format: ${id}`);
3028
+ }
3029
+ return id;
3030
+ }
3031
+ function parseHbar(amount) {
3032
+ const num = parseFloat(amount);
3033
+ if (isNaN(num) || num < 0) {
3034
+ throw new Error(`Invalid HBAR amount: ${amount}`);
3035
+ }
3036
+ return num;
3037
+ }
3038
+ function hbarToTinybars(hbar) {
3039
+ const amount = typeof hbar === "string" ? parseFloat(hbar) : hbar;
3040
+ return (amount * 1e8).toFixed(0);
3041
+ }
3042
+ function tinybarsToHbar(tinybars) {
3043
+ const amount = typeof tinybars === "string" ? parseInt(tinybars, 10) : tinybars;
3044
+ return (amount / 1e8).toString();
3045
+ }
3046
+ function formatHederaTokenId(id) {
3047
+ if (!/^\d+\.\d+\.\d+$/.test(id)) {
3048
+ throw new Error(`Invalid Hedera token ID format: ${id}`);
3049
+ }
3050
+ return id;
3051
+ }
3052
+ function formatHederaTopicId(id) {
3053
+ if (!/^\d+\.\d+\.\d+$/.test(id)) {
3054
+ throw new Error(`Invalid Hedera topic ID format: ${id}`);
3055
+ }
3056
+ return id;
3057
+ }
3058
+
3059
+ // src/chains/xrpl.ts
3060
+ var xrpl_exports = {};
3061
+ __export(xrpl_exports, {
3062
+ dropsToXrp: () => dropsToXrp,
3063
+ formatXRPLAddress: () => formatXRPLAddress,
3064
+ parseXRP: () => parseXRP,
3065
+ validateCurrencyCode: () => validateCurrencyCode,
3066
+ validateXRPLAddress: () => validateXRPLAddress,
3067
+ xrpToDrops: () => xrpToDrops
3068
+ });
3069
+ function validateXRPLAddress(address) {
3070
+ return /^r[1-9A-HJ-NP-Za-km-z]{25,34}$/.test(address);
3071
+ }
3072
+ function formatXRPLAddress(address) {
3073
+ if (!validateXRPLAddress(address)) {
3074
+ throw new Error(`Invalid XRPL address format: ${address}`);
3075
+ }
3076
+ return address;
3077
+ }
3078
+ function xrpToDrops(xrp) {
3079
+ const amount = typeof xrp === "string" ? parseFloat(xrp) : xrp;
3080
+ if (isNaN(amount) || amount < 0) {
3081
+ throw new Error(`Invalid XRP amount: ${xrp}`);
3082
+ }
3083
+ return (amount * 1e6).toFixed(0);
3084
+ }
3085
+ function dropsToXrp(drops) {
3086
+ const amount = typeof drops === "string" ? parseInt(drops, 10) : drops;
3087
+ if (isNaN(amount) || amount < 0) {
3088
+ throw new Error(`Invalid drops amount: ${drops}`);
3089
+ }
3090
+ return (amount / 1e6).toString();
3091
+ }
3092
+ function parseXRP(amount) {
3093
+ const num = parseFloat(amount);
3094
+ if (isNaN(num) || num < 0) {
3095
+ throw new Error(`Invalid XRP amount: ${amount}`);
3096
+ }
3097
+ return num;
3098
+ }
3099
+ function validateCurrencyCode(code) {
3100
+ return /^[A-Z]{3}$/.test(code) || /^[0-9A-F]{40}$/i.test(code);
3101
+ }
3102
+
3103
+ // src/chains/polkadot.ts
3104
+ var polkadot_exports = {};
3105
+ __export(polkadot_exports, {
3106
+ dotToPlanck: () => dotToPlanck,
3107
+ formatDot: () => formatDot,
3108
+ formatPolkadotAddress: () => formatPolkadotAddress,
3109
+ parseDotString: () => parseDotString,
3110
+ planckToDot: () => planckToDot,
3111
+ validatePolkadotAddress: () => validatePolkadotAddress
3112
+ });
3113
+ var PLANCK_PER_DOT = 10000000000n;
3114
+ function validatePolkadotAddress(address) {
3115
+ if (!address || typeof address !== "string") {
3116
+ return false;
3117
+ }
3118
+ const ss58Regex = /^[1-9A-HJ-NP-Za-km-z]{47,48}$/;
3119
+ return ss58Regex.test(address);
3120
+ }
3121
+ function formatPolkadotAddress(address, prefixLength = 6, suffixLength = 5) {
3122
+ if (!address || address.length <= prefixLength + suffixLength) {
3123
+ return address;
3124
+ }
3125
+ return `${address.slice(0, prefixLength)}...${address.slice(-suffixLength)}`;
3126
+ }
3127
+ function dotToPlanck(dot) {
3128
+ if (dot < 0) {
3129
+ throw new Error("DOT amount cannot be negative");
3130
+ }
3131
+ const [whole, decimal = ""] = dot.toString().split(".");
3132
+ const paddedDecimal = decimal.padEnd(10, "0").slice(0, 10);
3133
+ return BigInt(whole) * PLANCK_PER_DOT + BigInt(paddedDecimal);
3134
+ }
3135
+ function planckToDot(planck) {
3136
+ if (planck < 0n) {
3137
+ throw new Error("Planck amount cannot be negative");
3138
+ }
3139
+ const whole = planck / PLANCK_PER_DOT;
3140
+ const remainder = planck % PLANCK_PER_DOT;
3141
+ return Number(whole) + Number(remainder) / Number(PLANCK_PER_DOT);
3142
+ }
3143
+ function formatDot(planck, decimals = 4) {
3144
+ const dot = planckToDot(planck);
3145
+ return `${dot.toFixed(decimals)} DOT`;
3146
+ }
3147
+ function parseDotString(dotString) {
3148
+ const cleaned = dotString.replace(/\s*DOT\s*$/i, "").trim();
3149
+ const dot = parseFloat(cleaned);
3150
+ if (isNaN(dot)) {
3151
+ throw new Error(`Invalid DOT amount: ${dotString}`);
3152
+ }
3153
+ return dotToPlanck(dot);
3154
+ }
3155
+
3156
+ // src/chains/solana.ts
3157
+ var solana_exports = {};
3158
+ __export(solana_exports, {
3159
+ formatSol: () => formatSol,
3160
+ formatSolanaAddress: () => formatSolanaAddress,
3161
+ isTransactionSignature: () => isTransactionSignature,
3162
+ lamportsToSol: () => lamportsToSol,
3163
+ parseSolString: () => parseSolString,
3164
+ solToLamports: () => solToLamports,
3165
+ validateSolanaPublicKey: () => validateSolanaPublicKey
3166
+ });
3167
+ var LAMPORTS_PER_SOL = 1000000000n;
3168
+ var BASE58_CHARS = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
3169
+ function validateSolanaPublicKey(publicKey) {
3170
+ if (!publicKey || typeof publicKey !== "string") {
3171
+ return false;
3172
+ }
3173
+ if (publicKey.length < 32 || publicKey.length > 44) {
3174
+ return false;
3175
+ }
3176
+ for (const char of publicKey) {
3177
+ if (!BASE58_CHARS.includes(char)) {
3178
+ return false;
3179
+ }
3180
+ }
3181
+ return true;
3182
+ }
3183
+ function formatSolanaAddress(address, prefixLength = 4, suffixLength = 4) {
3184
+ if (!address || address.length <= prefixLength + suffixLength) {
3185
+ return address;
3186
+ }
3187
+ return `${address.slice(0, prefixLength)}...${address.slice(-suffixLength)}`;
3188
+ }
3189
+ function solToLamports(sol) {
3190
+ if (sol < 0) {
3191
+ throw new Error("SOL amount cannot be negative");
3192
+ }
3193
+ const [whole, decimal = ""] = sol.toString().split(".");
3194
+ const paddedDecimal = decimal.padEnd(9, "0").slice(0, 9);
3195
+ return BigInt(whole) * LAMPORTS_PER_SOL + BigInt(paddedDecimal);
3196
+ }
3197
+ function lamportsToSol(lamports) {
3198
+ if (lamports < 0n) {
3199
+ throw new Error("Lamports amount cannot be negative");
3200
+ }
3201
+ const whole = lamports / LAMPORTS_PER_SOL;
3202
+ const remainder = lamports % LAMPORTS_PER_SOL;
3203
+ return Number(whole) + Number(remainder) / Number(LAMPORTS_PER_SOL);
3204
+ }
3205
+ function formatSol(lamports, decimals = 4) {
3206
+ const sol = lamportsToSol(lamports);
3207
+ return `${sol.toFixed(decimals)} SOL`;
3208
+ }
3209
+ function parseSolString(solString) {
3210
+ const cleaned = solString.replace(/\s*SOL\s*$/i, "").trim();
3211
+ const sol = parseFloat(cleaned);
3212
+ if (isNaN(sol)) {
3213
+ throw new Error(`Invalid SOL amount: ${solString}`);
3214
+ }
3215
+ return solToLamports(sol);
3216
+ }
3217
+ function isTransactionSignature(signature) {
3218
+ if (!signature || typeof signature !== "string") {
3219
+ return false;
3220
+ }
3221
+ if (signature.length < 87 || signature.length > 88) {
3222
+ return false;
3223
+ }
3224
+ for (const char of signature) {
3225
+ if (!BASE58_CHARS.includes(char)) {
3226
+ return false;
3227
+ }
3228
+ }
3229
+ return true;
3230
+ }
3231
+
3232
+ // src/chains/stellar.ts
3233
+ var stellar_exports = {};
3234
+ __export(stellar_exports, {
3235
+ stroopsToXlm: () => stroopsToXlm,
3236
+ validateStellarAddress: () => validateStellarAddress,
3237
+ xlmToStroops: () => xlmToStroops
3238
+ });
3239
+ function validateStellarAddress(address) {
3240
+ if (!address || address.length !== 56 || !address.startsWith("G")) {
3241
+ return false;
3242
+ }
3243
+ return /^G[A-Z2-7]{55}$/.test(address);
3244
+ }
3245
+ function stroopsToXlm(stroops) {
3246
+ const amount = typeof stroops === "string" ? parseInt(stroops, 10) : stroops;
3247
+ if (isNaN(amount) || amount < 0) {
3248
+ throw new Error(`Invalid stroops amount: ${stroops}`);
3249
+ }
3250
+ return (amount / 1e7).toString();
3251
+ }
3252
+ function xlmToStroops(xlm) {
3253
+ const amount = typeof xlm === "string" ? parseFloat(xlm) : xlm;
3254
+ if (isNaN(amount) || amount < 0) {
3255
+ throw new Error(`Invalid XLM amount: ${xlm}`);
3256
+ }
3257
+ return (amount * 1e7).toFixed(0);
3258
+ }
3259
+
3260
+ // src/chains/bitcoin.ts
3261
+ var bitcoin_exports = {};
3262
+ __export(bitcoin_exports, {
3263
+ btcToSatoshis: () => btcToSatoshis,
3264
+ satoshisToBtc: () => satoshisToBtc,
3265
+ validateBitcoinAddress: () => validateBitcoinAddress
3266
+ });
3267
+ function validateBitcoinAddress(address) {
3268
+ if (!address) return false;
3269
+ const p2pkh = /^1[1-9A-HJ-NP-Za-km-z]{24,33}$/;
3270
+ const p2sh = /^3[1-9A-HJ-NP-Za-km-z]{24,33}$/;
3271
+ const bech32 = /^bc1[a-z0-9]{38,58}$/;
3272
+ return p2pkh.test(address) || p2sh.test(address) || bech32.test(address);
3273
+ }
3274
+ function satoshisToBtc(satoshis) {
3275
+ const amount = typeof satoshis === "string" ? parseInt(satoshis, 10) : satoshis;
3276
+ if (isNaN(amount) || amount < 0) {
3277
+ throw new Error(`Invalid satoshis amount: ${satoshis}`);
3278
+ }
3279
+ return (amount / 1e8).toString();
3280
+ }
3281
+ function btcToSatoshis(btc) {
3282
+ const amount = typeof btc === "string" ? parseFloat(btc) : btc;
3283
+ if (isNaN(amount) || amount < 0) {
3284
+ throw new Error(`Invalid BTC amount: ${btc}`);
3285
+ }
3286
+ return (amount * 1e8).toFixed(0);
3287
+ }
3288
+
3289
+ // src/baas/index.ts
3290
+ var baas_exports = {};
3291
+ __export(baas_exports, {
3292
+ AgentsClient: () => AgentsClient,
3293
+ BaasClient: () => BaasClient,
3294
+ BaasError: () => BaasError,
3295
+ DatabaseClient: () => DatabaseClient,
3296
+ DeploymentClient: () => DeploymentClient,
3297
+ FunctionsClient: () => FunctionsClient,
3298
+ MessagingClient: () => MessagingClient,
3299
+ StorageClient: () => StorageClient,
3300
+ validateAgentRules: () => validateAgentRules
3301
+ });
3302
+
3303
+ // src/baas/database/index.ts
3304
+ var DatabaseClient = class {
3305
+ constructor(http, getAppId) {
3306
+ this.http = http;
3307
+ this.getAppId = getAppId;
3308
+ }
3309
+ http;
3310
+ getAppId;
3311
+ /**
3312
+ * Insert a document into a collection
3313
+ */
3314
+ async insert(collection, document) {
3315
+ const appId = this.getAppId();
3316
+ return this.http.post(
3317
+ `/api/db/${encodeURIComponent(appId)}/${encodeURIComponent(collection)}`,
3318
+ document
3319
+ );
3320
+ }
3321
+ /**
3322
+ * Find documents in a collection
3323
+ */
3324
+ async find(collection, query, options) {
3325
+ const appId = this.getAppId();
3326
+ const params = new URLSearchParams();
3327
+ if (query && Object.keys(query).length > 0) {
3328
+ params.set("query", JSON.stringify(query));
3329
+ }
3330
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
3331
+ if (options?.skip !== void 0) params.set("skip", String(options.skip));
3332
+ if (options?.sort) params.set("sort", options.sort);
3333
+ const qs = params.toString();
3334
+ return this.http.get(
3335
+ `/api/db/${encodeURIComponent(appId)}/${encodeURIComponent(collection)}${qs ? `?${qs}` : ""}`
3336
+ );
3337
+ }
3338
+ /**
3339
+ * Update a document in a collection
3340
+ */
3341
+ async update(collection, documentId, updates) {
3342
+ const appId = this.getAppId();
3343
+ return this.http.put(
3344
+ `/api/db/${encodeURIComponent(appId)}/${encodeURIComponent(collection)}/${encodeURIComponent(documentId)}`,
3345
+ updates
3346
+ );
3347
+ }
3348
+ /**
3349
+ * Delete a document from a collection
3350
+ */
3351
+ async delete(collection, documentId) {
3352
+ const appId = this.getAppId();
3353
+ return this.http.delete(
3354
+ `/api/db/${encodeURIComponent(appId)}/${encodeURIComponent(collection)}/${encodeURIComponent(documentId)}`
3355
+ );
3356
+ }
3357
+ /**
3358
+ * List collections for the app
3359
+ */
3360
+ async listCollections() {
3361
+ const appId = this.getAppId();
3362
+ return this.http.get(`/api/db/${encodeURIComponent(appId)}`);
3363
+ }
3364
+ // ========== State Proofs ==========
3365
+ /**
3366
+ * Get the current state root for the app
3367
+ */
3368
+ async getStateRoot() {
3369
+ const appId = this.getAppId();
3370
+ return this.http.get(`/api/db/${encodeURIComponent(appId)}/state/root`);
3371
+ }
3372
+ /**
3373
+ * Get a Merkle proof for a specific document
3374
+ */
3375
+ async getDocumentProof(documentId) {
3376
+ const appId = this.getAppId();
3377
+ return this.http.get(
3378
+ `/api/db/${encodeURIComponent(appId)}/${encodeURIComponent(documentId)}/proof`
3379
+ );
3380
+ }
3381
+ /**
3382
+ * Get state transitions (audit log)
3383
+ */
3384
+ async getStateTransitions(options) {
3385
+ const appId = this.getAppId();
3386
+ const params = new URLSearchParams();
3387
+ if (options?.fromBlock !== void 0) params.set("fromBlock", String(options.fromBlock));
3388
+ if (options?.toBlock !== void 0) params.set("toBlock", String(options.toBlock));
3389
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
3390
+ const qs = params.toString();
3391
+ return this.http.get(
3392
+ `/api/db/${encodeURIComponent(appId)}/state/transitions${qs ? `?${qs}` : ""}`
3393
+ );
3394
+ }
3395
+ /**
3396
+ * Get database statistics
3397
+ */
3398
+ async getDbStats() {
3399
+ const appId = this.getAppId();
3400
+ return this.http.get(`/api/db/${encodeURIComponent(appId)}/stats`);
3401
+ }
3402
+ };
3403
+
3404
+ // src/baas/storage/index.ts
3405
+ var StorageClient = class {
3406
+ constructor(http, getAppId) {
3407
+ this.http = http;
3408
+ this.getAppId = getAppId;
3409
+ }
3410
+ http;
3411
+ getAppId;
3412
+ /**
3413
+ * Upload a file to storage
3414
+ */
3415
+ async upload(file, filename, metadata) {
3416
+ const appId = this.getAppId();
3417
+ return this.http.upload(`/api/storage/${encodeURIComponent(appId)}/upload`, file, filename, metadata);
3418
+ }
3419
+ /**
3420
+ * Download a file by CID
3421
+ */
3422
+ async download(cid) {
3423
+ return this.http.get(`/api/storage/download/${encodeURIComponent(cid)}`);
3424
+ }
3425
+ /**
3426
+ * Get file metadata
3427
+ */
3428
+ async getMetadata(cid) {
3429
+ return this.http.get(`/api/storage/metadata/${encodeURIComponent(cid)}`);
3430
+ }
3431
+ /**
3432
+ * Delete a file
3433
+ */
3434
+ async delete(cid) {
3435
+ const appId = this.getAppId();
3436
+ return this.http.delete(`/api/storage/${encodeURIComponent(appId)}/${encodeURIComponent(cid)}`);
3437
+ }
3438
+ /**
3439
+ * Get file info
3440
+ */
3441
+ async getFile(cid) {
3442
+ const appId = this.getAppId();
3443
+ return this.http.get(`/api/storage/${encodeURIComponent(appId)}/${encodeURIComponent(cid)}`);
3444
+ }
3445
+ /**
3446
+ * List all files for the app
3447
+ */
3448
+ async listFiles(pagination) {
3449
+ const appId = this.getAppId();
3450
+ const params = new URLSearchParams();
3451
+ if (pagination?.limit !== void 0) params.set("limit", String(pagination.limit));
3452
+ if (pagination?.skip !== void 0) params.set("skip", String(pagination.skip));
3453
+ const qs = params.toString();
3454
+ return this.http.get(`/api/storage/${encodeURIComponent(appId)}/files${qs ? `?${qs}` : ""}`);
3455
+ }
3456
+ /**
3457
+ * Get storage usage for the current app
3458
+ */
3459
+ async getUsage() {
3460
+ return this.http.get("/api/storage/usage");
3461
+ }
3462
+ /**
3463
+ * Check if a file exists
3464
+ */
3465
+ async exists(cid) {
3466
+ return this.http.get(`/api/storage/exists/${encodeURIComponent(cid)}`);
3467
+ }
3468
+ };
3469
+
3470
+ // src/baas/functions/index.ts
3471
+ var FunctionsClient = class {
3472
+ constructor(http, getAppId) {
3473
+ this.http = http;
3474
+ this.getAppId = getAppId;
3475
+ }
3476
+ http;
3477
+ getAppId;
3478
+ /**
3479
+ * Deploy a new function
3480
+ */
3481
+ async deploy(request) {
3482
+ const appId = this.getAppId();
3483
+ return this.http.post(`/api/functions/${encodeURIComponent(appId)}`, request);
3484
+ }
3485
+ /**
3486
+ * Invoke a function
3487
+ */
3488
+ async invoke(functionId, payload) {
3489
+ return this.http.post(`/api/functions/${encodeURIComponent(functionId)}/invoke`, payload ?? {});
3490
+ }
3491
+ /**
3492
+ * List all functions
3493
+ */
3494
+ async list() {
3495
+ return this.http.get("/api/functions");
3496
+ }
3497
+ /**
3498
+ * Get function details
3499
+ */
3500
+ async get(functionId) {
3501
+ return this.http.get(`/api/functions/${encodeURIComponent(functionId)}`);
3502
+ }
3503
+ /**
3504
+ * Update a function
3505
+ */
3506
+ async update(functionId, updates) {
3507
+ return this.http.put(`/api/functions/${encodeURIComponent(functionId)}`, updates);
3508
+ }
3509
+ /**
3510
+ * Delete a function
3511
+ */
3512
+ async delete(functionId) {
3513
+ return this.http.delete(`/api/functions/${encodeURIComponent(functionId)}`);
3514
+ }
3515
+ /**
3516
+ * Get function execution logs
3517
+ */
3518
+ async getLogs(functionId, options) {
3519
+ const params = new URLSearchParams();
3520
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
3521
+ if (options?.startTime) params.set("startTime", options.startTime);
3522
+ if (options?.level) params.set("level", options.level);
3523
+ const qs = params.toString();
3524
+ return this.http.get(`/api/functions/${encodeURIComponent(functionId)}/logs${qs ? `?${qs}` : ""}`);
3525
+ }
3526
+ /**
3527
+ * Get function statistics for an app
3528
+ */
3529
+ async getStats() {
3530
+ const appId = this.getAppId();
3531
+ return this.http.get(`/api/functions/${encodeURIComponent(appId)}/stats`);
3532
+ }
3533
+ };
3534
+
3535
+ // src/baas/messaging/index.ts
3536
+ var MessagingClient = class {
3537
+ constructor(http, getAppId) {
3538
+ this.http = http;
3539
+ this.getAppId = getAppId;
3540
+ }
3541
+ http;
3542
+ getAppId;
3543
+ /**
3544
+ * Create a new channel
3545
+ */
3546
+ async createChannel(config) {
3547
+ const appId = this.getAppId();
3548
+ return this.http.post(`/api/messaging/${encodeURIComponent(appId)}/channels`, config);
3549
+ }
3550
+ /**
3551
+ * Delete a channel
3552
+ */
3553
+ async deleteChannel(channelId) {
3554
+ const appId = this.getAppId();
3555
+ return this.http.delete(`/api/messaging/${encodeURIComponent(appId)}/channels/${encodeURIComponent(channelId)}`);
3556
+ }
3557
+ /**
3558
+ * Get a channel by ID
3559
+ */
3560
+ async getChannel(channelId) {
3561
+ const appId = this.getAppId();
3562
+ return this.http.get(`/api/messaging/${encodeURIComponent(appId)}/channels/${encodeURIComponent(channelId)}`);
3563
+ }
3564
+ /**
3565
+ * List all channels for the app
3566
+ */
3567
+ async listChannels() {
3568
+ const appId = this.getAppId();
3569
+ return this.http.get(`/api/messaging/${encodeURIComponent(appId)}/channels`);
3570
+ }
3571
+ /**
3572
+ * Publish a message to a channel
3573
+ */
3574
+ async publish(channel, message, metadata) {
3575
+ const appId = this.getAppId();
3576
+ return this.http.post(
3577
+ `/api/messaging/${encodeURIComponent(appId)}/channels/${encodeURIComponent(channel)}/publish`,
3578
+ { data: message, metadata }
3579
+ );
3580
+ }
3581
+ /**
3582
+ * Get message history for a channel
3583
+ */
3584
+ async getHistory(channel, options) {
3585
+ const appId = this.getAppId();
3586
+ const params = new URLSearchParams();
3587
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
3588
+ if (options?.before) params.set("before", options.before);
3589
+ if (options?.after) params.set("after", options.after);
3590
+ const qs = params.toString();
3591
+ return this.http.get(
3592
+ `/api/messaging/${encodeURIComponent(appId)}/channels/${encodeURIComponent(channel)}/history${qs ? `?${qs}` : ""}`
3593
+ );
3594
+ }
3595
+ /**
3596
+ * Set presence for a member
3597
+ */
3598
+ async setPresence(member) {
3599
+ const appId = this.getAppId();
3600
+ return this.http.post(`/api/messaging/${encodeURIComponent(appId)}/presence`, member);
3601
+ }
3602
+ /**
3603
+ * Remove presence for a member
3604
+ */
3605
+ async removePresence(memberId) {
3606
+ const appId = this.getAppId();
3607
+ return this.http.delete(`/api/messaging/${encodeURIComponent(appId)}/presence/${encodeURIComponent(memberId)}`);
3608
+ }
3609
+ /**
3610
+ * Get presence info for a channel
3611
+ */
3612
+ async getPresence(channel) {
3613
+ const appId = this.getAppId();
3614
+ return this.http.get(`/api/messaging/${encodeURIComponent(appId)}/presence/${encodeURIComponent(channel)}`);
3615
+ }
3616
+ /**
3617
+ * Get messaging statistics
3618
+ */
3619
+ async getStats() {
3620
+ const appId = this.getAppId();
3621
+ return this.http.get(`/api/messaging/${encodeURIComponent(appId)}/stats`);
3622
+ }
3623
+ };
3624
+
3625
+ // src/baas/deployment/index.ts
3626
+ var DeploymentClient = class {
3627
+ constructor(http) {
3628
+ this.http = http;
3629
+ }
3630
+ http;
3631
+ /**
3632
+ * Create (deploy) a new app
3633
+ */
3634
+ async create(request) {
3635
+ return this.http.post("/api/deployment/apps", request);
3636
+ }
3637
+ /**
3638
+ * List all deployed apps
3639
+ */
3640
+ async list() {
3641
+ return this.http.get("/api/deployment/apps");
3642
+ }
3643
+ /**
3644
+ * Get app details
3645
+ */
3646
+ async get(appId) {
3647
+ return this.http.get(`/api/deployment/apps/${encodeURIComponent(appId)}`);
3648
+ }
3649
+ /**
3650
+ * Update app configuration
3651
+ */
3652
+ async update(appId, updates) {
3653
+ return this.http.put(`/api/deployment/apps/${encodeURIComponent(appId)}`, updates);
3654
+ }
3655
+ /**
3656
+ * Delete an app
3657
+ */
3658
+ async delete(appId) {
3659
+ return this.http.delete(`/api/deployment/apps/${encodeURIComponent(appId)}`);
3660
+ }
3661
+ /**
3662
+ * Suspend an app
3663
+ */
3664
+ async suspend(appId) {
3665
+ return this.http.post(`/api/deployment/apps/${encodeURIComponent(appId)}/suspend`, {});
3666
+ }
3667
+ /**
3668
+ * Resume a suspended app
3669
+ */
3670
+ async resume(appId) {
3671
+ return this.http.post(`/api/deployment/apps/${encodeURIComponent(appId)}/resume`, {});
3672
+ }
3673
+ /**
3674
+ * Get deployment statistics
3675
+ */
3676
+ async getStats() {
3677
+ return this.http.get("/api/deployment/stats");
3678
+ }
3679
+ };
3680
+
3681
+ // src/baas/agents/types.ts
3682
+ var VALID_CHAIN_NAMES = /* @__PURE__ */ new Set([
3683
+ "hedera",
3684
+ "xrpl",
3685
+ "polkadot",
3686
+ "solana",
3687
+ "stellar",
3688
+ "ethereum",
3689
+ "polygon",
3690
+ "bitcoin"
3691
+ ]);
3692
+ function validateAgentRules(rules) {
3693
+ const errors = [];
3694
+ if (rules.maxTradeAmount !== void 0) {
3695
+ if (!isPositiveDecimalString(rules.maxTradeAmount)) {
3696
+ errors.push("maxTradeAmount must be a positive decimal string");
3697
+ }
3698
+ }
3699
+ if (rules.allowedPairs !== void 0) {
3700
+ if (!Array.isArray(rules.allowedPairs)) {
3701
+ errors.push("allowedPairs must be an array of strings");
3702
+ } else {
3703
+ for (const pair of rules.allowedPairs) {
3704
+ if (typeof pair !== "string" || pair.trim().length === 0) {
3705
+ errors.push("allowedPairs contains an empty or non-string entry");
3706
+ break;
3707
+ }
3708
+ }
3709
+ }
3710
+ }
3711
+ if (rules.allowedChains !== void 0) {
3712
+ if (!Array.isArray(rules.allowedChains)) {
3713
+ errors.push("allowedChains must be an array of strings");
3714
+ } else {
3715
+ for (const chain of rules.allowedChains) {
3716
+ if (!VALID_CHAIN_NAMES.has(chain)) {
3717
+ errors.push(`allowedChains contains invalid chain name: ${chain}`);
3718
+ }
3719
+ }
3720
+ }
3721
+ }
3722
+ if (rules.dailyLimit !== void 0) {
3723
+ if (!isPositiveDecimalString(rules.dailyLimit)) {
3724
+ errors.push("dailyLimit must be a positive decimal string");
3725
+ }
3726
+ }
3727
+ if (rules.requireApprovalAbove !== void 0) {
3728
+ if (!isPositiveDecimalString(rules.requireApprovalAbove)) {
3729
+ errors.push("requireApprovalAbove must be a positive decimal string");
3730
+ }
3731
+ }
3732
+ return { valid: errors.length === 0, errors };
3733
+ }
3734
+ function isPositiveDecimalString(value) {
3735
+ if (typeof value !== "string") return false;
3736
+ const num = Number(value);
3737
+ return !Number.isNaN(num) && num > 0;
3738
+ }
3739
+
3740
+ // src/baas/agents/index.ts
3741
+ var AgentsClient = class {
3742
+ constructor(http) {
3743
+ this.http = http;
3744
+ }
3745
+ http;
3746
+ /** Register a new agent */
3747
+ async register(request) {
3748
+ return this.http.post("/api/agents/register", request);
3749
+ }
3750
+ /** Get agent details */
3751
+ async get(agentId) {
3752
+ return this.http.get(`/api/agents/${encodeURIComponent(agentId)}`);
3753
+ }
3754
+ /** List all agents */
3755
+ async list() {
3756
+ return this.http.get("/api/agents");
3757
+ }
3758
+ /** Fund an agent */
3759
+ async fund(agentId, request) {
3760
+ return this.http.post(`/api/agents/${encodeURIComponent(agentId)}/fund`, request);
3761
+ }
3762
+ /** Execute a trade */
3763
+ async trade(agentId, request) {
3764
+ return this.http.post(`/api/agents/${encodeURIComponent(agentId)}/trade`, request);
3765
+ }
3766
+ /** Withdraw funds from agent */
3767
+ async withdraw(agentId, request) {
3768
+ return this.http.post(`/api/agents/${encodeURIComponent(agentId)}/withdraw`, request);
3769
+ }
3770
+ /** Pause an agent */
3771
+ async pause(agentId) {
3772
+ return this.http.post(`/api/agents/${encodeURIComponent(agentId)}/pause`, {});
3773
+ }
3774
+ /** Resume a paused agent */
3775
+ async resume(agentId) {
3776
+ return this.http.post(`/api/agents/${encodeURIComponent(agentId)}/resume`, {});
3777
+ }
3778
+ /** Revoke an agent (permanent) */
3779
+ async revoke(agentId) {
3780
+ return this.http.post(`/api/agents/${encodeURIComponent(agentId)}/revoke`, {});
3781
+ }
3782
+ /** Update agent rules */
3783
+ async updateRules(agentId, rules) {
3784
+ return this.http.put(`/api/agents/${encodeURIComponent(agentId)}/rules`, rules);
3785
+ }
3786
+ /** Get agent events */
3787
+ async getEvents(agentId) {
3788
+ return this.http.get(`/api/agents/${encodeURIComponent(agentId)}/events`);
3789
+ }
3790
+ /** Get agent balances across chains */
3791
+ async getBalances(agentId) {
3792
+ return this.http.get(`/api/agents/${encodeURIComponent(agentId)}/balances`);
3793
+ }
3794
+ /** Approve a pending agent operation */
3795
+ async approve(agentId, operationId) {
3796
+ return this.http.post(`/api/agents/${encodeURIComponent(agentId)}/approve/${encodeURIComponent(operationId)}`, {});
3797
+ }
3798
+ /** Reject a pending agent operation */
3799
+ async reject(agentId, operationId) {
3800
+ return this.http.post(`/api/agents/${encodeURIComponent(agentId)}/reject/${encodeURIComponent(operationId)}`, {});
3801
+ }
3802
+ };
3803
+
3804
+ // src/baas/client.ts
3805
+ var BaasClient = class {
3806
+ hostUrl;
3807
+ pathPrefix;
3808
+ appId;
3809
+ timeout;
3810
+ allowInsecure;
3811
+ authToken = null;
3812
+ http;
3813
+ /** Last HTTP error (for getHttpHealth) */
3814
+ lastHttpError;
3815
+ // ========== Sub-Clients ==========
3816
+ /** Trustless database with state proofs and Merkle verification */
3817
+ db;
3818
+ /** Decentralized file storage */
3819
+ storage;
3820
+ /** Serverless function deployment and invocation */
3821
+ functions;
3822
+ /** Real-time pub/sub messaging with channels, history, and presence */
3823
+ messaging;
3824
+ /** App deployment lifecycle management */
3825
+ deployment;
3826
+ /** Autonomous smart agent management */
3827
+ agents;
3828
+ constructor(config) {
3829
+ this.allowInsecure = config.allowInsecure ?? false;
3830
+ this.hostUrl = validateUrl2(config.hostUrl, this.allowInsecure);
3831
+ this.appId = config.appId;
3832
+ this.timeout = config.timeout ?? 3e4;
3833
+ const prefix = (config.pathPrefix ?? "").replace(/\/$/, "");
3834
+ this.pathPrefix = prefix ? prefix.startsWith("/") ? prefix : `/${prefix}` : "";
3835
+ const baseUrlWithPrefix = this.pathPrefix ? this.hostUrl.replace(/\/$/, "") + this.pathPrefix : this.hostUrl;
3836
+ this.http = createHttpClient({
3837
+ baseUrl: baseUrlWithPrefix,
3838
+ timeout: this.timeout
3839
+ });
3840
+ const getAppId = () => this.requireAppId();
3841
+ this.db = new DatabaseClient(this.http, getAppId);
3842
+ this.storage = new StorageClient(this.http, getAppId);
3843
+ this.functions = new FunctionsClient(this.http, getAppId);
3844
+ this.messaging = new MessagingClient(this.http, getAppId);
3845
+ this.deployment = new DeploymentClient(this.http);
3846
+ this.agents = new AgentsClient(this.http);
3847
+ }
3848
+ /** Set the app ID (for newly registered apps) */
3849
+ setAppId(appId) {
3850
+ this.appId = appId;
3851
+ }
3852
+ /** Check if the client is authenticated */
3853
+ isAuthenticated() {
3854
+ return this.authToken !== null;
3855
+ }
3856
+ /** Get the current app ID */
3857
+ getAppId() {
3858
+ return this.appId;
3859
+ }
3860
+ /**
3861
+ * Get HTTP resilience health information
3862
+ * @returns Object with circuit breaker state and last error (if any)
3863
+ */
3864
+ getHttpHealth() {
3865
+ return {
3866
+ breaker: null,
3867
+ lastError: this.lastHttpError
3868
+ };
3869
+ }
3870
+ requireAppId() {
3871
+ if (!this.appId) {
3872
+ throw new BaasError(
3873
+ "App ID required. Either provide appId in config or call register() first.",
3874
+ 400
3875
+ );
3876
+ }
3877
+ return this.appId;
3878
+ }
3879
+ // ========== Authentication ==========
3880
+ /**
3881
+ * Authenticate with the BaaS host using wallet challenge-response
3882
+ *
3883
+ * 1. Requests a challenge message from the host
3884
+ * 2. Signs the challenge with the provided signing function
3885
+ * 3. Submits the signature for verification
3886
+ * 4. Stores the JWT token for subsequent requests
3887
+ */
3888
+ async authenticate(options) {
3889
+ const { chain, walletAddress, publicKey, signFn } = options;
3890
+ const challenge = await this.post("/api/auth/challenge", {
3891
+ chain,
3892
+ walletAddress,
3893
+ appId: this.appId
3894
+ });
3895
+ const signature = await signFn(challenge.message);
3896
+ const result = await this.post("/api/auth/verify", {
3897
+ challengeId: challenge.challengeId,
3898
+ signature,
3899
+ publicKey
3900
+ });
3901
+ this.authToken = result.token;
3902
+ this.http.setAuthToken?.(result.token);
3903
+ return result;
3904
+ }
3905
+ /** Validate the current session */
3906
+ async validateSession() {
3907
+ this.requireAuth();
3908
+ return this.get("/api/auth/session");
3909
+ }
3910
+ /** Destroy the current session on server and clear local token */
3911
+ async logout() {
3912
+ if (this.authToken) {
3913
+ try {
3914
+ await this.post("/api/auth/logout", {});
3915
+ } catch {
3916
+ }
3917
+ }
3918
+ this.authToken = null;
3919
+ }
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
+ // ========== HTTP Helpers ==========
3927
+ requireAuth() {
3928
+ if (!this.authToken) {
3929
+ throw new BaasError("Authentication required. Call authenticate() first.", 401);
3930
+ }
3931
+ }
3932
+ getHeaders() {
3933
+ const headers = {
3934
+ "Content-Type": "application/json"
3935
+ };
3936
+ if (this.authToken) {
3937
+ headers["Authorization"] = `Bearer ${this.authToken}`;
3938
+ }
3939
+ return headers;
3940
+ }
3941
+ async post(path, body) {
3942
+ return this.request("POST", path, body);
3943
+ }
3944
+ async get(path) {
3945
+ return this.request("GET", path);
3946
+ }
3947
+ async request(method, path, body) {
3948
+ const url = `${this.hostUrl}${this.pathPrefix}${path}`;
3949
+ const controller = new AbortController();
3950
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3951
+ try {
3952
+ const options = {
3953
+ method,
3954
+ headers: this.getHeaders(),
3955
+ signal: controller.signal
3956
+ };
3957
+ if (body !== void 0) {
3958
+ options.body = JSON.stringify(body);
3959
+ }
3960
+ const response = await fetch(url, options);
3961
+ clearTimeout(timeoutId);
3962
+ if (!response.ok) {
3963
+ const errorData = await response.json().catch(() => ({}));
3964
+ throw new BaasError(
3965
+ errorData.message || `API error: ${response.status} ${response.statusText}`,
3966
+ response.status,
3967
+ errorData
3968
+ );
3969
+ }
3970
+ const text = await response.text();
3971
+ if (!text) return void 0;
3972
+ return JSON.parse(text);
3973
+ } catch (error) {
3974
+ clearTimeout(timeoutId);
3975
+ if (error instanceof BaasError) throw error;
3976
+ const err = error;
3977
+ if (err.name === "AbortError") {
3978
+ throw new BaasError("Request timeout", 408);
3979
+ }
3980
+ throw new BaasError(`Network error: ${err.message}`, 0, { originalError: err.message });
3981
+ }
3982
+ }
3983
+ };
3984
+ var BaasError = class extends Error {
3985
+ constructor(message, statusCode, details) {
3986
+ super(message);
3987
+ this.statusCode = statusCode;
3988
+ this.details = details;
3989
+ this.name = "BaasError";
3990
+ }
3991
+ statusCode;
3992
+ details;
3993
+ };
3994
+ function validateUrl2(url, allowInsecure = false) {
3995
+ try {
3996
+ const parsed = new URL(url);
3997
+ if (!["http:", "https:"].includes(parsed.protocol)) {
3998
+ throw new BaasError(`Invalid protocol: ${parsed.protocol}`, 400);
3999
+ }
4000
+ if (!allowInsecure && parsed.protocol !== "https:") {
4001
+ throw new BaasError(
4002
+ "HTTPS is required for secure connections. Set allowInsecure=true for local development.",
4003
+ 400
4004
+ );
4005
+ }
4006
+ return parsed.origin;
4007
+ } catch (error) {
4008
+ if (error instanceof BaasError) throw error;
4009
+ throw new BaasError(`Invalid URL: ${url}`, 400);
4010
+ }
4011
+ }
4012
+
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
+ exports.AgentsClient = AgentsClient;
4301
+ exports.BaasClient = BaasClient;
4302
+ exports.BaasError = BaasError;
4303
+ exports.CapabilityNotEnabledError = CapabilityNotEnabledError;
4304
+ exports.CapabilityValidationError = CapabilityValidationError;
4305
+ exports.CircuitBreaker = CircuitBreaker;
4306
+ exports.CircuitBreakerOpenError = CircuitBreakerOpenError;
4307
+ exports.DEFAULT_CIRCUIT_BREAKER_CONFIG = DEFAULT_CIRCUIT_BREAKER_CONFIG;
4308
+ exports.DEFAULT_RETRY_CONFIG = DEFAULT_RETRY_CONFIG;
4309
+ exports.DatabaseClient = DatabaseClient;
4310
+ exports.DeploymentClient = DeploymentClient;
4311
+ exports.DnsClient = DnsClient;
4312
+ exports.DomainsClient = DomainsClient;
4313
+ exports.ErrorCode = ErrorCode;
4314
+ exports.FunctionsClient = FunctionsClient;
4315
+ exports.IPFSClient = IPFSClient;
4316
+ exports.MIRROR_NODE_URLS = MIRROR_NODE_URLS;
4317
+ exports.MessagingClient = MessagingClient;
4318
+ exports.MirrorNodeClient = MirrorNodeClient;
4319
+ exports.MirrorNodeError = MirrorNodeError;
4320
+ exports.RateLimiter = RateLimiter;
4321
+ exports.RoutingClient = RoutingClient;
4322
+ exports.SMART_ENGINE_CONFIG = SMART_ENGINE_CONFIG;
4323
+ exports.SdkHttpError = SdkHttpError;
4324
+ exports.SettlementClient = SettlementClient;
4325
+ exports.SmartEngineClient = SmartEngineClient;
4326
+ exports.SmartEngineError = SmartEngineError;
4327
+ exports.SmartGatewayClient = SmartGatewayClient;
4328
+ exports.SnapshotsClient = SnapshotsClient;
4329
+ exports.StorageClient = StorageClient;
4330
+ exports.SubscriptionClient = SubscriptionClient;
4331
+ exports.TSSClient = TSSClient;
4332
+ exports.TransactionsClient = TransactionsClient;
4333
+ exports.UnsupportedCapabilityError = UnsupportedCapabilityError;
4334
+ exports.ValidatorAuthClient = ValidatorAuthClient;
4335
+ exports.ValidatorAuthError = ValidatorAuthError;
4336
+ exports.ValidatorDiscoveryClient = ValidatorDiscoveryClient;
4337
+ exports.auth = auth_exports;
4338
+ exports.baas = baas_exports;
4339
+ exports.chains = chains_exports;
4340
+ exports.createHttpClient = createHttpClient;
4341
+ exports.createResilientFetchWithBreaker = createResilientFetchWithBreaker;
4342
+ exports.discovery = discovery_exports;
4343
+ exports.encodePathParam = encodePathParam;
4344
+ exports.nestjs = nestjs_exports;
4345
+ exports.resilientFetch = resilientFetch;
4346
+ exports.settlement = settlement_exports;
4347
+ exports.subscription = subscription_exports;
4348
+ exports.validateAgentRules = validateAgentRules;
4349
+ //# sourceMappingURL=index.js.map
4350
+ //# sourceMappingURL=index.js.map