stxer 0.4.5 → 0.7.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/src/ast.ts ADDED
@@ -0,0 +1,120 @@
1
+ /**
2
+ * WARNING:
3
+ *
4
+ * this file will be used in cross-runtime environments (browser, cloudflare workers, XLinkSDK, etc.),
5
+ * so please be careful when adding `import`s to it.
6
+ */
7
+
8
+ import { DEFAULT_STXER_API } from './constants';
9
+ import type { ClarityEpoch, ContractAST } from './types';
10
+
11
+ export interface AstOptions {
12
+ stxerApi?: string;
13
+ }
14
+
15
+ export interface GetContractAstOptions extends AstOptions {
16
+ contractId: string;
17
+ }
18
+
19
+ /**
20
+ * Fetch the AST for an on-chain contract.
21
+ * @param options - Contract ID and optional API endpoint
22
+ * @returns The contract AST with metadata
23
+ */
24
+ export async function getContractAST(
25
+ options: GetContractAstOptions,
26
+ ): Promise<ContractAST> {
27
+ const url = `${options.stxerApi ?? DEFAULT_STXER_API}/contracts/${options.contractId}`;
28
+
29
+ const response = await fetch(url, {
30
+ method: 'GET',
31
+ headers: {
32
+ Accept: 'application/json',
33
+ },
34
+ });
35
+
36
+ if (!response.ok) {
37
+ throw new Error(
38
+ `Failed to fetch contract AST: ${response.status} ${response.statusText}`,
39
+ );
40
+ }
41
+
42
+ const text = await response.text();
43
+ if (!text.startsWith('{')) {
44
+ throw new Error(`Invalid response from contracts endpoint: ${text}`);
45
+ }
46
+
47
+ return JSON.parse(text) as ContractAST;
48
+ }
49
+
50
+ export interface ParseContractOptions extends AstOptions {
51
+ sourceCode: string;
52
+ contractId: string;
53
+ clarityVersion?: '1' | '2' | '3' | '4';
54
+ epoch?: ClarityEpoch;
55
+ }
56
+
57
+ /**
58
+ * Parse contract source code into an AST.
59
+ * @param options - Source code, contract ID, and optional configuration
60
+ * @returns The parsed contract AST
61
+ */
62
+ export async function parseContract(
63
+ options: ParseContractOptions,
64
+ ): Promise<ContractAST> {
65
+ const url = `${options.stxerApi ?? DEFAULT_STXER_API}/contracts:parse`;
66
+
67
+ const payload: {
68
+ contract_id: string;
69
+ source_code: string;
70
+ clarity_version?: string;
71
+ epoch?: string;
72
+ } = {
73
+ contract_id: options.contractId,
74
+ source_code: options.sourceCode,
75
+ };
76
+
77
+ if (options.clarityVersion !== undefined) {
78
+ payload.clarity_version = options.clarityVersion;
79
+ }
80
+ if (options.epoch !== undefined) {
81
+ payload.epoch = options.epoch;
82
+ }
83
+
84
+ const response = await fetch(url, {
85
+ method: 'POST',
86
+ body: JSON.stringify(payload),
87
+ headers: {
88
+ 'Content-Type': 'application/json',
89
+ Accept: 'application/json',
90
+ },
91
+ });
92
+
93
+ if (!response.ok) {
94
+ throw new Error(
95
+ `Failed to parse contract: ${response.status} ${response.statusText}`,
96
+ );
97
+ }
98
+
99
+ const text = await response.text();
100
+ if (!text.startsWith('{')) {
101
+ throw new Error(`Invalid response from contract parse endpoint: ${text}`);
102
+ }
103
+
104
+ return JSON.parse(text) as ContractAST;
105
+ }
106
+
107
+ // Re-export AST-related types for convenience
108
+ export type {
109
+ ClarityAbi,
110
+ ClarityAbiFunction,
111
+ ClarityAbiFungibleToken,
112
+ ClarityAbiMap,
113
+ ClarityAbiNonFungibleToken,
114
+ ClarityAbiType,
115
+ ClarityAbiVariable,
116
+ ClarityEpoch,
117
+ ClarityVersion,
118
+ ContractAST,
119
+ SymbolicExpression,
120
+ } from './types';
@@ -31,7 +31,8 @@ export interface BatchReads {
31
31
  }
32
32
 
33
33
  export interface BatchReadsResult {
34
- tip: string;
34
+ /** Index block hash the batch ran against. Matches the wire field name. */
35
+ index_block_hash: string;
35
36
  vars: (ClarityValue | Error)[];
36
37
  maps: (ClarityValue | Error)[];
37
38
  readonly: (ClarityValue | Error)[];
@@ -44,10 +45,10 @@ export interface BatchApiOptions {
44
45
  const DEFAULT_STXER_API = 'https://api.stxer.xyz';
45
46
 
46
47
  function convertResults(
47
- rs: ({ Ok: string } | { Err: string })[],
48
+ rs: ({ Ok: string } | { Err: string })[] | undefined,
48
49
  ): (ClarityValue | Error)[] {
49
50
  const results: (ClarityValue | Error)[] = [];
50
- for (const v of rs) {
51
+ for (const v of rs ?? []) {
51
52
  if ('Ok' in v) {
52
53
  results.push(deserializeCV(v.Ok));
53
54
  } else {
@@ -123,14 +124,14 @@ export async function batchRead(
123
124
  }
124
125
 
125
126
  const rs = JSON.parse(text) as {
126
- tip: string;
127
- vars: ({ Ok: string } | { Err: string })[];
128
- maps: ({ Ok: string } | { Err: string })[];
129
- readonly: ({ Ok: string } | { Err: string })[];
127
+ index_block_hash: string;
128
+ vars?: ({ Ok: string } | { Err: string })[];
129
+ maps?: ({ Ok: string } | { Err: string })[];
130
+ readonly?: ({ Ok: string } | { Err: string })[];
130
131
  };
131
132
 
132
133
  return {
133
- tip: rs.tip,
134
+ index_block_hash: rs.index_block_hash,
134
135
  vars: convertResults(rs.vars),
135
136
  maps: convertResults(rs.maps),
136
137
  readonly: convertResults(rs.readonly),
@@ -10,7 +10,7 @@ import {
10
10
  contractPrincipalCV,
11
11
  type OptionalCV,
12
12
  } from '@stacks/transactions';
13
- import { type BatchReads, batchRead } from './BatchAPI';
13
+ import { type BatchReads, batchRead } from './batch-api';
14
14
 
15
15
  export interface ReadOnlyRequest {
16
16
  mode: 'readonly';
@@ -19,7 +19,7 @@ import type {
19
19
  InferVariableType,
20
20
  } from 'ts-clarity';
21
21
  import { decodeAbi, encodeAbi } from 'ts-clarity';
22
- import { BatchProcessor } from './BatchProcessor';
22
+ import { BatchProcessor } from './batch-processor';
23
23
 
24
24
  // Shared processor instance with default settings
25
25
  const defaultProcessor = new BatchProcessor({
@@ -0,0 +1,12 @@
1
+ /**
2
+ * API endpoint constants
3
+ */
4
+
5
+ /** Default stxer API endpoint for mainnet */
6
+ export const STXER_API_MAINNET = 'https://api.stxer.xyz';
7
+
8
+ /** stxer API endpoint for testnet */
9
+ export const STXER_API_TESTNET = 'https://testnet-api.stxer.xyz';
10
+
11
+ /** Default stxer API endpoint (mainnet) */
12
+ export const DEFAULT_STXER_API = STXER_API_MAINNET;
package/src/index.ts CHANGED
@@ -1,3 +1,12 @@
1
- export * from './BatchAPI';
1
+ // `dts build` (rollup-plugin-typescript2 + babel) does not enable
2
+ // `@babel/preset-typescript` on the entry, so inline `type` specifiers
3
+ // inside `export {}` and standalone `export type {}` blocks both crash
4
+ // the build (babel falls back to flow grammar). Stick with `export *`.
5
+ export * from './ast';
6
+ export * from './batch-api';
2
7
  export * from './clarity-api';
8
+ export * from './constants';
3
9
  export * from './simulation';
10
+ export * from './simulation-api';
11
+ export * from './tip';
12
+ export * from './types';
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Low-level programmatic simulation APIs
3
+ *
4
+ * These functions provide direct access to the stxer V2 simulation endpoints
5
+ * for programmatic use cases where you need more control than SimulationBuilder provides.
6
+ */
7
+
8
+ import { DEFAULT_STXER_API } from './constants';
9
+ import type {
10
+ InstantSimulationRequest,
11
+ InstantSimulationResponse,
12
+ SimulationBatchReadsRequest,
13
+ SimulationBatchReadsResponse,
14
+ SimulationResult,
15
+ SubmitSimulationStepsRequest,
16
+ SubmitSimulationStepsResponse,
17
+ } from './types';
18
+
19
+ /**
20
+ * Options for API calls
21
+ */
22
+ export interface SimulationApiOptions {
23
+ /** stxer API endpoint (default: https://api.stxer.xyz) */
24
+ stxerApi?: string;
25
+ }
26
+
27
+ /**
28
+ * Create simulation session options
29
+ */
30
+ export interface CreateSessionOptions {
31
+ /** Block height for simulation (optional, uses tip if not provided) */
32
+ block_height?: number;
33
+ /** Block hash corresponding to block_height */
34
+ block_hash?: string;
35
+ /** Skip debug tracing for faster simulations */
36
+ skip_tracing?: boolean;
37
+ }
38
+
39
+ /**
40
+ * Instantly simulate a transaction
41
+ *
42
+ * This is useful for apps/wallets to get the result of a transaction before sending it.
43
+ * Lightweight - no debug tracing information.
44
+ *
45
+ * @param request - Instant simulation request
46
+ * @param options - API options
47
+ * @returns Instant simulation response with receipt and optional reads
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * import { instantSimulation } from 'stxer';
52
+ *
53
+ * const result = await instantSimulation({
54
+ * transaction: '0x...',
55
+ * block_height: 130818,
56
+ * block_hash: '0x...',
57
+ * reads: [
58
+ * { DataVar: ['SP...contract', 'my-var'] },
59
+ * { StxBalance: 'SP...' }
60
+ * ]
61
+ * });
62
+ * console.log(result.receipt.result);
63
+ * ```
64
+ */
65
+ export async function instantSimulation(
66
+ request: InstantSimulationRequest,
67
+ options: SimulationApiOptions = {},
68
+ ): Promise<InstantSimulationResponse> {
69
+ const apiEndpoint = options.stxerApi ?? DEFAULT_STXER_API;
70
+
71
+ const response = await fetch(
72
+ `${apiEndpoint}/devtools/v2/simulations:instant`,
73
+ {
74
+ method: 'POST',
75
+ body: JSON.stringify(request),
76
+ headers: {
77
+ 'Content-Type': 'application/json',
78
+ Accept: 'application/json',
79
+ },
80
+ },
81
+ );
82
+
83
+ if (!response.ok) {
84
+ const text = await response.text();
85
+ throw new Error(`Instant simulation failed: ${text}`);
86
+ }
87
+
88
+ return response.json() as Promise<InstantSimulationResponse>;
89
+ }
90
+
91
+ /**
92
+ * Create a new simulation session
93
+ *
94
+ * A session allows you to run multiple steps in a forked chain state.
95
+ *
96
+ * @param options - Create session options
97
+ * @param apiOptions - API options
98
+ * @returns Session ID
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * import { createSimulationSession } from 'stxer';
103
+ *
104
+ * const sessionId = await createSimulationSession({
105
+ * block_height: 130818,
106
+ * skip_tracing: false
107
+ * });
108
+ * ```
109
+ */
110
+ export async function createSimulationSession(
111
+ options: CreateSessionOptions = {},
112
+ apiOptions: SimulationApiOptions = {},
113
+ ): Promise<string> {
114
+ const apiEndpoint = apiOptions.stxerApi ?? DEFAULT_STXER_API;
115
+
116
+ const response = await fetch(`${apiEndpoint}/devtools/v2/simulations`, {
117
+ method: 'POST',
118
+ body: JSON.stringify(options),
119
+ headers: {
120
+ 'Content-Type': 'application/json',
121
+ Accept: 'application/json',
122
+ },
123
+ });
124
+
125
+ if (!response.ok) {
126
+ const text = await response.text();
127
+ throw new Error(`Failed to create simulation session: ${text}`);
128
+ }
129
+
130
+ const result = (await response.json()) as { id: string };
131
+ return result.id;
132
+ }
133
+
134
+ /**
135
+ * Submit steps to a simulation session
136
+ *
137
+ * Steps are executed sequentially in the session's forked chain state.
138
+ *
139
+ * @param sessionId - Simulation session ID
140
+ * @param request - Steps to submit
141
+ * @param options - API options
142
+ * @returns Array of step results
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * import { submitSimulationSteps } from 'stxer';
147
+ *
148
+ * const results = await submitSimulationSteps(sessionId, {
149
+ * steps: [
150
+ * { Transaction: '0x...' },
151
+ * { Eval: ['SP...', '', 'SP...contract', '(var-get my-var)'] },
152
+ * { Reads: [{ DataVar: ['SP...contract', 'my-var'] }] }
153
+ * ]
154
+ * });
155
+ * ```
156
+ */
157
+ export async function submitSimulationSteps(
158
+ sessionId: string,
159
+ request: SubmitSimulationStepsRequest,
160
+ options: SimulationApiOptions = {},
161
+ ): Promise<SubmitSimulationStepsResponse> {
162
+ const apiEndpoint = options.stxerApi ?? DEFAULT_STXER_API;
163
+
164
+ const response = await fetch(
165
+ `${apiEndpoint}/devtools/v2/simulations/${sessionId}`,
166
+ {
167
+ method: 'POST',
168
+ body: JSON.stringify(request),
169
+ headers: {
170
+ 'Content-Type': 'application/json',
171
+ Accept: 'application/json',
172
+ },
173
+ },
174
+ );
175
+
176
+ if (!response.ok) {
177
+ const text = await response.text();
178
+ throw new Error(`Failed to submit simulation steps: ${text}`);
179
+ }
180
+
181
+ return response.json() as Promise<SubmitSimulationStepsResponse>;
182
+ }
183
+
184
+ /**
185
+ * Get simulation session results
186
+ *
187
+ * Returns the full simulation result including metadata and all step results.
188
+ *
189
+ * @param sessionId - Simulation session ID
190
+ * @param options - API options
191
+ * @returns Complete simulation result
192
+ *
193
+ * @example
194
+ * ```typescript
195
+ * import { getSimulationResult } from 'stxer';
196
+ *
197
+ * const result = await getSimulationResult(sessionId);
198
+ * console.log(result.metadata);
199
+ * console.log(result.steps);
200
+ * ```
201
+ */
202
+ export async function getSimulationResult(
203
+ sessionId: string,
204
+ options: SimulationApiOptions = {},
205
+ ): Promise<SimulationResult> {
206
+ const apiEndpoint = options.stxerApi ?? DEFAULT_STXER_API;
207
+
208
+ const response = await fetch(
209
+ `${apiEndpoint}/devtools/v2/simulations/${sessionId}`,
210
+ {
211
+ method: 'GET',
212
+ headers: {
213
+ Accept: 'application/json',
214
+ },
215
+ },
216
+ );
217
+
218
+ if (!response.ok) {
219
+ const text = await response.text();
220
+ throw new Error(`Failed to get simulation result: ${text}`);
221
+ }
222
+
223
+ return response.json() as Promise<SimulationResult>;
224
+ }
225
+
226
+ /**
227
+ * Batch reads from a simulation session
228
+ *
229
+ * Similar to sidecar batch reads, but reads from the simulation's forked state.
230
+ *
231
+ * @param sessionId - Simulation session ID
232
+ * @param request - Batch reads request
233
+ * @param options - API options
234
+ * @returns Batch read results
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * import { simulationBatchReads } from 'stxer';
239
+ *
240
+ * const results = await simulationBatchReads(sessionId, {
241
+ * vars: [['SP...contract', 'my-var']],
242
+ * maps: [['SP...contract', 'my-map', '0x...']],
243
+ * stx: ['SP...']
244
+ * });
245
+ * console.log(results.vars);
246
+ * ```
247
+ */
248
+ export async function simulationBatchReads(
249
+ sessionId: string,
250
+ request: SimulationBatchReadsRequest,
251
+ options: SimulationApiOptions = {},
252
+ ): Promise<SimulationBatchReadsResponse> {
253
+ const apiEndpoint = options.stxerApi ?? DEFAULT_STXER_API;
254
+
255
+ const response = await fetch(
256
+ `${apiEndpoint}/devtools/v2/simulations/${sessionId}/reads`,
257
+ {
258
+ method: 'POST',
259
+ body: JSON.stringify(request),
260
+ headers: {
261
+ 'Content-Type': 'application/json',
262
+ Accept: 'application/json',
263
+ },
264
+ },
265
+ );
266
+
267
+ if (!response.ok) {
268
+ const text = await response.text();
269
+ throw new Error(`Failed to batch reads from simulation: ${text}`);
270
+ }
271
+
272
+ return response.json() as Promise<SimulationBatchReadsResponse>;
273
+ }