@phala/cloud 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,2349 @@
1
+ // src/client.ts
2
+ import { ofetch } from "ofetch";
3
+
4
+ // src/types/client.ts
5
+ import { z } from "zod";
6
+ var ApiErrorSchema = z.object({
7
+ detail: z.union([
8
+ z.string(),
9
+ z.array(
10
+ z.object({
11
+ msg: z.string(),
12
+ type: z.string().optional(),
13
+ ctx: z.record(z.unknown()).optional()
14
+ })
15
+ ),
16
+ z.record(z.unknown())
17
+ ]),
18
+ type: z.string().optional(),
19
+ code: z.string().optional()
20
+ });
21
+ var RequestError = class _RequestError extends Error {
22
+ constructor(message, options) {
23
+ super(message);
24
+ this.name = "RequestError";
25
+ this.isRequestError = true;
26
+ this.status = options?.status;
27
+ this.statusText = options?.statusText;
28
+ this.data = options?.data;
29
+ this.request = options?.request;
30
+ this.response = options?.response;
31
+ this.detail = options?.detail || message;
32
+ this.code = options?.code;
33
+ this.type = options?.type;
34
+ }
35
+ /**
36
+ * Create RequestError from FetchError
37
+ */
38
+ static fromFetchError(error) {
39
+ const parseResult = ApiErrorSchema.safeParse(error.data);
40
+ if (parseResult.success) {
41
+ return new _RequestError(error.message, {
42
+ status: error.status ?? void 0,
43
+ statusText: error.statusText ?? void 0,
44
+ data: error.data,
45
+ request: error.request ?? void 0,
46
+ response: error.response ?? void 0,
47
+ detail: parseResult.data.detail,
48
+ code: parseResult.data.code ?? void 0,
49
+ type: parseResult.data.type ?? void 0
50
+ });
51
+ }
52
+ return new _RequestError(error.message, {
53
+ status: error.status ?? void 0,
54
+ statusText: error.statusText ?? void 0,
55
+ data: error.data,
56
+ request: error.request ?? void 0,
57
+ response: error.response ?? void 0,
58
+ detail: error.data?.detail || "Unknown API error",
59
+ code: error.status?.toString() ?? void 0
60
+ });
61
+ }
62
+ /**
63
+ * Create RequestError from generic Error
64
+ */
65
+ static fromError(error, request) {
66
+ return new _RequestError(error.message, {
67
+ request: request ?? void 0,
68
+ detail: error.message
69
+ });
70
+ }
71
+ };
72
+
73
+ // src/client.ts
74
+ var Client = class {
75
+ constructor(config = {}) {
76
+ const resolvedConfig = {
77
+ ...config,
78
+ apiKey: config.apiKey || process.env.PHALA_CLOUD_API_KEY,
79
+ baseURL: config.baseURL || process.env.PHALA_CLOUD_API_PREFIX || "https://cloud-api.phala.network/api/v1"
80
+ };
81
+ this.config = resolvedConfig;
82
+ if (!resolvedConfig.apiKey) {
83
+ throw new Error(
84
+ "API key is required. Provide it via config.apiKey or set PHALA_CLOUD_API_KEY environment variable."
85
+ );
86
+ }
87
+ const { apiKey, baseURL, timeout, headers, ...fetchOptions } = resolvedConfig;
88
+ this.fetchInstance = ofetch.create({
89
+ baseURL,
90
+ timeout: timeout || 3e4,
91
+ headers: {
92
+ "X-API-Key": apiKey,
93
+ "Content-Type": "application/json",
94
+ ...headers || {}
95
+ },
96
+ ...fetchOptions,
97
+ // Generic handlers for response error (similar to request.ts)
98
+ onResponseError: ({ response }) => {
99
+ console.warn(`HTTP ${response.status}: ${response.url}`);
100
+ }
101
+ });
102
+ }
103
+ /**
104
+ * Get the underlying ofetch instance for advanced usage
105
+ */
106
+ get raw() {
107
+ return this.fetchInstance;
108
+ }
109
+ // ===== Direct methods (throw on error) =====
110
+ /**
111
+ * Perform GET request (throws on error)
112
+ */
113
+ async get(request, options) {
114
+ return this.fetchInstance(request, {
115
+ ...options,
116
+ method: "GET"
117
+ });
118
+ }
119
+ /**
120
+ * Perform POST request (throws on error)
121
+ */
122
+ async post(request, body, options) {
123
+ return this.fetchInstance(request, {
124
+ ...options,
125
+ method: "POST",
126
+ body
127
+ });
128
+ }
129
+ /**
130
+ * Perform PUT request (throws on error)
131
+ */
132
+ async put(request, body, options) {
133
+ return this.fetchInstance(request, {
134
+ ...options,
135
+ method: "PUT",
136
+ body
137
+ });
138
+ }
139
+ /**
140
+ * Perform PATCH request (throws on error)
141
+ */
142
+ async patch(request, body, options) {
143
+ return this.fetchInstance(request, {
144
+ ...options,
145
+ method: "PATCH",
146
+ body
147
+ });
148
+ }
149
+ /**
150
+ * Perform DELETE request (throws on error)
151
+ */
152
+ async delete(request, options) {
153
+ return this.fetchInstance(request, {
154
+ ...options,
155
+ method: "DELETE"
156
+ });
157
+ }
158
+ // ===== Safe methods (return SafeResult) =====
159
+ /**
160
+ * Safe wrapper for any request method (zod-style result)
161
+ */
162
+ async safeRequest(fn) {
163
+ try {
164
+ const data = await fn();
165
+ return { success: true, data };
166
+ } catch (error) {
167
+ if (error && typeof error === "object" && "data" in error) {
168
+ const requestError2 = RequestError.fromFetchError(error);
169
+ return { success: false, error: requestError2 };
170
+ }
171
+ if (error instanceof Error) {
172
+ const requestError2 = RequestError.fromError(error);
173
+ return { success: false, error: requestError2 };
174
+ }
175
+ const requestError = new RequestError("Unknown error occurred", {
176
+ detail: "Unknown error occurred"
177
+ });
178
+ return { success: false, error: requestError };
179
+ }
180
+ }
181
+ /**
182
+ * Safe GET request (returns SafeResult)
183
+ */
184
+ async safeGet(request, options) {
185
+ return this.safeRequest(() => this.get(request, options));
186
+ }
187
+ /**
188
+ * Safe POST request (returns SafeResult)
189
+ */
190
+ async safePost(request, body, options) {
191
+ return this.safeRequest(() => this.post(request, body, options));
192
+ }
193
+ /**
194
+ * Safe PUT request (returns SafeResult)
195
+ */
196
+ async safePut(request, body, options) {
197
+ return this.safeRequest(() => this.put(request, body, options));
198
+ }
199
+ /**
200
+ * Safe PATCH request (returns SafeResult)
201
+ */
202
+ async safePatch(request, body, options) {
203
+ return this.safeRequest(() => this.patch(request, body, options));
204
+ }
205
+ /**
206
+ * Safe DELETE request (returns SafeResult)
207
+ */
208
+ async safeDelete(request, options) {
209
+ return this.safeRequest(() => this.delete(request, options));
210
+ }
211
+ };
212
+ function createClient(config = {}) {
213
+ return new Client(config);
214
+ }
215
+
216
+ // src/actions/get_current_user.ts
217
+ import { z as z2 } from "zod";
218
+
219
+ // src/utils/index.ts
220
+ import { encryptEnvVars } from "@phala/dstack-sdk/encrypt-env-vars";
221
+
222
+ // src/utils/get_error_message.ts
223
+ function getErrorMessage(error) {
224
+ if (typeof error.detail === "string") {
225
+ return error.detail;
226
+ }
227
+ if (Array.isArray(error.detail)) {
228
+ if (error.detail.length > 0) {
229
+ return error.detail[0]?.msg || "Validation error";
230
+ }
231
+ return "Validation error";
232
+ }
233
+ if (typeof error.detail === "object" && error.detail !== null) {
234
+ return JSON.stringify(error.detail);
235
+ }
236
+ return "Unknown error occurred";
237
+ }
238
+
239
+ // src/utils/as-hex.ts
240
+ import { isHex } from "viem";
241
+ function asHex(value) {
242
+ if (typeof value === "string") {
243
+ if (value.startsWith("0x") && isHex(value)) {
244
+ return value;
245
+ } else if (isHex(`0x${value}`)) {
246
+ return `0x${value}`;
247
+ }
248
+ }
249
+ throw new Error(`Invalid hex value: ${value}`);
250
+ }
251
+
252
+ // src/utils/validate-parameters.ts
253
+ function validateActionParameters(parameters) {
254
+ if (parameters?.schema !== void 0 && parameters?.schema !== false) {
255
+ if (typeof parameters.schema !== "object" || parameters.schema === null || !("parse" in parameters.schema) || typeof parameters.schema.parse !== "function") {
256
+ throw new Error("Invalid schema: must be a Zod schema object, false, or undefined");
257
+ }
258
+ }
259
+ }
260
+ function safeValidateActionParameters(parameters) {
261
+ if (parameters?.schema !== void 0 && parameters?.schema !== false) {
262
+ if (typeof parameters.schema !== "object" || parameters.schema === null || !("parse" in parameters.schema) || typeof parameters.schema.parse !== "function") {
263
+ return {
264
+ success: false,
265
+ error: {
266
+ name: "ZodError",
267
+ message: "Invalid schema: must be a Zod schema object, false, or undefined",
268
+ issues: [
269
+ {
270
+ code: "invalid_type",
271
+ expected: "object",
272
+ received: typeof parameters.schema,
273
+ path: ["schema"],
274
+ message: "Invalid schema: must be a Zod schema object, false, or undefined"
275
+ }
276
+ ]
277
+ }
278
+ };
279
+ }
280
+ }
281
+ return void 0;
282
+ }
283
+
284
+ // src/utils/network.ts
285
+ var NetworkError = class extends Error {
286
+ constructor(message, code, details) {
287
+ super(message);
288
+ this.code = code;
289
+ this.details = details;
290
+ this.name = "NetworkError";
291
+ }
292
+ };
293
+ var WalletError = class extends Error {
294
+ constructor(message, code, details) {
295
+ super(message);
296
+ this.code = code;
297
+ this.details = details;
298
+ this.name = "WalletError";
299
+ }
300
+ };
301
+ var TransactionError = class extends Error {
302
+ constructor(message, hash, details) {
303
+ super(message);
304
+ this.hash = hash;
305
+ this.details = details;
306
+ this.name = "TransactionError";
307
+ }
308
+ };
309
+ function createNetworkClients(publicClient, walletClient, address, chainId) {
310
+ return {
311
+ publicClient,
312
+ walletClient,
313
+ address,
314
+ chainId
315
+ };
316
+ }
317
+ async function checkNetworkStatus(clients, targetChainId) {
318
+ try {
319
+ const currentChainId = await clients.walletClient.getChainId();
320
+ return {
321
+ isCorrectNetwork: currentChainId === targetChainId,
322
+ currentChainId
323
+ };
324
+ } catch (error) {
325
+ throw new NetworkError(
326
+ `Failed to check network status: ${error instanceof Error ? error.message : "Unknown error"}`,
327
+ "NETWORK_CHECK_FAILED",
328
+ error
329
+ );
330
+ }
331
+ }
332
+ async function checkBalance(publicClient, address, minBalance) {
333
+ try {
334
+ const balance = await publicClient.getBalance({ address });
335
+ return {
336
+ address,
337
+ balance,
338
+ sufficient: minBalance ? balance >= minBalance : true,
339
+ required: minBalance
340
+ };
341
+ } catch (error) {
342
+ throw new NetworkError(
343
+ `Failed to check balance: ${error instanceof Error ? error.message : "Unknown error"}`,
344
+ "BALANCE_CHECK_FAILED",
345
+ error
346
+ );
347
+ }
348
+ }
349
+ async function waitForTransactionReceipt(publicClient, hash, options = {}) {
350
+ const {
351
+ timeout = 6e4,
352
+ // 60 seconds default
353
+ pollingInterval = 2e3,
354
+ // 2 seconds default
355
+ confirmations = 1
356
+ } = options;
357
+ const startTime = Date.now();
358
+ return new Promise((resolve, reject) => {
359
+ const poll = async () => {
360
+ try {
361
+ const receipt = await publicClient.getTransactionReceipt({ hash });
362
+ if (receipt) {
363
+ if (confirmations > 1) {
364
+ const currentBlock = await publicClient.getBlockNumber();
365
+ const confirmationCount = currentBlock - receipt.blockNumber + 1n;
366
+ if (confirmationCount < BigInt(confirmations)) {
367
+ const elapsed = Date.now() - startTime;
368
+ if (elapsed >= timeout) {
369
+ reject(
370
+ new TransactionError(`Transaction confirmation timeout after ${timeout}ms`, hash)
371
+ );
372
+ return;
373
+ }
374
+ setTimeout(poll, pollingInterval);
375
+ return;
376
+ }
377
+ }
378
+ resolve(receipt);
379
+ } else {
380
+ const elapsed = Date.now() - startTime;
381
+ if (elapsed >= timeout) {
382
+ reject(new TransactionError(`Transaction receipt timeout after ${timeout}ms`, hash));
383
+ return;
384
+ }
385
+ setTimeout(poll, pollingInterval);
386
+ }
387
+ } catch (error) {
388
+ const elapsed = Date.now() - startTime;
389
+ if (elapsed >= timeout) {
390
+ reject(
391
+ new TransactionError(`Transaction receipt timeout after ${timeout}ms`, hash, error)
392
+ );
393
+ return;
394
+ }
395
+ setTimeout(poll, pollingInterval);
396
+ }
397
+ };
398
+ poll();
399
+ });
400
+ }
401
+ async function executeTransaction(clients, operation, args, options = {}) {
402
+ const { timeout = 6e4, confirmations = 1, onSubmitted, onConfirmed, onError } = options;
403
+ try {
404
+ const hash = await operation(clients, ...args);
405
+ onSubmitted?.(hash);
406
+ const receipt = await waitForTransactionReceipt(clients.publicClient, hash, {
407
+ timeout,
408
+ confirmations
409
+ });
410
+ const success = receipt.status === "success";
411
+ if (success) {
412
+ onConfirmed?.(receipt);
413
+ } else {
414
+ const error = new TransactionError("Transaction failed on-chain", hash, receipt);
415
+ onError?.(error, hash);
416
+ throw error;
417
+ }
418
+ return {
419
+ hash,
420
+ receipt,
421
+ success
422
+ };
423
+ } catch (error) {
424
+ const txError = error instanceof TransactionError ? error : new TransactionError(
425
+ `Transaction execution failed: ${error instanceof Error ? error.message : "Unknown error"}`,
426
+ void 0,
427
+ error
428
+ );
429
+ onError?.(txError, txError.hash);
430
+ throw txError;
431
+ }
432
+ }
433
+ async function extractNetworkClients(publicClient, walletClient) {
434
+ try {
435
+ const address = walletClient.account?.address;
436
+ if (!address) {
437
+ throw new WalletError("WalletClient must have an account", "NO_ACCOUNT");
438
+ }
439
+ const chainId = await walletClient.getChainId();
440
+ return createNetworkClients(publicClient, walletClient, address, chainId);
441
+ } catch (error) {
442
+ throw new WalletError(
443
+ `Failed to extract network clients: ${error instanceof Error ? error.message : "Unknown error"}`,
444
+ "EXTRACTION_FAILED",
445
+ error
446
+ );
447
+ }
448
+ }
449
+ async function validateNetworkPrerequisites(clients, requirements) {
450
+ const { targetChainId, minBalance, requiredAddress } = requirements;
451
+ const networkStatus = await checkNetworkStatus(clients, targetChainId);
452
+ const balanceResult = await checkBalance(clients.publicClient, clients.address, minBalance);
453
+ const addressValid = requiredAddress ? clients.address.toLowerCase() === requiredAddress.toLowerCase() : true;
454
+ return {
455
+ networkValid: networkStatus.isCorrectNetwork,
456
+ balanceValid: balanceResult.sufficient,
457
+ addressValid,
458
+ details: {
459
+ currentChainId: networkStatus.currentChainId,
460
+ balance: balanceResult.balance,
461
+ address: clients.address
462
+ }
463
+ };
464
+ }
465
+
466
+ // src/utils/transaction.ts
467
+ function createTransactionTracker() {
468
+ let status = { state: "idle" };
469
+ let timeoutHandle;
470
+ let abortController;
471
+ const updateStatus = (newStatus) => {
472
+ status = { ...status, ...newStatus };
473
+ };
474
+ const reset = () => {
475
+ if (timeoutHandle) {
476
+ clearTimeout(timeoutHandle);
477
+ timeoutHandle = void 0;
478
+ }
479
+ if (abortController) {
480
+ abortController.abort();
481
+ abortController = void 0;
482
+ }
483
+ status = { state: "idle" };
484
+ };
485
+ const abort = () => {
486
+ if (abortController) {
487
+ abortController.abort();
488
+ }
489
+ if (timeoutHandle) {
490
+ clearTimeout(timeoutHandle);
491
+ timeoutHandle = void 0;
492
+ }
493
+ updateStatus({
494
+ state: "error",
495
+ aborted: true,
496
+ error: "Transaction aborted by user"
497
+ });
498
+ };
499
+ const execute = async (operation, clients, args, options = {}) => {
500
+ const {
501
+ timeout = 6e4,
502
+ confirmations = 1,
503
+ onSubmitted,
504
+ onConfirmed,
505
+ onError,
506
+ signal
507
+ } = options;
508
+ try {
509
+ reset();
510
+ abortController = new AbortController();
511
+ if (signal) {
512
+ if (signal.aborted) {
513
+ throw new TransactionError("Operation was aborted before execution");
514
+ }
515
+ signal.addEventListener("abort", () => {
516
+ abort();
517
+ });
518
+ }
519
+ updateStatus({
520
+ state: "submitting",
521
+ startTime: Date.now(),
522
+ error: void 0,
523
+ hash: void 0,
524
+ receipt: void 0,
525
+ aborted: false
526
+ });
527
+ if (abortController.signal.aborted) {
528
+ throw new TransactionError("Transaction aborted");
529
+ }
530
+ const hash = await operation(clients, ...args);
531
+ if (abortController.signal.aborted) {
532
+ throw new TransactionError("Transaction aborted after submission", hash);
533
+ }
534
+ updateStatus({
535
+ state: "pending",
536
+ hash,
537
+ submitTime: Date.now()
538
+ });
539
+ onSubmitted?.(hash);
540
+ if (timeout > 0) {
541
+ timeoutHandle = setTimeout(() => {
542
+ if (status.state === "pending" && !abortController?.signal.aborted) {
543
+ updateStatus({
544
+ state: "timeout",
545
+ error: `Transaction timeout after ${timeout}ms`
546
+ });
547
+ }
548
+ }, timeout);
549
+ }
550
+ const receipt = await Promise.race([
551
+ waitForTransactionReceipt(clients.publicClient, hash, { timeout, confirmations }),
552
+ new Promise((_, reject) => {
553
+ abortController?.signal.addEventListener("abort", () => {
554
+ reject(new TransactionError("Transaction aborted while waiting for receipt", hash));
555
+ });
556
+ })
557
+ ]);
558
+ if (timeoutHandle) {
559
+ clearTimeout(timeoutHandle);
560
+ timeoutHandle = void 0;
561
+ }
562
+ const success = receipt.status === "success";
563
+ updateStatus({
564
+ state: success ? "success" : "error",
565
+ receipt,
566
+ confirmTime: Date.now(),
567
+ error: success ? void 0 : "Transaction failed on-chain"
568
+ });
569
+ if (success) {
570
+ onConfirmed?.(receipt);
571
+ } else {
572
+ const error = new TransactionError("Transaction failed on-chain", hash, receipt);
573
+ onError?.(error, hash);
574
+ throw error;
575
+ }
576
+ return {
577
+ hash,
578
+ receipt,
579
+ success
580
+ };
581
+ } catch (error) {
582
+ const txError = error instanceof TransactionError ? error : new TransactionError(
583
+ `Transaction execution failed: ${error instanceof Error ? error.message : "Unknown error"}`,
584
+ status.hash,
585
+ error
586
+ );
587
+ updateStatus({
588
+ state: "error",
589
+ error: txError.message
590
+ });
591
+ onError?.(txError, status.hash);
592
+ throw txError;
593
+ }
594
+ };
595
+ return {
596
+ get status() {
597
+ return { ...status };
598
+ },
599
+ get isIdle() {
600
+ return status.state === "idle";
601
+ },
602
+ get isSubmitting() {
603
+ return status.state === "submitting";
604
+ },
605
+ get isPending() {
606
+ return status.state === "pending";
607
+ },
608
+ get isSuccess() {
609
+ return status.state === "success";
610
+ },
611
+ get isError() {
612
+ return status.state === "error";
613
+ },
614
+ get isTimeout() {
615
+ return status.state === "timeout";
616
+ },
617
+ get isAborted() {
618
+ return status.aborted === true;
619
+ },
620
+ get isComplete() {
621
+ return ["success", "error", "timeout"].includes(status.state);
622
+ },
623
+ abort,
624
+ reset,
625
+ execute
626
+ };
627
+ }
628
+ async function executeBatchTransactions(operations, clients, batchOptions) {
629
+ const { mode, failFast = false, onProgress } = batchOptions;
630
+ const results = [];
631
+ if (mode === "sequential") {
632
+ for (let i = 0; i < operations.length; i++) {
633
+ const op = operations[i];
634
+ if (!op) continue;
635
+ const { operation, args, options } = op;
636
+ try {
637
+ const tracker = createTransactionTracker();
638
+ const result = await tracker.execute(operation, clients, args, options);
639
+ results.push(result);
640
+ onProgress?.(i + 1, operations.length, results);
641
+ } catch (error) {
642
+ const txError = error instanceof Error ? error : new Error(String(error));
643
+ results.push(txError);
644
+ onProgress?.(i + 1, operations.length, results);
645
+ if (failFast) {
646
+ for (let j = i + 1; j < operations.length; j++) {
647
+ results.push(new Error("Cancelled due to previous failure"));
648
+ }
649
+ break;
650
+ }
651
+ }
652
+ }
653
+ } else {
654
+ const promises = operations.map(async ({ operation, args, options }) => {
655
+ try {
656
+ const tracker = createTransactionTracker();
657
+ return await tracker.execute(operation, clients, args, options);
658
+ } catch (error) {
659
+ return error instanceof Error ? error : new Error(String(error));
660
+ }
661
+ });
662
+ const allResults = await Promise.allSettled(promises);
663
+ results.push(...allResults.map((r) => r.status === "fulfilled" ? r.value : r.reason));
664
+ onProgress?.(operations.length, operations.length, results);
665
+ }
666
+ const successCount = results.filter((r) => !(r instanceof Error)).length;
667
+ const errorCount = results.length - successCount;
668
+ return {
669
+ results,
670
+ successCount,
671
+ errorCount,
672
+ allSuccessful: errorCount === 0
673
+ };
674
+ }
675
+ async function executeTransactionWithRetry(operation, clients, args, options = {}, retryOptions = {}) {
676
+ const {
677
+ maxRetries = 3,
678
+ initialDelay = 1e3,
679
+ maxDelay = 1e4,
680
+ backoffFactor = 2,
681
+ retryCondition = () => true
682
+ } = retryOptions;
683
+ let lastError;
684
+ let delay = initialDelay;
685
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
686
+ try {
687
+ const tracker = createTransactionTracker();
688
+ return await tracker.execute(operation, clients, args, options);
689
+ } catch (error) {
690
+ lastError = error instanceof Error ? error : new Error(String(error));
691
+ if (attempt === maxRetries) {
692
+ break;
693
+ }
694
+ if (!retryCondition(lastError)) {
695
+ break;
696
+ }
697
+ await new Promise((resolve) => setTimeout(resolve, delay));
698
+ delay = Math.min(delay * backoffFactor, maxDelay);
699
+ }
700
+ }
701
+ throw lastError;
702
+ }
703
+ async function estimateTransactionGas(clients, transaction, options = {}) {
704
+ const {
705
+ gasLimitMultiplier = 1.2,
706
+ maxFeePerGasMultiplier = 1.1,
707
+ priorityFeeMultiplier = 1.1
708
+ } = options;
709
+ try {
710
+ const estimatedGas = await clients.publicClient.estimateGas(transaction);
711
+ const gasLimit = BigInt(Math.ceil(Number(estimatedGas) * gasLimitMultiplier));
712
+ let maxFeePerGas;
713
+ let maxPriorityFeePerGas;
714
+ try {
715
+ const feeData = await clients.publicClient.estimateFeesPerGas();
716
+ if (feeData.maxFeePerGas) {
717
+ maxFeePerGas = BigInt(Math.ceil(Number(feeData.maxFeePerGas) * maxFeePerGasMultiplier));
718
+ }
719
+ if (feeData.maxPriorityFeePerGas) {
720
+ maxPriorityFeePerGas = BigInt(
721
+ Math.ceil(Number(feeData.maxPriorityFeePerGas) * priorityFeeMultiplier)
722
+ );
723
+ }
724
+ } catch (error) {
725
+ }
726
+ return {
727
+ gasLimit,
728
+ maxFeePerGas,
729
+ maxPriorityFeePerGas
730
+ };
731
+ } catch (error) {
732
+ throw new TransactionError(
733
+ `Gas estimation failed: ${error instanceof Error ? error.message : "Unknown error"}`,
734
+ void 0,
735
+ error
736
+ );
737
+ }
738
+ }
739
+
740
+ // src/utils/client-factories.ts
741
+ import {
742
+ createPublicClient,
743
+ createWalletClient,
744
+ http,
745
+ custom
746
+ } from "viem";
747
+ import { privateKeyToAccount } from "viem/accounts";
748
+ function isBrowser() {
749
+ return typeof window !== "undefined" && typeof window.ethereum !== "undefined";
750
+ }
751
+ function getEthereumProvider() {
752
+ if (!isBrowser()) return null;
753
+ const ethereum = window.ethereum;
754
+ return ethereum || null;
755
+ }
756
+ function createClientsFromPrivateKey(chain, privateKey, rpcUrl) {
757
+ try {
758
+ const account = privateKeyToAccount(privateKey);
759
+ const publicClient = createPublicClient({
760
+ chain,
761
+ transport: http(rpcUrl || chain.rpcUrls.default.http[0])
762
+ });
763
+ const walletClient = createWalletClient({
764
+ account,
765
+ chain,
766
+ transport: http(rpcUrl || chain.rpcUrls.default.http[0])
767
+ });
768
+ return createNetworkClients(publicClient, walletClient, account.address, chain.id);
769
+ } catch (error) {
770
+ throw new WalletError(
771
+ `Failed to create clients from private key: ${error instanceof Error ? error.message : "Unknown error"}`,
772
+ "CLIENT_CREATION_FAILED",
773
+ error
774
+ );
775
+ }
776
+ }
777
+ async function createClientsFromBrowser(chain, rpcUrl) {
778
+ if (!isBrowser()) {
779
+ throw new WalletError(
780
+ "Browser wallet connection is only available in browser environment",
781
+ "NOT_BROWSER_ENVIRONMENT"
782
+ );
783
+ }
784
+ const provider = getEthereumProvider();
785
+ if (!provider) {
786
+ throw new WalletError(
787
+ "No Ethereum provider found. Please install a wallet like MetaMask.",
788
+ "NO_PROVIDER"
789
+ );
790
+ }
791
+ try {
792
+ const accounts = await provider.request({
793
+ method: "eth_requestAccounts"
794
+ });
795
+ if (!accounts || accounts.length === 0) {
796
+ throw new WalletError("No accounts available", "NO_ACCOUNTS");
797
+ }
798
+ const address = accounts[0];
799
+ const chainId = await provider.request({ method: "eth_chainId" });
800
+ const currentChainId = parseInt(chainId, 16);
801
+ if (currentChainId !== chain.id) {
802
+ await switchToNetwork(provider, chain.id);
803
+ }
804
+ const publicClient = createPublicClient({
805
+ chain,
806
+ transport: http(rpcUrl || chain.rpcUrls.default.http[0])
807
+ });
808
+ const walletClient = createWalletClient({
809
+ account: address,
810
+ chain,
811
+ transport: custom(provider)
812
+ });
813
+ return createNetworkClients(publicClient, walletClient, address, chain.id);
814
+ } catch (error) {
815
+ if (error instanceof WalletError || error instanceof NetworkError) {
816
+ throw error;
817
+ }
818
+ throw new WalletError(
819
+ `Failed to connect browser wallet: ${error instanceof Error ? error.message : "Unknown error"}`,
820
+ "BROWSER_CONNECTION_FAILED",
821
+ error
822
+ );
823
+ }
824
+ }
825
+ async function switchToNetwork(provider, chainId) {
826
+ try {
827
+ await provider.request({
828
+ method: "wallet_switchEthereumChain",
829
+ params: [{ chainId: `0x${chainId.toString(16)}` }]
830
+ });
831
+ } catch (error) {
832
+ const errorObj = error;
833
+ if (errorObj.code === 4902) {
834
+ throw new NetworkError(
835
+ `Network ${chainId} not found in wallet. Please add it manually.`,
836
+ "NETWORK_NOT_FOUND",
837
+ error
838
+ );
839
+ }
840
+ throw new NetworkError(
841
+ `Failed to switch network: ${errorObj.message || "Unknown error"}`,
842
+ "NETWORK_SWITCH_FAILED",
843
+ error
844
+ );
845
+ }
846
+ }
847
+ async function addNetwork(provider, config) {
848
+ try {
849
+ await provider.request({
850
+ method: "wallet_addEthereumChain",
851
+ params: [
852
+ {
853
+ chainId: `0x${config.chainId.toString(16)}`,
854
+ chainName: config.name,
855
+ rpcUrls: [config.rpcUrl],
856
+ blockExplorerUrls: config.blockExplorer ? [config.blockExplorer] : void 0,
857
+ nativeCurrency: {
858
+ name: "ETH",
859
+ symbol: "ETH",
860
+ decimals: 18
861
+ }
862
+ }
863
+ ]
864
+ });
865
+ } catch (error) {
866
+ const errorObj = error;
867
+ throw new NetworkError(
868
+ `Failed to add network: ${errorObj.message || "Unknown error"}`,
869
+ "NETWORK_ADD_FAILED",
870
+ error
871
+ );
872
+ }
873
+ }
874
+ async function autoCreateClients(chain, options = {}) {
875
+ const { privateKey, rpcUrl, preferBrowser = false } = options;
876
+ if (privateKey) {
877
+ return createClientsFromPrivateKey(chain, privateKey, rpcUrl);
878
+ }
879
+ if (isBrowser() && (preferBrowser || !privateKey)) {
880
+ return createClientsFromBrowser(chain, rpcUrl);
881
+ }
882
+ throw new WalletError(
883
+ "No wallet connection method available. Provide a private key for server-side usage or use in browser environment.",
884
+ "NO_CONNECTION_METHOD"
885
+ );
886
+ }
887
+
888
+ // src/actions/get_current_user.ts
889
+ var CurrentUserSchema = z2.object({
890
+ username: z2.string(),
891
+ email: z2.string(),
892
+ credits: z2.number(),
893
+ granted_credits: z2.number(),
894
+ avatar: z2.string(),
895
+ team_name: z2.string(),
896
+ team_tier: z2.string()
897
+ }).passthrough();
898
+ async function getCurrentUser(client, parameters) {
899
+ validateActionParameters(parameters);
900
+ const response = await client.get("/auth/me");
901
+ if (parameters?.schema === false) {
902
+ return response;
903
+ }
904
+ const schema = parameters?.schema || CurrentUserSchema;
905
+ return schema.parse(response);
906
+ }
907
+ async function safeGetCurrentUser(client, parameters) {
908
+ const parameterValidationError = safeValidateActionParameters(parameters);
909
+ if (parameterValidationError) {
910
+ return parameterValidationError;
911
+ }
912
+ const httpResult = await client.safeGet("/auth/me");
913
+ if (!httpResult.success) {
914
+ return httpResult;
915
+ }
916
+ if (parameters?.schema === false) {
917
+ return { success: true, data: httpResult.data };
918
+ }
919
+ const schema = parameters?.schema || CurrentUserSchema;
920
+ return schema.safeParse(httpResult.data);
921
+ }
922
+
923
+ // src/actions/get_available_nodes.ts
924
+ import { z as z4 } from "zod";
925
+
926
+ // src/types/kms_info.ts
927
+ import { z as z3 } from "zod";
928
+ var KmsInfoSchema = z3.object({
929
+ id: z3.string(),
930
+ slug: z3.string().nullable(),
931
+ url: z3.string(),
932
+ version: z3.string(),
933
+ chain_id: z3.number().nullable(),
934
+ kms_contract_address: z3.string().nullable().transform((val) => val),
935
+ gateway_app_id: z3.string().nullable().transform((val) => val)
936
+ }).passthrough();
937
+
938
+ // src/actions/get_available_nodes.ts
939
+ var AvailableOSImageSchema = z4.object({
940
+ name: z4.string(),
941
+ is_dev: z4.boolean(),
942
+ version: z4.tuple([z4.number(), z4.number(), z4.number()]),
943
+ os_image_hash: z4.string().nullable().optional()
944
+ }).passthrough();
945
+ var TeepodCapacitySchema = z4.object({
946
+ teepod_id: z4.number(),
947
+ name: z4.string(),
948
+ listed: z4.boolean(),
949
+ resource_score: z4.number(),
950
+ remaining_vcpu: z4.number(),
951
+ remaining_memory: z4.number(),
952
+ remaining_cvm_slots: z4.number(),
953
+ images: z4.array(AvailableOSImageSchema),
954
+ dedicated_for_team_id: z4.number().nullable().optional(),
955
+ support_onchain_kms: z4.boolean().optional(),
956
+ fmspc: z4.string().nullable().optional(),
957
+ device_id: z4.string().nullable().optional()
958
+ }).passthrough();
959
+ var ResourceThresholdSchema = z4.object({
960
+ max_instances: z4.number().nullable().optional(),
961
+ max_vcpu: z4.number().nullable().optional(),
962
+ max_memory: z4.number().nullable().optional(),
963
+ max_disk: z4.number().nullable().optional()
964
+ }).passthrough();
965
+ var AvailableNodesSchema = z4.object({
966
+ tier: z4.string(),
967
+ // TeamTier is string enum
968
+ capacity: ResourceThresholdSchema,
969
+ nodes: z4.array(TeepodCapacitySchema),
970
+ kms_list: z4.array(KmsInfoSchema)
971
+ }).passthrough();
972
+ async function getAvailableNodes(client, parameters) {
973
+ const response = await client.get("/teepods/available");
974
+ if (parameters?.schema === false) {
975
+ return response;
976
+ }
977
+ const schema = parameters?.schema || AvailableNodesSchema;
978
+ return schema.parse(response);
979
+ }
980
+ async function safeGetAvailableNodes(client, parameters) {
981
+ const httpResult = await client.safeGet("/teepods/available");
982
+ if (!httpResult.success) {
983
+ return httpResult;
984
+ }
985
+ if (parameters?.schema === false) {
986
+ return { success: true, data: httpResult.data };
987
+ }
988
+ const schema = parameters?.schema || AvailableNodesSchema;
989
+ return schema.safeParse(httpResult.data);
990
+ }
991
+
992
+ // src/actions/provision_cvm.ts
993
+ import { z as z5 } from "zod";
994
+ var ProvisionCvmSchema = z5.object({
995
+ app_id: z5.string().nullable().optional(),
996
+ app_env_encrypt_pubkey: z5.string().nullable().optional(),
997
+ compose_hash: z5.string(),
998
+ fmspc: z5.string().nullable().optional(),
999
+ device_id: z5.string().nullable().optional(),
1000
+ os_image_hash: z5.string().nullable().optional(),
1001
+ node_id: z5.number().nullable().optional()
1002
+ // Transformed from teepod_id in response
1003
+ }).passthrough();
1004
+ var ProvisionCvmRequestSchema = z5.object({
1005
+ node_id: z5.number().optional(),
1006
+ // recommended
1007
+ teepod_id: z5.number().optional(),
1008
+ // deprecated, for compatibility
1009
+ name: z5.string(),
1010
+ image: z5.string(),
1011
+ vcpu: z5.number(),
1012
+ memory: z5.number(),
1013
+ disk_size: z5.number(),
1014
+ compose_file: z5.object({
1015
+ allowed_envs: z5.array(z5.string()).optional(),
1016
+ pre_launch_script: z5.string().optional(),
1017
+ docker_compose_file: z5.string().optional(),
1018
+ name: z5.string().optional(),
1019
+ kms_enabled: z5.boolean().optional(),
1020
+ public_logs: z5.boolean().optional(),
1021
+ public_sysinfo: z5.boolean().optional(),
1022
+ gateway_enabled: z5.boolean().optional(),
1023
+ // recommended
1024
+ tproxy_enabled: z5.boolean().optional()
1025
+ // deprecated, for compatibility
1026
+ }),
1027
+ listed: z5.boolean().optional(),
1028
+ instance_type: z5.string().nullable().optional(),
1029
+ kms_id: z5.string().optional(),
1030
+ env_keys: z5.array(z5.string()).optional()
1031
+ }).passthrough();
1032
+ function autofillComposeFileName(appCompose) {
1033
+ if (appCompose.compose_file && !appCompose.compose_file.name) {
1034
+ return {
1035
+ ...appCompose,
1036
+ compose_file: {
1037
+ ...appCompose.compose_file,
1038
+ name: appCompose.name
1039
+ }
1040
+ };
1041
+ }
1042
+ return appCompose;
1043
+ }
1044
+ function handleGatewayCompatibility(appCompose) {
1045
+ if (!appCompose.compose_file) {
1046
+ return appCompose;
1047
+ }
1048
+ const composeFile = { ...appCompose.compose_file };
1049
+ if (typeof composeFile.gateway_enabled === "boolean" && typeof composeFile.tproxy_enabled === "boolean") {
1050
+ delete composeFile.tproxy_enabled;
1051
+ } else if (typeof composeFile.tproxy_enabled === "boolean" && typeof composeFile.gateway_enabled === "undefined") {
1052
+ composeFile.gateway_enabled = composeFile.tproxy_enabled;
1053
+ delete composeFile.tproxy_enabled;
1054
+ if (typeof window !== "undefined" ? window.console : globalThis.console) {
1055
+ console.warn(
1056
+ "[phala/cloud] tproxy_enabled is deprecated, please use gateway_enabled instead. See docs for migration."
1057
+ );
1058
+ }
1059
+ }
1060
+ return {
1061
+ ...appCompose,
1062
+ compose_file: composeFile
1063
+ };
1064
+ }
1065
+ function transformResponse(data, isDefaultSchema) {
1066
+ if (!isDefaultSchema || !data || typeof data !== "object") {
1067
+ return data;
1068
+ }
1069
+ if (data && typeof data === "object" && "teepod_id" in data) {
1070
+ const { teepod_id, ...rest } = data;
1071
+ return { ...rest, node_id: teepod_id };
1072
+ }
1073
+ return data;
1074
+ }
1075
+ async function provisionCvm(client, appCompose, parameters) {
1076
+ validateActionParameters(parameters);
1077
+ const body = handleGatewayCompatibility(autofillComposeFileName(appCompose));
1078
+ let requestBody = { ...body };
1079
+ if (typeof body.node_id === "number") {
1080
+ requestBody = { ...body, teepod_id: body.node_id };
1081
+ delete requestBody.node_id;
1082
+ } else if (typeof body.teepod_id === "number") {
1083
+ console.warn("[phala/cloud] teepod_id is deprecated, please use node_id instead.");
1084
+ }
1085
+ const response = await client.post("/cvms/provision", requestBody);
1086
+ const isDefaultSchema = parameters?.schema === void 0;
1087
+ const transformedData = transformResponse(response, isDefaultSchema);
1088
+ if (parameters?.schema === false) {
1089
+ return transformedData;
1090
+ }
1091
+ const usedSchema = parameters?.schema || ProvisionCvmSchema;
1092
+ return usedSchema.parse(transformedData);
1093
+ }
1094
+ async function safeProvisionCvm(client, appCompose, parameters) {
1095
+ const parameterValidationError = safeValidateActionParameters(parameters);
1096
+ if (parameterValidationError) {
1097
+ return parameterValidationError;
1098
+ }
1099
+ const schema = parameters?.schema;
1100
+ const body = handleGatewayCompatibility(autofillComposeFileName(appCompose));
1101
+ let requestBody = { ...body };
1102
+ if (typeof body.node_id === "number") {
1103
+ requestBody = { ...body, teepod_id: body.node_id };
1104
+ delete requestBody.node_id;
1105
+ } else if (typeof body.teepod_id === "number") {
1106
+ console.warn("[phala/cloud] teepod_id is deprecated, please use node_id instead.");
1107
+ }
1108
+ const httpResult = await client.safePost("/cvms/provision", requestBody);
1109
+ if (!httpResult.success) {
1110
+ return httpResult;
1111
+ }
1112
+ if (schema === false) {
1113
+ return { success: true, data: httpResult.data };
1114
+ }
1115
+ const isDefaultSchema = !schema;
1116
+ const usedSchema = schema || ProvisionCvmSchema;
1117
+ const transformResult = usedSchema.safeParse(transformResponse(httpResult.data, isDefaultSchema));
1118
+ return transformResult;
1119
+ }
1120
+
1121
+ // src/actions/commit_cvm_provision.ts
1122
+ import { z as z6 } from "zod";
1123
+ var CommitCvmProvisionSchema = z6.object({
1124
+ id: z6.number(),
1125
+ name: z6.string(),
1126
+ status: z6.string(),
1127
+ teepod_id: z6.number(),
1128
+ teepod: z6.object({
1129
+ id: z6.number(),
1130
+ name: z6.string()
1131
+ }).nullable(),
1132
+ user_id: z6.number().nullable(),
1133
+ app_id: z6.string().nullable(),
1134
+ vm_uuid: z6.string().nullable(),
1135
+ instance_id: z6.string().nullable(),
1136
+ app_url: z6.string().nullable(),
1137
+ base_image: z6.string().nullable(),
1138
+ vcpu: z6.number(),
1139
+ memory: z6.number(),
1140
+ disk_size: z6.number(),
1141
+ manifest_version: z6.number().nullable(),
1142
+ version: z6.string().nullable(),
1143
+ runner: z6.string().nullable(),
1144
+ docker_compose_file: z6.string().nullable(),
1145
+ features: z6.array(z6.string()).nullable(),
1146
+ created_at: z6.string(),
1147
+ encrypted_env_pubkey: z6.string().nullable().optional(),
1148
+ app_auth_contract_address: z6.string().nullable().optional(),
1149
+ deployer_address: z6.string().nullable().optional()
1150
+ }).passthrough();
1151
+ var CommitCvmProvisionRequestSchema = z6.object({
1152
+ encrypted_env: z6.string().optional().nullable(),
1153
+ app_id: z6.string(),
1154
+ compose_hash: z6.string().optional(),
1155
+ kms_id: z6.string().optional(),
1156
+ contract_address: z6.string().optional(),
1157
+ deployer_address: z6.string().optional(),
1158
+ env_keys: z6.array(z6.string()).optional().nullable()
1159
+ }).passthrough();
1160
+ async function commitCvmProvision(client, payload, parameters) {
1161
+ validateActionParameters(parameters);
1162
+ const response = await client.post("/cvms", payload);
1163
+ if (parameters?.schema === false) {
1164
+ return response;
1165
+ }
1166
+ const schema = parameters?.schema || CommitCvmProvisionSchema;
1167
+ return schema.parse(response);
1168
+ }
1169
+ async function safeCommitCvmProvision(client, payload, parameters) {
1170
+ const parameterValidationError = safeValidateActionParameters(parameters);
1171
+ if (parameterValidationError) {
1172
+ return parameterValidationError;
1173
+ }
1174
+ const httpResult = await client.safePost("/cvms", payload);
1175
+ if (!httpResult.success) {
1176
+ return httpResult;
1177
+ }
1178
+ if (parameters?.schema === false) {
1179
+ return { success: true, data: httpResult.data };
1180
+ }
1181
+ const schema = parameters?.schema || CommitCvmProvisionSchema;
1182
+ const validationResult = schema.safeParse(httpResult.data);
1183
+ return validationResult;
1184
+ }
1185
+
1186
+ // src/actions/deploy_app_auth.ts
1187
+ import { z as z7 } from "zod";
1188
+ import {
1189
+ createPublicClient as createPublicClient2,
1190
+ createWalletClient as createWalletClient2,
1191
+ http as http2,
1192
+ parseEventLogs,
1193
+ parseEther
1194
+ } from "viem";
1195
+ import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
1196
+ var kmsAuthAbi = [
1197
+ {
1198
+ inputs: [
1199
+ { name: "deployer", type: "address" },
1200
+ { name: "disableUpgrades", type: "bool" },
1201
+ { name: "allowAnyDevice", type: "bool" },
1202
+ { name: "deviceId", type: "bytes32" },
1203
+ { name: "composeHash", type: "bytes32" }
1204
+ ],
1205
+ name: "deployAndRegisterApp",
1206
+ outputs: [{ name: "", type: "address" }],
1207
+ stateMutability: "nonpayable",
1208
+ type: "function"
1209
+ },
1210
+ {
1211
+ inputs: [
1212
+ { name: "appId", type: "address", indexed: true },
1213
+ { name: "deployer", type: "address", indexed: true }
1214
+ ],
1215
+ name: "AppDeployedViaFactory",
1216
+ type: "event",
1217
+ anonymous: false
1218
+ },
1219
+ {
1220
+ inputs: [{ name: "appId", type: "address", indexed: false }],
1221
+ name: "AppRegistered",
1222
+ type: "event",
1223
+ anonymous: false
1224
+ }
1225
+ ];
1226
+ var DeployAppAuthRequestBaseSchema = z7.object({
1227
+ // Chain configuration (conditionally required)
1228
+ chain: z7.unknown().optional(),
1229
+ // Contract configuration (required)
1230
+ kmsContractAddress: z7.string(),
1231
+ // Authentication mode: either privateKey OR walletClient (required, mutually exclusive)
1232
+ privateKey: z7.string().optional(),
1233
+ walletClient: z7.unknown().optional(),
1234
+ // Public client (optional, will create default if not provided)
1235
+ publicClient: z7.unknown().optional(),
1236
+ // App configuration (optional)
1237
+ allowAnyDevice: z7.boolean().optional().default(false),
1238
+ deviceId: z7.string().optional().default("0000000000000000000000000000000000000000000000000000000000000000"),
1239
+ composeHash: z7.string().optional().default("0000000000000000000000000000000000000000000000000000000000000000"),
1240
+ disableUpgrades: z7.boolean().optional().default(false),
1241
+ // Validation configuration (optional)
1242
+ skipPrerequisiteChecks: z7.boolean().optional().default(false),
1243
+ minBalance: z7.string().optional()
1244
+ // ETH amount as string, e.g., "0.01"
1245
+ }).passthrough();
1246
+ var DeployAppAuthRequestSchema = DeployAppAuthRequestBaseSchema.refine(
1247
+ (data) => {
1248
+ const hasPrivateKey = !!data.privateKey;
1249
+ const hasWalletClient = !!data.walletClient;
1250
+ return hasPrivateKey !== hasWalletClient;
1251
+ },
1252
+ {
1253
+ message: "Either 'privateKey' or 'walletClient' must be provided, but not both",
1254
+ path: ["privateKey", "walletClient"]
1255
+ }
1256
+ ).refine(
1257
+ (data) => {
1258
+ const hasPublicClient = !!data.publicClient;
1259
+ const hasWalletClient = !!data.walletClient;
1260
+ const hasChain = !!data.chain;
1261
+ if (hasPublicClient && hasWalletClient) {
1262
+ return true;
1263
+ }
1264
+ return hasChain;
1265
+ },
1266
+ {
1267
+ message: "Chain is required when publicClient or walletClient is not provided",
1268
+ path: ["chain"]
1269
+ }
1270
+ );
1271
+ var DeployAppAuthSchema = z7.object({
1272
+ appId: z7.string(),
1273
+ appAuthAddress: z7.string(),
1274
+ deployer: z7.string(),
1275
+ transactionHash: z7.string(),
1276
+ blockNumber: z7.bigint().optional(),
1277
+ gasUsed: z7.bigint().optional()
1278
+ }).passthrough();
1279
+ function parseDeploymentResult(receipt, deployer, kmsContractAddress) {
1280
+ try {
1281
+ const logs = parseEventLogs({
1282
+ abi: kmsAuthAbi,
1283
+ eventName: "AppDeployedViaFactory",
1284
+ logs: receipt.logs,
1285
+ strict: false
1286
+ });
1287
+ if (logs.length === 0) {
1288
+ if (receipt.status === "reverted") {
1289
+ throw new Error(`Transaction failed: ${receipt.transactionHash}`);
1290
+ }
1291
+ throw new Error(
1292
+ `Transaction ${receipt.transactionHash} has no AppDeployedViaFactory events. The deployment failed. Status: ${receipt.status}. Found ${receipt.logs.length} logs.`
1293
+ );
1294
+ }
1295
+ const deploymentEvent = logs[0];
1296
+ if (!deploymentEvent?.args) {
1297
+ throw new Error("Event has no data");
1298
+ }
1299
+ const { appId, deployer: eventDeployer } = deploymentEvent.args;
1300
+ if (!appId) {
1301
+ throw new Error("Event missing appId");
1302
+ }
1303
+ return {
1304
+ appId,
1305
+ appAuthAddress: appId,
1306
+ deployer,
1307
+ transactionHash: receipt.transactionHash,
1308
+ blockNumber: receipt.blockNumber,
1309
+ gasUsed: receipt.gasUsed
1310
+ };
1311
+ } catch (error) {
1312
+ if (error instanceof Error) {
1313
+ throw error;
1314
+ }
1315
+ throw new Error(`Parse failed: ${error}`);
1316
+ }
1317
+ }
1318
+ async function deployAppAuth(request, parameters) {
1319
+ const validatedRequest = DeployAppAuthRequestSchema.parse(request);
1320
+ const {
1321
+ chain,
1322
+ kmsContractAddress,
1323
+ privateKey,
1324
+ walletClient: providedWalletClient,
1325
+ publicClient: providedPublicClient,
1326
+ allowAnyDevice: rawAllowAnyDevice = false,
1327
+ deviceId = "0000000000000000000000000000000000000000000000000000000000000000",
1328
+ composeHash = "0000000000000000000000000000000000000000000000000000000000000000",
1329
+ disableUpgrades = false,
1330
+ skipPrerequisiteChecks = false,
1331
+ minBalance,
1332
+ timeout = 12e4,
1333
+ // 2 minutes default
1334
+ retryOptions,
1335
+ signal,
1336
+ onTransactionStateChange,
1337
+ onTransactionSubmitted,
1338
+ onTransactionConfirmed
1339
+ } = validatedRequest;
1340
+ const defaultDeviceId = "0000000000000000000000000000000000000000000000000000000000000000";
1341
+ const hasSpecificDevice = deviceId !== defaultDeviceId && deviceId !== "0x" + defaultDeviceId;
1342
+ const allowAnyDevice = hasSpecificDevice ? false : rawAllowAnyDevice;
1343
+ let publicClient;
1344
+ let walletClient;
1345
+ let deployerAddress;
1346
+ let chainId;
1347
+ if (privateKey) {
1348
+ const account = privateKeyToAccount2(privateKey);
1349
+ if (providedPublicClient) {
1350
+ if (typeof providedPublicClient !== "object" || !providedPublicClient) {
1351
+ throw new Error("publicClient is invalid");
1352
+ }
1353
+ publicClient = providedPublicClient;
1354
+ } else {
1355
+ if (!chain) {
1356
+ throw new Error("Chain required for publicClient");
1357
+ }
1358
+ publicClient = createPublicClient2({
1359
+ chain,
1360
+ transport: http2()
1361
+ });
1362
+ }
1363
+ if (!chain) {
1364
+ throw new Error("Chain required for walletClient");
1365
+ }
1366
+ walletClient = createWalletClient2({
1367
+ account,
1368
+ chain,
1369
+ transport: http2()
1370
+ });
1371
+ deployerAddress = account.address;
1372
+ chainId = chain.id;
1373
+ } else if (providedWalletClient) {
1374
+ if (typeof providedWalletClient !== "object" || !providedWalletClient) {
1375
+ throw new Error("walletClient is invalid");
1376
+ }
1377
+ walletClient = providedWalletClient;
1378
+ if (providedPublicClient) {
1379
+ if (typeof providedPublicClient !== "object" || !providedPublicClient) {
1380
+ throw new Error("publicClient is invalid");
1381
+ }
1382
+ publicClient = providedPublicClient;
1383
+ } else {
1384
+ if (!chain) {
1385
+ throw new Error("Chain required for publicClient");
1386
+ }
1387
+ publicClient = createPublicClient2({
1388
+ chain,
1389
+ transport: http2()
1390
+ });
1391
+ }
1392
+ if (!walletClient.account?.address) {
1393
+ throw new Error("WalletClient needs an account");
1394
+ }
1395
+ deployerAddress = walletClient.account.address;
1396
+ if (chain) {
1397
+ chainId = chain.id;
1398
+ } else {
1399
+ chainId = await walletClient.getChainId();
1400
+ }
1401
+ } else {
1402
+ throw new Error("Need privateKey or walletClient");
1403
+ }
1404
+ const networkClients = {
1405
+ publicClient,
1406
+ walletClient,
1407
+ address: deployerAddress,
1408
+ chainId
1409
+ };
1410
+ const transactionTracker = createTransactionTracker();
1411
+ if (onTransactionStateChange && typeof onTransactionStateChange === "function") {
1412
+ const pollStatus = () => {
1413
+ onTransactionStateChange(
1414
+ transactionTracker.status
1415
+ );
1416
+ if (!transactionTracker.isComplete) {
1417
+ setTimeout(pollStatus, 100);
1418
+ }
1419
+ };
1420
+ setTimeout(pollStatus, 10);
1421
+ }
1422
+ if (!skipPrerequisiteChecks) {
1423
+ const requirements = {
1424
+ targetChainId: chainId,
1425
+ minBalance: minBalance ? parseEther(minBalance) : parseEther("0.001")
1426
+ // Default 0.001 ETH
1427
+ };
1428
+ const validation = await validateNetworkPrerequisites(networkClients, requirements);
1429
+ if (!validation.networkValid) {
1430
+ throw new Error(
1431
+ `Wrong network. Need chain ${requirements.targetChainId}, got ${validation.details.currentChainId}`
1432
+ );
1433
+ }
1434
+ if (!validation.balanceValid) {
1435
+ const requiredEth = Number(requirements.minBalance) / 1e18;
1436
+ const currentEth = Number(validation.details.balance) / 1e18;
1437
+ throw new Error(`Not enough ETH. Need ${requiredEth}, have ${currentEth.toFixed(6)}`);
1438
+ }
1439
+ }
1440
+ const deviceIdHex = asHex(deviceId);
1441
+ const composeHashHex = asHex(composeHash);
1442
+ const deviceIdBytes = `0x${deviceIdHex.slice(2).padEnd(64, "0")}`;
1443
+ const composeHashBytes = `0x${composeHashHex.slice(2).padEnd(64, "0")}`;
1444
+ const deployOperation = async (clients) => {
1445
+ try {
1446
+ const code = await clients.publicClient.getCode({ address: kmsContractAddress });
1447
+ if (!code || code === "0x") {
1448
+ throw new Error(`No contract at ${kmsContractAddress}`);
1449
+ }
1450
+ } catch (error) {
1451
+ if (error instanceof Error && error.message.includes("No contract at")) {
1452
+ throw error;
1453
+ }
1454
+ }
1455
+ const contractCall = {
1456
+ address: kmsContractAddress,
1457
+ abi: kmsAuthAbi,
1458
+ functionName: "deployAndRegisterApp",
1459
+ args: [
1460
+ clients.address,
1461
+ disableUpgrades,
1462
+ allowAnyDevice,
1463
+ deviceIdBytes,
1464
+ composeHashBytes
1465
+ ],
1466
+ account: clients.walletClient.account || clients.address,
1467
+ chain: chain || null
1468
+ };
1469
+ return await clients.walletClient.writeContract(contractCall);
1470
+ };
1471
+ const transactionResult = retryOptions ? await executeTransactionWithRetry(
1472
+ deployOperation,
1473
+ networkClients,
1474
+ [],
1475
+ {
1476
+ timeout,
1477
+ confirmations: 1,
1478
+ onSubmitted: onTransactionSubmitted,
1479
+ onConfirmed: onTransactionConfirmed,
1480
+ signal
1481
+ },
1482
+ retryOptions
1483
+ ) : await transactionTracker.execute(deployOperation, networkClients, [], {
1484
+ timeout,
1485
+ confirmations: 1,
1486
+ onSubmitted: onTransactionSubmitted,
1487
+ onConfirmed: onTransactionConfirmed,
1488
+ signal
1489
+ });
1490
+ const result = parseDeploymentResult(
1491
+ transactionResult.receipt,
1492
+ deployerAddress,
1493
+ kmsContractAddress
1494
+ );
1495
+ if (parameters?.schema === false) {
1496
+ return result;
1497
+ }
1498
+ const schema = parameters?.schema || DeployAppAuthSchema;
1499
+ return schema.parse(result);
1500
+ }
1501
+ async function safeDeployAppAuth(request, parameters) {
1502
+ try {
1503
+ const result = await deployAppAuth(request, parameters);
1504
+ return { success: true, data: result };
1505
+ } catch (error) {
1506
+ const errorMessage = error instanceof Error ? error.message : "Unknown deployment error";
1507
+ const requestError = {
1508
+ isRequestError: true,
1509
+ message: errorMessage,
1510
+ status: 500,
1511
+ // Use 500 for blockchain errors since they're not HTTP errors
1512
+ detail: errorMessage
1513
+ };
1514
+ return {
1515
+ success: false,
1516
+ error: requestError
1517
+ };
1518
+ }
1519
+ }
1520
+
1521
+ // src/actions/add_compose_hash.ts
1522
+ import { z as z8 } from "zod";
1523
+ import {
1524
+ createPublicClient as createPublicClient3,
1525
+ createWalletClient as createWalletClient3,
1526
+ http as http3,
1527
+ parseEventLogs as parseEventLogs2,
1528
+ parseEther as parseEther2
1529
+ } from "viem";
1530
+ import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
1531
+ var appAuthAbi = [
1532
+ {
1533
+ inputs: [{ name: "composeHash", type: "bytes32" }],
1534
+ name: "addComposeHash",
1535
+ outputs: [],
1536
+ stateMutability: "nonpayable",
1537
+ type: "function"
1538
+ },
1539
+ {
1540
+ inputs: [{ name: "composeHash", type: "bytes32", indexed: false }],
1541
+ name: "ComposeHashAdded",
1542
+ type: "event",
1543
+ anonymous: false
1544
+ }
1545
+ ];
1546
+ var AddComposeHashRequestSchema = z8.object({
1547
+ // Chain configuration (conditionally required)
1548
+ chain: z8.unknown().optional(),
1549
+ // Contract configuration (required)
1550
+ kmsContractAddress: z8.string(),
1551
+ appId: z8.string(),
1552
+ composeHash: z8.string(),
1553
+ // Authentication mode: either privateKey OR walletClient (required, mutually exclusive)
1554
+ privateKey: z8.string().optional(),
1555
+ walletClient: z8.unknown().optional(),
1556
+ // Public client (optional, will create default if not provided)
1557
+ publicClient: z8.unknown().optional(),
1558
+ // Validation configuration (optional)
1559
+ skipPrerequisiteChecks: z8.boolean().optional().default(false),
1560
+ minBalance: z8.string().optional(),
1561
+ // ETH amount as string, e.g., "0.01"
1562
+ // Transaction control options
1563
+ timeout: z8.number().optional().default(12e4),
1564
+ retryOptions: z8.unknown().optional(),
1565
+ signal: z8.unknown().optional(),
1566
+ // Progress callbacks
1567
+ onTransactionStateChange: z8.function().optional(),
1568
+ onTransactionSubmitted: z8.function().optional(),
1569
+ onTransactionConfirmed: z8.function().optional()
1570
+ }).passthrough().refine(
1571
+ (data) => {
1572
+ const hasPrivateKey = !!data.privateKey;
1573
+ const hasWalletClient = !!data.walletClient;
1574
+ return hasPrivateKey !== hasWalletClient;
1575
+ },
1576
+ {
1577
+ message: "Either 'privateKey' or 'walletClient' must be provided, but not both",
1578
+ path: ["privateKey", "walletClient"]
1579
+ }
1580
+ ).refine(
1581
+ (data) => {
1582
+ const hasPublicClient = !!data.publicClient;
1583
+ const hasWalletClient = !!data.walletClient;
1584
+ const hasChain = !!data.chain;
1585
+ if (hasPublicClient && hasWalletClient) return true;
1586
+ return hasChain;
1587
+ },
1588
+ {
1589
+ message: "Chain is required when publicClient or walletClient is not provided",
1590
+ path: ["chain"]
1591
+ }
1592
+ );
1593
+ var AddComposeHashSchema = z8.object({
1594
+ composeHash: z8.string(),
1595
+ appId: z8.string(),
1596
+ transactionHash: z8.string(),
1597
+ blockNumber: z8.bigint().optional(),
1598
+ gasUsed: z8.bigint().optional()
1599
+ }).passthrough();
1600
+ function parseComposeHashResult(receipt, composeHash, appAuthAddress, appId) {
1601
+ console.log(receipt.logs);
1602
+ try {
1603
+ const logs = parseEventLogs2({
1604
+ abi: appAuthAbi,
1605
+ eventName: "ComposeHashAdded",
1606
+ logs: receipt.logs,
1607
+ strict: false
1608
+ });
1609
+ if (logs.length > 0) {
1610
+ const event = logs[0];
1611
+ if (event?.args?.composeHash !== composeHash) {
1612
+ console.warn(
1613
+ `Event compose hash (${event?.args?.composeHash}) does not match expected (${composeHash})`
1614
+ );
1615
+ }
1616
+ }
1617
+ return {
1618
+ composeHash,
1619
+ appAuthAddress,
1620
+ appId,
1621
+ transactionHash: receipt.transactionHash,
1622
+ blockNumber: receipt.blockNumber,
1623
+ gasUsed: receipt.gasUsed
1624
+ };
1625
+ } catch (parseError) {
1626
+ console.warn("Failed to parse ComposeHashAdded event, returning basic result:", parseError);
1627
+ return {
1628
+ composeHash,
1629
+ appAuthAddress,
1630
+ appId,
1631
+ transactionHash: receipt.transactionHash,
1632
+ blockNumber: receipt.blockNumber,
1633
+ gasUsed: receipt.gasUsed
1634
+ };
1635
+ }
1636
+ }
1637
+ async function addComposeHash(request, parameters) {
1638
+ const validatedRequest = AddComposeHashRequestSchema.parse(request);
1639
+ const {
1640
+ chain,
1641
+ appId,
1642
+ composeHash,
1643
+ privateKey,
1644
+ walletClient: providedWalletClient,
1645
+ publicClient: providedPublicClient,
1646
+ timeout = 12e4,
1647
+ retryOptions,
1648
+ signal,
1649
+ onTransactionStateChange,
1650
+ onTransactionSubmitted,
1651
+ onTransactionConfirmed,
1652
+ skipPrerequisiteChecks = false,
1653
+ minBalance
1654
+ } = validatedRequest;
1655
+ let publicClient;
1656
+ let walletClient;
1657
+ let address;
1658
+ let chainId;
1659
+ const appAuthAddress = appId.startsWith("0x") ? appId : `0x${appId}`;
1660
+ if (privateKey) {
1661
+ const account = privateKeyToAccount3(privateKey);
1662
+ if (providedPublicClient) {
1663
+ publicClient = providedPublicClient;
1664
+ } else {
1665
+ if (!chain) throw new Error("Chain required when creating publicClient");
1666
+ publicClient = createPublicClient3({ chain, transport: http3() });
1667
+ }
1668
+ if (!chain) throw new Error("Chain required when creating walletClient");
1669
+ walletClient = createWalletClient3({
1670
+ account,
1671
+ chain,
1672
+ transport: http3()
1673
+ });
1674
+ address = account.address;
1675
+ chainId = chain.id;
1676
+ } else if (providedWalletClient) {
1677
+ walletClient = providedWalletClient;
1678
+ if (providedPublicClient) {
1679
+ publicClient = providedPublicClient;
1680
+ } else {
1681
+ if (!chain) throw new Error("Chain required when creating publicClient");
1682
+ publicClient = createPublicClient3({ chain, transport: http3() });
1683
+ }
1684
+ if (!walletClient.account?.address) {
1685
+ throw new Error("WalletClient must have an account with address");
1686
+ }
1687
+ address = walletClient.account.address;
1688
+ chainId = chain ? chain.id : await walletClient.getChainId();
1689
+ } else {
1690
+ throw new Error("Either privateKey or walletClient must be provided");
1691
+ }
1692
+ const networkClients = {
1693
+ publicClient,
1694
+ walletClient,
1695
+ address,
1696
+ chainId
1697
+ };
1698
+ const transactionTracker = createTransactionTracker();
1699
+ if (onTransactionStateChange && typeof onTransactionStateChange === "function") {
1700
+ const pollStatus = () => {
1701
+ onTransactionStateChange(transactionTracker.status);
1702
+ if (!transactionTracker.isComplete) {
1703
+ setTimeout(pollStatus, 100);
1704
+ }
1705
+ };
1706
+ setTimeout(pollStatus, 10);
1707
+ }
1708
+ if (!skipPrerequisiteChecks) {
1709
+ const requirements = {
1710
+ targetChainId: chainId,
1711
+ minBalance: minBalance ? parseEther2(minBalance) : parseEther2("0.001")
1712
+ };
1713
+ const validation = await validateNetworkPrerequisites(networkClients, requirements);
1714
+ if (!validation.networkValid) {
1715
+ throw new Error(
1716
+ `Network mismatch: Expected chain ${requirements.targetChainId}, but wallet is on chain ${validation.details.currentChainId}`
1717
+ );
1718
+ }
1719
+ if (!validation.balanceValid) {
1720
+ const requiredEth = Number(requirements.minBalance) / 1e18;
1721
+ const currentEth = Number(validation.details.balance) / 1e18;
1722
+ throw new Error(
1723
+ `Insufficient balance: Required ${requiredEth} ETH, but account has ${currentEth.toFixed(6)} ETH`
1724
+ );
1725
+ }
1726
+ }
1727
+ const addComposeHashOperation = async (clients) => {
1728
+ const hash = await clients.walletClient.writeContract({
1729
+ address: appAuthAddress,
1730
+ abi: appAuthAbi,
1731
+ functionName: "addComposeHash",
1732
+ args: [asHex(composeHash)],
1733
+ account: clients.walletClient.account || clients.address,
1734
+ chain: chain || null
1735
+ });
1736
+ return hash;
1737
+ };
1738
+ const transactionResult = retryOptions ? await executeTransactionWithRetry(
1739
+ addComposeHashOperation,
1740
+ networkClients,
1741
+ [],
1742
+ {
1743
+ timeout,
1744
+ confirmations: 1,
1745
+ onSubmitted: onTransactionSubmitted,
1746
+ onConfirmed: onTransactionConfirmed,
1747
+ signal
1748
+ },
1749
+ retryOptions
1750
+ ) : await transactionTracker.execute(addComposeHashOperation, networkClients, [], {
1751
+ timeout,
1752
+ confirmations: 1,
1753
+ onSubmitted: onTransactionSubmitted,
1754
+ onConfirmed: onTransactionConfirmed,
1755
+ signal
1756
+ });
1757
+ const result = parseComposeHashResult(
1758
+ transactionResult.receipt,
1759
+ asHex(composeHash),
1760
+ appAuthAddress,
1761
+ appId
1762
+ );
1763
+ if (parameters?.schema === false) {
1764
+ return result;
1765
+ }
1766
+ const schema = parameters?.schema || AddComposeHashSchema;
1767
+ return schema.parse(result);
1768
+ }
1769
+ async function safeAddComposeHash(request, parameters) {
1770
+ try {
1771
+ const result = await addComposeHash(request, parameters);
1772
+ return { success: true, data: result };
1773
+ } catch (error) {
1774
+ const errorMessage = error instanceof Error ? error.message : "Unknown blockchain error";
1775
+ return {
1776
+ success: false,
1777
+ error: {
1778
+ isRequestError: true,
1779
+ message: errorMessage,
1780
+ status: 500,
1781
+ // Blockchain errors use 500
1782
+ detail: errorMessage
1783
+ }
1784
+ };
1785
+ }
1786
+ }
1787
+
1788
+ // src/actions/get_cvm_compose_file.ts
1789
+ import { z as z9 } from "zod";
1790
+ var GetCvmComposeFileResultSchema = z9.object({
1791
+ allowed_envs: z9.array(z9.string()).optional(),
1792
+ docker_compose_file: z9.string(),
1793
+ features: z9.array(z9.string()).optional(),
1794
+ name: z9.string().optional(),
1795
+ manifest_version: z9.number().optional(),
1796
+ kms_enabled: z9.boolean().optional(),
1797
+ public_logs: z9.boolean().optional(),
1798
+ public_sysinfo: z9.boolean().optional(),
1799
+ tproxy_enabled: z9.boolean().optional(),
1800
+ pre_launch_script: z9.string().optional()
1801
+ }).passthrough();
1802
+ var GetCvmComposeFileRequestSchema = z9.object({
1803
+ id: z9.string().optional(),
1804
+ uuid: z9.string().regex(/^[0-9a-f]{8}[-]?[0-9a-f]{4}[-]?4[0-9a-f]{3}[-]?[89ab][0-9a-f]{3}[-]?[0-9a-f]{12}$/i).optional(),
1805
+ app_id: z9.string().refine(
1806
+ (val) => !val.startsWith("app_") && val.length === 40,
1807
+ "app_id should be 40 characters without prefix"
1808
+ ).transform((val) => val.startsWith("app_") ? val : `app_${val}`).optional(),
1809
+ instance_id: z9.string().refine(
1810
+ (val) => !val.startsWith("instance_") && val.length === 40,
1811
+ "instance_id should be 40 characters without prefix"
1812
+ ).transform((val) => val.startsWith("instance_") ? val : `instance_${val}`).optional()
1813
+ }).refine(
1814
+ (data) => !!(data.id || data.uuid || data.app_id || data.instance_id),
1815
+ "One of id, uuid, app_id, or instance_id must be provided"
1816
+ ).transform((data) => ({
1817
+ cvmId: data.id || data.uuid || data.app_id || data.instance_id,
1818
+ _raw: data
1819
+ }));
1820
+ async function getCvmComposeFile(client, request, parameters) {
1821
+ const validatedRequest = GetCvmComposeFileRequestSchema.parse(request);
1822
+ const response = await client.get(`/cvms/${validatedRequest.cvmId}/compose_file`);
1823
+ if (parameters?.schema === false) {
1824
+ return response;
1825
+ }
1826
+ const schema = parameters?.schema || GetCvmComposeFileResultSchema;
1827
+ return schema.parse(response);
1828
+ }
1829
+ async function safeGetCvmComposeFile(client, request, parameters) {
1830
+ const requestValidation = GetCvmComposeFileRequestSchema.safeParse(request);
1831
+ if (!requestValidation.success) {
1832
+ return requestValidation;
1833
+ }
1834
+ const httpResult = await client.safeGet(`/cvms/${requestValidation.data.cvmId}/compose_file`);
1835
+ if (!httpResult.success) {
1836
+ return httpResult;
1837
+ }
1838
+ if (parameters?.schema === false) {
1839
+ return { success: true, data: httpResult.data };
1840
+ }
1841
+ const schema = parameters?.schema || GetCvmComposeFileResultSchema;
1842
+ return schema.safeParse(httpResult.data);
1843
+ }
1844
+
1845
+ // src/actions/provision_cvm_compose_file_update.ts
1846
+ import { z as z10 } from "zod";
1847
+ var ProvisionCvmComposeFileUpdateRequestSchema = z10.object({
1848
+ id: z10.string().optional(),
1849
+ uuid: z10.string().regex(/^[0-9a-f]{8}[-]?[0-9a-f]{4}[-]?4[0-9a-f]{3}[-]?[89ab][0-9a-f]{3}[-]?[0-9a-f]{12}$/i).optional(),
1850
+ app_id: z10.string().refine(
1851
+ (val) => !val.startsWith("app_") && val.length === 40,
1852
+ "app_id should be 40 characters without prefix"
1853
+ ).transform((val) => val.startsWith("app_") ? val : `app_${val}`).optional(),
1854
+ instance_id: z10.string().refine(
1855
+ (val) => !val.startsWith("instance_") && val.length === 40,
1856
+ "instance_id should be 40 characters without prefix"
1857
+ ).transform((val) => val.startsWith("instance_") ? val : `instance_${val}`).optional(),
1858
+ app_compose: z10.object({
1859
+ allowed_envs: z10.array(z10.string()).optional(),
1860
+ docker_compose_file: z10.string().min(1, "Docker compose file is required"),
1861
+ name: z10.string(),
1862
+ kms_enabled: z10.boolean().optional(),
1863
+ public_logs: z10.boolean().optional(),
1864
+ public_sysinfo: z10.boolean().optional(),
1865
+ pre_launch_script: z10.string().optional()
1866
+ })
1867
+ }).refine(
1868
+ (data) => !!(data.id || data.uuid || data.app_id || data.instance_id),
1869
+ "One of id, uuid, app_id, or instance_id must be provided"
1870
+ ).transform((data) => ({
1871
+ cvmId: data.id || data.uuid || data.app_id || data.instance_id,
1872
+ request: data.app_compose,
1873
+ _raw: data
1874
+ }));
1875
+ var ProvisionCvmComposeFileUpdateResultSchema = z10.object({
1876
+ app_id: z10.string().nullable(),
1877
+ device_id: z10.string().nullable(),
1878
+ compose_hash: z10.string(),
1879
+ kms_info: KmsInfoSchema.nullable().optional()
1880
+ }).passthrough();
1881
+ async function provisionCvmComposeFileUpdate(client, request, parameters) {
1882
+ const validatedRequest = ProvisionCvmComposeFileUpdateRequestSchema.parse(request);
1883
+ const response = await client.post(
1884
+ `/cvms/${validatedRequest.cvmId}/compose_file/provision`,
1885
+ validatedRequest.request
1886
+ );
1887
+ if (parameters?.schema === false) {
1888
+ return response;
1889
+ }
1890
+ const schema = parameters?.schema || ProvisionCvmComposeFileUpdateResultSchema;
1891
+ return schema.parse(response);
1892
+ }
1893
+ async function safeProvisionCvmComposeFileUpdate(client, request, parameters) {
1894
+ const requestValidation = ProvisionCvmComposeFileUpdateRequestSchema.safeParse(request);
1895
+ if (!requestValidation.success) {
1896
+ return requestValidation;
1897
+ }
1898
+ const httpResult = await client.safePost(
1899
+ `/cvms/${requestValidation.data.cvmId}/compose_file/provision`,
1900
+ requestValidation.data.request
1901
+ );
1902
+ if (!httpResult.success) {
1903
+ return httpResult;
1904
+ }
1905
+ if (parameters?.schema === false) {
1906
+ return { success: true, data: httpResult.data };
1907
+ }
1908
+ const schema = parameters?.schema || ProvisionCvmComposeFileUpdateResultSchema;
1909
+ return schema.safeParse(httpResult.data);
1910
+ }
1911
+
1912
+ // src/actions/commit_cvm_compose_file_update.ts
1913
+ import { z as z11 } from "zod";
1914
+ var CommitCvmComposeFileUpdateRequestSchema = z11.object({
1915
+ id: z11.string().optional(),
1916
+ uuid: z11.string().regex(/^[0-9a-f]{8}[-]?[0-9a-f]{4}[-]?4[0-9a-f]{3}[-]?[89ab][0-9a-f]{3}[-]?[0-9a-f]{12}$/i).optional(),
1917
+ app_id: z11.string().refine(
1918
+ (val) => !val.startsWith("app_") && val.length === 40,
1919
+ "app_id should be 40 characters without prefix"
1920
+ ).transform((val) => val.startsWith("app_") ? val : `app_${val}`).optional(),
1921
+ instance_id: z11.string().refine(
1922
+ (val) => !val.startsWith("instance_") && val.length === 40,
1923
+ "instance_id should be 40 characters without prefix"
1924
+ ).transform((val) => val.startsWith("instance_") ? val : `instance_${val}`).optional(),
1925
+ compose_hash: z11.string().min(1, "Compose hash is required"),
1926
+ encrypted_env: z11.string().optional(),
1927
+ env_keys: z11.array(z11.string()).optional()
1928
+ }).refine(
1929
+ (data) => !!(data.id || data.uuid || data.app_id || data.instance_id),
1930
+ "One of id, uuid, app_id, or instance_id must be provided"
1931
+ ).transform((data) => ({
1932
+ cvmId: data.id || data.uuid || data.app_id || data.instance_id,
1933
+ compose_hash: data.compose_hash,
1934
+ encrypted_env: data.encrypted_env,
1935
+ env_keys: data.env_keys,
1936
+ _raw: data
1937
+ }));
1938
+ var CommitCvmComposeFileUpdateSchema = z11.any().transform(() => void 0);
1939
+ async function commitCvmComposeFileUpdate(client, request, parameters) {
1940
+ const validatedRequest = CommitCvmComposeFileUpdateRequestSchema.parse(request);
1941
+ const response = await client.patch(`/cvms/${validatedRequest.cvmId}/compose_file`, {
1942
+ compose_hash: validatedRequest.compose_hash,
1943
+ encrypted_env: validatedRequest.encrypted_env,
1944
+ env_keys: validatedRequest.env_keys
1945
+ });
1946
+ if (parameters?.schema === false) {
1947
+ return response;
1948
+ }
1949
+ const schema = parameters?.schema || CommitCvmComposeFileUpdateSchema;
1950
+ return schema.parse(response);
1951
+ }
1952
+ async function safeCommitCvmComposeFileUpdate(client, request, parameters) {
1953
+ const requestValidation = CommitCvmComposeFileUpdateRequestSchema.safeParse(request);
1954
+ if (!requestValidation.success) {
1955
+ return requestValidation;
1956
+ }
1957
+ const httpResult = await client.safePatch(`/cvms/${requestValidation.data.cvmId}/compose_file`, {
1958
+ compose_hash: requestValidation.data.compose_hash,
1959
+ encrypted_env: requestValidation.data.encrypted_env,
1960
+ env_keys: requestValidation.data.env_keys
1961
+ });
1962
+ if (!httpResult.success) {
1963
+ return httpResult;
1964
+ }
1965
+ if (parameters?.schema === false) {
1966
+ return { success: true, data: httpResult.data };
1967
+ }
1968
+ const schema = parameters?.schema || CommitCvmComposeFileUpdateSchema;
1969
+ return schema.safeParse(httpResult.data);
1970
+ }
1971
+
1972
+ // src/actions/get_app_env_encrypt_pubkey.ts
1973
+ import { z as z12 } from "zod";
1974
+ var GetAppEnvEncryptPubKeyRequestSchema = z12.object({
1975
+ kms: z12.string().min(1, "KMS ID or slug is required"),
1976
+ app_id: z12.string().length(40, "App ID must be exactly 40 characters")
1977
+ }).strict();
1978
+ var GetAppEnvEncryptPubKeySchema = z12.object({
1979
+ public_key: z12.string(),
1980
+ signature: z12.string()
1981
+ }).strict();
1982
+ var getAppEnvEncryptPubKey = async (client, payload, parameters) => {
1983
+ const validatedRequest = GetAppEnvEncryptPubKeyRequestSchema.parse(payload);
1984
+ validateActionParameters(parameters);
1985
+ const response = await client.get(
1986
+ `/kms/${validatedRequest.kms}/pubkey/${validatedRequest.app_id}`
1987
+ );
1988
+ if (parameters?.schema === false) {
1989
+ return response;
1990
+ }
1991
+ const schema = parameters?.schema || GetAppEnvEncryptPubKeySchema;
1992
+ return schema.parse(response);
1993
+ };
1994
+ var safeGetAppEnvEncryptPubKey = async (client, payload, parameters) => {
1995
+ const requestValidation = GetAppEnvEncryptPubKeyRequestSchema.safeParse(payload);
1996
+ if (!requestValidation.success) {
1997
+ return requestValidation;
1998
+ }
1999
+ const parameterValidationError = safeValidateActionParameters(parameters);
2000
+ if (parameterValidationError) {
2001
+ return parameterValidationError;
2002
+ }
2003
+ const httpResult = await client.safeGet(
2004
+ `/kms/${requestValidation.data.kms}/pubkey/${requestValidation.data.app_id}`
2005
+ );
2006
+ if (!httpResult.success) {
2007
+ return httpResult;
2008
+ }
2009
+ if (parameters?.schema === false) {
2010
+ return { success: true, data: httpResult.data };
2011
+ }
2012
+ const schema = parameters?.schema || GetAppEnvEncryptPubKeySchema;
2013
+ return schema.safeParse(httpResult.data);
2014
+ };
2015
+
2016
+ // src/actions/get_cvm_info.ts
2017
+ import { z as z14 } from "zod";
2018
+
2019
+ // src/types/cvm_info.ts
2020
+ import { z as z13 } from "zod";
2021
+ var VmInfoSchema = z13.object({
2022
+ id: z13.string(),
2023
+ name: z13.string(),
2024
+ status: z13.string(),
2025
+ uptime: z13.string(),
2026
+ app_url: z13.string().nullable(),
2027
+ app_id: z13.string(),
2028
+ instance_id: z13.string().nullable(),
2029
+ configuration: z13.any().optional(),
2030
+ // TODO: add VmConfiguration schema if needed
2031
+ exited_at: z13.string().nullable(),
2032
+ boot_progress: z13.string().nullable(),
2033
+ boot_error: z13.string().nullable(),
2034
+ shutdown_progress: z13.string().nullable(),
2035
+ image_version: z13.string().nullable()
2036
+ });
2037
+ var ManagedUserSchema = z13.object({
2038
+ id: z13.number(),
2039
+ username: z13.string()
2040
+ });
2041
+ var CvmNodeSchema = z13.object({
2042
+ id: z13.number(),
2043
+ name: z13.string(),
2044
+ region_identifier: z13.string().optional()
2045
+ });
2046
+ var CvmNetworkUrlsSchema = z13.object({
2047
+ app: z13.string(),
2048
+ instance: z13.string()
2049
+ });
2050
+ var KMSInfoSchema = z13.object({
2051
+ id: z13.string(),
2052
+ // HashedId is represented as string in JS
2053
+ slug: z13.string(),
2054
+ url: z13.string(),
2055
+ version: z13.string(),
2056
+ chain_id: z13.number().optional(),
2057
+ kms_contract_address: z13.string().optional(),
2058
+ gateway_app_id: z13.string().optional()
2059
+ });
2060
+ var CvmInfoSchema = z13.object({
2061
+ hosted: VmInfoSchema,
2062
+ name: z13.string(),
2063
+ managed_user: ManagedUserSchema.optional().nullable(),
2064
+ node: CvmNodeSchema.optional().nullable(),
2065
+ listed: z13.boolean().default(false),
2066
+ status: z13.string(),
2067
+ in_progress: z13.boolean().default(false),
2068
+ dapp_dashboard_url: z13.string().nullable(),
2069
+ syslog_endpoint: z13.string().nullable(),
2070
+ allow_upgrade: z13.boolean().default(false),
2071
+ project_id: z13.string().nullable(),
2072
+ // HashedId is represented as string in JS
2073
+ project_type: z13.string().nullable(),
2074
+ billing_period: z13.string().nullable(),
2075
+ kms_info: KMSInfoSchema.nullable(),
2076
+ vcpu: z13.number().nullable(),
2077
+ memory: z13.number().nullable(),
2078
+ disk_size: z13.number().nullable(),
2079
+ gateway_domain: z13.string().nullable(),
2080
+ public_urls: z13.array(CvmNetworkUrlsSchema)
2081
+ }).partial();
2082
+
2083
+ // src/actions/get_cvm_info.ts
2084
+ var GetCvmInfoSchema = CvmInfoSchema;
2085
+ var GetCvmInfoRequestSchema = z14.object({
2086
+ id: z14.string().optional(),
2087
+ uuid: z14.string().regex(/^[0-9a-f]{8}[-]?[0-9a-f]{4}[-]?4[0-9a-f]{3}[-]?[89ab][0-9a-f]{3}[-]?[0-9a-f]{12}$/i).optional(),
2088
+ app_id: z14.string().refine(
2089
+ (val) => !val.startsWith("app_") && val.length === 40,
2090
+ "app_id should be 40 characters without prefix"
2091
+ ).transform((val) => val.startsWith("app_") ? val : `app_${val}`).optional(),
2092
+ instance_id: z14.string().refine(
2093
+ (val) => !val.startsWith("instance_") && val.length === 40,
2094
+ "instance_id should be 40 characters without prefix"
2095
+ ).transform((val) => val.startsWith("instance_") ? val : `instance_${val}`).optional()
2096
+ }).refine(
2097
+ (data) => !!(data.id || data.uuid || data.app_id || data.instance_id),
2098
+ "One of id, uuid, app_id, or instance_id must be provided"
2099
+ ).transform((data) => ({
2100
+ cvmId: data.id || data.uuid || data.app_id || data.instance_id,
2101
+ _raw: data
2102
+ }));
2103
+ async function getCvmInfo(client, request, parameters) {
2104
+ const validatedRequest = GetCvmInfoRequestSchema.parse(request);
2105
+ validateActionParameters(parameters);
2106
+ const response = await client.get(`/cvms/${validatedRequest.cvmId}`);
2107
+ if (parameters?.schema === false) {
2108
+ return response;
2109
+ }
2110
+ const schema = parameters?.schema || GetCvmInfoSchema;
2111
+ return schema.parse(response);
2112
+ }
2113
+ async function safeGetCvmInfo(client, request, parameters) {
2114
+ const requestValidation = GetCvmInfoRequestSchema.safeParse(request);
2115
+ if (!requestValidation.success) {
2116
+ return requestValidation;
2117
+ }
2118
+ const parameterValidationError = safeValidateActionParameters(parameters);
2119
+ if (parameterValidationError) {
2120
+ return parameterValidationError;
2121
+ }
2122
+ const httpResult = await client.safeGet(`/cvms/${requestValidation.data.cvmId}`);
2123
+ if (!httpResult.success) {
2124
+ return httpResult;
2125
+ }
2126
+ if (parameters?.schema === false) {
2127
+ return {
2128
+ success: true,
2129
+ data: httpResult.data
2130
+ };
2131
+ }
2132
+ const schema = parameters?.schema || GetCvmInfoSchema;
2133
+ const validationResult = schema.safeParse(httpResult.data);
2134
+ return validationResult;
2135
+ }
2136
+
2137
+ // src/actions/get_cvm_list.ts
2138
+ import { z as z15 } from "zod";
2139
+ var GetCvmListRequestSchema = z15.object({
2140
+ page: z15.number().int().min(1).optional(),
2141
+ page_size: z15.number().int().min(1).optional(),
2142
+ node_id: z15.number().int().min(1).optional()
2143
+ }).strict();
2144
+ var GetCvmListSchema = z15.object({
2145
+ items: z15.array(CvmInfoSchema),
2146
+ total: z15.number(),
2147
+ page: z15.number(),
2148
+ page_size: z15.number(),
2149
+ pages: z15.number()
2150
+ }).strict();
2151
+ async function getCvmList(client, request, parameters) {
2152
+ const validatedRequest = GetCvmListRequestSchema.parse(request ?? {});
2153
+ validateActionParameters(parameters);
2154
+ const response = await client.get("/cvms/paginated", { params: validatedRequest });
2155
+ if (parameters?.schema === false) {
2156
+ return response;
2157
+ }
2158
+ const schema = parameters?.schema || GetCvmListSchema;
2159
+ return schema.parse(response);
2160
+ }
2161
+ async function safeGetCvmList(client, request, parameters) {
2162
+ const requestValidation = GetCvmListRequestSchema.safeParse(request ?? {});
2163
+ if (!requestValidation.success) {
2164
+ return requestValidation;
2165
+ }
2166
+ const parameterValidationError = safeValidateActionParameters(parameters);
2167
+ if (parameterValidationError) {
2168
+ return parameterValidationError;
2169
+ }
2170
+ const httpResult = await client.safeGet("/cvms/paginated", { params: requestValidation.data });
2171
+ if (!httpResult.success) {
2172
+ return httpResult;
2173
+ }
2174
+ if (parameters?.schema === false) {
2175
+ return {
2176
+ success: true,
2177
+ data: httpResult.data
2178
+ };
2179
+ }
2180
+ const schema = parameters?.schema || GetCvmListSchema;
2181
+ const validationResult = schema.safeParse(httpResult.data);
2182
+ return validationResult;
2183
+ }
2184
+
2185
+ // src/actions/get_kms_info.ts
2186
+ import { z as z16 } from "zod";
2187
+ var GetKmsInfoRequestSchema = z16.object({
2188
+ kms_id: z16.string().min(1, "KMS ID is required")
2189
+ });
2190
+ async function getKmsInfo(client, request, parameters) {
2191
+ const validatedRequest = GetKmsInfoRequestSchema.parse(request);
2192
+ validateActionParameters(parameters);
2193
+ const response = await client.get(`/kms/${validatedRequest.kms_id}`);
2194
+ if (parameters?.schema === false) {
2195
+ return response;
2196
+ }
2197
+ const schema = parameters?.schema || KmsInfoSchema;
2198
+ return schema.parse(response);
2199
+ }
2200
+ async function safeGetKmsInfo(client, request, parameters) {
2201
+ const requestValidation = GetKmsInfoRequestSchema.safeParse(request);
2202
+ if (!requestValidation.success) {
2203
+ return requestValidation;
2204
+ }
2205
+ const parameterValidationError = safeValidateActionParameters(parameters);
2206
+ if (parameterValidationError) {
2207
+ return parameterValidationError;
2208
+ }
2209
+ const httpResult = await client.safeGet(`/kms/${requestValidation.data.kms_id}`);
2210
+ if (!httpResult.success) {
2211
+ return httpResult;
2212
+ }
2213
+ if (parameters?.schema === false) {
2214
+ return { success: true, data: httpResult.data };
2215
+ }
2216
+ const schema = parameters?.schema || KmsInfoSchema;
2217
+ const validationResult = schema.safeParse(httpResult.data);
2218
+ return validationResult;
2219
+ }
2220
+
2221
+ // src/actions/get_kms_list.ts
2222
+ import { z as z17 } from "zod";
2223
+ var GetKmsListRequestSchema = z17.object({
2224
+ page: z17.number().int().min(1).optional(),
2225
+ page_size: z17.number().int().min(1).optional(),
2226
+ is_onchain: z17.boolean().optional()
2227
+ }).strict();
2228
+ var GetKmsListSchema = z17.object({
2229
+ items: z17.array(KmsInfoSchema),
2230
+ total: z17.number(),
2231
+ page: z17.number(),
2232
+ page_size: z17.number(),
2233
+ pages: z17.number()
2234
+ }).strict();
2235
+ async function getKmsList(client, request, parameters) {
2236
+ const validatedRequest = GetKmsListRequestSchema.parse(request ?? {});
2237
+ validateActionParameters(parameters);
2238
+ const response = await client.get("/kms", { params: validatedRequest });
2239
+ if (parameters?.schema === false) {
2240
+ return response;
2241
+ }
2242
+ const schema = parameters?.schema || GetKmsListSchema;
2243
+ return schema.parse(response);
2244
+ }
2245
+ async function safeGetKmsList(client, request, parameters) {
2246
+ const requestValidation = GetKmsListRequestSchema.safeParse(request ?? {});
2247
+ if (!requestValidation.success) {
2248
+ return requestValidation;
2249
+ }
2250
+ const parameterValidationError = safeValidateActionParameters(parameters);
2251
+ if (parameterValidationError) {
2252
+ return parameterValidationError;
2253
+ }
2254
+ const httpResult = await client.safeGet("/kms", { params: requestValidation.data });
2255
+ if (!httpResult.success) {
2256
+ return httpResult;
2257
+ }
2258
+ if (parameters?.schema === false) {
2259
+ return {
2260
+ success: true,
2261
+ data: httpResult.data
2262
+ };
2263
+ }
2264
+ const schema = parameters?.schema || GetKmsListSchema;
2265
+ const validationResult = schema.safeParse(httpResult.data);
2266
+ return validationResult;
2267
+ }
2268
+
2269
+ // src/index.ts
2270
+ import { encryptEnvVars as encryptEnvVars2 } from "@phala/dstack-sdk/encrypt-env-vars";
2271
+ import { getComposeHash as getComposeHash2 } from "@phala/dstack-sdk";
2272
+ import { verifyEnvEncryptPublicKey } from "@phala/dstack-sdk";
2273
+ export {
2274
+ AddComposeHashSchema,
2275
+ ApiErrorSchema,
2276
+ AvailableNodesSchema,
2277
+ CommitCvmComposeFileUpdateRequestSchema,
2278
+ CommitCvmComposeFileUpdateSchema,
2279
+ CommitCvmProvisionRequestSchema,
2280
+ CommitCvmProvisionSchema,
2281
+ CurrentUserSchema,
2282
+ DeployAppAuthRequestSchema,
2283
+ DeployAppAuthSchema,
2284
+ GetAppEnvEncryptPubKeySchema,
2285
+ GetCvmComposeFileResultSchema,
2286
+ GetCvmInfoSchema,
2287
+ GetCvmListSchema,
2288
+ GetKmsListSchema,
2289
+ NetworkError,
2290
+ ProvisionCvmComposeFileUpdateRequestSchema,
2291
+ ProvisionCvmComposeFileUpdateResultSchema,
2292
+ ProvisionCvmRequestSchema,
2293
+ ProvisionCvmSchema,
2294
+ RequestError,
2295
+ TransactionError,
2296
+ WalletError,
2297
+ addComposeHash,
2298
+ addNetwork,
2299
+ asHex,
2300
+ autoCreateClients,
2301
+ checkBalance,
2302
+ checkNetworkStatus,
2303
+ commitCvmComposeFileUpdate,
2304
+ commitCvmProvision,
2305
+ createClient,
2306
+ createClientsFromBrowser,
2307
+ createClientsFromPrivateKey,
2308
+ createNetworkClients,
2309
+ createTransactionTracker,
2310
+ deployAppAuth,
2311
+ encryptEnvVars2 as encryptEnvVars,
2312
+ estimateTransactionGas,
2313
+ executeBatchTransactions,
2314
+ executeTransaction,
2315
+ executeTransactionWithRetry,
2316
+ extractNetworkClients,
2317
+ getAppEnvEncryptPubKey,
2318
+ getAvailableNodes,
2319
+ getComposeHash2 as getComposeHash,
2320
+ getCurrentUser,
2321
+ getCvmComposeFile,
2322
+ getCvmInfo,
2323
+ getCvmList,
2324
+ getErrorMessage,
2325
+ getKmsInfo,
2326
+ getKmsList,
2327
+ provisionCvm,
2328
+ provisionCvmComposeFileUpdate,
2329
+ safeAddComposeHash,
2330
+ safeCommitCvmComposeFileUpdate,
2331
+ safeCommitCvmProvision,
2332
+ safeDeployAppAuth,
2333
+ safeGetAppEnvEncryptPubKey,
2334
+ safeGetAvailableNodes,
2335
+ safeGetCurrentUser,
2336
+ safeGetCvmComposeFile,
2337
+ safeGetCvmInfo,
2338
+ safeGetCvmList,
2339
+ safeGetKmsInfo,
2340
+ safeGetKmsList,
2341
+ safeProvisionCvm,
2342
+ safeProvisionCvmComposeFileUpdate,
2343
+ safeValidateActionParameters,
2344
+ switchToNetwork,
2345
+ validateActionParameters,
2346
+ validateNetworkPrerequisites,
2347
+ verifyEnvEncryptPublicKey,
2348
+ waitForTransactionReceipt
2349
+ };