@ton/sandbox 0.39.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/blockchain/Blockchain.d.ts +15 -1
  3. package/dist/blockchain/Blockchain.js +45 -8
  4. package/dist/blockchain/MessageQueueManager.d.ts +2 -2
  5. package/dist/blockchain/MessageQueueManager.js +6 -3
  6. package/dist/blockchain/SmartContract.d.ts +3 -2
  7. package/dist/blockchain/SmartContract.js +5 -4
  8. package/dist/executor/emulator-emscripten.debugger.bpatch.gzip.js +1 -1
  9. package/dist/executor/emulator-emscripten.js +2 -20
  10. package/dist/executor/emulator-emscripten.wasm.js +1 -1
  11. package/dist/jest/uiSetup.d.ts +1 -0
  12. package/dist/jest/uiSetup.js +38 -0
  13. package/dist/ui/UIManager.d.ts +18 -0
  14. package/dist/ui/UIManager.js +31 -0
  15. package/dist/ui/connection/UIConnector.d.ts +3 -0
  16. package/dist/ui/connection/UIConnector.js +2 -0
  17. package/dist/ui/connection/websocket/ManagedWebSocketConnector.d.ts +10 -0
  18. package/dist/ui/connection/websocket/ManagedWebSocketConnector.js +38 -0
  19. package/dist/ui/connection/websocket/OneTimeWebSocketConnector.d.ts +7 -0
  20. package/dist/ui/connection/websocket/OneTimeWebSocketConnector.js +31 -0
  21. package/dist/ui/connection/websocket/constants.d.ts +3 -0
  22. package/dist/ui/connection/websocket/constants.js +6 -0
  23. package/dist/ui/connection/websocket/types.d.ts +4 -0
  24. package/dist/ui/connection/websocket/types.js +2 -0
  25. package/dist/ui/protocol.d.ts +48 -0
  26. package/dist/ui/protocol.js +48 -0
  27. package/dist/utils/environment.d.ts +7 -0
  28. package/dist/utils/environment.js +15 -0
  29. package/dist/utils/noop.d.ts +1 -0
  30. package/dist/utils/noop.js +4 -0
  31. package/dist/utils/require.d.ts +1 -1
  32. package/dist/utils/require.js +5 -8
  33. package/package.json +3 -2
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const crypto_1 = require("crypto");
4
+ const Blockchain_1 = require("../blockchain/Blockchain");
5
+ const ManagedWebSocketConnector_1 = require("../ui/connection/websocket/ManagedWebSocketConnector");
6
+ let websocketConnector;
7
+ beforeAll(() => {
8
+ const originalCreate = Blockchain_1.Blockchain.create.bind(Blockchain_1.Blockchain);
9
+ Blockchain_1.Blockchain.create = async (...args) => {
10
+ let [opts, ...otherArgs] = args;
11
+ if (!opts?.uiOptions?.connector) {
12
+ if (!websocketConnector) {
13
+ websocketConnector = new ManagedWebSocketConnector_1.ManagedWebSocketConnector(opts?.uiOptions);
14
+ // eslint-disable-next-line no-console
15
+ console.log('Connecting to websocket connector...');
16
+ await websocketConnector.connect();
17
+ }
18
+ opts = {
19
+ ...opts,
20
+ uiOptions: {
21
+ ...opts?.uiOptions,
22
+ enabled: true,
23
+ connector: websocketConnector,
24
+ },
25
+ };
26
+ }
27
+ return await originalCreate(opts, ...otherArgs);
28
+ };
29
+ });
30
+ beforeEach(() => {
31
+ expect.setState({ testId: (0, crypto_1.randomUUID)() });
32
+ });
33
+ afterEach(() => {
34
+ expect.setState({ testId: undefined });
35
+ });
36
+ afterAll(() => {
37
+ websocketConnector?.disconnect();
38
+ });
@@ -0,0 +1,18 @@
1
+ import { Address } from '@ton/core';
2
+ import { BlockchainTransaction } from '../blockchain/Blockchain';
3
+ import { ContractMeta } from '../meta/ContractsMeta';
4
+ import { SmartContract } from '../blockchain/SmartContract';
5
+ import { IUIConnector } from './connection/UIConnector';
6
+ export interface IUIManager {
7
+ publishTransactions(transactions: BlockchainTransaction[]): void;
8
+ }
9
+ export declare class UIManager implements IUIManager {
10
+ private readonly connector;
11
+ private readonly blockchain;
12
+ constructor(connector: IUIConnector, blockchain: {
13
+ getMeta(address: Address): ContractMeta | undefined;
14
+ knownContracts(): SmartContract[];
15
+ });
16
+ publishTransactions(txs: BlockchainTransaction[]): void;
17
+ private getTestInfo;
18
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UIManager = void 0;
4
+ const protocol_1 = require("./protocol");
5
+ class UIManager {
6
+ connector;
7
+ blockchain;
8
+ constructor(connector, blockchain) {
9
+ this.connector = connector;
10
+ this.blockchain = blockchain;
11
+ }
12
+ publishTransactions(txs) {
13
+ let testInfo = this.getTestInfo();
14
+ const transactions = (0, protocol_1.serializeTransactions)(txs);
15
+ const knownContracts = this.blockchain.knownContracts();
16
+ const contracts = (0, protocol_1.serializeContracts)(knownContracts.map((contract) => ({ contract, meta: this.blockchain.getMeta(contract.address) })));
17
+ this.connector.send(JSON.stringify({ type: 'test-data', testInfo, transactions, contracts }));
18
+ }
19
+ getTestInfo() {
20
+ if (expect === undefined) {
21
+ return;
22
+ }
23
+ const expectState = expect.getState();
24
+ return {
25
+ id: expectState.testId,
26
+ name: expectState.currentTestName,
27
+ path: expectState.testPath,
28
+ };
29
+ }
30
+ }
31
+ exports.UIManager = UIManager;
@@ -0,0 +1,3 @@
1
+ export interface IUIConnector {
2
+ send(data: string): void;
3
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,10 @@
1
+ import { WebSocketConnectionOptions } from './types';
2
+ import { IUIConnector } from '../UIConnector';
3
+ export declare class ManagedWebSocketConnector implements IUIConnector {
4
+ private readonly websocketAddress;
5
+ ws: WebSocket | undefined;
6
+ constructor({ wsPort, wsHost }?: WebSocketConnectionOptions);
7
+ connect(): Promise<void>;
8
+ disconnect(): void;
9
+ send(data: string): void;
10
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ManagedWebSocketConnector = void 0;
4
+ const environment_1 = require("../../../utils/environment");
5
+ const constants_1 = require("./constants");
6
+ class ManagedWebSocketConnector {
7
+ websocketAddress;
8
+ ws;
9
+ constructor({ wsPort = constants_1.DEFAULT_PORT, wsHost = constants_1.DEFAULT_HOST } = {}) {
10
+ this.websocketAddress = (0, environment_1.getOptionalEnv)('SANDBOX_WEBSOCKET_ADDR') ?? `ws://${wsHost}:${wsPort}`;
11
+ }
12
+ async connect() {
13
+ try {
14
+ this.ws = await new Promise((resolve, reject) => {
15
+ const ws = new WebSocket(this.websocketAddress);
16
+ ws.addEventListener('open', () => resolve(ws), { once: true });
17
+ ws.addEventListener('error', (err) => {
18
+ ws.close();
19
+ reject(err);
20
+ }, { once: true });
21
+ });
22
+ }
23
+ catch (err) {
24
+ // eslint-disable-next-line no-console
25
+ console.warn(constants_1.CONNECT_ERROR_MESSAGE, err);
26
+ }
27
+ }
28
+ disconnect() {
29
+ this.ws?.close();
30
+ this.ws = undefined;
31
+ }
32
+ send(data) {
33
+ if (this?.ws?.readyState === WebSocket.OPEN) {
34
+ this.ws.send(data);
35
+ }
36
+ }
37
+ }
38
+ exports.ManagedWebSocketConnector = ManagedWebSocketConnector;
@@ -0,0 +1,7 @@
1
+ import { WebSocketConnectionOptions } from './types';
2
+ import { IUIConnector } from '../UIConnector';
3
+ export declare class OneTimeWebSocketConnector implements IUIConnector {
4
+ private readonly websocketAddress;
5
+ constructor({ wsPort, wsHost }: WebSocketConnectionOptions);
6
+ send(data: string): void;
7
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OneTimeWebSocketConnector = void 0;
4
+ const environment_1 = require("../../../utils/environment");
5
+ const constants_1 = require("./constants");
6
+ class OneTimeWebSocketConnector {
7
+ websocketAddress;
8
+ constructor({ wsPort = constants_1.DEFAULT_PORT, wsHost = constants_1.DEFAULT_HOST }) {
9
+ this.websocketAddress = (0, environment_1.getOptionalEnv)('SANDBOX_WEBSOCKET_ADDR') ?? `ws://${wsHost}:${wsPort}`;
10
+ }
11
+ send(data) {
12
+ // This solution, which requires a reconnection for each send, may seem inefficient.
13
+ // However, when Jest is not used, it’s unclear when the connection should be closed.
14
+ // Until the connection is closed, the Node process will not terminate, and Jest will issue
15
+ // a warning, while the test will continue to wait for the connection to close.
16
+ //
17
+ // This solution avoids that problem, as the connection is closed immediately after sending.
18
+ // Meanwhile, the reconnection time is short enough to be unnoticeable during tests.
19
+ const ws = new WebSocket(this.websocketAddress);
20
+ ws.addEventListener('open', () => {
21
+ ws.send(data);
22
+ ws.close();
23
+ }, { once: true });
24
+ ws.addEventListener('error', (err) => {
25
+ // eslint-disable-next-line no-console
26
+ console.warn(constants_1.CONNECT_ERROR_MESSAGE, err);
27
+ ws.close();
28
+ }, { once: true });
29
+ }
30
+ }
31
+ exports.OneTimeWebSocketConnector = OneTimeWebSocketConnector;
@@ -0,0 +1,3 @@
1
+ export declare const DEFAULT_PORT = 7743;
2
+ export declare const DEFAULT_HOST = "localhost";
3
+ export declare const CONNECT_ERROR_MESSAGE = "Unable to connect to websocket server. Make sure the port and host match the sandbox server or VS Code settings. You can set the WebSocket address globally with `SANDBOX_WEBSOCKET_ADDR=ws://localhost:7743` or via `Blockchain.create({ uiOptions: { enabled: true, wsHost: \"localhost\", wsPort: 7743 } })`.";
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CONNECT_ERROR_MESSAGE = exports.DEFAULT_HOST = exports.DEFAULT_PORT = void 0;
4
+ exports.DEFAULT_PORT = 7743;
5
+ exports.DEFAULT_HOST = 'localhost';
6
+ exports.CONNECT_ERROR_MESSAGE = 'Unable to connect to websocket server. Make sure the port and host match the sandbox server or VS Code settings. You can set the WebSocket address globally with `SANDBOX_WEBSOCKET_ADDR=ws://localhost:7743` or via `Blockchain.create({ uiOptions: { enabled: true, wsHost: "localhost", wsPort: 7743 } })`.';
@@ -0,0 +1,4 @@
1
+ export type WebSocketConnectionOptions = {
2
+ wsPort?: number;
3
+ wsHost?: string;
4
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,48 @@
1
+ import { BlockchainTransaction } from '../blockchain/Blockchain';
2
+ import { ContractMeta } from '../meta/ContractsMeta';
3
+ import { SmartContract } from '../blockchain/SmartContract';
4
+ declare const hexBrand: unique symbol;
5
+ export type HexString = string & {
6
+ readonly [hexBrand]: true;
7
+ };
8
+ export type MessageTestData = {
9
+ readonly type: 'test-data';
10
+ readonly testInfo: TestInfo | undefined;
11
+ readonly transactions: RawTransactionsInfo;
12
+ readonly contracts: readonly RawContractData[];
13
+ };
14
+ export type Message = MessageTestData;
15
+ export type RawTransactionsInfo = {
16
+ readonly transactions: readonly RawTransactionInfo[];
17
+ };
18
+ export type RawTransactionInfo = {
19
+ readonly transaction: string;
20
+ readonly blockchainLogs: string;
21
+ readonly vmLogs: string;
22
+ readonly debugLogs: string;
23
+ readonly code: string | undefined;
24
+ readonly sourceMap: object | undefined;
25
+ readonly contractName: string | undefined;
26
+ readonly parentId: string | undefined;
27
+ readonly childrenIds: string[];
28
+ readonly oldStorage: HexString | undefined;
29
+ readonly newStorage: HexString | undefined;
30
+ readonly callStack: string | undefined;
31
+ };
32
+ export declare function serializeTransactions(transactions: BlockchainTransaction[]): RawTransactionsInfo;
33
+ export type RawContractData = {
34
+ readonly address: string;
35
+ readonly meta: ContractMeta | undefined;
36
+ readonly stateInit: HexString | undefined;
37
+ readonly account: HexString | undefined;
38
+ };
39
+ export declare function serializeContracts(contracts: {
40
+ contract: SmartContract;
41
+ meta?: ContractMeta;
42
+ }[]): RawContractData[];
43
+ export type TestInfo = {
44
+ readonly id?: string;
45
+ readonly name?: string;
46
+ readonly path?: string;
47
+ };
48
+ export {};
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serializeTransactions = serializeTransactions;
4
+ exports.serializeContracts = serializeContracts;
5
+ const core_1 = require("@ton/core");
6
+ function serializeTransactions(transactions) {
7
+ return {
8
+ transactions: transactions.map((t) => {
9
+ const tx = (0, core_1.beginCell)()
10
+ .store((0, core_1.storeTransaction)(t))
11
+ .endCell()
12
+ .toBoc()
13
+ .toString('hex');
14
+ return {
15
+ transaction: tx,
16
+ blockchainLogs: t.blockchainLogs,
17
+ vmLogs: t.vmLogs,
18
+ debugLogs: t.debugLogs,
19
+ code: undefined,
20
+ sourceMap: undefined,
21
+ contractName: undefined,
22
+ parentId: t.parent?.lt.toString(),
23
+ childrenIds: t.children?.map((c) => c?.lt?.toString()),
24
+ oldStorage: t.oldStorage?.toBoc().toString('hex'),
25
+ newStorage: t.newStorage?.toBoc().toString('hex'),
26
+ callStack: t.callStack,
27
+ };
28
+ }),
29
+ };
30
+ }
31
+ function serializeContracts(contracts) {
32
+ return contracts.map(({ contract, meta }) => {
33
+ const state = contract.accountState;
34
+ const stateInit = (0, core_1.beginCell)();
35
+ if (state?.type === 'active') {
36
+ stateInit.store((0, core_1.storeStateInit)(state.state));
37
+ }
38
+ const stateInitCell = stateInit.asCell();
39
+ const account = contract.account;
40
+ const accountCell = (0, core_1.beginCell)().store((0, core_1.storeShardAccount)(account)).endCell();
41
+ return {
42
+ address: contract.address.toString(),
43
+ meta,
44
+ stateInit: stateInitCell.bits.length === 0 ? undefined : stateInitCell.toBoc().toString('hex'),
45
+ account: accountCell.toBoc().toString('hex'),
46
+ };
47
+ });
48
+ }
@@ -1 +1,8 @@
1
1
  export declare function isBrowser(): boolean;
2
+ declare const converters: {
3
+ readonly boolean: (value: string | undefined) => boolean | undefined;
4
+ readonly string: (value: string | undefined) => string | undefined;
5
+ };
6
+ type Converters = typeof converters;
7
+ export declare function getOptionalEnv<EnvType extends keyof Converters = 'string'>(envName: string, envType?: EnvType): ReturnType<Converters[EnvType]> | undefined;
8
+ export {};
@@ -1,7 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isBrowser = isBrowser;
4
+ exports.getOptionalEnv = getOptionalEnv;
4
5
  function isBrowser() {
5
6
  // eslint-disable-next-line no-undef
6
7
  return typeof window !== 'undefined' && typeof window.document !== 'undefined';
7
8
  }
9
+ const converters = {
10
+ boolean: (value) => {
11
+ if (!value)
12
+ return;
13
+ return value.toLowerCase() === 'true';
14
+ },
15
+ string: (value) => value,
16
+ };
17
+ function getOptionalEnv(envName, envType) {
18
+ if (!process || !process.env)
19
+ return undefined;
20
+ const converter = envType ? converters[envType] : converters.string;
21
+ return converter(process.env[envName]);
22
+ }
@@ -0,0 +1 @@
1
+ export declare function noop(): void;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noop = noop;
4
+ function noop() { }
@@ -1 +1 @@
1
- export declare function requireOptional(id: string): any | undefined;
1
+ export declare function requireTestUtils(): any | undefined;
@@ -1,16 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.requireOptional = requireOptional;
3
+ exports.requireTestUtils = requireTestUtils;
4
4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
- function requireOptional(id) {
5
+ function requireTestUtils() {
6
6
  try {
7
7
  // eslint-disable-next-line @typescript-eslint/no-require-imports
8
- return require(id);
8
+ return require('@ton/test-utils');
9
9
  }
10
- catch (error) {
11
- if (String(error).includes('Cannot find module')) {
12
- return undefined;
13
- }
14
- throw error;
10
+ catch {
11
+ return undefined;
15
12
  }
16
13
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ton/sandbox",
3
- "version": "0.39.0",
3
+ "version": "0.40.0",
4
4
  "description": "TON transaction emulator",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",
@@ -26,6 +26,7 @@
26
26
  "@types/jest": "^30.0.0",
27
27
  "@types/node": "^24.1.0",
28
28
  "eslint": "^9.28.0",
29
+ "globals": "^16.4.0",
29
30
  "jest": "^30.0.5",
30
31
  "jest-config": "^30.0.5",
31
32
  "jest-environment-node": "^30.0.5",
@@ -64,6 +65,6 @@
64
65
  "chalk": "^4.1.2",
65
66
  "fflate": "^0.8.2",
66
67
  "table": "^6.9.0",
67
- "ton-assembly": "0.1.2"
68
+ "ton-assembly": "0.6.1"
68
69
  }
69
70
  }