@tradejs/cli 3.1.16 → 3.1.17-beta.231

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.
@@ -48,6 +48,166 @@ var import_node_util = require("util");
48
48
  var import_node_crypto = require("crypto");
49
49
  var import_promises = __toESM(require("fs/promises"));
50
50
  var import_node_path = __toESM(require("path"));
51
+
52
+ // src/lib/runtimeEvidenceDeployment.ts
53
+ var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
54
+ var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
55
+ var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
56
+ var isPackageVersionMap = (value) => isRecord(value) && Object.keys(value).length > 0 && Object.entries(value).every(
57
+ ([name, version]) => name.startsWith("@tradejs/") && isNonEmptyString(version)
58
+ );
59
+ var INTERVALS = /* @__PURE__ */ new Set([
60
+ "1",
61
+ "3",
62
+ "5",
63
+ "15",
64
+ "30",
65
+ "60",
66
+ "120",
67
+ "240",
68
+ "360",
69
+ "720",
70
+ "D",
71
+ "W",
72
+ "M"
73
+ ]);
74
+ var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
75
+ var isRuntimeStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => key === "tickers") && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every((ticker) => isNonEmptyString(ticker));
76
+ var samePackageVersions = (left, right) => {
77
+ if (!left || !right) return false;
78
+ const leftEntries = Object.entries(left).sort(
79
+ ([a], [b]) => a.localeCompare(b)
80
+ );
81
+ const rightEntries = Object.entries(right).sort(
82
+ ([a], [b]) => a.localeCompare(b)
83
+ );
84
+ return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
85
+ };
86
+ var runtimeLineageMatchesStrategySnapshot = ({
87
+ lineage,
88
+ deployment,
89
+ strategy
90
+ }) => lineage?.schemaVersion === 3 && lineage.strategyRevision === strategy.strategyRevision && lineage.deploymentCompositionId === deployment.deploymentCompositionId && lineage.strategyPackageVersion === strategy.strategyPackageVersion && lineage.runtimePackageVersion === strategy.runtimePackageVersion && samePackageVersions(
91
+ lineage.strategyDependencyVersions,
92
+ strategy.strategyDependencyVersions
93
+ );
94
+ var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
95
+ if (!isRecord(value) || value.schemaVersion !== 2 || !isNonEmptyString(value.id) || !isNonEmptyString(value.deploymentCompositionId) || !/^dc1:[a-f0-9]{16}$/.test(value.deploymentCompositionId) || !isNonEmptyString(value.label) || !isNonEmptyString(value.connectorName) || !isNonEmptyString(value.provider) || !isNonEmptyString(value.accountId) || typeof value.enabled !== "boolean" || !Array.isArray(value.strategies)) {
96
+ throw new Error(
97
+ "Runtime evidence deployment snapshot is missing or invalid"
98
+ );
99
+ }
100
+ const strategies = value.strategies.map((candidate) => {
101
+ if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !isNonEmptyString(candidate.strategyRevision) || !/^sr1:[a-f0-9]{16}$/.test(candidate.strategyRevision) || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isPackageVersionMap(candidate.strategyDependencyVersions) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig) || !isRuntimeStrategySelection(candidate.selection)) {
102
+ throw new Error(
103
+ "Runtime evidence deployment strategy snapshot is invalid"
104
+ );
105
+ }
106
+ if (String(candidate.strategyConfig.INTERVAL) !== String(candidate.interval) || String(candidate.strategyConfig.UNIVERSE) !== String(candidate.universe)) {
107
+ throw new Error(
108
+ `Runtime evidence strategy config does not match its scope: ${candidate.strategyName}`
109
+ );
110
+ }
111
+ if (candidate.accountId != null && (!isNonEmptyString(candidate.accountId) || candidate.accountId !== value.accountId)) {
112
+ throw new Error(
113
+ `Runtime evidence strategy account does not match deployment: ${candidate.strategyName}`
114
+ );
115
+ }
116
+ return candidate;
117
+ });
118
+ const identities = /* @__PURE__ */ new Set();
119
+ for (const strategy of strategies) {
120
+ if (identities.has(strategy.strategyName)) {
121
+ throw new Error(
122
+ `Duplicate runtime evidence strategy: ${strategy.strategyName}`
123
+ );
124
+ }
125
+ identities.add(strategy.strategyName);
126
+ }
127
+ return {
128
+ ...value,
129
+ strategies
130
+ };
131
+ };
132
+ var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
133
+ var unwrapRuntimeEvidenceRows = (value, field) => (Array.isArray(value) ? value : []).map((candidate) => {
134
+ const record = isRecord(candidate) ? candidate : null;
135
+ const nested = record && isRecord(record[field]) ? record[field] : null;
136
+ return nested ?? record;
137
+ }).filter((record) => record != null);
138
+ var assertCurrentRuntimeEvidenceArtifact = (artifact) => {
139
+ if (!isRecord(artifact) || artifact.reportType !== "runtime-evidence") {
140
+ throw new Error("Invalid runtime evidence artifact");
141
+ }
142
+ const deployment = parseRuntimeEvidenceDeploymentSnapshot(
143
+ artifact.deployment
144
+ );
145
+ const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
146
+ if (activeStrategies.length === 0) {
147
+ throw new Error("Runtime evidence deployment has no enabled strategies");
148
+ }
149
+ const runtime = isRecord(artifact.runtime) ? artifact.runtime : null;
150
+ if (!runtime) {
151
+ throw new Error("Runtime evidence payload is missing");
152
+ }
153
+ if ("strategyConfigs" in runtime) {
154
+ throw new Error(
155
+ "Runtime evidence payload contains removed strategyConfigs data"
156
+ );
157
+ }
158
+ const rowFields = [
159
+ "trades",
160
+ "signals",
161
+ "evaluations",
162
+ "lineageScopes"
163
+ ];
164
+ for (const field of rowFields) {
165
+ if (!Array.isArray(runtime[field])) {
166
+ throw new Error(`Runtime evidence payload ${field} must be an array`);
167
+ }
168
+ }
169
+ const snapshots = new Map(
170
+ activeStrategies.map((strategy) => [strategy.strategyName, strategy])
171
+ );
172
+ const assertRows = (label, rows, lineageField) => {
173
+ for (const row of rows) {
174
+ const strategyName = String(row.strategy ?? "").trim();
175
+ const strategy = snapshots.get(strategyName);
176
+ if (!strategy || row.deploymentId !== deployment.id || row.accountId !== deployment.accountId || !runtimeLineageMatchesStrategySnapshot({
177
+ lineage: isRecord(row[lineageField]) ? row[lineageField] : void 0,
178
+ deployment,
179
+ strategy
180
+ })) {
181
+ throw new Error(
182
+ `Runtime evidence ${label} row is outside the current embedded deployment lineage`
183
+ );
184
+ }
185
+ }
186
+ };
187
+ assertRows(
188
+ "trade",
189
+ unwrapRuntimeEvidenceRows(runtime.trades, "trade"),
190
+ "runtimeLineage"
191
+ );
192
+ assertRows(
193
+ "signal",
194
+ unwrapRuntimeEvidenceRows(runtime.signals, "signal"),
195
+ "runtimeLineage"
196
+ );
197
+ assertRows(
198
+ "evaluation",
199
+ unwrapRuntimeEvidenceRows(runtime.evaluations, "evaluation"),
200
+ "runtimeLineage"
201
+ );
202
+ assertRows(
203
+ "lineage scope",
204
+ unwrapRuntimeEvidenceRows(runtime.lineageScopes, "lineageScope"),
205
+ "lineage"
206
+ );
207
+ return deployment;
208
+ };
209
+
210
+ // src/lib/runtimeEvidenceArtifacts.ts
51
211
  var RUNTIME_EVIDENCE_MANIFEST_FILE = "manifest.json";
52
212
  var RUNTIME_EVIDENCE_PAYLOAD_FILE = "runtime-evidence.json";
53
213
  var RUNTIME_EVIDENCE_COMPLETE_FILE = ".complete";
@@ -117,6 +277,10 @@ var verifyRuntimeEvidenceBundle = async (bundleDir) => {
117
277
  if (artifact?.reportType !== "runtime-evidence" || artifactWindow?.startTime !== manifest.window.startTime || artifactWindow.endTime !== manifest.window.endTime) {
118
278
  throw new Error(`Runtime evidence payload mismatch in ${bundleDir}`);
119
279
  }
280
+ const deployment = assertCurrentRuntimeEvidenceArtifact(artifact);
281
+ if (deployment.id !== manifest.deploymentId) {
282
+ throw new Error(`Runtime evidence deployment mismatch in ${bundleDir}`);
283
+ }
120
284
  return {
121
285
  bundleDir,
122
286
  manifestPath,
@@ -151,70 +315,6 @@ var discoverRuntimeEvidenceBundles = async (rootDir) => {
151
315
  return bundles.sort();
152
316
  };
153
317
 
154
- // src/lib/runtimeEvidenceDeployment.ts
155
- var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
156
- var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
157
- var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
158
- var isPackageVersionMap = (value) => isRecord(value) && Object.keys(value).length > 0 && Object.entries(value).every(
159
- ([name, version]) => name.startsWith("@tradejs/") && isNonEmptyString(version)
160
- );
161
- var INTERVALS = /* @__PURE__ */ new Set([
162
- "1",
163
- "3",
164
- "5",
165
- "15",
166
- "30",
167
- "60",
168
- "120",
169
- "240",
170
- "360",
171
- "720",
172
- "D",
173
- "W",
174
- "M"
175
- ]);
176
- var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
177
- var isRuntimeStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => key === "tickers") && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every((ticker) => isNonEmptyString(ticker));
178
- var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
179
- if (!isRecord(value) || value.schemaVersion !== 2 || !isNonEmptyString(value.id) || !isNonEmptyString(value.deploymentCompositionId) || !/^dc1:[a-f0-9]{16}$/.test(value.deploymentCompositionId) || !isNonEmptyString(value.label) || !isNonEmptyString(value.connectorName) || !isNonEmptyString(value.provider) || !isNonEmptyString(value.accountId) || typeof value.enabled !== "boolean" || !Array.isArray(value.strategies)) {
180
- throw new Error(
181
- "Runtime evidence deployment snapshot is missing or invalid"
182
- );
183
- }
184
- const strategies = value.strategies.map((candidate) => {
185
- if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !isNonEmptyString(candidate.strategyRevision) || !/^sr1:[a-f0-9]{16}$/.test(candidate.strategyRevision) || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isPackageVersionMap(candidate.strategyDependencyVersions) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig) || !isRuntimeStrategySelection(candidate.selection)) {
186
- throw new Error(
187
- "Runtime evidence deployment strategy snapshot is invalid"
188
- );
189
- }
190
- if (String(candidate.strategyConfig.INTERVAL) !== String(candidate.interval) || String(candidate.strategyConfig.UNIVERSE) !== String(candidate.universe)) {
191
- throw new Error(
192
- `Runtime evidence strategy config does not match its scope: ${candidate.strategyName}`
193
- );
194
- }
195
- if (candidate.accountId != null && (!isNonEmptyString(candidate.accountId) || candidate.accountId !== value.accountId)) {
196
- throw new Error(
197
- `Runtime evidence strategy account does not match deployment: ${candidate.strategyName}`
198
- );
199
- }
200
- return candidate;
201
- });
202
- const identities = /* @__PURE__ */ new Set();
203
- for (const strategy of strategies) {
204
- if (identities.has(strategy.strategyName)) {
205
- throw new Error(
206
- `Duplicate runtime evidence strategy: ${strategy.strategyName}`
207
- );
208
- }
209
- identities.add(strategy.strategyName);
210
- }
211
- return {
212
- ...value,
213
- strategies
214
- };
215
- };
216
- var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
217
-
218
318
  // src/lib/runtimeEvidenceSync.ts
219
319
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
220
320
  var isExistingDestinationError = (error) => {
@@ -248,25 +348,7 @@ var buildRuntimeEvidenceRsyncArgs = ({
248
348
  ];
249
349
  var receiptPath = (receiptsRoot, artifactId) => import_node_path2.default.join(receiptsRoot, `${safeSegment(artifactId, "artifact")}.json`);
250
350
  var compareBundles = (left, right) => left.manifest.window.endTime - right.manifest.window.endTime || left.manifest.createdAt - right.manifest.createdAt;
251
- var inspectRuntimeEvidenceBundleSupport = (bundle) => {
252
- try {
253
- const deployment = parseRuntimeEvidenceDeploymentSnapshot(
254
- bundle.artifact.deployment
255
- );
256
- if (activeRuntimeEvidenceStrategies(deployment).length === 0) {
257
- throw new Error(
258
- "Runtime evidence deployment has no enabled active strategies"
259
- );
260
- }
261
- return { supported: true };
262
- } catch (error) {
263
- return {
264
- supported: false,
265
- reason: error instanceof Error ? error.message : String(error)
266
- };
267
- }
268
- };
269
- var listRuntimeEvidenceBundleStatuses = async ({
351
+ var listPendingRuntimeEvidenceBundles = async ({
270
352
  evidenceRoot,
271
353
  deploymentId
272
354
  }) => {
@@ -275,29 +357,19 @@ var listRuntimeEvidenceBundleStatuses = async ({
275
357
  const receiptsRoot = import_node_path2.default.join(evidenceRoot, "receipts", safeDeploymentId);
276
358
  const bundles = await discoverRuntimeEvidenceBundles(artifactsRoot);
277
359
  const pending = [];
278
- const unsupported = [];
279
360
  for (const bundleDir of bundles) {
280
361
  const verified = await verifyRuntimeEvidenceBundle(bundleDir);
281
362
  if (verified.manifest.deploymentId !== safeDeploymentId) continue;
363
+ assertCurrentRuntimeEvidenceArtifact(verified.artifact);
282
364
  try {
283
365
  await import_promises2.default.access(receiptPath(receiptsRoot, verified.manifest.artifactId));
284
366
  continue;
285
367
  } catch (error) {
286
368
  if (error.code !== "ENOENT") throw error;
287
369
  }
288
- const support = inspectRuntimeEvidenceBundleSupport(verified);
289
- if (support.supported) {
290
- pending.push(verified);
291
- } else {
292
- unsupported.push({ bundle: verified, reason: support.reason });
293
- }
370
+ pending.push(verified);
294
371
  }
295
- return {
296
- pending: pending.sort(compareBundles),
297
- unsupported: unsupported.sort(
298
- (left, right) => compareBundles(left.bundle, right.bundle)
299
- )
300
- };
372
+ return pending.sort(compareBundles);
301
373
  };
302
374
  var syncRuntimeEvidenceBundles = async ({
303
375
  source,
@@ -331,6 +403,7 @@ var syncRuntimeEvidenceBundles = async ({
331
403
  `Artifact deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
332
404
  );
333
405
  }
406
+ assertCurrentRuntimeEvidenceArtifact(verified.artifact);
334
407
  const destinationDir = import_node_path2.default.join(
335
408
  artifactsRoot,
336
409
  ...dateParts(verified.manifest.window.endTime),
@@ -351,7 +424,7 @@ var syncRuntimeEvidenceBundles = async ({
351
424
  }
352
425
  received.push(await verifyRuntimeEvidenceBundle(destinationDir));
353
426
  }
354
- const statuses = await listRuntimeEvidenceBundleStatuses({
427
+ const pending = await listPendingRuntimeEvidenceBundles({
355
428
  evidenceRoot,
356
429
  deploymentId: safeDeploymentId
357
430
  });
@@ -360,7 +433,7 @@ var syncRuntimeEvidenceBundles = async ({
360
433
  stdout: String(transfer.stdout ?? ""),
361
434
  stderr: String(transfer.stderr ?? ""),
362
435
  received,
363
- ...statuses
436
+ pending
364
437
  };
365
438
  };
366
439
 
@@ -397,7 +470,7 @@ var runtimeEvidenceSync = async () => {
397
470
  });
398
471
  console.log(
399
472
  import_chalk.default.green(
400
- `Runtime evidence sync completed: received=${result.received.length} pending=${result.pending.length} unsupported=${result.unsupported.length}`
473
+ `Runtime evidence sync completed: received=${result.received.length} pending=${result.pending.length}`
401
474
  )
402
475
  );
403
476
  console.log(
@@ -414,13 +487,6 @@ var runtimeEvidenceSync = async () => {
414
487
  bundleDir: bundle.bundleDir,
415
488
  payloadPath: bundle.payloadPath,
416
489
  window: bundle.manifest.window
417
- })),
418
- unsupported: result.unsupported.map(({ bundle, reason }) => ({
419
- artifactId: bundle.manifest.artifactId,
420
- bundleDir: bundle.bundleDir,
421
- payloadPath: bundle.payloadPath,
422
- window: bundle.manifest.window,
423
- reason
424
490
  }))
425
491
  },
426
492
  null,
@@ -411,9 +411,7 @@ var loadRuntimeTrades = async (userName, {
411
411
  dedupedBucketTrades.set(trade.orderId, trade);
412
412
  }
413
413
  const windowedTrades = [...dedupedBucketTrades.values()].filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
414
- if (windowedTrades.length > 0 || dayKeys.length === 0) {
415
- return windowedTrades;
416
- }
414
+ return windowedTrades;
417
415
  }
418
416
  const tradePrefix = import_redis.redisKeys.runtimeTrades(userName);
419
417
  const bucketPrefix = import_redis.redisKeys.runtimeTradeBuckets(userName);