openbroker 1.3.2 → 1.4.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 (167) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/auto/audit.d.ts +57 -0
  3. package/dist/auto/audit.d.ts.map +1 -0
  4. package/dist/auto/audit.js +407 -0
  5. package/dist/auto/cli.d.ts +2 -0
  6. package/dist/auto/cli.d.ts.map +1 -0
  7. package/dist/auto/cli.js +423 -0
  8. package/dist/auto/events.d.ts +11 -0
  9. package/dist/auto/events.d.ts.map +1 -0
  10. package/dist/auto/events.js +36 -0
  11. package/dist/auto/examples/dca.d.ts +4 -0
  12. package/dist/auto/examples/dca.d.ts.map +1 -0
  13. package/dist/auto/examples/dca.js +60 -0
  14. package/dist/auto/examples/funding-arb.d.ts +4 -0
  15. package/dist/auto/examples/funding-arb.d.ts.map +1 -0
  16. package/dist/auto/examples/funding-arb.js +81 -0
  17. package/dist/auto/examples/grid.d.ts +4 -0
  18. package/dist/auto/examples/grid.d.ts.map +1 -0
  19. package/dist/auto/examples/grid.js +114 -0
  20. package/dist/auto/examples/mm-maker.d.ts +4 -0
  21. package/dist/auto/examples/mm-maker.d.ts.map +1 -0
  22. package/dist/auto/examples/mm-maker.js +131 -0
  23. package/dist/auto/examples/mm-spread.d.ts +4 -0
  24. package/dist/auto/examples/mm-spread.d.ts.map +1 -0
  25. package/dist/auto/examples/mm-spread.js +119 -0
  26. package/dist/auto/examples/price-alert.d.ts +4 -0
  27. package/dist/auto/examples/price-alert.d.ts.map +1 -0
  28. package/dist/auto/examples/price-alert.js +85 -0
  29. package/dist/auto/keep-awake.d.ts +11 -0
  30. package/dist/auto/keep-awake.d.ts.map +1 -0
  31. package/dist/auto/keep-awake.js +70 -0
  32. package/dist/auto/loader.d.ts +22 -0
  33. package/dist/auto/loader.d.ts.map +1 -0
  34. package/dist/auto/loader.js +127 -0
  35. package/dist/auto/prune.d.ts +40 -0
  36. package/dist/auto/prune.d.ts.map +1 -0
  37. package/dist/auto/prune.js +204 -0
  38. package/dist/auto/registry.d.ts +24 -0
  39. package/dist/auto/registry.d.ts.map +1 -0
  40. package/dist/auto/registry.js +93 -0
  41. package/dist/auto/report.d.ts +3 -0
  42. package/dist/auto/report.d.ts.map +1 -0
  43. package/dist/auto/report.js +385 -0
  44. package/dist/auto/runtime.d.ts +33 -0
  45. package/dist/auto/runtime.d.ts.map +1 -0
  46. package/dist/auto/runtime.js +844 -0
  47. package/dist/auto/types.d.ts +236 -0
  48. package/dist/auto/types.d.ts.map +1 -0
  49. package/dist/auto/types.js +3 -0
  50. package/dist/core/client.d.ts +684 -0
  51. package/dist/core/client.d.ts.map +1 -0
  52. package/dist/core/client.js +2040 -0
  53. package/dist/core/config.d.ts +22 -0
  54. package/dist/core/config.d.ts.map +1 -0
  55. package/dist/core/config.js +143 -0
  56. package/dist/core/types.d.ts +221 -0
  57. package/dist/core/types.d.ts.map +1 -0
  58. package/dist/core/types.js +2 -0
  59. package/dist/core/utils.d.ts +61 -0
  60. package/dist/core/utils.d.ts.map +1 -0
  61. package/dist/core/utils.js +142 -0
  62. package/dist/core/ws.d.ts +121 -0
  63. package/dist/core/ws.d.ts.map +1 -0
  64. package/dist/core/ws.js +222 -0
  65. package/dist/info/account.d.ts +3 -0
  66. package/dist/info/account.d.ts.map +1 -0
  67. package/dist/info/account.js +198 -0
  68. package/dist/info/all-markets.d.ts +3 -0
  69. package/dist/info/all-markets.d.ts.map +1 -0
  70. package/dist/info/all-markets.js +272 -0
  71. package/dist/info/candles.d.ts +3 -0
  72. package/dist/info/candles.d.ts.map +1 -0
  73. package/dist/info/candles.js +120 -0
  74. package/dist/info/fees.d.ts +3 -0
  75. package/dist/info/fees.d.ts.map +1 -0
  76. package/dist/info/fees.js +87 -0
  77. package/dist/info/fills.d.ts +3 -0
  78. package/dist/info/fills.d.ts.map +1 -0
  79. package/dist/info/fills.js +105 -0
  80. package/dist/info/funding-history.d.ts +3 -0
  81. package/dist/info/funding-history.d.ts.map +1 -0
  82. package/dist/info/funding-history.js +98 -0
  83. package/dist/info/funding-scan.d.ts +3 -0
  84. package/dist/info/funding-scan.d.ts.map +1 -0
  85. package/dist/info/funding-scan.js +178 -0
  86. package/dist/info/funding.d.ts +3 -0
  87. package/dist/info/funding.d.ts.map +1 -0
  88. package/dist/info/funding.js +158 -0
  89. package/dist/info/markets.d.ts +3 -0
  90. package/dist/info/markets.d.ts.map +1 -0
  91. package/dist/info/markets.js +178 -0
  92. package/dist/info/order-status.d.ts +3 -0
  93. package/dist/info/order-status.d.ts.map +1 -0
  94. package/dist/info/order-status.js +85 -0
  95. package/dist/info/orders.d.ts +3 -0
  96. package/dist/info/orders.d.ts.map +1 -0
  97. package/dist/info/orders.js +162 -0
  98. package/dist/info/outcomes.d.ts +3 -0
  99. package/dist/info/outcomes.d.ts.map +1 -0
  100. package/dist/info/outcomes.js +175 -0
  101. package/dist/info/positions.d.ts +3 -0
  102. package/dist/info/positions.d.ts.map +1 -0
  103. package/dist/info/positions.js +127 -0
  104. package/dist/info/rate-limit.d.ts +3 -0
  105. package/dist/info/rate-limit.d.ts.map +1 -0
  106. package/dist/info/rate-limit.js +58 -0
  107. package/dist/info/search-markets.d.ts +3 -0
  108. package/dist/info/search-markets.d.ts.map +1 -0
  109. package/dist/info/search-markets.js +296 -0
  110. package/dist/info/spot.d.ts +3 -0
  111. package/dist/info/spot.d.ts.map +1 -0
  112. package/dist/info/spot.js +192 -0
  113. package/dist/info/trades.d.ts +3 -0
  114. package/dist/info/trades.d.ts.map +1 -0
  115. package/dist/info/trades.js +97 -0
  116. package/dist/lib.d.ts +14 -0
  117. package/dist/lib.d.ts.map +1 -0
  118. package/dist/lib.js +17 -0
  119. package/dist/operations/bracket.d.ts +28 -0
  120. package/dist/operations/bracket.d.ts.map +1 -0
  121. package/dist/operations/bracket.js +266 -0
  122. package/dist/operations/cancel.d.ts +3 -0
  123. package/dist/operations/cancel.d.ts.map +1 -0
  124. package/dist/operations/cancel.js +107 -0
  125. package/dist/operations/chase.d.ts +25 -0
  126. package/dist/operations/chase.d.ts.map +1 -0
  127. package/dist/operations/chase.js +215 -0
  128. package/dist/operations/limit-order.d.ts +3 -0
  129. package/dist/operations/limit-order.d.ts.map +1 -0
  130. package/dist/operations/limit-order.js +144 -0
  131. package/dist/operations/market-order.d.ts +3 -0
  132. package/dist/operations/market-order.d.ts.map +1 -0
  133. package/dist/operations/market-order.js +153 -0
  134. package/dist/operations/outcome-order.d.ts +3 -0
  135. package/dist/operations/outcome-order.d.ts.map +1 -0
  136. package/dist/operations/outcome-order.js +171 -0
  137. package/dist/operations/scale.d.ts +3 -0
  138. package/dist/operations/scale.d.ts.map +1 -0
  139. package/dist/operations/scale.js +212 -0
  140. package/dist/operations/set-tpsl.d.ts +3 -0
  141. package/dist/operations/set-tpsl.d.ts.map +1 -0
  142. package/dist/operations/set-tpsl.js +277 -0
  143. package/dist/operations/spot-order.d.ts +3 -0
  144. package/dist/operations/spot-order.d.ts.map +1 -0
  145. package/dist/operations/spot-order.js +173 -0
  146. package/dist/operations/trigger-order.d.ts +3 -0
  147. package/dist/operations/trigger-order.d.ts.map +1 -0
  148. package/dist/operations/trigger-order.js +177 -0
  149. package/dist/operations/twap-cancel.d.ts +3 -0
  150. package/dist/operations/twap-cancel.d.ts.map +1 -0
  151. package/dist/operations/twap-cancel.js +57 -0
  152. package/dist/operations/twap-status.d.ts +3 -0
  153. package/dist/operations/twap-status.d.ts.map +1 -0
  154. package/dist/operations/twap-status.js +81 -0
  155. package/dist/operations/twap.d.ts +3 -0
  156. package/dist/operations/twap.d.ts.map +1 -0
  157. package/dist/operations/twap.js +124 -0
  158. package/dist/setup/approve-builder.d.ts +3 -0
  159. package/dist/setup/approve-builder.d.ts.map +1 -0
  160. package/dist/setup/approve-builder.js +155 -0
  161. package/dist/setup/env.d.ts +4 -0
  162. package/dist/setup/env.d.ts.map +1 -0
  163. package/dist/setup/env.js +8 -0
  164. package/dist/setup/onboard.d.ts +10 -0
  165. package/dist/setup/onboard.d.ts.map +1 -0
  166. package/dist/setup/onboard.js +462 -0
  167. package/package.json +10 -4
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to Open Broker will be documented in this file.
4
4
 
5
+ ## [1.4.0] - 2026-05-31
6
+
7
+ ### Fixed
8
+ - **Library is now runtime-importable by external consumers.** The package entry
9
+ previously pointed at raw TypeScript source (`main: ./scripts/lib.ts`), so any
10
+ in-process consumer running outside a TS loader (or under a runner that doesn't
11
+ transpile `node_modules`, e.g. tsx) imported an **empty module**. Added a build
12
+ (`npm run build` → `tsc`) that emits compiled JS + type declarations to `dist/`,
13
+ and pointed `main`/`types`/`exports` at `dist/lib.js` / `dist/lib.d.ts`. The CLI
14
+ still runs from source via tsx; only the library entry changed. `prepublishOnly`
15
+ now builds before publishing. No public API changes.
16
+
5
17
  ## [1.3.0] - 2026-05-07
6
18
 
7
19
  ### Added
@@ -0,0 +1,57 @@
1
+ export interface AutomationAuditSink {
2
+ readonly runId: string;
3
+ readonly dbPath: string;
4
+ recordLog(level: 'info' | 'warn' | 'error' | 'debug', message: string, timestamp?: number): void;
5
+ recordEvent(eventType: string, source: 'poll' | 'ws' | 'manual', payload: unknown, timestamp?: number): void;
6
+ recordAction(args: {
7
+ actionId?: string;
8
+ phase: 'request' | 'response' | 'error';
9
+ method: string;
10
+ payload?: unknown;
11
+ result?: unknown;
12
+ error?: unknown;
13
+ dryRun?: boolean;
14
+ timestamp?: number;
15
+ }): void;
16
+ recordSnapshot(snapshot: {
17
+ pollCount: number;
18
+ equity: number;
19
+ marginUsed: number;
20
+ marginUsedPct: number;
21
+ positions: unknown[];
22
+ timestamp?: number;
23
+ }): void;
24
+ recordOrderUpdate(payload: unknown, timestamp?: number): void;
25
+ recordFill(payload: unknown, timestamp?: number): void;
26
+ recordUserEvent(payload: unknown, timestamp?: number): void;
27
+ recordStateChange(op: 'set' | 'delete' | 'clear', key: string | null, value?: unknown, timestamp?: number): void;
28
+ recordPublish(message: string, options: unknown, delivered: boolean, timestamp?: number): void;
29
+ recordError(stage: string, error: unknown, timestamp?: number): void;
30
+ recordNote(kind: string, payload?: unknown, timestamp?: number): void;
31
+ recordMetric(name: string, value: number, tags?: Record<string, unknown>, timestamp?: number): void;
32
+ stop(args: {
33
+ status: 'stopped' | 'error';
34
+ stopReason: string;
35
+ pollCount: number;
36
+ eventsEmitted: number;
37
+ timestamp?: number;
38
+ }): Promise<void>;
39
+ }
40
+ export interface AuditStartOptions {
41
+ automationId: string;
42
+ scriptPath: string;
43
+ dryRun: boolean;
44
+ verbose: boolean;
45
+ pollIntervalMs: number;
46
+ useWebSocket: boolean;
47
+ accountAddress: string;
48
+ walletAddress: string;
49
+ isApiWallet: boolean;
50
+ initialState?: Record<string, unknown>;
51
+ persistedState?: Record<string, unknown>;
52
+ }
53
+ export declare const AUDIT_DB_PATH: string;
54
+ export declare const AUDIT_SOCKET_PATH: string;
55
+ export declare function toSerializable<T = unknown>(value: T): T;
56
+ export declare function createAutomationAudit(options: AuditStartOptions): AutomationAuditSink;
57
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../scripts/auto/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,407 @@
1
+ import { spawn } from 'child_process';
2
+ import { randomUUID } from 'crypto';
3
+ import { once } from 'events';
4
+ import net from 'net';
5
+ import path from 'path';
6
+ import readline from 'readline';
7
+ import { setTimeout as delay } from 'timers/promises';
8
+ import { fileURLToPath } from 'url';
9
+ import { ensureConfigDir } from '../core/config.js';
10
+ export const AUDIT_DB_PATH = process.env.OPENBROKER_AUDIT_DB_PATH
11
+ || path.join(ensureConfigDir(), 'automation-audit.sqlite');
12
+ export const AUDIT_SOCKET_PATH = process.env.OPENBROKER_AUDIT_SOCKET_PATH
13
+ || (process.platform === 'win32'
14
+ ? '\\\\.\\pipe\\openbroker-automation-audit-v2'
15
+ : path.join(ensureConfigDir(), 'automation-audit.v2.sock'));
16
+ function internalWarn(automationId, message) {
17
+ console.error(`[auto:${automationId}:audit] ${message}`);
18
+ }
19
+ export function toSerializable(value) {
20
+ const seen = new WeakSet();
21
+ const encoded = JSON.stringify(value, (_key, currentValue) => {
22
+ if (typeof currentValue === 'bigint') {
23
+ return currentValue.toString();
24
+ }
25
+ if (currentValue instanceof Error) {
26
+ return {
27
+ name: currentValue.name,
28
+ message: currentValue.message,
29
+ stack: currentValue.stack,
30
+ };
31
+ }
32
+ if (currentValue instanceof Map) {
33
+ return Object.fromEntries(currentValue.entries());
34
+ }
35
+ if (currentValue instanceof Set) {
36
+ return [...currentValue.values()];
37
+ }
38
+ if (typeof currentValue === 'object' && currentValue !== null) {
39
+ if (seen.has(currentValue)) {
40
+ return '[Circular]';
41
+ }
42
+ seen.add(currentValue);
43
+ }
44
+ return currentValue;
45
+ });
46
+ if (encoded === undefined) {
47
+ return null;
48
+ }
49
+ return JSON.parse(encoded);
50
+ }
51
+ class NoopAuditSink {
52
+ runId = randomUUID();
53
+ dbPath = AUDIT_DB_PATH;
54
+ recordLog() { }
55
+ recordEvent() { }
56
+ recordAction() { }
57
+ recordSnapshot() { }
58
+ recordOrderUpdate() { }
59
+ recordFill() { }
60
+ recordUserEvent() { }
61
+ recordStateChange() { }
62
+ recordPublish() { }
63
+ recordError() { }
64
+ recordNote() { }
65
+ recordMetric() { }
66
+ async stop() { }
67
+ }
68
+ class DaemonAuditSink {
69
+ automationId;
70
+ runId = randomUUID();
71
+ dbPath = AUDIT_DB_PATH;
72
+ socketPath = AUDIT_SOCKET_PATH;
73
+ socket = null;
74
+ lineReader = null;
75
+ connectPromise = null;
76
+ flushPromise = null;
77
+ closed = false;
78
+ daemonSpawnedAt = 0;
79
+ pendingQueue = [];
80
+ inFlight = new Map();
81
+ ackWaiters = new Map();
82
+ constructor(automationId, options) {
83
+ this.automationId = automationId;
84
+ this.enqueue({
85
+ type: 'init',
86
+ payload: {
87
+ runId: this.runId,
88
+ automationId: options.automationId,
89
+ scriptPath: options.scriptPath,
90
+ dryRun: options.dryRun,
91
+ verbose: options.verbose,
92
+ pollIntervalMs: options.pollIntervalMs,
93
+ useWebSocket: options.useWebSocket,
94
+ accountAddress: options.accountAddress,
95
+ walletAddress: options.walletAddress,
96
+ isApiWallet: options.isApiWallet,
97
+ initialState: toSerializable(options.initialState ?? {}),
98
+ persistedState: toSerializable(options.persistedState ?? {}),
99
+ pid: process.pid,
100
+ startedAt: Date.now(),
101
+ },
102
+ });
103
+ }
104
+ handleSocketClose() {
105
+ if (this.lineReader) {
106
+ this.lineReader.close();
107
+ this.lineReader = null;
108
+ }
109
+ const inflight = [...this.inFlight.values()];
110
+ this.inFlight.clear();
111
+ if (inflight.length > 0) {
112
+ this.pendingQueue = inflight.concat(this.pendingQueue);
113
+ }
114
+ this.socket = null;
115
+ if (!this.closed) {
116
+ void this.ensureConnected();
117
+ }
118
+ }
119
+ handleResponse(line) {
120
+ let response;
121
+ try {
122
+ response = JSON.parse(line);
123
+ }
124
+ catch (error) {
125
+ internalWarn(this.automationId, `failed to parse audit daemon response: ${error instanceof Error ? error.message : String(error)}`);
126
+ return;
127
+ }
128
+ this.inFlight.delete(response.messageId);
129
+ const waiter = this.ackWaiters.get(response.messageId);
130
+ if (!waiter)
131
+ return;
132
+ this.ackWaiters.delete(response.messageId);
133
+ if (response.ok) {
134
+ waiter.resolve();
135
+ }
136
+ else {
137
+ waiter.reject(new Error(response.error || 'audit daemon returned an error'));
138
+ }
139
+ }
140
+ async openConnection() {
141
+ const socket = net.createConnection(this.socketPath);
142
+ await new Promise((resolve, reject) => {
143
+ let settled = false;
144
+ const onConnect = () => {
145
+ if (settled)
146
+ return;
147
+ settled = true;
148
+ socket.off('error', onError);
149
+ resolve();
150
+ };
151
+ const onError = (error) => {
152
+ if (settled)
153
+ return;
154
+ settled = true;
155
+ socket.off('connect', onConnect);
156
+ socket.destroy();
157
+ reject(error);
158
+ };
159
+ socket.once('connect', onConnect);
160
+ socket.once('error', onError);
161
+ });
162
+ socket.setEncoding('utf8');
163
+ socket.on('close', () => this.handleSocketClose());
164
+ socket.on('error', (error) => {
165
+ if (!this.closed) {
166
+ internalWarn(this.automationId, `audit socket error: ${error.message}`);
167
+ }
168
+ });
169
+ this.lineReader = readline.createInterface({
170
+ input: socket,
171
+ crlfDelay: Infinity,
172
+ });
173
+ this.lineReader.on('line', (line) => this.handleResponse(line));
174
+ this.socket = socket;
175
+ }
176
+ async spawnDaemon() {
177
+ const now = Date.now();
178
+ if (now - this.daemonSpawnedAt < 1_000)
179
+ return;
180
+ this.daemonSpawnedAt = now;
181
+ const daemonPath = fileURLToPath(new URL('./audit-daemon.js', import.meta.url));
182
+ const child = spawn(process.execPath, ['--no-warnings', '--experimental-sqlite', daemonPath, this.dbPath, this.socketPath], {
183
+ detached: true,
184
+ stdio: 'ignore',
185
+ env: { ...process.env },
186
+ });
187
+ child.unref();
188
+ }
189
+ async ensureConnected() {
190
+ if (this.closed)
191
+ return;
192
+ if (this.socket && !this.socket.destroyed)
193
+ return;
194
+ if (this.connectPromise)
195
+ return this.connectPromise;
196
+ this.connectPromise = (async () => {
197
+ try {
198
+ await this.openConnection();
199
+ }
200
+ catch {
201
+ await this.spawnDaemon();
202
+ let lastError = null;
203
+ for (let attempt = 0; attempt < 30 && !this.closed; attempt++) {
204
+ try {
205
+ await delay(100 + (attempt * 50));
206
+ await this.openConnection();
207
+ lastError = null;
208
+ break;
209
+ }
210
+ catch (error) {
211
+ lastError = error instanceof Error ? error : new Error(String(error));
212
+ }
213
+ }
214
+ if (lastError) {
215
+ throw lastError;
216
+ }
217
+ }
218
+ await this.flushQueue();
219
+ })().catch((error) => {
220
+ internalWarn(this.automationId, `audit daemon unavailable: ${error instanceof Error ? error.message : String(error)}`);
221
+ }).finally(() => {
222
+ this.connectPromise = null;
223
+ });
224
+ return this.connectPromise;
225
+ }
226
+ enqueue(message) {
227
+ const payload = message.type === 'init'
228
+ ? message.payload
229
+ : { runId: this.runId, ...message.payload };
230
+ const wire = {
231
+ messageId: randomUUID(),
232
+ type: message.type,
233
+ payload,
234
+ };
235
+ this.pendingQueue.push(wire);
236
+ void this.ensureConnected();
237
+ if (this.socket && !this.socket.destroyed) {
238
+ void this.flushQueue();
239
+ }
240
+ return wire;
241
+ }
242
+ async flushQueue() {
243
+ if (this.flushPromise)
244
+ return this.flushPromise;
245
+ this.flushPromise = (async () => {
246
+ while (!this.closed && this.socket && !this.socket.destroyed && this.pendingQueue.length > 0) {
247
+ const message = this.pendingQueue.shift();
248
+ this.inFlight.set(message.messageId, message);
249
+ const line = `${JSON.stringify(message)}\n`;
250
+ const writable = this.socket.write(line);
251
+ if (!writable && this.socket) {
252
+ await once(this.socket, 'drain');
253
+ }
254
+ }
255
+ })().finally(() => {
256
+ this.flushPromise = null;
257
+ });
258
+ return this.flushPromise;
259
+ }
260
+ send(message, waitForAck = false) {
261
+ if (this.closed)
262
+ return Promise.resolve();
263
+ const wire = this.enqueue(message);
264
+ if (!waitForAck)
265
+ return Promise.resolve();
266
+ return new Promise((resolve, reject) => {
267
+ this.ackWaiters.set(wire.messageId, { resolve, reject });
268
+ void this.flushQueue();
269
+ });
270
+ }
271
+ recordLog(level, message, timestamp = Date.now()) {
272
+ void this.send({ type: 'log', payload: { timestamp, level, message } });
273
+ }
274
+ recordEvent(eventType, source, payload, timestamp = Date.now()) {
275
+ void this.send({ type: 'event', payload: { timestamp, eventType, source, payload: toSerializable(payload) } });
276
+ }
277
+ recordAction(args) {
278
+ void this.send({
279
+ type: 'action',
280
+ payload: {
281
+ timestamp: args.timestamp ?? Date.now(),
282
+ actionId: args.actionId ?? randomUUID(),
283
+ phase: args.phase,
284
+ method: args.method,
285
+ payload: toSerializable(args.payload),
286
+ result: toSerializable(args.result),
287
+ error: toSerializable(args.error),
288
+ dryRun: args.dryRun ?? false,
289
+ },
290
+ });
291
+ }
292
+ recordSnapshot(snapshot) {
293
+ void this.send({
294
+ type: 'snapshot',
295
+ payload: {
296
+ timestamp: snapshot.timestamp ?? Date.now(),
297
+ pollCount: snapshot.pollCount,
298
+ equity: snapshot.equity,
299
+ marginUsed: snapshot.marginUsed,
300
+ marginUsedPct: snapshot.marginUsedPct,
301
+ positions: toSerializable(snapshot.positions),
302
+ },
303
+ });
304
+ }
305
+ recordOrderUpdate(payload, timestamp = Date.now()) {
306
+ void this.send({ type: 'order_update', payload: { timestamp, payload: toSerializable(payload) } });
307
+ }
308
+ recordFill(payload, timestamp = Date.now()) {
309
+ void this.send({ type: 'fill', payload: { timestamp, payload: toSerializable(payload) } });
310
+ }
311
+ recordUserEvent(payload, timestamp = Date.now()) {
312
+ void this.send({ type: 'user_event', payload: { timestamp, payload: toSerializable(payload) } });
313
+ }
314
+ recordStateChange(op, key, value, timestamp = Date.now()) {
315
+ void this.send({
316
+ type: 'state_change',
317
+ payload: {
318
+ timestamp,
319
+ op,
320
+ key,
321
+ value: toSerializable(value),
322
+ },
323
+ });
324
+ }
325
+ recordPublish(message, options, delivered, timestamp = Date.now()) {
326
+ void this.send({
327
+ type: 'publish',
328
+ payload: {
329
+ timestamp,
330
+ message,
331
+ options: toSerializable(options),
332
+ delivered,
333
+ },
334
+ });
335
+ }
336
+ recordError(stage, error, timestamp = Date.now()) {
337
+ void this.send({
338
+ type: 'error',
339
+ payload: {
340
+ timestamp,
341
+ stage,
342
+ error: toSerializable(error),
343
+ },
344
+ });
345
+ }
346
+ recordNote(kind, payload, timestamp = Date.now()) {
347
+ void this.send({
348
+ type: 'note',
349
+ payload: {
350
+ timestamp,
351
+ kind,
352
+ payload: toSerializable(payload),
353
+ },
354
+ });
355
+ }
356
+ recordMetric(name, value, tags, timestamp = Date.now()) {
357
+ void this.send({
358
+ type: 'metric',
359
+ payload: {
360
+ timestamp,
361
+ name,
362
+ value,
363
+ tags: toSerializable(tags ?? {}),
364
+ },
365
+ });
366
+ }
367
+ async stop(args) {
368
+ if (this.closed)
369
+ return;
370
+ try {
371
+ await this.send({
372
+ type: 'stop',
373
+ payload: {
374
+ timestamp: args.timestamp ?? Date.now(),
375
+ status: args.status,
376
+ stopReason: args.stopReason,
377
+ pollCount: args.pollCount,
378
+ eventsEmitted: args.eventsEmitted,
379
+ },
380
+ }, true);
381
+ }
382
+ catch (error) {
383
+ internalWarn(this.automationId, `failed to flush stop audit message: ${error instanceof Error ? error.message : String(error)}`);
384
+ }
385
+ this.closed = true;
386
+ if (this.lineReader) {
387
+ this.lineReader.close();
388
+ this.lineReader = null;
389
+ }
390
+ if (this.socket && !this.socket.destroyed) {
391
+ this.socket.end();
392
+ }
393
+ this.socket = null;
394
+ this.pendingQueue = [];
395
+ this.inFlight.clear();
396
+ this.ackWaiters.clear();
397
+ }
398
+ }
399
+ export function createAutomationAudit(options) {
400
+ try {
401
+ return new DaemonAuditSink(options.automationId, options);
402
+ }
403
+ catch (error) {
404
+ internalWarn(options.automationId, `audit disabled: ${error instanceof Error ? error.message : String(error)}`);
405
+ return new NoopAuditSink();
406
+ }
407
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../scripts/auto/cli.ts"],"names":[],"mappings":""}