@nosana/scenario 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # @nosana/scenario
2
+
3
+ Network-aware scenario test helpers for Nosana. Run the same tests against localnet, devnet, or mainnet — controlled entirely via environment variables.
4
+
5
+ Uses [`@nosana/localnet`](../localnet) for Docker infrastructure and [`@nosana/kit`](../kit) for the Nosana SDK.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npm install --save-dev @nosana/scenario
11
+ ```
12
+
13
+ ### Write Tests
14
+
15
+ ```ts
16
+ import { describe, it, expect } from 'vitest';
17
+ import { getScenarioClient } from '@nosana/scenario';
18
+
19
+ describe('scenario: basic', () => {
20
+ it('works with the Nosana SDK', async () => {
21
+ const client = await getScenarioClient();
22
+ const balance = await client.solana.getBalance();
23
+ expect(balance).toBeGreaterThan(0);
24
+ });
25
+ });
26
+ ```
27
+
28
+ ### Run Against Different Networks
29
+
30
+ No code changes needed — just set environment variables:
31
+
32
+ ```bash
33
+ # Localnet (default) — starts a local Solana validator via Docker
34
+ npm run test:scenario:localnet
35
+
36
+ # Devnet — requires a funded wallet
37
+ NOSANA_NETWORK=devnet NOSANA_WALLET=~/.config/solana/id.json npm run test:scenario
38
+
39
+ # Mainnet
40
+ NOSANA_NETWORK=mainnet NOSANA_WALLET=/path/to/keypair.json npm run test:scenario
41
+ ```
42
+
43
+ ### Environment Variables
44
+
45
+ | Variable | Default | Description |
46
+ |----------|---------|-------------|
47
+ | `NOSANA_NETWORK` | `localnet` | Target network: `localnet`, `devnet`, or `mainnet` |
48
+ | `NOSANA_WALLET` | — | Path to a Solana keypair JSON file (required for devnet/mainnet) |
49
+
50
+ ### Vitest Integration
51
+
52
+ ```ts
53
+ // vitest.scenario.config.ts
54
+ import { defineScenarioVitestConfig } from '@nosana/scenario';
55
+
56
+ export default defineScenarioVitestConfig({
57
+ test: {
58
+ include: ['tests/scenarios/**/*.test.ts'],
59
+ },
60
+ });
61
+ ```
62
+
63
+ ### npm Scripts
64
+
65
+ These scripts are already included in `@nosana/scenario`'s `package.json`:
66
+
67
+ | Script | Description |
68
+ |--------|-------------|
69
+ | `test:scenario` | Run scenario tests with vitest |
70
+ | `test:scenario:localnet` | Start localnet + run scenario tests |
71
+ | `localnet:up` | Start the Docker-based Solana validator |
72
+ | `localnet:down` | Stop the validator and clean up |
73
+
74
+ From the workspace root:
75
+
76
+ ```bash
77
+ # Run everything
78
+ pnpm --filter @nosana/scenario run test:scenario:localnet
79
+
80
+ # Or step by step
81
+ pnpm run localnet:up
82
+ pnpm --filter @nosana/scenario run test:scenario
83
+ pnpm run localnet:down
84
+ ```
85
+
86
+ ## API Reference
87
+
88
+ ### `getScenarioClient(options?): Promise<NosanaClient>`
89
+
90
+ Returns a cached `NosanaClient` for the target network.
91
+
92
+ The network is determined by (in order of precedence):
93
+ 1. `options.network`
94
+ 2. `NOSANA_NETWORK` environment variable
95
+ 3. `'localnet'` (default)
96
+
97
+ The wallet is determined by (in order of precedence):
98
+ 1. `options.wallet`
99
+ 2. `NOSANA_WALLET` environment variable (path to a Solana keypair JSON file)
100
+ 3. Auto-generated keypair (localnet only)
101
+
102
+ | Option | Type | Default | Description |
103
+ |--------|------|---------|-------------|
104
+ | `network` | `'localnet' \| 'devnet' \| 'mainnet'` | `NOSANA_NETWORK` env or `'localnet'` | Target network |
105
+ | `wallet` | `Wallet` | `NOSANA_WALLET` env or auto-generated (localnet) | Wallet signer |
106
+ | `airdropAmount` | `bigint` | `2_000_000_000n` | SOL airdrop amount (localnet only) |
107
+ | `mintAmount` | `bigint` | `1_000_000_000n` | NOS mint amount (localnet only) |
108
+ | `config` | `Partial<NosanaClientConfig>` | — | Override client config |
109
+
110
+ **Localnet** (default): generates a random keypair, airdrops SOL, and mints NOS tokens.
111
+
112
+ **Devnet / Mainnet**: connects with the provided wallet (via option or `NOSANA_WALLET` env var). No airdrop or minting is performed.
113
+
114
+ ### `getLocalnetClient(options?): Promise<NosanaClient>`
115
+
116
+ Returns a cached `NosanaClient` connected to localnet. Equivalent to `getScenarioClient({ network: 'localnet' })`.
117
+
118
+ ### `mintNosTo(client, recipient, amount): Promise<void>`
119
+
120
+ Mint NOS tokens to any address on the localnet.
121
+
122
+ ### `ensureLocalnetMint(client): Promise<{ mintAuthority, mintAddress }>`
123
+
124
+ Ensures the NOS mint exists on localnet. Creates it if it doesn't exist.
125
+
126
+ ### `executeInstructionPlan(client, plan): Promise<void>`
127
+
128
+ Execute a Solana instruction plan using the client's wallet as fee payer.
129
+
130
+ ### `defineScenarioVitestConfig(overrides?): object`
131
+
132
+ Returns a Vitest config object with the scenario setup file pre-configured.
133
+
134
+ ### Re-exports from `@nosana/localnet`
135
+
136
+ - `startLocalnet`, `stopLocalnet`
137
+ - `LOCALNET_RPC_ENDPOINT`, `LOCALNET_WS_ENDPOINT`
138
+
139
+ ### Re-exports from `@nosana/kit`
140
+
141
+ - `NosanaNetwork`, `type NosanaClient`, `type Wallet`, `type Address`
@@ -0,0 +1,8 @@
1
+ export { getScenarioClient, getLocalnetClient, type ScenarioClientOptions, type LocalnetClientOptions, } from './setup.js';
2
+ export { mintNosTo, ensureLocalnetMint, executeInstructionPlan, loadMintKeypairSigner, loadMintAuthoritySigner, } from './utils.js';
3
+ export { scenarioVitestSetup } from './vitest-setup-fn.js';
4
+ export { defineScenarioVitestConfig } from './vitest-config.js';
5
+ export { startLocalnet, stopLocalnet, LOCALNET_RPC_ENDPOINT, LOCALNET_WS_ENDPOINT, type LocalnetOptions, } from '@nosana/localnet';
6
+ export type { NosanaClient, Wallet, Address } from '@nosana/kit';
7
+ export { NosanaNetwork } from '@nosana/kit';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,GAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAGhE,OAAO,EACL,aAAa,EACb,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,EACpB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { getScenarioClient, getLocalnetClient, } from './setup.js';
2
+ export { mintNosTo, ensureLocalnetMint, executeInstructionPlan, loadMintKeypairSigner, loadMintAuthoritySigner, } from './utils.js';
3
+ export { scenarioVitestSetup } from './vitest-setup-fn.js';
4
+ export { defineScenarioVitestConfig } from './vitest-config.js';
5
+ // Re-export localnet helpers for convenience
6
+ export { startLocalnet, stopLocalnet, LOCALNET_RPC_ENDPOINT, LOCALNET_WS_ENDPOINT, } from '@nosana/localnet';
7
+ export { NosanaNetwork } from '@nosana/kit';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,GAGlB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAEhE,6CAA6C;AAC7C,OAAO,EACL,aAAa,EACb,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,GAErB,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,71 @@
1
+ import { type NosanaClient, type PartialClientConfig, type Wallet } from '@nosana/kit';
2
+ export interface LocalnetClientOptions {
3
+ /**
4
+ * Wallet to use. If not provided, a random keypair is generated and funded.
5
+ */
6
+ wallet?: Wallet;
7
+ /**
8
+ * Amount of SOL (in lamports) to airdrop. Default: 2 SOL.
9
+ */
10
+ airdropAmount?: bigint;
11
+ /**
12
+ * Amount of NOS (in raw token units) to mint. Default: 1 000 000 000.
13
+ */
14
+ mintAmount?: bigint;
15
+ /**
16
+ * Additional Nosana client config overrides.
17
+ */
18
+ config?: PartialClientConfig;
19
+ }
20
+ export interface ScenarioClientOptions extends LocalnetClientOptions {
21
+ /**
22
+ * Network to run scenarios against. Defaults to `'localnet'`.
23
+ * Can also be set via the `NOSANA_NETWORK` environment variable.
24
+ *
25
+ * - `'localnet'` — connects to `http://127.0.0.1:8899`, generates a keypair,
26
+ * airdrops SOL, and mints NOS tokens.
27
+ * - `'devnet'` / `'mainnet'` — connects to the respective Nosana network.
28
+ * Requires a funded wallet (via `wallet` option or `NOSANA_WALLET` env var
29
+ * pointing to a Solana keypair JSON file).
30
+ */
31
+ network?: 'localnet' | 'devnet' | 'mainnet';
32
+ }
33
+ /**
34
+ * Returns a cached Nosana client connected to localnet.
35
+ *
36
+ * Generates a random keypair, airdrops SOL, and mints NOS tokens automatically.
37
+ */
38
+ export declare function getLocalnetClient(options?: LocalnetClientOptions): Promise<NosanaClient>;
39
+ /**
40
+ * Returns a cached Nosana client for scenario tests, aware of the target network.
41
+ *
42
+ * The network is determined by (in order of precedence):
43
+ * 1. `options.network`
44
+ * 2. `NOSANA_NETWORK` environment variable
45
+ * 3. `'localnet'` (default)
46
+ *
47
+ * The wallet is determined by (in order of precedence):
48
+ * 1. `options.wallet`
49
+ * 2. `NOSANA_WALLET` environment variable (path to a Solana keypair JSON file)
50
+ *
51
+ * On localnet: delegates to {@link getLocalnetClient} from `@nosana/localnet`.
52
+ * On devnet / mainnet: connects using the provided wallet (required).
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * // Localnet (default — zero config)
57
+ * const client = await getScenarioClient();
58
+ *
59
+ * // Devnet via env vars (no code changes needed)
60
+ * // NOSANA_NETWORK=devnet NOSANA_WALLET=~/.config/solana/id.json
61
+ * const client = await getScenarioClient();
62
+ *
63
+ * // Devnet with explicit options
64
+ * const client = await getScenarioClient({
65
+ * network: 'devnet',
66
+ * wallet: myDevnetWallet,
67
+ * });
68
+ * ```
69
+ */
70
+ export declare function getScenarioClient(options?: ScenarioClientOptions): Promise<NosanaClient>;
71
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,MAAM,EACZ,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAClE;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;CAC7C;AAmCD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,CAAC,CAKxF;AAeD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,CAAC,CAKxF"}
package/dist/setup.js ADDED
@@ -0,0 +1,104 @@
1
+ import fs from 'fs';
2
+ import { createKeyPairSignerFromBytes, generateKeyPairSigner } from '@solana/kit';
3
+ import { createLocalnetClient, createNosanaClient, NosanaNetwork, } from '@nosana/kit';
4
+ import { mintNosTo } from './utils.js';
5
+ const globalWithLocalnet = globalThis;
6
+ const globalWithScenario = globalThis;
7
+ // ---------------------------------------------------------------------------
8
+ // Localnet client
9
+ // ---------------------------------------------------------------------------
10
+ async function createLocalnetClientInstance(options = {}) {
11
+ const wallet = options.wallet ?? (await generateKeyPairSigner());
12
+ const client = createLocalnetClient({ ...options.config, wallet });
13
+ const balance = await client.solana.getBalance(wallet.address);
14
+ if (balance === 0) {
15
+ await client.solana.airdrop({
16
+ recipient: wallet.address,
17
+ amount: options.airdropAmount ?? 2000000000n,
18
+ });
19
+ }
20
+ await mintNosTo(client, wallet.address, options.mintAmount ?? 1000000000n);
21
+ return client;
22
+ }
23
+ /**
24
+ * Returns a cached Nosana client connected to localnet.
25
+ *
26
+ * Generates a random keypair, airdrops SOL, and mints NOS tokens automatically.
27
+ */
28
+ export function getLocalnetClient(options) {
29
+ if (!globalWithLocalnet.__NOSANA_LOCALNET_CLIENT__) {
30
+ globalWithLocalnet.__NOSANA_LOCALNET_CLIENT__ = createLocalnetClientInstance(options);
31
+ }
32
+ return globalWithLocalnet.__NOSANA_LOCALNET_CLIENT__;
33
+ }
34
+ // ---------------------------------------------------------------------------
35
+ // Scenario client (network-aware)
36
+ // ---------------------------------------------------------------------------
37
+ /**
38
+ * Load a wallet from a Solana keypair JSON file.
39
+ */
40
+ async function loadWalletFromFile(filePath) {
41
+ const raw = fs.readFileSync(filePath, 'utf8');
42
+ const bytes = new Uint8Array(JSON.parse(raw));
43
+ return createKeyPairSignerFromBytes(bytes);
44
+ }
45
+ /**
46
+ * Returns a cached Nosana client for scenario tests, aware of the target network.
47
+ *
48
+ * The network is determined by (in order of precedence):
49
+ * 1. `options.network`
50
+ * 2. `NOSANA_NETWORK` environment variable
51
+ * 3. `'localnet'` (default)
52
+ *
53
+ * The wallet is determined by (in order of precedence):
54
+ * 1. `options.wallet`
55
+ * 2. `NOSANA_WALLET` environment variable (path to a Solana keypair JSON file)
56
+ *
57
+ * On localnet: delegates to {@link getLocalnetClient} from `@nosana/localnet`.
58
+ * On devnet / mainnet: connects using the provided wallet (required).
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * // Localnet (default — zero config)
63
+ * const client = await getScenarioClient();
64
+ *
65
+ * // Devnet via env vars (no code changes needed)
66
+ * // NOSANA_NETWORK=devnet NOSANA_WALLET=~/.config/solana/id.json
67
+ * const client = await getScenarioClient();
68
+ *
69
+ * // Devnet with explicit options
70
+ * const client = await getScenarioClient({
71
+ * network: 'devnet',
72
+ * wallet: myDevnetWallet,
73
+ * });
74
+ * ```
75
+ */
76
+ export function getScenarioClient(options) {
77
+ if (!globalWithScenario.__NOSANA_SCENARIO_CLIENT__) {
78
+ globalWithScenario.__NOSANA_SCENARIO_CLIENT__ = createScenarioClientInstance(options);
79
+ }
80
+ return globalWithScenario.__NOSANA_SCENARIO_CLIENT__;
81
+ }
82
+ async function createScenarioClientInstance(options) {
83
+ const network = options?.network ??
84
+ process.env.NOSANA_NETWORK ??
85
+ 'localnet';
86
+ if (network === 'localnet') {
87
+ return getLocalnetClient(options);
88
+ }
89
+ const wallet = options?.wallet ?? (await resolveWalletFromEnv());
90
+ if (!wallet) {
91
+ throw new Error(`A funded wallet is required on ${network}. ` +
92
+ 'Provide it via ScenarioClientOptions.wallet or set the NOSANA_WALLET ' +
93
+ 'environment variable to a Solana keypair JSON file path.');
94
+ }
95
+ const nosanaNetwork = network === 'mainnet' ? NosanaNetwork.MAINNET : NosanaNetwork.DEVNET;
96
+ return createNosanaClient(nosanaNetwork, { ...options?.config, wallet });
97
+ }
98
+ async function resolveWalletFromEnv() {
99
+ const walletPath = process.env.NOSANA_WALLET;
100
+ if (!walletPath)
101
+ return undefined;
102
+ return loadWalletFromFile(walletPath);
103
+ }
104
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,GAId,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA8CvC,MAAM,kBAAkB,GAAG,UAAsC,CAAC;AAClE,MAAM,kBAAkB,GAAG,UAAsC,CAAC;AAElE,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,KAAK,UAAU,4BAA4B,CACzC,UAAiC,EAAE;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,qBAAqB,EAAE,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,oBAAoB,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAEnE,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/D,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;QAClB,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;YAC1B,SAAS,EAAE,MAAM,CAAC,OAAO;YACzB,MAAM,EAAE,OAAO,CAAC,aAAa,IAAI,WAAc;SAChD,CAAC,CAAC;IACL,CAAC;IAED,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,IAAI,WAAc,CAAC,CAAC;IAC9E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA+B;IAC/D,IAAI,CAAC,kBAAkB,CAAC,0BAA0B,EAAE,CAAC;QACnD,kBAAkB,CAAC,0BAA0B,GAAG,4BAA4B,CAAC,OAAO,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,kBAAkB,CAAC,0BAA0B,CAAC;AACvD,CAAC;AAED,8EAA8E;AAC9E,kCAAkC;AAClC,8EAA8E;AAE9E;;GAEG;AACH,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IAChD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,OAAO,4BAA4B,CAAC,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA+B;IAC/D,IAAI,CAAC,kBAAkB,CAAC,0BAA0B,EAAE,CAAC;QACnD,kBAAkB,CAAC,0BAA0B,GAAG,4BAA4B,CAAC,OAAO,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,kBAAkB,CAAC,0BAA0B,CAAC;AACvD,CAAC;AAED,KAAK,UAAU,4BAA4B,CACzC,OAA+B;IAE/B,MAAM,OAAO,GACX,OAAO,EAAE,OAAO;QACf,OAAO,CAAC,GAAG,CAAC,cAAmD;QAChE,UAAU,CAAC;IAEb,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3B,OAAO,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,CAAC,MAAM,oBAAoB,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,kCAAkC,OAAO,IAAI;YAC3C,uEAAuE;YACvE,0DAA0D,CAC7D,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC;IAC3F,OAAO,kBAAkB,CAAC,aAAa,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED,KAAK,UAAU,oBAAoB;IACjC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC7C,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAClC,OAAO,kBAAkB,CAAC,UAAU,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { address, type InstructionPlan, type Address, type TransactionSigner } from '@solana/kit';
2
+ import type { NosanaClient } from '@nosana/kit';
3
+ /**
4
+ * Load the NOS mint keypair signer from the bundled keys directory,
5
+ * or from a custom path via `LOCALNET_NOS_MINT_KEYPAIR` env var.
6
+ */
7
+ export declare function loadMintKeypairSigner(): Promise<import("@solana/kit").KeyPairSigner<string>>;
8
+ /**
9
+ * Load the NOS mint authority signer from the bundled keys directory,
10
+ * or from a custom path via `LOCALNET_NOS_MINT_AUTHORITY_KEYPAIR` env var.
11
+ */
12
+ export declare function loadMintAuthoritySigner(): Promise<TransactionSigner>;
13
+ /**
14
+ * Ensure the NOS mint exists on the localnet validator.
15
+ * Creates it if it doesn't exist, validates the authority if it does.
16
+ */
17
+ export declare function ensureLocalnetMint(client: NosanaClient): Promise<{
18
+ mintAuthority: TransactionSigner;
19
+ mintAddress: Address;
20
+ }>;
21
+ /**
22
+ * Execute a Solana instruction plan using the client's wallet as fee payer.
23
+ */
24
+ export declare function executeInstructionPlan(client: NosanaClient, plan: InstructionPlan): Promise<void>;
25
+ /**
26
+ * Mint NOS tokens to a recipient address on the localnet.
27
+ */
28
+ export declare function mintNosTo(client: NosanaClient, recipient: string | ReturnType<typeof address>, amount: bigint): Promise<void>;
29
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,OAAO,EAKP,KAAK,eAAe,EAKpB,KAAK,OAAO,EACZ,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAOrB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgBhD;;;GAGG;AACH,wBAAsB,qBAAqB,yDAO1C;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,+BAY5C;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,YAAY;;;GAqD5D;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,iBAoBvF;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,EAC9C,MAAM,EAAE,MAAM,iBAef"}
package/dist/utils.js ADDED
@@ -0,0 +1,128 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { address, createKeyPairSignerFromBytes, createTransactionMessage, createTransactionPlanner, getAllSingleTransactionPlans, pipe, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, unwrapOption, } from '@solana/kit';
4
+ import { fetchMint, fetchMaybeMint, getCreateMintInstructionPlan, getMintToATAInstructionPlanAsync, } from '@solana-program/token';
5
+ import { KEYS_DIR } from '@nosana/localnet';
6
+ const NOS_MINT_DECIMALS = 6;
7
+ const DEFAULT_NOS_MINT_KEYPAIR_PATH = path.join(KEYS_DIR, 'devr1BGQndEW5k5zfvG5FsLyZv1Ap73vNgAHcQ9sUVP.json');
8
+ const DEFAULT_NOS_MINT_AUTHORITY_KEYPAIR_PATH = path.join(KEYS_DIR, 'dumQVNHZ1KNcLmzjMaDPEA5vFCzwHEEcQmZ8JHmmCNH.json');
9
+ let cachedMintAuthority = null;
10
+ let cachedMintAddress = null;
11
+ /**
12
+ * Load the NOS mint keypair signer from the bundled keys directory,
13
+ * or from a custom path via `LOCALNET_NOS_MINT_KEYPAIR` env var.
14
+ */
15
+ export async function loadMintKeypairSigner() {
16
+ const keypairPath = process.env.LOCALNET_NOS_MINT_KEYPAIR ?? DEFAULT_NOS_MINT_KEYPAIR_PATH;
17
+ const resolvedPath = path.isAbsolute(keypairPath)
18
+ ? keypairPath
19
+ : path.join(process.cwd(), keypairPath);
20
+ const keypair = JSON.parse(fs.readFileSync(resolvedPath, 'utf8'));
21
+ return createKeyPairSignerFromBytes(new Uint8Array(keypair));
22
+ }
23
+ /**
24
+ * Load the NOS mint authority signer from the bundled keys directory,
25
+ * or from a custom path via `LOCALNET_NOS_MINT_AUTHORITY_KEYPAIR` env var.
26
+ */
27
+ export async function loadMintAuthoritySigner() {
28
+ if (cachedMintAuthority) {
29
+ return cachedMintAuthority;
30
+ }
31
+ const keypairPath = process.env.LOCALNET_NOS_MINT_AUTHORITY_KEYPAIR ?? DEFAULT_NOS_MINT_AUTHORITY_KEYPAIR_PATH;
32
+ const resolvedPath = path.isAbsolute(keypairPath)
33
+ ? keypairPath
34
+ : path.join(process.cwd(), keypairPath);
35
+ const keypair = JSON.parse(fs.readFileSync(resolvedPath, 'utf8'));
36
+ cachedMintAuthority = await createKeyPairSignerFromBytes(new Uint8Array(keypair));
37
+ return cachedMintAuthority;
38
+ }
39
+ /**
40
+ * Ensure the NOS mint exists on the localnet validator.
41
+ * Creates it if it doesn't exist, validates the authority if it does.
42
+ */
43
+ export async function ensureLocalnetMint(client) {
44
+ if (cachedMintAuthority && cachedMintAddress) {
45
+ return {
46
+ mintAuthority: cachedMintAuthority,
47
+ mintAddress: cachedMintAddress,
48
+ };
49
+ }
50
+ const mintKeypair = await loadMintKeypairSigner();
51
+ const mintAuthority = await loadMintAuthoritySigner();
52
+ const envMint = process.env.LOCALNET_NOS_MINT;
53
+ if (envMint && address(envMint) !== mintKeypair.address) {
54
+ throw new Error(`LOCALNET_NOS_MINT (${envMint}) does not match mint keypair address (${mintKeypair.address}).`);
55
+ }
56
+ const mintAddress = envMint ? address(envMint) : mintKeypair.address;
57
+ const existingMint = await fetchMaybeMint(client.solana.rpc, mintAddress);
58
+ if (!existingMint.exists) {
59
+ const createMintPlan = getCreateMintInstructionPlan({
60
+ payer: client.wallet,
61
+ newMint: mintKeypair,
62
+ decimals: NOS_MINT_DECIMALS,
63
+ mintAuthority: mintAuthority.address,
64
+ freezeAuthority: null,
65
+ });
66
+ try {
67
+ await executeInstructionPlan(client, createMintPlan);
68
+ }
69
+ catch (error) {
70
+ const message = error instanceof Error ? error.message : String(error);
71
+ if (message.includes('already in use') || message.includes('custom program error: #0')) {
72
+ const existingAfter = await fetchMaybeMint(client.solana.rpc, mintAddress);
73
+ if (!existingAfter.exists) {
74
+ throw error;
75
+ }
76
+ }
77
+ else {
78
+ throw error;
79
+ }
80
+ }
81
+ }
82
+ else {
83
+ const mintAuthorityOnChain = unwrapOption(existingMint.data.mintAuthority);
84
+ if (mintAuthorityOnChain && mintAuthorityOnChain !== mintAuthority.address) {
85
+ throw new Error(`Localnet NOS mint already exists with a different mint authority (${mintAuthorityOnChain}). ` +
86
+ 'Reset the validator or provide the matching authority keypair.');
87
+ }
88
+ }
89
+ cachedMintAuthority = mintAuthority;
90
+ cachedMintAddress = mintAddress;
91
+ return { mintAuthority: cachedMintAuthority, mintAddress };
92
+ }
93
+ /**
94
+ * Execute a Solana instruction plan using the client's wallet as fee payer.
95
+ */
96
+ export async function executeInstructionPlan(client, plan) {
97
+ const planner = createTransactionPlanner({
98
+ createTransactionMessage: async () => {
99
+ const { value: latestBlockhash } = await client.solana.rpc.getLatestBlockhash().send();
100
+ return pipe(createTransactionMessage({ version: 0 }), (tx) => setTransactionMessageFeePayerSigner(client.wallet, tx), (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx));
101
+ },
102
+ });
103
+ const transactionPlan = await planner(plan);
104
+ const messages = getAllSingleTransactionPlans(transactionPlan).map((p) => p.message);
105
+ for (const message of messages) {
106
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
107
+ const signed = await client.solana.signTransaction(message);
108
+ await client.solana.sendTransaction(signed, { commitment: 'confirmed' });
109
+ }
110
+ }
111
+ /**
112
+ * Mint NOS tokens to a recipient address on the localnet.
113
+ */
114
+ export async function mintNosTo(client, recipient, amount) {
115
+ const { mintAuthority, mintAddress } = await ensureLocalnetMint(client);
116
+ const owner = typeof recipient === 'string' ? address(recipient) : recipient;
117
+ const mintAccount = await fetchMint(client.solana.rpc, mintAddress);
118
+ const mintToPlan = await getMintToATAInstructionPlanAsync({
119
+ payer: client.wallet,
120
+ owner,
121
+ mint: mintAddress,
122
+ mintAuthority,
123
+ decimals: mintAccount.data.decimals,
124
+ amount,
125
+ });
126
+ await executeInstructionPlan(client, mintToPlan);
127
+ }
128
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Create a Vitest config for scenario tests.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * // vitest.scenario.config.ts
7
+ * import { defineScenarioVitestConfig } from '@nosana/scenario';
8
+ *
9
+ * export default defineScenarioVitestConfig({
10
+ * test: {
11
+ * include: ['tests/scenarios/**\/*.test.ts'],
12
+ * },
13
+ * });
14
+ * ```
15
+ */
16
+ export declare function defineScenarioVitestConfig(overrides?: Record<string, unknown>): {
17
+ test: {
18
+ setupFiles: string[];
19
+ environment: string;
20
+ globals: boolean;
21
+ };
22
+ };
23
+ //# sourceMappingURL=vitest-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest-config.d.ts","sourceRoot":"","sources":["../src/vitest-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;EAa7E"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Create a Vitest config for scenario tests.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * // vitest.scenario.config.ts
7
+ * import { defineScenarioVitestConfig } from '@nosana/scenario';
8
+ *
9
+ * export default defineScenarioVitestConfig({
10
+ * test: {
11
+ * include: ['tests/scenarios/**\/*.test.ts'],
12
+ * },
13
+ * });
14
+ * ```
15
+ */
16
+ export function defineScenarioVitestConfig(overrides) {
17
+ const testOverrides = (overrides?.test ?? {});
18
+ const existingSetupFiles = (testOverrides.setupFiles ?? []);
19
+ return {
20
+ ...overrides,
21
+ test: {
22
+ environment: 'node',
23
+ globals: true,
24
+ ...testOverrides,
25
+ setupFiles: ['@nosana/scenario/dist/vitest-setup.js', ...existingSetupFiles],
26
+ },
27
+ };
28
+ }
29
+ //# sourceMappingURL=vitest-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest-config.js","sourceRoot":"","sources":["../src/vitest-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,0BAA0B,CAAC,SAAmC;IAC5E,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,IAAI,IAAI,EAAE,CAA4B,CAAC;IACzE,MAAM,kBAAkB,GAAG,CAAC,aAAa,CAAC,UAAU,IAAI,EAAE,CAAa,CAAC;IAExE,OAAO;QACL,GAAG,SAAS;QACZ,IAAI,EAAE;YACJ,WAAW,EAAE,MAAM;YACnB,OAAO,EAAE,IAAI;YACb,GAAG,aAAa;YAChB,UAAU,EAAE,CAAC,uCAAuC,EAAE,GAAG,kBAAkB,CAAC;SAC7E;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Vitest setup function that initializes the scenario test client.
3
+ * Exported for programmatic use. For vitest setupFiles, use
4
+ * `@nosana/scenario/dist/vitest-setup.js` which auto-runs this.
5
+ */
6
+ export declare function scenarioVitestSetup(): Promise<void>;
7
+ //# sourceMappingURL=vitest-setup-fn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest-setup-fn.d.ts","sourceRoot":"","sources":["../src/vitest-setup-fn.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAsB,mBAAmB,kBAExC"}
@@ -0,0 +1,10 @@
1
+ import { getScenarioClient } from './setup.js';
2
+ /**
3
+ * Vitest setup function that initializes the scenario test client.
4
+ * Exported for programmatic use. For vitest setupFiles, use
5
+ * `@nosana/scenario/dist/vitest-setup.js` which auto-runs this.
6
+ */
7
+ export async function scenarioVitestSetup() {
8
+ await getScenarioClient();
9
+ }
10
+ //# sourceMappingURL=vitest-setup-fn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest-setup-fn.js","sourceRoot":"","sources":["../src/vitest-setup-fn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,iBAAiB,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Vitest setup file — auto-runs getScenarioClient() when loaded.
3
+ *
4
+ * Use as a vitest setupFile:
5
+ * ```ts
6
+ * // vitest.scenario.config.ts
7
+ * import { defineScenarioVitestConfig } from '@nosana/scenario';
8
+ * export default defineScenarioVitestConfig();
9
+ * ```
10
+ *
11
+ * Or reference directly:
12
+ * ```ts
13
+ * setupFiles: ['@nosana/scenario/dist/vitest-setup.js']
14
+ * ```
15
+ */
16
+ export { scenarioVitestSetup } from './vitest-setup-fn.js';
17
+ //# sourceMappingURL=vitest-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest-setup.d.ts","sourceRoot":"","sources":["../src/vitest-setup.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { getScenarioClient } from './setup.js';
2
+ /**
3
+ * Vitest setup file — auto-runs getScenarioClient() when loaded.
4
+ *
5
+ * Use as a vitest setupFile:
6
+ * ```ts
7
+ * // vitest.scenario.config.ts
8
+ * import { defineScenarioVitestConfig } from '@nosana/scenario';
9
+ * export default defineScenarioVitestConfig();
10
+ * ```
11
+ *
12
+ * Or reference directly:
13
+ * ```ts
14
+ * setupFiles: ['@nosana/scenario/dist/vitest-setup.js']
15
+ * ```
16
+ */
17
+ export { scenarioVitestSetup } from './vitest-setup-fn.js';
18
+ // Auto-run when used as a setup file
19
+ await getScenarioClient();
20
+ //# sourceMappingURL=vitest-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest-setup.js","sourceRoot":"","sources":["../src/vitest-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,qCAAqC;AACrC,MAAM,iBAAiB,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@nosana/scenario",
3
+ "version": "2.2.0",
4
+ "description": "Nosana scenario test helpers: network-aware client setup for localnet, devnet, and mainnet",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "build:with-deps": "pnpm --filter $npm_package_name... run build",
14
+ "dev": "tsc --watch",
15
+ "dev:with-deps": "pnpm --filter $npm_package_name... run dev --parallel",
16
+ "lint": "eslint .",
17
+ "lint:fix": "eslint . --fix",
18
+ "format": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --check \"**/*.ts\"",
19
+ "format:fix": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --write \"**/*.ts\"",
20
+ "test:scenario": "NODE_NO_WARNINGS=1 vitest run --config vitest.config.ts",
21
+ "test:scenario:localnet": "pnpm run localnet:up && pnpm run test:scenario",
22
+ "localnet:up": "docker compose -f ../localnet/docker/docker-compose.yml up -d --wait --force-recreate",
23
+ "localnet:down": "docker compose -f ../localnet/docker/docker-compose.yml down -v",
24
+ "localnet:logs": "docker compose -f ../localnet/docker/docker-compose.yml logs -f"
25
+ },
26
+ "keywords": [
27
+ "nosana",
28
+ "solana",
29
+ "scenario",
30
+ "testing"
31
+ ],
32
+ "author": "Nosana",
33
+ "license": "MIT",
34
+ "dependencies": {
35
+ "@nosana/kit": "2.2.0",
36
+ "@nosana/localnet": "2.2.0",
37
+ "@solana-program/token": "0.9.0",
38
+ "@solana/kit": "5.4.0"
39
+ },
40
+ "devDependencies": {
41
+ "prettier": "^3.7.4",
42
+ "typescript": "^5.9.3",
43
+ "vitest": "^4.0.16"
44
+ },
45
+ "peerDependencies": {
46
+ "vitest": ">=2.0.0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "vitest": {
50
+ "optional": true
51
+ }
52
+ },
53
+ "packageManager": "pnpm@10.28.1",
54
+ "engines": {
55
+ "node": ">=20.18.0"
56
+ },
57
+ "files": [
58
+ "dist",
59
+ "package.json",
60
+ "README.md"
61
+ ],
62
+ "gitHead": "fe1fb33d98b537b781b3cce80f78f6e61c1d1cd4"
63
+ }