From c2a852b8ad2d1c2a9f68fb775fc6adffcfc82ae9 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Tue, 19 May 2026 18:44:04 +0800 Subject: [PATCH 01/13] feat(sdk/js): make getKey path argument optional align with Rust SDK (Option) and Python SDK (str | None) where path defaults to empty string when not provided. --- sdk/js/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/js/src/index.ts b/sdk/js/src/index.ts index 72d47255..b7d4956c 100644 --- a/sdk/js/src/index.ts +++ b/sdk/js/src/index.ts @@ -213,7 +213,7 @@ export class DstackClient { } } - async getKey(path: string, purpose: string = '', algorithm: string = 'secp256k1'): Promise { + async getKey(path: string = '', purpose: string = '', algorithm: string = 'secp256k1'): Promise { await this.ensureAlgorithmSupported(algorithm) const payload = JSON.stringify({ path: path, From f5ad5be9c11e654d9489c25e51cbb58160e8c147 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Tue, 19 May 2026 18:44:27 +0800 Subject: [PATCH 02/13] feat(sdk/js): surface cloud_vendor and cloud_product on InfoResponse proto AppInfo gained these fields in dstack 0.5.7 (commit 63f30ce7). Mark them optional so callers on older guest-agent versions still parse cleanly. --- sdk/js/src/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sdk/js/src/index.ts b/sdk/js/src/index.ts index b7d4956c..1c487be9 100644 --- a/sdk/js/src/index.ts +++ b/sdk/js/src/index.ts @@ -87,6 +87,10 @@ export interface InfoResponse { key_provider_info: string compose_hash: string vm_config?: string + // Cloud provider sys_vendor (e.g. "Google"). Available on dstack OS >= 0.5.7. + cloud_vendor?: string + // Cloud provider product_name (e.g. "Google Compute Engine"). Available on dstack OS >= 0.5.7. + cloud_product?: string } export interface GetQuoteResponse { From dc5fc2186aa9f2b1bcbfa9d632ed4c868f12ca73 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Tue, 19 May 2026 18:44:44 +0800 Subject: [PATCH 03/13] feat(sdk/js): add notBefore/notAfter/withAppInfo TLS key options proto GetTlsKeyArgs gained these fields in dstack 0.5.7 (commits 029f167f, c6d1d1ba). When the caller sets any of them, probe the guest-agent with Version() first (reusing the algorithm-gating pattern) so older OS versions fail loudly instead of silently dropping the options. --- sdk/js/src/index.ts | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/sdk/js/src/index.ts b/sdk/js/src/index.ts index 1c487be9..bc84f914 100644 --- a/sdk/js/src/index.ts +++ b/sdk/js/src/index.ts @@ -179,6 +179,12 @@ export interface TlsKeyOptions { usageRaTls?: boolean; usageServerAuth?: boolean; usageClientAuth?: boolean; + // Certificate validity start (seconds since UNIX epoch). Requires dstack OS >= 0.5.7. + notBefore?: number; + // Certificate validity end (seconds since UNIX epoch). Requires dstack OS >= 0.5.7. + notAfter?: number; + // Embed app info into the certificate. Requires dstack OS >= 0.5.7. + withAppInfo?: boolean; } const SECP256K1_ALGORITHMS = new Set(['secp256k1', 'k256', '']) @@ -217,6 +223,14 @@ export class DstackClient { } } + private async ensureTlsKeyOptionsSupported(featureNames: string[]): Promise { + try { + await this.version() + } catch { + throw new Error(`TLS key options [${featureNames.join(', ')}] are not supported: OS version too old (Version RPC unavailable)`) + } + } + async getKey(path: string = '', purpose: string = '', algorithm: string = 'secp256k1'): Promise { await this.ensureAlgorithmSupported(algorithm) const payload = JSON.stringify({ @@ -239,8 +253,19 @@ export class DstackClient { usageRaTls = false, usageServerAuth = true, usageClientAuth = false, + notBefore, + notAfter, + withAppInfo, } = options; + const newFeatures: string[] = [] + if (notBefore !== undefined) newFeatures.push('notBefore') + if (notAfter !== undefined) newFeatures.push('notAfter') + if (withAppInfo !== undefined) newFeatures.push('withAppInfo') + if (newFeatures.length > 0) { + await this.ensureTlsKeyOptionsSupported(newFeatures) + } + let raw: Record = { subject, usage_ra_tls: usageRaTls, @@ -250,6 +275,15 @@ export class DstackClient { if (altNames && altNames.length) { raw['alt_names'] = altNames } + if (notBefore !== undefined) { + raw['not_before'] = notBefore + } + if (notAfter !== undefined) { + raw['not_after'] = notAfter + } + if (withAppInfo !== undefined) { + raw['with_app_info'] = withAppInfo + } const payload = JSON.stringify(raw) const result = await send_rpc_request(this.endpoint, '/GetTlsKey', payload) const asUint8Array = (length?: number) => x509key_to_uint8array(result.key, length) From 3539db3327d27719d8825d08ae64579114c46217 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Tue, 19 May 2026 20:08:58 +0800 Subject: [PATCH 04/13] refactor(sdk/js): use @noble/hashes instead of node crypto replace crypto.createHash('sha384'|'sha256') calls with @noble/hashes sha384/sha256, which work identically in node and browsers without needing a polyfill. @noble/hashes is already a peer dependency. this prepares for removing crypto-browserify, whose upstream chain (elliptic, create-ecdh, browserify-sign) carries unpatched advisories. --- sdk/js/src/get-compose-hash.browser.ts | 12 +++--------- sdk/js/src/get-compose-hash.ts | 5 +++-- sdk/js/src/index.ts | 6 ++---- sdk/js/src/solana.ts | 13 ++++--------- sdk/js/src/viem.ts | 12 ++++-------- 5 files changed, 16 insertions(+), 32 deletions(-) diff --git a/sdk/js/src/get-compose-hash.browser.ts b/sdk/js/src/get-compose-hash.browser.ts index b99bdfff..17b80b0e 100644 --- a/sdk/js/src/get-compose-hash.browser.ts +++ b/sdk/js/src/get-compose-hash.browser.ts @@ -2,7 +2,8 @@ // // SPDX-License-Identifier: Apache-2.0 -import crypto from 'crypto'; +import { sha256 } from '@noble/hashes/sha256'; +import { bytesToHex } from '@noble/hashes/utils'; type SortableValue = string | number | boolean | null | undefined | SortableObject | SortableArray; interface SortableObject { @@ -27,15 +28,8 @@ function sortObjectKeys(obj: SortableValue): SortableValue { return sortedObj; } -/** - * Browser-compatible SHA-256 hash using crypto-browserify - * @param data - Data to hash - * @returns Promise resolving to hex-encoded hash - */ async function sha256Hash(data: string): Promise { - const hash = crypto.createHash('sha256'); - hash.update(data, 'utf8'); - return hash.digest('hex'); + return bytesToHex(sha256(new TextEncoder().encode(data))); } /** diff --git a/sdk/js/src/get-compose-hash.ts b/sdk/js/src/get-compose-hash.ts index 3f3a44ef..2eb357b1 100644 --- a/sdk/js/src/get-compose-hash.ts +++ b/sdk/js/src/get-compose-hash.ts @@ -2,7 +2,8 @@ // // SPDX-License-Identifier: Apache-2.0 -import crypto from "crypto"; +import { sha256 } from "@noble/hashes/sha256"; +import { bytesToHex } from "@noble/hashes/utils"; type SortableValue = string | number | boolean | null | undefined | SortableObject | SortableArray; interface SortableObject { @@ -104,5 +105,5 @@ export function getComposeHash(app_compose: AppCompose, normalize: boolean = fal app_compose = preprocessAppCompose(app_compose); } const manifest_str = toDeterministicJson(app_compose); - return crypto.createHash("sha256").update(manifest_str, "utf8").digest("hex"); + return bytesToHex(sha256(new TextEncoder().encode(manifest_str))); } diff --git a/sdk/js/src/index.ts b/sdk/js/src/index.ts index bc84f914..b582dec6 100644 --- a/sdk/js/src/index.ts +++ b/sdk/js/src/index.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 import fs from 'fs' -import crypto from 'crypto' +import { sha384 } from '@noble/hashes/sha512' import { send_rpc_request } from './send-rpc-request' export { getComposeHash } from './get-compose-hash' export { verifyEnvEncryptPublicKey, verifyEnvEncryptPublicKeyLegacy } from './verify-env-encrypt-public-key' @@ -154,9 +154,7 @@ function replay_rtmr(history: string[]): string { const padding = Buffer.alloc(48 - contentBuffer.length, 0) contentBuffer = Buffer.concat([contentBuffer, padding]) } - mr = Buffer.from(crypto.createHash('sha384') - .update(Buffer.concat([mr, contentBuffer])) - .digest()) + mr = Buffer.from(sha384(Buffer.concat([mr, contentBuffer]))) } return mr.toString('hex') } diff --git a/sdk/js/src/solana.ts b/sdk/js/src/solana.ts index dffc86b5..7891c0e8 100644 --- a/sdk/js/src/solana.ts +++ b/sdk/js/src/solana.ts @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import crypto from 'crypto' +import { sha256 } from '@noble/hashes/sha256' import { type GetKeyResponse, type GetTlsKeyResponse } from './index' import { Keypair } from '@solana/web3.js' @@ -28,14 +28,9 @@ export function toKeypair(keyResponse: GetTlsKeyResponse | GetKeyResponse) { export function toKeypairSecure(keyResponse: GetTlsKeyResponse | GetKeyResponse) { // Keep legacy behavior for GetTlsKeyResponse, but with warning. if (keyResponse.__name__ === 'GetTlsKeyResponse') { - try { - console.warn('toKeypairSecure: Please don\'t use `deriveKey` method to get key, use `getKey` instead.') - // Get supported hash algorithm by `openssl list -digest-algorithms`, but it's not guaranteed to be supported by node.js - const buf = crypto.createHash('sha256').update(keyResponse.asUint8Array()).digest() - return Keypair.fromSeed(buf) - } catch (err) { - throw new Error('toKeypairSecure: missing sha256 support, please upgrade your openssl and node.js') - } + console.warn('toKeypairSecure: Please don\'t use `deriveKey` method to get key, use `getKey` instead.') + const buf = sha256(keyResponse.asUint8Array()) + return Keypair.fromSeed(buf) } return Keypair.fromSeed(keyResponse.key) } \ No newline at end of file diff --git a/sdk/js/src/viem.ts b/sdk/js/src/viem.ts index b0b4652f..208fcc78 100644 --- a/sdk/js/src/viem.ts +++ b/sdk/js/src/viem.ts @@ -2,7 +2,8 @@ // // SPDX-License-Identifier: Apache-2.0 -import crypto from 'crypto' +import { sha256 } from '@noble/hashes/sha256' +import { bytesToHex } from '@noble/hashes/utils' import { type GetKeyResponse, type GetTlsKeyResponse } from './index' import { privateKeyToAccount } from 'viem/accounts' @@ -29,13 +30,8 @@ export function toViemAccountSecure(keyResponse: GetKeyResponse | GetTlsKeyRespo // Keep legacy behavior for GetTlsKeyResponse, but with warning. if (keyResponse.__name__ === 'GetTlsKeyResponse') { console.warn('toViemAccountSecure: Please don\'t use `deriveKey` method to get key, use `getKey` instead.') - try { - // Get supported hash algorithm by `openssl list -digest-algorithms`, but it's not guaranteed to be supported by node.js - const hex = crypto.createHash('sha256').update(keyResponse.asUint8Array()).digest('hex') - return privateKeyToAccount(`0x${hex}`) - } catch (err) { - throw new Error('toViemAccountSecure: missing sha256 support, please upgrade your openssl and node.js') - } + const hex = bytesToHex(sha256(keyResponse.asUint8Array())) + return privateKeyToAccount(`0x${hex}`) } const hex = Array.from(keyResponse.key).map(b => b.toString(16).padStart(2, '0')).join('') return privateKeyToAccount(`0x${hex}`) From 24eccb438a19ae9a1ba6845550cf2094f3195d6f Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Tue, 19 May 2026 20:10:32 +0800 Subject: [PATCH 05/13] chore(sdk/js): drop crypto-browserify dependency remove the crypto-browserify dep and the package.json browser field that aliased node's crypto to it. the only consumers of node crypto in this SDK already moved to @noble/hashes in the previous commit. this removes the elliptic / create-ecdh / browserify-sign / bn.js (4.x) transitive chain whose advisories have no upstream fix. --- sdk/js/package.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sdk/js/package.json b/sdk/js/package.json index cfc8d8c4..f9a08c58 100644 --- a/sdk/js/package.json +++ b/sdk/js/package.json @@ -4,9 +4,6 @@ "description": "dstack SDK", "main": "dist/node/index.js", "types": "dist/node/index.d.ts", - "browser": { - "crypto": "crypto-browserify" - }, "exports": { ".": { "import": "./dist/node/index.js", @@ -99,9 +96,6 @@ }, "author": "Leechael Yim", "license": "Apache-2.0", - "dependencies": { - "crypto-browserify": "^3.12.0" - }, "devDependencies": { "@types/node": "latest", "typescript": "^5.7.0", From 2ed501576ce4ff9989a48605468362c194d80a7a Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Tue, 19 May 2026 20:42:42 +0800 Subject: [PATCH 06/13] chore(sdk/js): regenerate lockfile to fix bn.js vulnerability bun.lockb pinned bn.js@5.2.2, which is below the patched 5.2.3 for advisory GHSA-378v-28hj-76wf (infinite loop). @solana/web3.js@1.98.4 declares `bn.js: ^5.2.1`, so a fresh resolution picks 5.2.3 naturally. incidentally migrates to bun's text-format `bun.lock` (default since bun 1.2), replacing the binary `bun.lockb`. The text format is diffable in git. --- sdk/js/bun.lock | 365 +++++++++++++++++++++++++++++++++++++++++++++++ sdk/js/bun.lockb | Bin 88184 -> 0 bytes 2 files changed, 365 insertions(+) create mode 100644 sdk/js/bun.lock delete mode 100755 sdk/js/bun.lockb diff --git a/sdk/js/bun.lock b/sdk/js/bun.lock new file mode 100644 index 00000000..6597252b --- /dev/null +++ b/sdk/js/bun.lock @@ -0,0 +1,365 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "@phala/dstack-sdk", + "devDependencies": { + "@types/node": "latest", + "typescript": "^5.7.0", + "vitest": "^3.2.4", + }, + "optionalDependencies": { + "@noble/curves": "^1.8.1", + "@solana/web3.js": "^1.98.4", + "viem": "^2.43.3", + }, + "peerDependencies": { + "@noble/curves": "^1.8.1", + "@noble/hashes": "^1.6.1", + "@solana/web3.js": "*", + "viem": "*", + }, + "optionalPeers": [ + "@noble/curves", + "@solana/web3.js", + "viem", + ], + }, + }, + "packages": { + "@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.11.1", "", {}, "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ=="], + + "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], + + "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + + "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.4", "", { "os": "android", "cpu": "arm" }, "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.4", "", { "os": "android", "cpu": "arm64" }, "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.4", "", { "os": "linux", "cpu": "arm" }, "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.4", "", { "os": "linux", "cpu": "arm" }, "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.4", "", { "os": "linux", "cpu": "x64" }, "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.4", "", { "os": "none", "cpu": "arm64" }, "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.4", "", { "os": "win32", "cpu": "x64" }, "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.4", "", { "os": "win32", "cpu": "x64" }, "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw=="], + + "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], + + "@scure/bip32": ["@scure/bip32@1.7.0", "", { "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw=="], + + "@scure/bip39": ["@scure/bip39@1.6.0", "", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], + + "@solana/buffer-layout": ["@solana/buffer-layout@4.0.1", "", { "dependencies": { "buffer": "~6.0.3" } }, "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA=="], + + "@solana/codecs-core": ["@solana/codecs-core@2.3.0", "", { "dependencies": { "@solana/errors": "2.3.0" }, "peerDependencies": { "typescript": ">=5.3.3" } }, "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw=="], + + "@solana/codecs-numbers": ["@solana/codecs-numbers@2.3.0", "", { "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/errors": "2.3.0" }, "peerDependencies": { "typescript": ">=5.3.3" } }, "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg=="], + + "@solana/errors": ["@solana/errors@2.3.0", "", { "dependencies": { "chalk": "^5.4.1", "commander": "^14.0.0" }, "peerDependencies": { "typescript": ">=5.3.3" }, "bin": { "errors": "bin/cli.mjs" } }, "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ=="], + + "@solana/web3.js": ["@solana/web3.js@1.98.4", "", { "dependencies": { "@babel/runtime": "^7.25.0", "@noble/curves": "^1.4.2", "@noble/hashes": "^1.4.0", "@solana/buffer-layout": "^4.0.1", "@solana/codecs-numbers": "^2.1.0", "agentkeepalive": "^4.5.0", "bn.js": "^5.2.1", "borsh": "^0.7.0", "bs58": "^4.0.1", "buffer": "6.0.3", "fast-stable-stringify": "^1.0.0", "jayson": "^4.1.1", "node-fetch": "^2.7.0", "rpc-websockets": "^9.0.2", "superstruct": "^2.0.2" } }, "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw=="], + + "@swc/helpers": ["@swc/helpers@0.5.21", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg=="], + + "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], + + "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], + + "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], + + "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], + + "@types/node": ["@types/node@25.9.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ=="], + + "@types/ws": ["@types/ws@7.4.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww=="], + + "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], + + "@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="], + + "@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], + + "@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="], + + "@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="], + + "@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], + + "@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], + + "abitype": ["abitype@1.2.3", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg=="], + + "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], + + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], + + "base-x": ["base-x@3.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "bn.js": ["bn.js@5.2.3", "", {}, "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w=="], + + "borsh": ["borsh@0.7.0", "", { "dependencies": { "bn.js": "^5.2.0", "bs58": "^4.0.0", "text-encoding-utf-8": "^1.0.2" } }, "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA=="], + + "bs58": ["bs58@4.0.1", "", { "dependencies": { "base-x": "^3.0.2" } }, "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw=="], + + "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + + "bufferutil": ["bufferutil@4.1.0", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw=="], + + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + + "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], + + "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], + + "commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], + + "delay": ["delay@5.0.0", "", {}, "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw=="], + + "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + + "es6-promise": ["es6-promise@4.2.8", "", {}, "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="], + + "es6-promisify": ["es6-promisify@5.0.0", "", { "dependencies": { "es6-promise": "^4.0.3" } }, "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ=="], + + "esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], + + "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + + "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], + + "eyes": ["eyes@0.1.8", "", {}, "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ=="], + + "fast-stable-stringify": ["fast-stable-stringify@1.0.0", "", {}, "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "isomorphic-ws": ["isomorphic-ws@4.0.1", "", { "peerDependencies": { "ws": "*" } }, "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w=="], + + "isows": ["isows@1.0.7", "", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="], + + "jayson": ["jayson@4.3.0", "", { "dependencies": { "@types/connect": "^3.4.33", "@types/node": "^12.12.54", "@types/ws": "^7.4.4", "commander": "^2.20.3", "delay": "^5.0.0", "es6-promisify": "^5.0.0", "eyes": "^0.1.8", "isomorphic-ws": "^4.0.1", "json-stringify-safe": "^5.0.1", "stream-json": "^1.9.1", "uuid": "^8.3.2", "ws": "^7.5.10" }, "bin": { "jayson": "bin/jayson.js" } }, "sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ=="], + + "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + + "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], + + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + + "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], + + "ox": ["ox@0.14.22", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-nb5msL8qWbPglhIfZbGJAfw3cqiJjFMiWmACt7kgyWtLib12tcctbHufMT9Hb0Lr6Pt4k9I3dbpueTpbhvbqvA=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], + + "rollup": ["rollup@4.60.4", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.4", "@rollup/rollup-android-arm64": "4.60.4", "@rollup/rollup-darwin-arm64": "4.60.4", "@rollup/rollup-darwin-x64": "4.60.4", "@rollup/rollup-freebsd-arm64": "4.60.4", "@rollup/rollup-freebsd-x64": "4.60.4", "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", "@rollup/rollup-linux-arm-musleabihf": "4.60.4", "@rollup/rollup-linux-arm64-gnu": "4.60.4", "@rollup/rollup-linux-arm64-musl": "4.60.4", "@rollup/rollup-linux-loong64-gnu": "4.60.4", "@rollup/rollup-linux-loong64-musl": "4.60.4", "@rollup/rollup-linux-ppc64-gnu": "4.60.4", "@rollup/rollup-linux-ppc64-musl": "4.60.4", "@rollup/rollup-linux-riscv64-gnu": "4.60.4", "@rollup/rollup-linux-riscv64-musl": "4.60.4", "@rollup/rollup-linux-s390x-gnu": "4.60.4", "@rollup/rollup-linux-x64-gnu": "4.60.4", "@rollup/rollup-linux-x64-musl": "4.60.4", "@rollup/rollup-openbsd-x64": "4.60.4", "@rollup/rollup-openharmony-arm64": "4.60.4", "@rollup/rollup-win32-arm64-msvc": "4.60.4", "@rollup/rollup-win32-ia32-msvc": "4.60.4", "@rollup/rollup-win32-x64-gnu": "4.60.4", "@rollup/rollup-win32-x64-msvc": "4.60.4", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g=="], + + "rpc-websockets": ["rpc-websockets@9.3.10", "", { "dependencies": { "@swc/helpers": "^0.5.11", "@types/ws": "^8.2.2", "buffer": "^6.0.3", "eventemitter3": "^5.0.1", "ws": "^8.5.0" }, "optionalDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^6.0.0" } }, "sha512-QT5PQ6LiWhA5RCS93oWwgxU4XzQltkYm8C3aTmmKEgj0HolGRo3VbdzELw7CEV35l9T7Amha8Vnr4rCfSjVP+w=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], + + "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + + "stream-chain": ["stream-chain@2.2.5", "", {}, "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA=="], + + "stream-json": ["stream-json@1.9.1", "", { "dependencies": { "stream-chain": "^2.2.5" } }, "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw=="], + + "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], + + "superstruct": ["superstruct@2.0.2", "", {}, "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A=="], + + "text-encoding-utf-8": ["text-encoding-utf-8@1.0.2", "", {}, "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg=="], + + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], + + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + + "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + + "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], + + "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], + + "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], + + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="], + + "utf-8-validate": ["utf-8-validate@6.0.6", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA=="], + + "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + + "viem": ["viem@2.50.4", "", { "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.2.3", "isows": "1.0.7", "ox": "0.14.22", "ws": "8.20.1" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-rf98F4s3Vlb+uJZEKfay3IbBw3CNCbVtx5Y3UIljlO2tSX420g/J0WQSYsjzBSasUFgxgsXabji14O9kGbiqgg=="], + + "vite": ["vite@7.3.3", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA=="], + + "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], + + "vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="], + + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + + "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], + + "ws": ["ws@8.20.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w=="], + + "@solana/errors/commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], + + "jayson/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], + + "jayson/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + + "ox/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + + "ox/eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + + "rollup/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "rpc-websockets/@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + + "viem/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + } +} diff --git a/sdk/js/bun.lockb b/sdk/js/bun.lockb deleted file mode 100755 index 63682ed7970ba5bb90defc3d884e8141c9750ca9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88184 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 X9XBf5bb*EM0B$9YeKh3%!hil3`Z(0R From a485ec8be272477952f91c22e132a9107dc13980 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Tue, 19 May 2026 21:25:31 +0800 Subject: [PATCH 07/13] chore(sdk/js)!: make solana/viem/curves peers truly opt-in move @solana/web3.js, viem, and @noble/curves out of optionalDependencies into peerDependencies (with optional meta). they were auto-installed by npm despite the "optional" label, dragging ~70 transitive packages into every downstream install. now a bare `npm install @phala/dstack-sdk` pulls only @noble/hashes. consumers that import /solana, /viem, /encrypt-env-vars, or /verify-env-encrypt-public-key submodules must install the matching peer explicitly. --- sdk/js/bun.lock | 21 ++++++++------------- sdk/js/package.json | 17 +++++++++-------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/sdk/js/bun.lock b/sdk/js/bun.lock index 6597252b..1388c0b6 100644 --- a/sdk/js/bun.lock +++ b/sdk/js/bun.lock @@ -5,20 +5,19 @@ "": { "name": "@phala/dstack-sdk", "devDependencies": { - "@types/node": "latest", - "typescript": "^5.7.0", - "vitest": "^3.2.4", - }, - "optionalDependencies": { "@noble/curves": "^1.8.1", + "@noble/hashes": "^1.6.1", "@solana/web3.js": "^1.98.4", + "@types/node": "latest", + "typescript": "^5.7.0", "viem": "^2.43.3", + "vitest": "^3.2.4", }, "peerDependencies": { "@noble/curves": "^1.8.1", "@noble/hashes": "^1.6.1", - "@solana/web3.js": "*", - "viem": "*", + "@solana/web3.js": "^1.98.4", + "viem": "^2.43.3", }, "optionalPeers": [ "@noble/curves", @@ -166,7 +165,7 @@ "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], - "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/node": ["@types/node@25.9.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ=="], @@ -232,7 +231,7 @@ "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], - "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], @@ -354,10 +353,6 @@ "ox/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], - "ox/eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], - - "rollup/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], - "rpc-websockets/@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], "viem/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], diff --git a/sdk/js/package.json b/sdk/js/package.json index f9a08c58..96c12b90 100644 --- a/sdk/js/package.json +++ b/sdk/js/package.json @@ -97,28 +97,29 @@ "author": "Leechael Yim", "license": "Apache-2.0", "devDependencies": { + "@noble/curves": "^1.8.1", + "@noble/hashes": "^1.6.1", + "@solana/web3.js": "^1.98.4", "@types/node": "latest", "typescript": "^5.7.0", + "viem": "^2.43.3", "vitest": "^3.2.4" }, - "optionalDependencies": { + "peerDependencies": { "@noble/curves": "^1.8.1", + "@noble/hashes": "^1.6.1", "@solana/web3.js": "^1.98.4", "viem": "^2.43.3" }, - "peerDependencies": { - "@noble/curves": "^1.8.1", - "@noble/hashes": "^1.6.1" - }, "peerDependenciesMeta": { - "viem": { - "optional": true - }, "@noble/curves": { "optional": true }, "@solana/web3.js": { "optional": true + }, + "viem": { + "optional": true } } } From fc48a0139e356ec30a27183ffbafda6177cc03dd Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Tue, 19 May 2026 22:22:36 +0800 Subject: [PATCH 08/13] chore(sdk/js): bump to 0.5.8-beta.1 for API parity beta --- sdk/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/js/package.json b/sdk/js/package.json index 96c12b90..a8f3c2a8 100644 --- a/sdk/js/package.json +++ b/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@phala/dstack-sdk", - "version": "0.5.8-beta.0", + "version": "0.5.8-beta.1", "description": "dstack SDK", "main": "dist/node/index.js", "types": "dist/node/index.d.ts", From d08160ffa924d015f09ed510b9c1d8f3ad54d9a9 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 20 May 2026 12:42:41 +0800 Subject: [PATCH 09/13] chore(sdk/js): restrict published package to dist/ only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add a \"files\" allowlist so npm pack ships only README, LICENSE, package.json, and dist/. drops .npmignore (replaced by the allowlist). before: 60 files / 230 KB unpacked / 57 KB tarball, including bun.lock, src/*.ts, test-outputs.js, tsconfig*.json, and .claude/settings.local.json. after: 43 files / 133 KB unpacked / 30 KB tarball — ~47% smaller, no extraneous files leaking out of the repo. --- sdk/js/.npmignore | 3 --- sdk/js/package.json | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 sdk/js/.npmignore diff --git a/sdk/js/.npmignore b/sdk/js/.npmignore deleted file mode 100644 index d50d9a76..00000000 --- a/sdk/js/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -README.md -bun.lockb -src/__tests__ diff --git a/sdk/js/package.json b/sdk/js/package.json index a8f3c2a8..d59f4329 100644 --- a/sdk/js/package.json +++ b/sdk/js/package.json @@ -75,6 +75,9 @@ "engines": { "node": ">=18.0.0" }, + "files": [ + "dist" + ], "scripts": { "build": "npm run build:node && npm run build:browser", "build:node": "tsc -p tsconfig.node.json", From 7536c6c24cd2cb0d453dc558218a324332197a34 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 20 May 2026 12:47:30 +0800 Subject: [PATCH 10/13] docs(sdk/js): rewrite README for 0.5.8-beta.1 API surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit reasons for rewrite: - npm install instructions did not mention peer deps (consumers now need @noble/hashes explicitly, plus per-submodule peers after the 0.5.8 optionalDependencies → peerDependencies change) - getKey signature was stale (missing algorithm arg, path shown as required, key return type listed as hex string instead of Uint8Array) - sign/verify section said "not yet released" though shipped in 0.5.7 - blockchain helpers used the deprecated toViemAccount / toKeypair variants instead of toViemAccountSecure / toKeypairSecure - no coverage of attest, version, info.cloud_vendor / cloud_product, getTlsKey notBefore / notAfter / withAppInfo, secp256k1_prehashed, AppCompose type, or the verify+encrypt env-var flow - migration content for the deprecated TappdClient surfaced ahead of the actual current API structure: one section per capability area (keys, attestation, sign & verify, diagnostics, blockchain, compose hash, encrypted env vars), single example per method, compatibility table mapping each feature to the minimum guest agent version, migration section moved to the bottom. length drops from 508 to 291 lines with broader and more accurate coverage. no AI-slop "Use Cases" / "Key Characteristics" filler. --- sdk/js/README.md | 577 +++++++++++++++-------------------------------- 1 file changed, 180 insertions(+), 397 deletions(-) diff --git a/sdk/js/README.md b/sdk/js/README.md index aebe7e3b..ebd13de6 100644 --- a/sdk/js/README.md +++ b/sdk/js/README.md @@ -1,508 +1,291 @@ -# dstack SDK for JavaScript/TypeScript +# @phala/dstack-sdk -Access TEE features from your JavaScript/TypeScript application running inside dstack. Derive deterministic keys, generate attestation quotes, create TLS certificates, and sign data—all backed by hardware security. +JavaScript / TypeScript client for the dstack guest agent. Derive deterministic keys, generate TDX attestation quotes, issue TLS certificates, sign / verify payloads, and encrypt environment variables for KMS-managed deployments — all against the guest agent socket inside a confidential VM (CVM). ## Installation ```bash -npm install @phala/dstack-sdk +npm install @phala/dstack-sdk @noble/hashes ``` -## Quick Start +`@noble/hashes` is the only required peer dependency (used by the core for sha256 / sha384). Install the matching peer when you import a submodule: -```typescript -import { DstackClient } from '@phala/dstack-sdk'; - -const client = new DstackClient(); +| Import path | Extra peer dependency | +| --- | --- | +| `@phala/dstack-sdk/viem` | `viem` | +| `@phala/dstack-sdk/solana` | `@solana/web3.js` | +| `@phala/dstack-sdk/encrypt-env-vars` | `@noble/curves` | +| `@phala/dstack-sdk/verify-env-encrypt-public-key` | `@noble/curves` | -// Derive a deterministic key for your wallet -const key = await client.getKey('wallet/eth'); -console.log(key.key); // Same path always returns the same key +> **Breaking change in 0.5.8.** Prior releases listed `@solana/web3.js`, `viem`, and `@noble/curves` under `optionalDependencies`, so npm installed them automatically. They are now opt-in peers — install them yourself when you use the corresponding submodule. -// Generate an attestation quote -const quote = await client.getQuote('my-app-state'); -console.log(quote.quote); -``` +Node 18+ supported. Tested through Node 24. -The client automatically connects to `/var/run/dstack.sock`. For local development with the simulator: +## Quick start ```typescript -const client = new DstackClient('http://localhost:8090'); -``` - -## Core API +import { DstackClient } from '@phala/dstack-sdk' -### Derive Keys +const client = new DstackClient() -`getKey()` derives deterministic keys bound to your application's identity (`app_id`). The same path always produces the same key for your app, but different apps get different keys even with the same path. +const key = await client.getKey('wallet/eth') +console.log(Buffer.from(key.key).toString('hex')) -```typescript -// Derive keys by path -const ethKey = await client.getKey('wallet/ethereum'); -const btcKey = await client.getKey('wallet/bitcoin'); - -// Use path to separate keys -const mainnetKey = await client.getKey('wallet/eth/mainnet'); -const testnetKey = await client.getKey('wallet/eth/testnet'); +const quote = await client.getQuote('app-state-snapshot') +console.log(quote.quote) +console.log(quote.replayRtmrs()) ``` -**Parameters:** -- `path`: Key derivation path (determines the key) -- `purpose` (optional): Included in signature chain message, does not affect the derived key - -**Returns:** `GetKeyResponse` -- `key`: Hex-encoded private key -- `signature_chain`: Signatures proving the key was derived in a genuine TEE - -### Generate Attestation Quotes - -`getQuote()` creates a TDX quote proving your code runs in a genuine TEE. +The constructor probes `/var/run/dstack.sock`, then `/run/dstack.sock`, then the `/var/run/dstack/` and `/run/dstack/` variants. Pass an explicit endpoint for HTTP or for a non-default socket: ```typescript -const quote = await client.getQuote('user:alice:nonce123'); - -// Replay RTMRs from the event log -const rtmrs = quote.replayRtmrs(); -console.log(rtmrs); +const client = new DstackClient('http://localhost:8090') // simulator +const client = new DstackClient('/run/dstack/dstack.sock') // custom path ``` -**Parameters:** -- `reportData`: Exactly 64 bytes recommended. If shorter, pad with zeros. If longer, hash it first (e.g., SHA-256). +`DSTACK_SIMULATOR_ENDPOINT` overrides the default when set. -**Returns:** `GetQuoteResponse` -- `quote`: Hex-encoded TDX quote -- `event_log`: JSON string of measured events -- `replayRtmrs()`: Method to compute RTMR values from event log +## Keys -### Get Instance Info +### `getKey(path?, purpose?, algorithm?)` -```typescript -const info = await client.info(); -console.log(info.app_id); -console.log(info.instance_id); -console.log(info.tcb_info); -``` - -**Returns:** `InfoResponse` -- `app_id`: Application identifier -- `instance_id`: Instance identifier -- `app_name`: Application name -- `tcb_info`: TCB measurements (MRTD, RTMRs, event log) -- `compose_hash`: Hash of the app configuration -- `app_cert`: Application certificate (PEM) - -### Generate TLS Certificates - -`getTlsKey()` creates fresh TLS certificates. Unlike `getKey()`, each call generates a new random key. +Derive a deterministic key. Same `(app_id, path, purpose, algorithm)` always returns the same key; different apps deriving on the same path get different keys. ```typescript -const tls = await client.getTlsKey({ - subject: 'api.example.com', - altNames: ['localhost'], - usageRaTls: true // Embed attestation in certificate -}); - -console.log(tls.key); // PEM private key -console.log(tls.certificate_chain); // Certificate chain +const eth = await client.getKey('wallet/ethereum') // secp256k1 (default) +const sol = await client.getKey('wallet/solana', 'mainnet', 'ed25519') // ed25519 ``` -**Parameters:** -- `subject` (optional): Certificate common name (e.g., domain name) -- `altNames` (optional): List of subject alternative names -- `usageRaTls` (optional): Embed TDX quote in certificate extension -- `usageServerAuth` (optional): Enable for server authentication (default: `true`) -- `usageClientAuth` (optional): Enable for client authentication (default: `false`) +Returns `{ key: Uint8Array, signature_chain: Uint8Array[] }`. The signature chain proves the key was derived inside a genuine TEE. -**Returns:** `GetTlsKeyResponse` -- `key`: PEM-encoded private key -- `certificate_chain`: List of PEM certificates +`algorithm`: `'secp256k1'` (default), `'k256'` (alias), or `'ed25519'`. ed25519 requires guest agent ≥ 0.5.7. -### Sign and Verify +### `getTlsKey(options?)` -Sign data using TEE-derived keys (not yet released): +Generate a fresh random TLS keypair plus certificate chain. Every call returns a new key — use `getKey` for deterministic material. ```typescript -const result = await client.sign('ed25519', 'message to sign'); -console.log(result.signature); -console.log(result.public_key); - -// Verify the signature -const valid = await client.verify('ed25519', 'message to sign', result.signature, result.public_key); -console.log(valid.valid); // true +const tls = await client.getTlsKey({ + subject: 'api.example.com', + altNames: ['localhost', '127.0.0.1'], + usageRaTls: true, // embed TDX quote in cert extension +}) ``` -**`sign()` Parameters:** -- `algorithm`: `'ed25519'`, `'secp256k1'`, or `'secp256k1_prehashed'` -- `data`: Data to sign (string, Buffer, or Uint8Array) - -**`sign()` Returns:** `SignResponse` -- `signature`: Hex-encoded signature -- `public_key`: Hex-encoded public key -- `signature_chain`: Signatures proving TEE origin +Options: `subject`, `altNames`, `usageRaTls`, `usageServerAuth` (default `true`), `usageClientAuth` (default `false`), and — on guest agent ≥ 0.5.7 — `notBefore`, `notAfter` (Unix seconds), `withAppInfo`. The client probes `version()` before sending the new options and throws a clear error on older agents instead of silently dropping them. -**`verify()` Parameters:** -- `algorithm`: Algorithm used for signing -- `data`: Original data -- `signature`: Signature to verify -- `public_key`: Public key to verify against +Returns `{ key: string, certificate_chain: string[], asUint8Array(maxLength?) }`. `key` is PEM-encoded. -**`verify()` Returns:** `VerifyResponse` -- `valid`: Boolean indicating if signature is valid +## Attestation -### Emit Events +### `getQuote(reportData)` -Extend RTMR3 with custom measurements for your application's boot sequence (requires dstack OS 0.5.0+). These measurements are append-only and become part of the attestation record. +Generate a raw TDX quote. `reportData` is up to 64 bytes (string, Buffer, or Uint8Array). ```typescript -await client.emitEvent('config_loaded', 'production'); -await client.emitEvent('plugin_initialized', 'auth-v2'); +const quote = await client.getQuote('user:alice:nonce123') +quote.quote // hex-encoded TDX quote +quote.event_log // JSON string of measured events +quote.replayRtmrs() // recompute RTMR[0..3] from the event log ``` -**Parameters:** -- `event`: Event name (string identifier) -- `payload`: Event value (string, Buffer, or Uint8Array) - -## Blockchain Integration +### `attest(reportData)` -### Ethereum with Viem +Versioned dstack attestation that works across TDX / GCP / Nitro providers. Preferred for cross-platform verifiers. ```typescript -import { toViemAccount } from '@phala/dstack-sdk/viem'; -import { createWalletClient, http } from 'viem'; -import { mainnet } from 'viem/chains'; - -const key = await client.getKey('wallet/ethereum'); -const account = toViemAccount(key); - -const wallet = createWalletClient({ - account, - chain: mainnet, - transport: http() -}); +const { attestation } = await client.attest('app-state-snapshot') ``` -### Solana +### `info()` -```typescript -import { toKeypair } from '@phala/dstack-sdk/solana'; +App identity and TCB metadata. -const key = await client.getKey('wallet/solana'); -const keypair = toKeypair(key); -console.log(keypair.publicKey.toBase58()); -``` - -## Development - -For local development without TDX hardware, use the simulator: - -```bash -git clone https://github.com/Dstack-TEE/dstack.git -cd dstack/sdk/simulator -./build.sh -./dstack-simulator -``` - -Then set the endpoint: - -```bash -export DSTACK_SIMULATOR_ENDPOINT=http://localhost:8090 +```typescript +const info = await client.info() +info.app_id // application identifier +info.instance_id // CVM instance identifier +info.tcb_info // parsed { mrtd, rtmr0..3, event_log, ... } +info.compose_hash +info.cloud_vendor // e.g. "Google" (guest agent ≥ 0.5.7) +info.cloud_product // e.g. "Google Compute Engine" (guest agent ≥ 0.5.7) ``` ---- +### `version()` -## Deployment Utilities +Returns `{ version, rev }` of the guest agent. Throws on agents older than 0.5.7 (the RPC didn't exist). -These utilities are for deployment scripts, not runtime SDK operations. +## Sign and verify -### Encrypt Environment Variables +### `sign(algorithm, data)` -Encrypt secrets before deploying to dstack: +Sign data with a derived key. The SDK rejects mismatched input early — `secp256k1_prehashed` requires a 32-byte digest. ```typescript -import { encryptEnvVars, verifyEnvEncryptPublicKey, verifyEnvEncryptPublicKeyLegacy, type EnvVar } from '@phala/dstack-sdk'; - -// Get and verify the KMS public key -// (obtain public_key, signature_v1, and timestamp from KMS API) - -// Prefer signature_v1 with timestamp (prevents replay attacks) -const kmsIdentity = verifyEnvEncryptPublicKey(publicKeyBytes, signatureV1Bytes, appId, timestamp); -if (!kmsIdentity) { - // Fall back to legacy signature for backward compatibility with older KMS - const legacyIdentity = verifyEnvEncryptPublicKeyLegacy(publicKeyBytes, signatureBytes, appId); - if (!legacyIdentity) { - throw new Error('Invalid KMS key'); - } - console.warn('Using legacy signature without timestamp protection'); -} - -// Encrypt variables -const envVars: EnvVar[] = [ - { key: 'DATABASE_URL', value: 'postgresql://...' }, - { key: 'API_KEY', value: 'secret' } -]; -const encrypted = await encryptEnvVars(envVars, publicKey); +const res = await client.sign('ed25519', 'hello dstack') +res.signature // Uint8Array +res.public_key // Uint8Array +res.signature_chain // Uint8Array[] — proves the signing key came from this TEE ``` -## API Reference - -### DstackClient +Algorithms: `ed25519`, `secp256k1`, `secp256k1_prehashed`. Requires guest agent ≥ 0.5.7. -#### Constructor +### `verify(algorithm, data, signature, publicKey)` ```typescript -new DstackClient(endpoint?: string) +const ok = await client.verify('ed25519', 'hello dstack', res.signature, res.public_key) +ok.valid // boolean ``` -**Parameters:** -- `endpoint` (optional): Connection endpoint - - Unix socket path (production): `/var/run/dstack.sock` - - HTTP/HTTPS URL (development): `http://localhost:8090` - - Environment variable: `DSTACK_SIMULATOR_ENDPOINT` - -**Production App Configuration:** - -The Docker Compose configuration is embedded in `app-compose.json`: - -```json -{ - "manifest_version": 1, - "name": "production-app", - "runner": "docker-compose", - "docker_compose_file": "services:\n app:\n image: your-app\n volumes:\n - /var/run/dstack.sock:/var/run/dstack.sock\n environment:\n - NODE_ENV=production", - "public_tcbinfo": true -} -``` - -**Important**: The `docker_compose_file` contains YAML content as a string, ensuring the volume binding for `/var/run/dstack.sock` is included. - -#### Methods - -##### `info(): Promise` - -Retrieves comprehensive information about the TEE instance. +### `emitEvent(event, payload)` -**Returns:** `InfoResponse` -- `app_id`: Unique application identifier -- `instance_id`: Unique instance identifier -- `app_name`: Application name from configuration -- `device_id`: TEE device identifier -- `tcb_info`: Trusted Computing Base information - - `mrtd`: Measurement of TEE domain - - `rtmr0-3`: Runtime Measurement Registers - - `event_log`: Boot and runtime events - - `os_image_hash`: Operating system measurement - - `compose_hash`: Application configuration hash -- `app_cert`: Application certificate in PEM format -- `key_provider_info`: Key management configuration - -##### `getKey(path: string, purpose?: string): Promise` - -Derives a deterministic secp256k1/K256 private key for blockchain and Web3 applications. This is the primary method for obtaining cryptographic keys for wallets, signing, and other deterministic key scenarios. - -**Parameters:** -- `path`: Unique identifier for key derivation (e.g., `"wallet/ethereum"`, `"signing/solana"`) -- `purpose` (optional): Additional context for key usage (default: `""`) - -**Returns:** `GetKeyResponse` -- `key`: 32-byte secp256k1 private key as `Uint8Array` (suitable for Ethereum, Bitcoin, Solana, etc.) -- `signature_chain`: Array of cryptographic signatures proving key authenticity - -**Key Characteristics:** -- **Deterministic**: Same path + purpose always generates identical key -- **Isolated**: Different paths produce cryptographically independent keys -- **Blockchain-Ready**: Compatible with secp256k1 curve (Ethereum, Bitcoin, Solana) -- **Verifiable**: Signature chain proves key was derived inside genuine TEE - -**Use Cases:** -- Cryptocurrency wallets -- Transaction signing -- DeFi protocol interactions -- NFT operations -- Any scenario requiring consistent, reproducible keys +Extends RTMR3 with a custom event. The event becomes part of the next quote's event log and cannot be removed. ```typescript -// Examples of deterministic key derivation -const ethWallet = await client.getKey('wallet/ethereum', 'mainnet'); -const btcWallet = await client.getKey('wallet/bitcoin', 'mainnet'); -const solWallet = await client.getKey('wallet/solana', 'mainnet'); - -// Same path always returns same key -const key1 = await client.getKey('my-app/signing'); -const key2 = await client.getKey('my-app/signing'); -// key1.key === key2.key (guaranteed identical) - -// Different paths return different keys -const userA = await client.getKey('user/alice/wallet'); -const userB = await client.getKey('user/bob/wallet'); -// userA.key !== userB.key (guaranteed different) +await client.emitEvent('config_loaded', 'v1.0.0') ``` -##### `getQuote(reportData: string | Buffer | Uint8Array): Promise` +Requires guest agent ≥ 0.5.0. -Generates a TDX attestation quote containing the provided report data. +## Diagnostics -**Parameters:** -- `reportData`: Data to include in quote (max 64 bytes) +### `isReachable()` -**Returns:** `GetQuoteResponse` -- `quote`: TDX quote as hex string -- `event_log`: JSON string of system events -- `replayRtmrs()`: Function returning computed RTMR values +Sub-500ms probe against `/Info`. Returns a boolean and never throws — useful for liveness checks. -**Use Cases:** -- Remote attestation of application state -- Cryptographic proof of execution environment -- Audit trail generation +## Blockchain helpers -##### `attest(reportData: string | Buffer | Uint8Array): Promise` +### Ethereum -Generates a versioned attestation containing the provided report data. +```typescript +import { toViemAccountSecure } from '@phala/dstack-sdk/viem' +import { createWalletClient, http } from 'viem' +import { mainnet } from 'viem/chains' -**Parameters:** -- `reportData`: Data to include in attestation (max 64 bytes) +const key = await client.getKey('wallet/ethereum') +const account = toViemAccountSecure(key) -**Returns:** `AttestResponse` -- `attestation`: Hex-encoded attestation payload +const wallet = createWalletClient({ account, chain: mainnet, transport: http() }) +``` -**Use Cases:** -- Remote attestation across multiple platform types -- Verifier APIs that accept versioned attestations +`toViemAccountSecure` hashes the derived key with SHA-256 before passing it to viem's `privateKeyToAccount`. The unhashed alternative `toViemAccount` is kept for migration only and emits a warning. -##### `getTlsKey(options?: TlsKeyOptions): Promise` +### Solana -Generates a fresh, random TLS key pair with X.509 certificate for TLS/SSL connections. **Important**: This method generates different keys on each call - use `getKey()` for deterministic keys. +```typescript +import { toKeypairSecure } from '@phala/dstack-sdk/solana' -**Parameters:** `TlsKeyOptions` -- `subject` (optional): Certificate subject (Common Name) - typically the domain name (default: `""`) -- `altNames` (optional): Subject Alternative Names - additional domains/IPs for the certificate (default: `[]`) -- `usageRaTls` (optional): Include TDX attestation quote in certificate extension for remote verification (default: `false`) -- `usageServerAuth` (optional): Enable server authentication - allows certificate to authenticate servers (default: `true`) -- `usageClientAuth` (optional): Enable client authentication - allows certificate to authenticate clients (default: `false`) +const key = await client.getKey('wallet/solana') +const keypair = toKeypairSecure(key) +console.log(keypair.publicKey.toBase58()) +``` -**Returns:** `GetTlsKeyResponse` -- `key`: Private key in PEM format (X.509/PKCS#8) -- `certificate_chain`: Certificate chain array +Same pattern as the Ethereum helper. `toKeypair` is the unhashed legacy variant. -**Key Characteristics:** -- **Random Generation**: Each call produces a completely different key -- **TLS-Optimized**: Keys and certificates designed for TLS/SSL scenarios -- **RA-TLS Support**: Optional remote attestation extension in certificates -- **TEE-Signed**: Certificates signed by TEE-resident Certificate Authority +## Compose hash -**Certificate Usage Scenarios:** +```typescript +import { getComposeHash, type AppCompose } from '@phala/dstack-sdk/get-compose-hash' + +const compose: AppCompose = { + manifest_version: 2, + name: 'my-app', + runner: 'docker-compose', + docker_compose_file: '...', + kms_enabled: true, +} -1. **Standard HTTPS Server** (`usageServerAuth: true`, `usageClientAuth: false`) - - Web servers, API endpoints - - Server authenticates to clients - - Most common TLS use case +const hash = getComposeHash(compose) +const normalized = getComposeHash(compose, true) // strip bash_script/docker_compose_file overlap +``` -2. **Remote Attestation Server** (`usageRaTls: true`) - - TEE-based services requiring proof of execution environment - - Clients can verify the server runs in genuine TEE - - Combines TLS with hardware attestation +Pure function — no TEE call required. Produces the canonical SHA-256 used by the on-chain KMS allowlist. -3. **mTLS Client Certificate** (`usageServerAuth: false`, `usageClientAuth: true`) - - Client authentication in mutual TLS - - API clients, service-to-service communication - - Client proves identity to server +## Encrypted environment variables -4. **Dual-Purpose Certificate** (`usageServerAuth: true`, `usageClientAuth: true`) - - Services that act as both client and server - - Microservices architectures - - Maximum flexibility for TLS roles +The full deployment flow mirrors `vmm-cli.py`: fetch the env-encrypt public key from KMS, verify its signature locally, then ECIES-encrypt the env vars against it. ```typescript -// Example 1: Standard HTTPS server certificate -const serverCert = await client.getTlsKey({ - subject: 'api.example.com', - altNames: ['api.example.com', 'www.api.example.com', '10.0.0.1'] - // usageServerAuth: true (default) - allows server authentication - // usageClientAuth: false (default) - no client authentication -}); - -// Example 2: Certificate with remote attestation (RA-TLS) -const attestedCert = await client.getTlsKey({ - subject: 'secure-api.example.com', - usageRaTls: true // Include TDX quote for remote verification - // Clients can verify the TEE environment through the certificate -}); - -// Example 3: Mutual TLS (mTLS) certificate for client authentication -const clientCert = await client.getTlsKey({ - subject: 'client.example.com', - usageServerAuth: false, // This certificate won't authenticate servers - usageClientAuth: true // Enable client authentication -}); - -// Example 4: Certificate for both server and client authentication -const dualUseCert = await client.getTlsKey({ - subject: 'dual.example.com', - usageServerAuth: true, // Can authenticate as server - usageClientAuth: true // Can authenticate as client -}); - -// ⚠️ Each call generates different keys (unlike getKey) -const cert1 = await client.getTlsKey(); -const cert2 = await client.getTlsKey(); -// cert1.key !== cert2.key (always different) - -// Use with Node.js HTTPS server -import https from 'https'; -const server = https.createServer({ - key: serverCert.key, - cert: serverCert.certificate_chain.join('\n') -}, app); -``` - -##### `emitEvent(event: string, payload: string | Buffer | Uint8Array): Promise` - -Extends RTMR3 with a custom event for audit logging. +import { + verifyEnvEncryptPublicKey, + verifyEnvEncryptPublicKeyLegacy, +} from '@phala/dstack-sdk' +import { encryptEnvVars, type EnvVar } from '@phala/dstack-sdk/encrypt-env-vars' + +const response = await fetch(`${kmsUrl}/prpc/GetAppEnvEncryptPubKey?json`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ app_id: appId }), +}).then(r => r.json()) + +const publicKey = Buffer.from(response.public_key, 'hex') + +// Prefer v1 (timestamp-protected against replay) +let signer = response.signature_v1 + ? verifyEnvEncryptPublicKey( + publicKey, + Buffer.from(response.signature_v1, 'hex'), + appId, + BigInt(response.timestamp), + ) + : null + +// Fall back to legacy signature on older KMS +if (!signer && response.signature) { + signer = verifyEnvEncryptPublicKeyLegacy( + publicKey, + Buffer.from(response.signature, 'hex'), + appId, + ) +} -**Parameters:** -- `event`: Event identifier string -- `payload`: Event data +if (!signer) throw new Error('KMS signature did not verify') -**Requirements:** -- dstack OS version 0.5.0 or later -- Events are permanently recorded in TEE measurements +const envs: EnvVar[] = [ + { key: 'DATABASE_URL', value: 'postgresql://…' }, + { key: 'API_KEY', value: 'sk-test-1234' }, +] +const encrypted = await encryptEnvVars(envs, response.public_key) +``` -##### `isReachable(): Promise` +Verify functions return the signer's compressed public key (hex) on success, or `null` on failure. Check the signer against your trusted-signer whitelist before encrypting. -Tests connectivity to the dstack service. +## Compatibility -**Returns:** `boolean` indicating service availability +| Feature | Minimum guest agent | +| --- | --- | +| `getKey`, `getTlsKey`, `getQuote`, `info` | 0.3.x | +| `emitEvent` | 0.5.0 | +| `attest`, `sign`, `verify`, `version`, ed25519 keys, `info.cloud_vendor` / `cloud_product`, `getTlsKey` `notBefore` / `notAfter` / `withAppInfo` | 0.5.7 | -## Utility Functions +The SDK's release versions track guest agent versions — `0.5.8-x` targets dstack 0.5.7+. -### Compose Hash Calculation +## Development -```typescript -import { getComposeHash } from '@phala/dstack-sdk'; +Run the standalone simulator instead of a real TDX host: -const hash = getComposeHash(appComposeObject); +```bash +cd dstack/sdk/simulator +./build.sh +./dstack-simulator +export DSTACK_SIMULATOR_ENDPOINT=http://localhost:8090 ``` ---- +Then point `new DstackClient()` at the simulator (it picks up `DSTACK_SIMULATOR_ENDPOINT` automatically). ## Migration from TappdClient -Replace `TappdClient` with `DstackClient`: +`TappdClient` and its `deriveKey` / `tdxQuote` methods are deprecated but still exported. Replace them with `DstackClient` and the new methods: -```typescript -// Before -import { TappdClient } from '@phala/dstack-sdk'; -const client = new TappdClient(); - -// After -import { DstackClient } from '@phala/dstack-sdk'; -const client = new DstackClient(); -``` +| Old | New | +| --- | --- | +| `new TappdClient()` | `new DstackClient()` | +| `client.deriveKey(path, subject)` | `client.getTlsKey({ subject })` | +| `client.tdxQuote(data)` | `client.getQuote(data)` | +| `/var/run/tappd.sock` | `/var/run/dstack.sock` | -Method changes: -- `deriveKey()` → `getTlsKey()` for TLS certificates -- `tdxQuote()` → `getQuote()` (raw data only, no hash algorithms) -- Socket path: `/var/run/tappd.sock` → `/var/run/dstack.sock` +`toViemAccount` and `toKeypair` are kept for the same reason; prefer their `Secure` variants in new code. ## License -Apache License 2.0 +Apache-2.0 From 48e091abbdef75c089e4881af61baac36a30495e Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 20 May 2026 17:40:17 +0800 Subject: [PATCH 11/13] refactor(sdk/js): unify browser and node sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit after moving to @noble/hashes and @noble/curves the .browser.ts variants were 95% identical to the node ones — only Buffer vs manual byte helpers and \"import crypto\" vs globalThis.crypto. rewrite both subpaths to use the universal pattern and drop the duplicates in the next commit. - encrypt-env-vars.ts: drop \`import crypto from 'crypto'\` and use the global Web Crypto (works on Node 18+ and browsers) - verify-env-encrypt-public-key.ts: drop Buffer (use manual hex / bigint helpers); make the function bodies stay synchronous like the previous node version, so the public signature does not change both still return the same types and behave identically. --- sdk/js/src/encrypt-env-vars.browser.ts | 66 ----- sdk/js/src/encrypt-env-vars.ts | 60 +++-- sdk/js/src/get-compose-hash.browser.ts | 49 ---- .../verify-env-encrypt-public-key.browser.ts | 205 ---------------- sdk/js/src/verify-env-encrypt-public-key.ts | 226 +++++++----------- sdk/js/tsconfig.browser.json | 18 -- sdk/js/tsconfig.node.json | 14 -- 7 files changed, 118 insertions(+), 520 deletions(-) delete mode 100644 sdk/js/src/encrypt-env-vars.browser.ts delete mode 100644 sdk/js/src/get-compose-hash.browser.ts delete mode 100644 sdk/js/src/verify-env-encrypt-public-key.browser.ts delete mode 100644 sdk/js/tsconfig.browser.json delete mode 100644 sdk/js/tsconfig.node.json diff --git a/sdk/js/src/encrypt-env-vars.browser.ts b/sdk/js/src/encrypt-env-vars.browser.ts deleted file mode 100644 index 0484b1b6..00000000 --- a/sdk/js/src/encrypt-env-vars.browser.ts +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-FileCopyrightText: © 2025 Phala Network -// -// SPDX-License-Identifier: Apache-2.0 - -import { x25519 } from "@noble/curves/ed25519" - -// Convert hex string to Uint8Array -function hexToUint8Array(hex: string) { - hex = hex.startsWith("0x") ? hex.slice(2) : hex; - return new Uint8Array( - hex.match(/.{1,2}/g)?.map((byte: string) => parseInt(byte, 16)) ?? [], - ); -} - -function uint8ArrayToHex(buffer: Uint8Array) { - return Array.from(buffer) - .map((byte: number) => byte.toString(16).padStart(2, "0")) - .join(""); -} - -export interface EnvVar { - key: string - value: string -} - -// Encrypt environment variables - using the same implementation as Node.js version -export async function encryptEnvVars(envs: EnvVar[], publicKeyHex: string) { - // Prepare environment data - const envsJson = JSON.stringify({ env: envs }); - - // Generate private key and derive public key - const privateKey = x25519.utils.randomPrivateKey(); - const publicKey = x25519.getPublicKey(privateKey); - - // Generate shared key - const remotePubkey = hexToUint8Array(publicKeyHex); - const shared = x25519.getSharedSecret(privateKey, remotePubkey); - - // Import shared key for AES-GCM - const importedShared = await crypto.subtle.importKey( - "raw", - new Uint8Array(shared), - { name: "AES-GCM", length: 256 }, - true, - ["encrypt"], - ); - - // Encrypt the data - const iv = crypto.getRandomValues(new Uint8Array(12)); - const encrypted = await crypto.subtle.encrypt( - { name: "AES-GCM", iv }, - importedShared, - new TextEncoder().encode(envsJson), - ); - - // Combine all components - const result = new Uint8Array( - publicKey.length + iv.length + encrypted.byteLength, - ); - - result.set(publicKey); - result.set(iv, publicKey.length); - result.set(new Uint8Array(encrypted), publicKey.length + iv.length); - - return uint8ArrayToHex(result); -} \ No newline at end of file diff --git a/sdk/js/src/encrypt-env-vars.ts b/sdk/js/src/encrypt-env-vars.ts index cef27b9f..b57f2001 100644 --- a/sdk/js/src/encrypt-env-vars.ts +++ b/sdk/js/src/encrypt-env-vars.ts @@ -3,20 +3,18 @@ // SPDX-License-Identifier: Apache-2.0 import { x25519 } from "@noble/curves/ed25519" -import crypto from 'crypto' -// Convert hex string to Uint8Array -function hexToUint8Array(hex: string) { - hex = hex.startsWith("0x") ? hex.slice(2) : hex; +function hexToUint8Array(hex: string): Uint8Array { + hex = hex.startsWith("0x") ? hex.slice(2) : hex return new Uint8Array( - hex.match(/.{1,2}/g)?.map((byte: string) => parseInt(byte, 16)) ?? [], - ); + hex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) ?? [], + ) } -function uint8ArrayToHex(buffer: Uint8Array) { +function uint8ArrayToHex(buffer: Uint8Array): string { return Array.from(buffer) - .map((byte: number) => byte.toString(16).padStart(2, "0")) - .join(""); + .map((byte) => byte.toString(16).padStart(2, "0")) + .join("") } export interface EnvVar { @@ -24,44 +22,44 @@ export interface EnvVar { value: string } -// Encrypt environment variables -export async function encryptEnvVars(envs: EnvVar[], publicKeyHex: string) { - // Prepare environment data - const envsJson = JSON.stringify({ env: envs }); +/** + * ECIES-encrypt a set of environment variables against a recipient's x25519 + * public key. Works on Node 18+ and modern browsers — uses `globalThis.crypto` + * (Web Crypto API) and @noble/curves. + */ +export async function encryptEnvVars( + envs: EnvVar[], + publicKeyHex: string, +): Promise { + const envsJson = JSON.stringify({ env: envs }) - // Generate private key and derive public key - const privateKey = x25519.utils.randomPrivateKey(); - const publicKey = x25519.getPublicKey(privateKey); + const privateKey = x25519.utils.randomPrivateKey() + const publicKey = x25519.getPublicKey(privateKey) - // Generate shared key - const remotePubkey = hexToUint8Array(publicKeyHex); - const shared = x25519.getSharedSecret(privateKey, remotePubkey); + const remotePubkey = hexToUint8Array(publicKeyHex) + const shared = x25519.getSharedSecret(privateKey, remotePubkey) - // Import shared key for AES-GCM const importedShared = await crypto.subtle.importKey( "raw", new Uint8Array(shared), { name: "AES-GCM", length: 256 }, true, ["encrypt"], - ); + ) - // Encrypt the data - const iv = crypto.getRandomValues(new Uint8Array(12)); + const iv = crypto.getRandomValues(new Uint8Array(12)) const encrypted = await crypto.subtle.encrypt( { name: "AES-GCM", iv }, importedShared, new TextEncoder().encode(envsJson), - ); + ) - // Combine all components const result = new Uint8Array( publicKey.length + iv.length + encrypted.byteLength, - ); + ) + result.set(publicKey) + result.set(iv, publicKey.length) + result.set(new Uint8Array(encrypted), publicKey.length + iv.length) - result.set(publicKey); - result.set(iv, publicKey.length); - result.set(new Uint8Array(encrypted), publicKey.length + iv.length); - - return uint8ArrayToHex(result); + return uint8ArrayToHex(result) } diff --git a/sdk/js/src/get-compose-hash.browser.ts b/sdk/js/src/get-compose-hash.browser.ts deleted file mode 100644 index 17b80b0e..00000000 --- a/sdk/js/src/get-compose-hash.browser.ts +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-FileCopyrightText: © 2025 Phala Network -// -// SPDX-License-Identifier: Apache-2.0 - -import { sha256 } from '@noble/hashes/sha256'; -import { bytesToHex } from '@noble/hashes/utils'; - -type SortableValue = string | number | boolean | null | undefined | SortableObject | SortableArray; -interface SortableObject { - [key: string]: SortableValue; -} -interface SortableArray extends Array {} - -/** - * Recursively sorts object keys lexicographically. - * @param obj - The object to sort - * @returns A new object with sorted keys - */ -function sortObjectKeys(obj: SortableValue): SortableValue { - if (obj === null || obj === undefined) return obj; - if (typeof obj !== 'object') return obj; - if (Array.isArray(obj)) return obj.map(sortObjectKeys); - - const sortedObj: SortableObject = {}; - Object.keys(obj).sort().forEach(key => { - sortedObj[key] = sortObjectKeys((obj as SortableObject)[key]); - }); - return sortedObj; -} - -async function sha256Hash(data: string): Promise { - return bytesToHex(sha256(new TextEncoder().encode(data))); -} - -/** - * Get the hash of a docker-compose configuration - * @param compose - The docker-compose configuration object - * @returns Promise resolving to hex-encoded hash - */ -export async function getComposeHash(compose: Record): Promise { - // Sort the object keys to ensure deterministic hashing - const sortedCompose = sortObjectKeys(compose); - - // Convert to JSON string with no extra whitespace - const jsonString = JSON.stringify(sortedCompose); - - // Return SHA-256 hash - return sha256Hash(jsonString); -} \ No newline at end of file diff --git a/sdk/js/src/verify-env-encrypt-public-key.browser.ts b/sdk/js/src/verify-env-encrypt-public-key.browser.ts deleted file mode 100644 index 523b52b4..00000000 --- a/sdk/js/src/verify-env-encrypt-public-key.browser.ts +++ /dev/null @@ -1,205 +0,0 @@ -// SPDX-FileCopyrightText: © 2025 Phala Network -// -// SPDX-License-Identifier: Apache-2.0 - -import { keccak_256 } from "@noble/hashes/sha3"; -import { secp256k1 } from "@noble/curves/secp256k1"; - -/** Default maximum age for timestamp verification (5 minutes) */ -const DEFAULT_MAX_AGE_SECONDS = 300; - -/** - * Options for verifying env encrypt public key - */ -export interface VerifyOptions { - /** - * Maximum age of the response in seconds. - * If the timestamp is older than this, verification fails. - * Default: 300 (5 minutes) - */ - maxAgeSeconds?: number; -} - -/** - * Convert a bigint to big-endian bytes - */ -function bigintToBeBytes(value: bigint, length: number): Uint8Array { - const bytes = new Uint8Array(length); - for (let i = length - 1; i >= 0; i--) { - bytes[i] = Number(value & 0xffn); - value >>= 8n; - } - return bytes; -} - -/** - * Convert hex string to Uint8Array - */ -function hexToBytes(hex: string): Uint8Array { - const bytes = new Uint8Array(hex.length / 2); - for (let i = 0; i < hex.length; i += 2) { - bytes[i / 2] = parseInt(hex.substr(i, 2), 16); - } - return bytes; -} - -/** - * Verify the signature of a public key with timestamp validation. - * - * @param publicKey - The public key bytes to verify (32 bytes) - * @param signature - The signature bytes (65 bytes) - * @param appId - The application ID - * @param timestamp - Unix timestamp in seconds when the response was generated - * @param options - Optional verification options - * @returns The compressed public key if valid, null otherwise - * - * @example - * ```typescript - * const publicKey = new Uint8Array([...]); - * const signature = new Uint8Array([...]); - * const appId = '00'.repeat(20); - * const timestamp = 1700000000n; - * const compressedPubkey = await verifyEnvEncryptPublicKey(publicKey, signature, appId, timestamp); - * ``` - */ -export async function verifyEnvEncryptPublicKey( - publicKey: Uint8Array, - signature: Uint8Array, - appId: string, - timestamp: bigint | number, - options?: VerifyOptions -): Promise { - if (signature.length !== 65) { - return null; - } - - // Convert timestamp to bigint for consistent handling - const ts = typeof timestamp === 'bigint' ? timestamp : BigInt(timestamp); - - // Validate timestamp freshness - const maxAge = options?.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS; - const now = BigInt(Math.floor(Date.now() / 1000)); - const age = now - ts; - - if (age < 0n) { - // Timestamp is in the future - allow small clock skew (60 seconds) - if (age < -60n) { - console.error('timestamp is too far in the future'); - return null; - } - } else if (age > BigInt(maxAge)) { - console.error(`timestamp is too old: ${age}s > ${maxAge}s`); - return null; - } - - // Create the message to verify - const prefix = new TextEncoder().encode("dstack-env-encrypt-pubkey"); - - // Remove 0x prefix if present - let cleanAppId = appId; - if (appId.startsWith("0x")) { - cleanAppId = appId.slice(2); - } - - const appIdBytes = hexToBytes(cleanAppId); - const separator = new TextEncoder().encode(":"); - - // Convert timestamp to big-endian bytes (8 bytes) - const timestampBytes = bigintToBeBytes(ts, 8); - - // Construct message: prefix + ":" + app_id + timestamp_be_bytes + public_key - const message = new Uint8Array(prefix.length + separator.length + appIdBytes.length + timestampBytes.length + publicKey.length); - let offset = 0; - message.set(prefix, offset); offset += prefix.length; - message.set(separator, offset); offset += separator.length; - message.set(appIdBytes, offset); offset += appIdBytes.length; - message.set(timestampBytes, offset); offset += timestampBytes.length; - message.set(publicKey, offset); - - // Hash the message with Keccak-256 - const messageHash = keccak_256(message); - - try { - // Extract r, s, v from signature (last byte is recovery id) - const r = signature.slice(0, 32); - const s = signature.slice(32, 64); - const recovery = signature[64]; - - // Create signature in DER format for secp256k1 - const sigBytes = new Uint8Array(64); - sigBytes.set(r, 0); - sigBytes.set(s, 32); - - // Recover the public key from the signature - const recoveredPubKey = secp256k1.Signature.fromCompact(sigBytes) - .addRecoveryBit(recovery) - .recoverPublicKey(messageHash); - - // Return compressed public key with 0x prefix - const compressedBytes = recoveredPubKey.toRawBytes(true); - return '0x' + Array.from(compressedBytes, b => b.toString(16).padStart(2, '0')).join(''); - } catch (error) { - console.error('signature verification failed:', error); - return null; - } -} - -/** - * @deprecated Use verifyEnvEncryptPublicKey with timestamp parameter instead. - * This function is kept for backward compatibility but does not protect against replay attacks. - */ -export async function verifyEnvEncryptPublicKeyLegacy( - publicKey: Uint8Array, - signature: Uint8Array, - appId: string -): Promise { - if (signature.length !== 65) { - return null; - } - - // Create the message to verify - const prefix = new TextEncoder().encode("dstack-env-encrypt-pubkey"); - - // Remove 0x prefix if present - let cleanAppId = appId; - if (appId.startsWith("0x")) { - cleanAppId = appId.slice(2); - } - - const appIdBytes = hexToBytes(cleanAppId); - const separator = new TextEncoder().encode(":"); - - // Construct message: prefix + ":" + app_id + public_key - const message = new Uint8Array(prefix.length + separator.length + appIdBytes.length + publicKey.length); - message.set(prefix, 0); - message.set(separator, prefix.length); - message.set(appIdBytes, prefix.length + separator.length); - message.set(publicKey, prefix.length + separator.length + appIdBytes.length); - - // Hash the message with Keccak-256 - const messageHash = keccak_256(message); - - try { - // Extract r, s, v from signature (last byte is recovery id) - const r = signature.slice(0, 32); - const s = signature.slice(32, 64); - const recovery = signature[64]; - - // Create signature in DER format for secp256k1 - const sigBytes = new Uint8Array(64); - sigBytes.set(r, 0); - sigBytes.set(s, 32); - - // Recover the public key from the signature - const recoveredPubKey = secp256k1.Signature.fromCompact(sigBytes) - .addRecoveryBit(recovery) - .recoverPublicKey(messageHash); - - // Return compressed public key with 0x prefix - const compressedBytes = recoveredPubKey.toRawBytes(true); - return '0x' + Array.from(compressedBytes, b => b.toString(16).padStart(2, '0')).join(''); - } catch (error) { - console.error('signature verification failed:', error); - return null; - } -} diff --git a/sdk/js/src/verify-env-encrypt-public-key.ts b/sdk/js/src/verify-env-encrypt-public-key.ts index 556fb625..7284af7e 100644 --- a/sdk/js/src/verify-env-encrypt-public-key.ts +++ b/sdk/js/src/verify-env-encrypt-public-key.ts @@ -2,170 +2,122 @@ // // SPDX-License-Identifier: Apache-2.0 -import { keccak_256 } from "@noble/hashes/sha3"; -import { secp256k1 } from "@noble/curves/secp256k1"; +import { keccak_256 } from "@noble/hashes/sha3" +import { secp256k1 } from "@noble/curves/secp256k1" -/** Default maximum age for timestamp verification (5 minutes) */ -const DEFAULT_MAX_AGE_SECONDS = 300; +const DEFAULT_MAX_AGE_SECONDS = 300 -/** - * Options for verifying env encrypt public key - */ export interface VerifyOptions { - /** - * Maximum age of the response in seconds. - * If the timestamp is older than this, verification fails. - * Default: 300 (5 minutes) - */ - maxAgeSeconds?: number; + /** Maximum age of the signed response in seconds. Default: 300 (5 minutes). */ + maxAgeSeconds?: number } -/** - * Verify the signature of a public key with timestamp validation. - * - * @param publicKey - The public key bytes to verify (32 bytes) - * @param signature - The signature bytes (65 bytes) - * @param appId - The application ID - * @param timestamp - Unix timestamp in seconds when the response was generated - * @param options - Optional verification options - * @returns The compressed public key if valid, null otherwise - * - * @example - * ```typescript - * const publicKey = new Uint8Array(Buffer.from('e33a1832c6562067ff8f844a61e51ad051f1180b66ec2551fb0251735f3ee90a', 'hex')); - * const signature = new Uint8Array(Buffer.from('...', 'hex')); - * const appId = '00'.repeat(20); - * const timestamp = 1700000000n; - * const compressedPubkey = verifyEnvEncryptPublicKey(publicKey, signature, appId, timestamp); - * ``` - */ -export function verifyEnvEncryptPublicKey( - publicKey: Uint8Array, - signature: Uint8Array, - appId: string, - timestamp: bigint | number, - options?: VerifyOptions -): string | null { - if (signature.length !== 65) { - return null; +function bigintToBeBytes(value: bigint, length: number): Uint8Array { + const bytes = new Uint8Array(length) + for (let i = length - 1; i >= 0; i--) { + bytes[i] = Number(value & 0xffn) + value >>= 8n } + return bytes +} - // Convert timestamp to bigint for consistent handling - const ts = typeof timestamp === 'bigint' ? timestamp : BigInt(timestamp); - - // Validate timestamp freshness - const maxAge = options?.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS; - const now = BigInt(Math.floor(Date.now() / 1000)); - const age = now - ts; - - if (age < 0n) { - // Timestamp is in the future - allow small clock skew (60 seconds) - if (age < -60n) { - console.error('timestamp is too far in the future'); - return null; - } - } else if (age > BigInt(maxAge)) { - console.error(`timestamp is too old: ${age}s > ${maxAge}s`); - return null; +function hexToBytes(hex: string): Uint8Array { + if (hex.startsWith("0x")) hex = hex.slice(2) + const bytes = new Uint8Array(hex.length / 2) + for (let i = 0; i < hex.length; i += 2) { + bytes[i / 2] = parseInt(hex.substr(i, 2), 16) } + return bytes +} - // Create the message to verify - const prefix = Buffer.from("dstack-env-encrypt-pubkey", "utf8"); +function bytesToHex(bytes: Uint8Array): string { + return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("") +} - // Remove 0x prefix if present - let cleanAppId = appId; - if (appId.startsWith("0x")) { - cleanAppId = appId.slice(2); +function concat(...parts: Uint8Array[]): Uint8Array { + const total = parts.reduce((n, p) => n + p.length, 0) + const out = new Uint8Array(total) + let offset = 0 + for (const part of parts) { + out.set(part, offset) + offset += part.length } + return out +} - const appIdBytes = Buffer.from(cleanAppId, "hex"); - const separator = Buffer.from(":", "utf8"); - - // Convert timestamp to big-endian bytes (8 bytes) - const timestampBytes = Buffer.alloc(8); - timestampBytes.writeBigUInt64BE(ts); - - // Construct message: prefix + ":" + app_id + timestamp_be_bytes + public_key - const message = Buffer.concat([prefix, separator, appIdBytes, timestampBytes, Buffer.from(publicKey)]); - - // Hash the message with Keccak-256 - const messageHash = keccak_256(message); - +function recoverSigner( + messageHash: Uint8Array, + signature: Uint8Array, +): string | null { try { - // Extract r, s, v from signature (last byte is recovery id) - const r = signature.slice(0, 32); - const s = signature.slice(32, 64); - const recovery = signature[64]; - - // Create signature in DER format for secp256k1 - const sigBytes = new Uint8Array(64); - sigBytes.set(r, 0); - sigBytes.set(s, 32); - - // Recover the public key from the signature + const sigBytes = signature.slice(0, 64) + const recovery = signature[64] const recoveredPubKey = secp256k1.Signature.fromCompact(sigBytes) .addRecoveryBit(recovery) - .recoverPublicKey(messageHash); - - // Return compressed public key with 0x prefix - return '0x' + Buffer.from(recoveredPubKey.toRawBytes(true)).toString('hex'); + .recoverPublicKey(messageHash) + return "0x" + bytesToHex(recoveredPubKey.toRawBytes(true)) } catch (error) { - console.error('signature verification failed:', error); - return null; + console.error("signature verification failed:", error) + return null } } /** - * @deprecated Use verifyEnvEncryptPublicKey with timestamp parameter instead. - * This function is kept for backward compatibility but does not protect against replay attacks. + * Verify a timestamp-protected KMS env-encrypt public key signature. + * + * Returns the signer's compressed secp256k1 public key on success, or `null` + * on failure (bad length, expired timestamp, invalid signature). */ -export function verifyEnvEncryptPublicKeyLegacy( +export function verifyEnvEncryptPublicKey( publicKey: Uint8Array, signature: Uint8Array, - appId: string + appId: string, + timestamp: bigint | number, + options?: VerifyOptions, ): string | null { - if (signature.length !== 65) { - return null; + if (signature.length !== 65) return null + + const ts = typeof timestamp === "bigint" ? timestamp : BigInt(timestamp) + const maxAge = options?.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS + const now = BigInt(Math.floor(Date.now() / 1000)) + const age = now - ts + if (age < -60n) { + console.error("timestamp is too far in the future") + return null } - - // Create the message to verify - const prefix = Buffer.from("dstack-env-encrypt-pubkey", "utf8"); - - // Remove 0x prefix if present - let cleanAppId = appId; - if (appId.startsWith("0x")) { - cleanAppId = appId.slice(2); + if (age > BigInt(maxAge)) { + console.error(`timestamp is too old: ${age}s > ${maxAge}s`) + return null } - const appIdBytes = Buffer.from(cleanAppId, "hex"); - const separator = Buffer.from(":", "utf8"); - - // Construct message: prefix + ":" + app_id + public_key - const message = Buffer.concat([prefix, separator, appIdBytes, Buffer.from(publicKey)]); - - // Hash the message with Keccak-256 - const messageHash = keccak_256(message); - - try { - // Extract r, s, v from signature (last byte is recovery id) - const r = signature.slice(0, 32); - const s = signature.slice(32, 64); - const recovery = signature[64]; - - // Create signature in DER format for secp256k1 - const sigBytes = new Uint8Array(64); - sigBytes.set(r, 0); - sigBytes.set(s, 32); + const prefix = new TextEncoder().encode("dstack-env-encrypt-pubkey") + const separator = new TextEncoder().encode(":") + const appIdBytes = hexToBytes(appId) + const timestampBytes = bigintToBeBytes(ts, 8) + const message = concat( + prefix, + separator, + appIdBytes, + timestampBytes, + publicKey, + ) + return recoverSigner(keccak_256(message), signature) +} - // Recover the public key from the signature - const recoveredPubKey = secp256k1.Signature.fromCompact(sigBytes) - .addRecoveryBit(recovery) - .recoverPublicKey(messageHash); +/** + * @deprecated Use {@link verifyEnvEncryptPublicKey} with timestamp. Legacy + * signatures do not protect against replay attacks. + */ +export function verifyEnvEncryptPublicKeyLegacy( + publicKey: Uint8Array, + signature: Uint8Array, + appId: string, +): string | null { + if (signature.length !== 65) return null - // Return compressed public key with 0x prefix - return '0x' + Buffer.from(recoveredPubKey.toRawBytes(true)).toString('hex'); - } catch (error) { - console.error('signature verification failed:', error); - return null; - } + const prefix = new TextEncoder().encode("dstack-env-encrypt-pubkey") + const separator = new TextEncoder().encode(":") + const appIdBytes = hexToBytes(appId) + const message = concat(prefix, separator, appIdBytes, publicKey) + return recoverSigner(keccak_256(message), signature) } diff --git a/sdk/js/tsconfig.browser.json b/sdk/js/tsconfig.browser.json deleted file mode 100644 index cd759b2d..00000000 --- a/sdk/js/tsconfig.browser.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "target": "es2020", - "module": "es2015", - "lib": ["es2018", "dom"], - "outDir": "./dist/browser", - "declaration": true, - "declarationMap": true, - "sourceMap": true - }, - "include": [ - "src/encrypt-env-vars.browser.ts", - "src/get-compose-hash.browser.ts", - "src/verify-env-encrypt-public-key.browser.ts" - ], - "exclude": ["node_modules", "**/*.test.ts"] -} diff --git a/sdk/js/tsconfig.node.json b/sdk/js/tsconfig.node.json deleted file mode 100644 index a8004eeb..00000000 --- a/sdk/js/tsconfig.node.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "target": "es2020", - "module": "commonjs", - "lib": ["es2018"], - "outDir": "./dist/node", - "declaration": true, - "declarationMap": true, - "sourceMap": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "**/*.test.ts", "src/*.browser.ts"] -} From 97d0374e794b3f386368ba101784508f842f586b Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 20 May 2026 17:40:49 +0800 Subject: [PATCH 12/13] build(sdk/js): switch to tsup for dual CJS+ESM publish, drop sourcemaps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace the two tsc invocations (node + browser) with a single tsup build that emits both formats from one entry list. - format: cjs (.js) and esm (.mjs); types as .d.ts and .d.mts - splitting/sourcemap off; treeshake on - exports use explicit \"types\"/\"import\"/\"require\" conditions per subpath so TypeScript picks .d.mts for ESM consumers and .d.ts for CommonJS, and runtime picks .mjs vs .js accordingly - drop tsconfig.node.json and tsconfig.browser.json — tsup carries its own config, the root tsconfig.json is still used for typecheck - drop .js.map / .d.ts.map outputs; the previous maps pointed at src/*.ts paths that the package did not ship, so they were dead weight published package shape vs current 0.5.8-beta.1 on npm: files : 60 → 27 unpacked: 230 KB → 107 KB (-54%) tarball : 57 KB → 23 KB (-60%) now also ships ESM (.mjs) — bundlers get tree-shaking, modern Node can \`import\` natively; legacy \`require()\` still works through the .js files. --- sdk/js/package.json | 98 ++++++++++++++++++------------------------- sdk/js/tsup.config.ts | 19 +++++++++ 2 files changed, 59 insertions(+), 58 deletions(-) create mode 100644 sdk/js/tsup.config.ts diff --git a/sdk/js/package.json b/sdk/js/package.json index d59f4329..42406516 100644 --- a/sdk/js/package.json +++ b/sdk/js/package.json @@ -2,74 +2,57 @@ "name": "@phala/dstack-sdk", "version": "0.5.8-beta.1", "description": "dstack SDK", - "main": "dist/node/index.js", - "types": "dist/node/index.d.ts", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", "exports": { ".": { - "import": "./dist/node/index.js", - "require": "./dist/node/index.js", - "types": "./dist/node/index.d.ts" + "types": { + "import": "./dist/index.d.mts", + "require": "./dist/index.d.ts" + }, + "import": "./dist/index.mjs", + "require": "./dist/index.js" }, "./viem": { - "import": "./dist/node/viem.js", - "require": "./dist/node/viem.js", - "types": "./dist/node/viem.d.ts" - }, - "./encrypt-env-vars": { - "node": { - "import": "./dist/node/encrypt-env-vars.js", - "require": "./dist/node/encrypt-env-vars.js", - "types": "./dist/node/encrypt-env-vars.d.ts" + "types": { + "import": "./dist/viem.d.mts", + "require": "./dist/viem.d.ts" }, - "browser": { - "import": "./dist/browser/encrypt-env-vars.browser.js", - "require": "./dist/browser/encrypt-env-vars.browser.js", - "types": "./dist/browser/encrypt-env-vars.browser.d.ts" - }, - "default": { - "import": "./dist/browser/encrypt-env-vars.browser.js", - "require": "./dist/browser/encrypt-env-vars.browser.js", - "types": "./dist/browser/encrypt-env-vars.browser.d.ts" - } + "import": "./dist/viem.mjs", + "require": "./dist/viem.js" }, "./solana": { - "import": "./dist/node/solana.js", - "require": "./dist/node/solana.js", - "types": "./dist/node/solana.d.ts" + "types": { + "import": "./dist/solana.d.mts", + "require": "./dist/solana.d.ts" + }, + "import": "./dist/solana.mjs", + "require": "./dist/solana.js" }, - "./get-compose-hash": { - "node": { - "import": "./dist/node/get-compose-hash.js", - "require": "./dist/node/get-compose-hash.js", - "types": "./dist/node/get-compose-hash.d.ts" + "./encrypt-env-vars": { + "types": { + "import": "./dist/encrypt-env-vars.d.mts", + "require": "./dist/encrypt-env-vars.d.ts" }, - "browser": { - "import": "./dist/browser/get-compose-hash.browser.js", - "require": "./dist/browser/get-compose-hash.browser.js", - "types": "./dist/browser/get-compose-hash.browser.d.ts" + "import": "./dist/encrypt-env-vars.mjs", + "require": "./dist/encrypt-env-vars.js" + }, + "./get-compose-hash": { + "types": { + "import": "./dist/get-compose-hash.d.mts", + "require": "./dist/get-compose-hash.d.ts" }, - "default": { - "import": "./dist/browser/get-compose-hash.browser.js", - "require": "./dist/browser/get-compose-hash.browser.js", - "types": "./dist/browser/get-compose-hash.browser.d.ts" - } + "import": "./dist/get-compose-hash.mjs", + "require": "./dist/get-compose-hash.js" }, "./verify-env-encrypt-public-key": { - "node": { - "import": "./dist/node/verify-env-encrypt-public-key.js", - "require": "./dist/node/verify-env-encrypt-public-key.js", - "types": "./dist/node/verify-env-encrypt-public-key.d.ts" - }, - "browser": { - "import": "./dist/browser/verify-env-encrypt-public-key.browser.js", - "require": "./dist/browser/verify-env-encrypt-public-key.browser.js", - "types": "./dist/browser/verify-env-encrypt-public-key.browser.d.ts" + "types": { + "import": "./dist/verify-env-encrypt-public-key.d.mts", + "require": "./dist/verify-env-encrypt-public-key.d.ts" }, - "default": { - "import": "./dist/browser/verify-env-encrypt-public-key.browser.js", - "require": "./dist/browser/verify-env-encrypt-public-key.browser.js", - "types": "./dist/browser/verify-env-encrypt-public-key.browser.d.ts" - } + "import": "./dist/verify-env-encrypt-public-key.mjs", + "require": "./dist/verify-env-encrypt-public-key.js" } }, "engines": { @@ -79,9 +62,7 @@ "dist" ], "scripts": { - "build": "npm run build:node && npm run build:browser", - "build:node": "tsc -p tsconfig.node.json", - "build:browser": "tsc -p tsconfig.browser.json", + "build": "tsup", "clean": "rm -rf dist", "test": "vitest", "test:ci": "vitest --run", @@ -104,6 +85,7 @@ "@noble/hashes": "^1.6.1", "@solana/web3.js": "^1.98.4", "@types/node": "latest", + "tsup": "^8.5.1", "typescript": "^5.7.0", "viem": "^2.43.3", "vitest": "^3.2.4" diff --git a/sdk/js/tsup.config.ts b/sdk/js/tsup.config.ts new file mode 100644 index 00000000..0aafa691 --- /dev/null +++ b/sdk/js/tsup.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from "tsup" + +export default defineConfig({ + entry: [ + "src/index.ts", + "src/viem.ts", + "src/solana.ts", + "src/encrypt-env-vars.ts", + "src/get-compose-hash.ts", + "src/verify-env-encrypt-public-key.ts", + ], + format: ["cjs", "esm"], + dts: true, + clean: true, + sourcemap: false, + splitting: false, + treeshake: true, + target: "es2020", +}) From d715af2d180b08e3fd1d84640d056860ec34c590 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 20 May 2026 18:48:54 +0800 Subject: [PATCH 13/13] chore(sdk/js): bump to 0.5.8-beta.2 for slim dual-format build --- sdk/js/bun.lock | 63 +++++++++++++++++++++++++++++++++++++++++++++ sdk/js/package.json | 2 +- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/sdk/js/bun.lock b/sdk/js/bun.lock index 1388c0b6..8a9836ad 100644 --- a/sdk/js/bun.lock +++ b/sdk/js/bun.lock @@ -9,6 +9,7 @@ "@noble/hashes": "^1.6.1", "@solana/web3.js": "^1.98.4", "@types/node": "latest", + "tsup": "^8.5.1", "typescript": "^5.7.0", "viem": "^2.43.3", "vitest": "^3.2.4", @@ -83,8 +84,14 @@ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], @@ -187,8 +194,12 @@ "abitype": ["abitype@1.2.3", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg=="], + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], + "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], "base-x": ["base-x@3.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA=="], @@ -205,6 +216,8 @@ "bufferutil": ["bufferutil@4.1.0", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw=="], + "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="], + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], @@ -213,8 +226,14 @@ "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + "commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + + "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], @@ -241,6 +260,8 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "fix-dts-default-cjs-exports": ["fix-dts-default-cjs-exports@1.0.1", "", { "dependencies": { "magic-string": "^0.30.17", "mlly": "^1.7.4", "rollup": "^4.34.8" } }, "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], @@ -253,22 +274,36 @@ "jayson": ["jayson@4.3.0", "", { "dependencies": { "@types/connect": "^3.4.33", "@types/node": "^12.12.54", "@types/ws": "^7.4.4", "commander": "^2.20.3", "delay": "^5.0.0", "es6-promisify": "^5.0.0", "eyes": "^0.1.8", "isomorphic-ws": "^4.0.1", "json-stringify-safe": "^5.0.1", "stream-json": "^1.9.1", "uuid": "^8.3.2", "ws": "^7.5.10" }, "bin": { "jayson": "bin/jayson.js" } }, "sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ=="], + "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], + "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="], + "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + "mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], + "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + "ox": ["ox@0.14.22", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-nb5msL8qWbPglhIfZbGJAfw3cqiJjFMiWmACt7kgyWtLib12tcctbHufMT9Hb0Lr6Pt4k9I3dbpueTpbhvbqvA=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -279,8 +314,18 @@ "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], + "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="], + + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + "rollup": ["rollup@4.60.4", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.4", "@rollup/rollup-android-arm64": "4.60.4", "@rollup/rollup-darwin-arm64": "4.60.4", "@rollup/rollup-darwin-x64": "4.60.4", "@rollup/rollup-freebsd-arm64": "4.60.4", "@rollup/rollup-freebsd-x64": "4.60.4", "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", "@rollup/rollup-linux-arm-musleabihf": "4.60.4", "@rollup/rollup-linux-arm64-gnu": "4.60.4", "@rollup/rollup-linux-arm64-musl": "4.60.4", "@rollup/rollup-linux-loong64-gnu": "4.60.4", "@rollup/rollup-linux-loong64-musl": "4.60.4", "@rollup/rollup-linux-ppc64-gnu": "4.60.4", "@rollup/rollup-linux-ppc64-musl": "4.60.4", "@rollup/rollup-linux-riscv64-gnu": "4.60.4", "@rollup/rollup-linux-riscv64-musl": "4.60.4", "@rollup/rollup-linux-s390x-gnu": "4.60.4", "@rollup/rollup-linux-x64-gnu": "4.60.4", "@rollup/rollup-linux-x64-musl": "4.60.4", "@rollup/rollup-openbsd-x64": "4.60.4", "@rollup/rollup-openharmony-arm64": "4.60.4", "@rollup/rollup-win32-arm64-msvc": "4.60.4", "@rollup/rollup-win32-ia32-msvc": "4.60.4", "@rollup/rollup-win32-x64-gnu": "4.60.4", "@rollup/rollup-win32-x64-msvc": "4.60.4", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g=="], "rpc-websockets": ["rpc-websockets@9.3.10", "", { "dependencies": { "@swc/helpers": "^0.5.11", "@types/ws": "^8.2.2", "buffer": "^6.0.3", "eventemitter3": "^5.0.1", "ws": "^8.5.0" }, "optionalDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^6.0.0" } }, "sha512-QT5PQ6LiWhA5RCS93oWwgxU4XzQltkYm8C3aTmmKEgj0HolGRo3VbdzELw7CEV35l9T7Amha8Vnr4rCfSjVP+w=="], @@ -289,6 +334,8 @@ "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], @@ -301,10 +348,16 @@ "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], + "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], + "superstruct": ["superstruct@2.0.2", "", {}, "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A=="], "text-encoding-utf-8": ["text-encoding-utf-8@1.0.2", "", {}, "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg=="], + "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], + + "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], @@ -319,10 +372,18 @@ "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], + + "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tsup": ["tsup@8.5.1", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.27.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "^0.7.6", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], + "undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="], "utf-8-validate": ["utf-8-validate@6.0.6", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA=="], @@ -355,6 +416,8 @@ "rpc-websockets/@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + "viem/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], } } diff --git a/sdk/js/package.json b/sdk/js/package.json index 42406516..ff95e5b4 100644 --- a/sdk/js/package.json +++ b/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@phala/dstack-sdk", - "version": "0.5.8-beta.1", + "version": "0.5.8-beta.2", "description": "dstack SDK", "main": "./dist/index.js", "module": "./dist/index.mjs",