@tradejs/node 3.1.11 → 3.1.12-beta.218

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.
@@ -30,13 +30,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/runtimeStrategies.ts
31
31
  var runtimeStrategies_exports = {};
32
32
  __export(runtimeStrategies_exports, {
33
+ RUNTIME_PACKAGE_MANIFEST_SCHEMA: () => RUNTIME_PACKAGE_MANIFEST_SCHEMA,
34
+ computeDeploymentCompositionId: () => computeDeploymentCompositionId,
35
+ computeStrategyRevision: () => computeStrategyRevision,
33
36
  getRuntimeDeployment: () => getRuntimeDeployment,
34
37
  getRuntimeStrategyPackageMetadata: () => getRuntimeStrategyPackageMetadata,
35
38
  listRuntimeDeployments: () => listRuntimeDeployments,
36
39
  loadResolvedRuntimeStrategies: () => loadResolvedRuntimeStrategies,
40
+ resolveRuntimeComposition: () => resolveRuntimeComposition,
37
41
  verifyRuntimeDeclaration: () => verifyRuntimeDeclaration
38
42
  });
39
43
  module.exports = __toCommonJS(runtimeStrategies_exports);
44
+ var import_node_crypto4 = require("crypto");
40
45
  var import_promises = require("fs/promises");
41
46
  var import_node_path = __toESM(require("path"));
42
47
  var import_runtimeControls = require("@tradejs/infra/runtimeControls");
@@ -45,10 +50,10 @@ var import_tradingAccounts = require("@tradejs/infra/tradingAccounts");
45
50
  // src/strategyRuntime.ts
46
51
  var import_constants5 = require("@tradejs/core/constants");
47
52
  var import_strategies6 = require("@tradejs/core/strategies");
48
- var import_logger11 = require("@tradejs/infra/logger");
53
+ var import_logger10 = require("@tradejs/infra/logger");
49
54
 
50
55
  // src/strategyHelpers/runtime.ts
51
- var import_logger9 = require("@tradejs/infra/logger");
56
+ var import_logger8 = require("@tradejs/infra/logger");
52
57
  var import_constants3 = require("@tradejs/core/constants");
53
58
  var import_ml2 = require("@tradejs/infra/ml");
54
59
 
@@ -630,7 +635,6 @@ var buildAiMarketContext = (signal) => ({
630
635
 
631
636
  // src/strategy/manifests.ts
632
637
  var import_indicators = require("@tradejs/core/indicators");
633
- var import_logger2 = require("@tradejs/infra/logger");
634
638
 
635
639
  // src/tradejsConfig.ts
636
640
  var import_fs = __toESM(require("fs"));
@@ -983,21 +987,34 @@ var extractIndicatorPluginDefinition = (moduleExport) => {
983
987
  );
984
988
  return indicatorEntries ? { indicatorEntries } : null;
985
989
  };
986
- var registerEntries = (entries, source, state) => {
987
- for (const entry of entries) {
988
- const strategyName = entry.manifest?.name;
989
- if (!strategyName) {
990
- import_logger2.logger.warn("Skip strategy entry without name from %s", source);
991
- continue;
990
+ var validateStrategyEntries = (moduleName, entries, state) => {
991
+ const issues = [];
992
+ const names = /* @__PURE__ */ new Set();
993
+ entries.forEach((entry, index) => {
994
+ const entryPath = `${moduleName}.strategyEntries[${index}]`;
995
+ const strategyName = entry?.manifest?.name;
996
+ if (typeof strategyName !== "string" || !strategyName.trim()) {
997
+ issues.push(`${entryPath}: manifest.name is required`);
998
+ } else if (names.has(strategyName) || state.strategyEntriesMap.has(strategyName)) {
999
+ issues.push(`${entryPath}: duplicate strategy ${strategyName}`);
1000
+ } else {
1001
+ names.add(strategyName);
992
1002
  }
993
- if (state.strategyCreators.has(strategyName)) {
994
- import_logger2.logger.warn(
995
- 'Skip duplicate strategy "%s" from %s: already registered',
996
- strategyName,
997
- source
998
- );
999
- continue;
1003
+ if (!entry || typeof entry !== "object" || !entry.defaults || typeof entry.defaults !== "object" || Array.isArray(entry.defaults)) {
1004
+ issues.push(`${entryPath}: defaults must be an object`);
1005
+ }
1006
+ if (typeof entry?.parseConfig !== "function") {
1007
+ issues.push(`${entryPath}: parseConfig is required`);
1008
+ }
1009
+ if (typeof entry?.createCore !== "function") {
1010
+ issues.push(`${entryPath}: createCore is required`);
1000
1011
  }
1012
+ });
1013
+ return issues;
1014
+ };
1015
+ var registerEntries = (entries, source, state) => {
1016
+ for (const entry of entries) {
1017
+ const strategyName = entry.manifest.name;
1001
1018
  state.strategyManifestsMap.set(strategyName, entry.manifest);
1002
1019
  state.strategyEntriesMap.set(strategyName, entry);
1003
1020
  state.strategySourcesMap.set(strategyName, source);
@@ -1054,6 +1071,7 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
1054
1071
  if (!pluginModuleNames.length) {
1055
1072
  return;
1056
1073
  }
1074
+ const issues = [];
1057
1075
  for (const moduleName of pluginModuleNames) {
1058
1076
  try {
1059
1077
  const resolvedModuleName = resolvePluginModuleSpecifier(
@@ -1067,24 +1085,30 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
1067
1085
  if (strategySet.has(moduleName)) {
1068
1086
  const pluginDefinition = extractStrategyPluginDefinition(moduleExport);
1069
1087
  if (!pluginDefinition) {
1070
- import_logger2.logger.warn(
1071
- 'Skip strategy plugin "%s": export { strategyEntries } is missing',
1072
- moduleName
1088
+ issues.push(
1089
+ `${moduleName}: export { strategyEntries } is missing`
1073
1090
  );
1074
1091
  } else {
1075
- registerEntries(
1076
- pluginDefinition.strategyEntries,
1092
+ const entryIssues = validateStrategyEntries(
1077
1093
  moduleName,
1094
+ pluginDefinition.strategyEntries,
1078
1095
  state
1079
1096
  );
1097
+ issues.push(...entryIssues);
1098
+ if (entryIssues.length === 0) {
1099
+ registerEntries(
1100
+ pluginDefinition.strategyEntries,
1101
+ moduleName,
1102
+ state
1103
+ );
1104
+ }
1080
1105
  }
1081
1106
  }
1082
1107
  if (indicatorSet.has(moduleName)) {
1083
1108
  const indicatorPluginDefinition = extractIndicatorPluginDefinition(moduleExport);
1084
1109
  if (!indicatorPluginDefinition) {
1085
- import_logger2.logger.warn(
1086
- 'Skip indicator plugin "%s": export { indicatorEntries } is missing',
1087
- moduleName
1110
+ issues.push(
1111
+ `${moduleName}: export { indicatorEntries } is missing`
1088
1112
  );
1089
1113
  } else {
1090
1114
  (0, import_indicators.registerIndicatorEntries)(
@@ -1095,19 +1119,17 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
1095
1119
  }
1096
1120
  }
1097
1121
  if (!strategySet.has(moduleName) && !indicatorSet.has(moduleName)) {
1098
- import_logger2.logger.warn(
1099
- 'Skip plugin "%s": no strategy/indicator sections requested in config',
1100
- moduleName
1101
- );
1122
+ issues.push(`${moduleName}: plugin is not declared in config`);
1102
1123
  }
1103
1124
  } catch (error) {
1104
- import_logger2.logger.warn(
1105
- 'Failed to load plugin "%s": %s',
1106
- moduleName,
1107
- String(error)
1108
- );
1125
+ issues.push(`${moduleName}: failed to import: ${String(error)}`);
1109
1126
  }
1110
1127
  }
1128
+ if (issues.length > 0) {
1129
+ throw new Error(
1130
+ ["Invalid TradeJS plugin catalog:", ...issues].join("\n")
1131
+ );
1132
+ }
1111
1133
  })();
1112
1134
  }
1113
1135
  await state.pluginsLoadPromise;
@@ -1117,6 +1139,11 @@ var getStrategyCreator = async (name, cwd = getTradejsProjectCwd()) => {
1117
1139
  const { state } = getStrategyRegistryState(cwd);
1118
1140
  return state.strategyCreators.get(name);
1119
1141
  };
1142
+ var getStrategyEntry = async (name, cwd = getTradejsProjectCwd()) => {
1143
+ await ensureStrategyPluginsLoaded(cwd);
1144
+ const { state } = getStrategyRegistryState(cwd);
1145
+ return state.strategyEntriesMap.get(name);
1146
+ };
1120
1147
  var getStrategyPluginSource = async (name, cwd = getTradejsProjectCwd()) => {
1121
1148
  await ensureStrategyPluginsLoaded(cwd);
1122
1149
  const { state } = getStrategyRegistryState(cwd);
@@ -1769,7 +1796,7 @@ var import_node_crypto = require("crypto");
1769
1796
  var import_constants = require("@tradejs/core/constants");
1770
1797
  var import_time = require("@tradejs/core/time");
1771
1798
  var import_trade = require("@tradejs/core/trade");
1772
- var import_logger3 = require("@tradejs/infra/logger");
1799
+ var import_logger2 = require("@tradejs/infra/logger");
1773
1800
  var import_redis2 = require("@tradejs/infra/redis");
1774
1801
  var now = () => Date.now();
1775
1802
  var toRandomOrderSuffix = () => (0, import_node_crypto.randomUUID)().replace(/-/g, "").slice(0, 12).toLowerCase();
@@ -1828,7 +1855,7 @@ var recordRuntimeTradeOpen = async (params) => {
1828
1855
  )
1829
1856
  ]);
1830
1857
  } catch (error) {
1831
- import_logger3.logger.error(
1858
+ import_logger2.logger.error(
1832
1859
  "runtime trade open journal failed: %s %s",
1833
1860
  record.symbol,
1834
1861
  error?.message || String(error)
@@ -1895,7 +1922,7 @@ var recordRuntimeTradeIncrease = async (params) => {
1895
1922
  )
1896
1923
  ]);
1897
1924
  } catch (error) {
1898
- import_logger3.logger.error(
1925
+ import_logger2.logger.error(
1899
1926
  "runtime trade increase journal failed: %s %s",
1900
1927
  symbol,
1901
1928
  error?.message || String(error)
@@ -2002,7 +2029,7 @@ var markRuntimeTradeClosed = async (params) => {
2002
2029
  )
2003
2030
  ]);
2004
2031
  } catch (error) {
2005
- import_logger3.logger.error(
2032
+ import_logger2.logger.error(
2006
2033
  "runtime trade close journal failed: %s %s",
2007
2034
  symbol,
2008
2035
  error?.message || String(error)
@@ -2012,11 +2039,11 @@ var markRuntimeTradeClosed = async (params) => {
2012
2039
  };
2013
2040
 
2014
2041
  // src/strategyHelpers/marketContextStages.ts
2015
- var import_logger8 = require("@tradejs/infra/logger");
2042
+ var import_logger7 = require("@tradejs/infra/logger");
2016
2043
 
2017
2044
  // src/strategyHelpers/binanceMarketContext.ts
2018
2045
  var import_marketContext = require("@tradejs/infra/timescale/marketContext");
2019
- var import_logger4 = require("@tradejs/infra/logger");
2046
+ var import_logger3 = require("@tradejs/infra/logger");
2020
2047
  var import_strategies = require("@tradejs/core/strategies");
2021
2048
 
2022
2049
  // src/binanceBreadthUniverses.ts
@@ -2612,7 +2639,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
2612
2639
  throw error;
2613
2640
  }
2614
2641
  binanceMarketContextUnavailable = true;
2615
- import_logger4.logger.warn(
2642
+ import_logger3.logger.warn(
2616
2643
  "Binance market context disabled after Timescale read failure: %s",
2617
2644
  String(error)
2618
2645
  );
@@ -2622,7 +2649,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
2622
2649
 
2623
2650
  // src/strategyHelpers/coinMarketCapContext.ts
2624
2651
  var import_strategies2 = require("@tradejs/core/strategies");
2625
- var import_logger5 = require("@tradejs/infra/logger");
2652
+ var import_logger4 = require("@tradejs/infra/logger");
2626
2653
  var import_marketContext2 = require("@tradejs/infra/timescale/marketContext");
2627
2654
  var DEFAULT_MAX_AGE_MS = 48 * 60 * 6e4;
2628
2655
  var SOURCE_GLOBAL_DAILY = "coinmarketcap_global";
@@ -3111,7 +3138,7 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
3111
3138
  throw error;
3112
3139
  }
3113
3140
  coinMarketCapContextUnavailable = true;
3114
- import_logger5.logger.warn(
3141
+ import_logger4.logger.warn(
3115
3142
  "CoinMarketCap context disabled after Timescale read failure: %s",
3116
3143
  String(error)
3117
3144
  );
@@ -3125,7 +3152,7 @@ var import_data = require("@tradejs/core/data");
3125
3152
  var import_strategies3 = require("@tradejs/core/strategies");
3126
3153
  var import_constants2 = require("@tradejs/core/constants");
3127
3154
  var import_derivatives = require("@tradejs/infra/timescale/derivatives");
3128
- var import_logger6 = require("@tradejs/infra/logger");
3155
+ var import_logger5 = require("@tradejs/infra/logger");
3129
3156
  var STORED_INTERVALS = ["15m", "1h"];
3130
3157
  var CONTEXT_INTERVALS = ["15m", "1h"];
3131
3158
  var DEFAULT_LOOKBACK_HOURS = 48;
@@ -3357,7 +3384,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
3357
3384
  throw error;
3358
3385
  }
3359
3386
  derivativesContextUnavailable = true;
3360
- import_logger6.logger.warn(
3387
+ import_logger5.logger.warn(
3361
3388
  "Derivatives context disabled after Timescale read failure: %s",
3362
3389
  String(error)
3363
3390
  );
@@ -3369,7 +3396,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
3369
3396
  var import_data2 = require("@tradejs/core/data");
3370
3397
  var import_strategies4 = require("@tradejs/core/strategies");
3371
3398
  var import_hyperliquidWhales2 = require("@tradejs/infra/timescale/hyperliquidWhales");
3372
- var import_logger7 = require("@tradejs/infra/logger");
3399
+ var import_logger6 = require("@tradejs/infra/logger");
3373
3400
 
3374
3401
  // src/hyperliquidWhaleUniverse.ts
3375
3402
  var import_node_crypto3 = require("crypto");
@@ -3889,7 +3916,7 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
3889
3916
  throw error;
3890
3917
  }
3891
3918
  hyperliquidWhaleContextUnavailable = true;
3892
- import_logger7.logger.warn(
3919
+ import_logger6.logger.warn(
3893
3920
  "Hyperliquid whale context disabled after Timescale read failure: %s",
3894
3921
  String(error)
3895
3922
  );
@@ -3972,7 +3999,7 @@ var runMarketContextStage = async ({
3972
3999
  elapsedMs: Date.now() - startedAt
3973
4000
  };
3974
4001
  if (status === "timed_out") {
3975
- import_logger8.logger.warn(
4002
+ import_logger7.logger.warn(
3976
4003
  "Market context stage timed out: %s after %sms",
3977
4004
  stage,
3978
4005
  result.elapsedMs
@@ -4162,7 +4189,7 @@ var enrichSignalWithAi = async ({
4162
4189
  signal.aiAnalysis = analysis;
4163
4190
  return resolveAiQuality(analysis, direction);
4164
4191
  } catch (err) {
4165
- import_logger9.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
4192
+ import_logger8.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
4166
4193
  }
4167
4194
  return void 0;
4168
4195
  };
@@ -4197,7 +4224,7 @@ var getOrderArrivalSnapshot = async ({
4197
4224
  spreadBps
4198
4225
  };
4199
4226
  } catch (error) {
4200
- import_logger9.logger.warn(
4227
+ import_logger8.logger.warn(
4201
4228
  "runtime order arrival snapshot failed: %s %s",
4202
4229
  symbol,
4203
4230
  error?.message || String(error)
@@ -4426,7 +4453,7 @@ var executeEntryOrder = async ({
4426
4453
  deploymentId: signal.deploymentId,
4427
4454
  policyProfileId: signal.policyProfileId,
4428
4455
  runtimeConfigId: signal.runtimeConfigId,
4429
- runtimeVersion: signal.runtimeVersion,
4456
+ strategyRevision: signal.strategyRevision,
4430
4457
  runtimeLineage: signal.runtimeLineage,
4431
4458
  ...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {}
4432
4459
  });
@@ -4978,7 +5005,7 @@ var canUseSharedReplayState = ({
4978
5005
  }) => (env === "BACKTEST" || env === "PARITY") && Boolean(sharedReplayKey);
4979
5006
 
4980
5007
  // src/strategy/runtimeExecution.ts
4981
- var import_logger10 = require("@tradejs/infra/logger");
5008
+ var import_logger9 = require("@tradejs/infra/logger");
4982
5009
  var import_types = require("@tradejs/types");
4983
5010
  var buildExitOrderSignal = ({
4984
5011
  strategyName,
@@ -5030,7 +5057,7 @@ var handleExitDecision = async ({
5030
5057
  deploymentId: connector.deploymentId
5031
5058
  });
5032
5059
  if (!activeTrade) {
5033
- import_logger10.logger.warn(
5060
+ import_logger9.logger.warn(
5034
5061
  "[%s] blocked closePosition for untracked runtime position: %s",
5035
5062
  strategyName ?? "unknown",
5036
5063
  symbol
@@ -5038,7 +5065,7 @@ var handleExitDecision = async ({
5038
5065
  return "CLOSE_BLOCKED_BY_UNTRACKED_POSITION";
5039
5066
  }
5040
5067
  if (!strategyName || activeTrade.strategy !== strategyName) {
5041
- import_logger10.logger.warn(
5068
+ import_logger9.logger.warn(
5042
5069
  "[%s] blocked closePosition for foreign runtime position: %s ownedBy=%s",
5043
5070
  strategyName ?? "unknown",
5044
5071
  symbol,
@@ -5090,7 +5117,7 @@ var handleExitDecision = async ({
5090
5117
  exitType: closedTrade?.exitType ?? "exit"
5091
5118
  });
5092
5119
  } catch (notificationError) {
5093
- import_logger10.logger.error(
5120
+ import_logger9.logger.error(
5094
5121
  "runtime close notification error: %s %s",
5095
5122
  symbol,
5096
5123
  notificationError
@@ -5104,7 +5131,7 @@ var handleExitDecision = async ({
5104
5131
  decision,
5105
5132
  market
5106
5133
  });
5107
- import_logger10.logger.error("close order error: %s %s", symbol, err);
5134
+ import_logger9.logger.error("close order error: %s %s", symbol, err);
5108
5135
  return "ORDER_ERROR";
5109
5136
  }
5110
5137
  return decision.code;
@@ -5131,7 +5158,7 @@ var handleProtectDecision = async ({
5131
5158
  decision,
5132
5159
  market
5133
5160
  });
5134
- import_logger10.logger.error("protect position error: %s %s", symbol, err);
5161
+ import_logger9.logger.error("protect position error: %s %s", symbol, err);
5135
5162
  return "ORDER_ERROR";
5136
5163
  }
5137
5164
  return decision.code;
@@ -5294,9 +5321,9 @@ var executeEntryDecision = async ({
5294
5321
  market
5295
5322
  });
5296
5323
  if (err?.message === import_types.BACKTEST_WARNING_CODES.TAKE_PROFIT_CROSSED_BEFORE_ENTRY) {
5297
- import_logger10.logger.warn("order warning: %s %s", symbol, err);
5324
+ import_logger9.logger.warn("order warning: %s %s", symbol, err);
5298
5325
  } else {
5299
- import_logger10.logger.error("order error: %s %s", symbol, err);
5326
+ import_logger9.logger.error("order error: %s %s", symbol, err);
5300
5327
  }
5301
5328
  return signal ?? "ORDER_ERROR";
5302
5329
  }
@@ -5337,7 +5364,7 @@ var createStrategyRuntime = ({
5337
5364
  deploymentId: requestedDeploymentId,
5338
5365
  policyProfileId,
5339
5366
  runtimeConfigId,
5340
- runtimeVersion,
5367
+ strategyRevision,
5341
5368
  entriesPaused = false,
5342
5369
  runtimeLineage,
5343
5370
  runtimeConfigSnapshot,
@@ -5450,7 +5477,7 @@ var createStrategyRuntime = ({
5450
5477
  try {
5451
5478
  await projectHook(errorParams);
5452
5479
  } catch (hookError) {
5453
- import_logger11.logger.error(
5480
+ import_logger10.logger.error(
5454
5481
  "project hook onRuntimeError failed: %s %s",
5455
5482
  strategyName,
5456
5483
  hookError
@@ -5464,7 +5491,7 @@ var createStrategyRuntime = ({
5464
5491
  try {
5465
5492
  await onRuntimeError(errorParams);
5466
5493
  } catch (hookError) {
5467
- import_logger11.logger.error(
5494
+ import_logger10.logger.error(
5468
5495
  "runtime hook onRuntimeError failed: %s %s",
5469
5496
  strategyName,
5470
5497
  hookError
@@ -5478,7 +5505,7 @@ var createStrategyRuntime = ({
5478
5505
  try {
5479
5506
  return await hook(params);
5480
5507
  } catch (error) {
5481
- import_logger11.logger.error(
5508
+ import_logger10.logger.error(
5482
5509
  'strategy hook "%s" failed for %s: %s',
5483
5510
  stage,
5484
5511
  strategyName,
@@ -6009,8 +6036,8 @@ var createStrategyRuntime = ({
6009
6036
  signal.signalId = `${signal.signalId}:${runtimeConfigId}`;
6010
6037
  }
6011
6038
  }
6012
- if (runtimeVersion) {
6013
- signal.runtimeVersion = runtimeVersion;
6039
+ if (strategyRevision) {
6040
+ signal.strategyRevision = strategyRevision;
6014
6041
  }
6015
6042
  if (decisionHookCtx.policyProfileId) {
6016
6043
  signal.policyProfileId = decisionHookCtx.policyProfileId;
@@ -6123,7 +6150,7 @@ var createStrategyRuntime = ({
6123
6150
  if (signal) {
6124
6151
  signal.orderStatus = "skipped";
6125
6152
  signal.orderSkipReason = skipReason;
6126
- signal.runtimeVersion = runtimeVersion;
6153
+ signal.strategyRevision = strategyRevision;
6127
6154
  }
6128
6155
  return signal ?? skipReason;
6129
6156
  }
@@ -6235,6 +6262,7 @@ var createStrategyRuntime = ({
6235
6262
  setStrategyRuntimeFactory(createStrategyRuntime);
6236
6263
 
6237
6264
  // src/runtimeStrategies.ts
6265
+ var RUNTIME_PACKAGE_MANIFEST_SCHEMA = "tradejs-runtime-package-manifest/v1";
6238
6266
  var INTERVALS = /* @__PURE__ */ new Set([
6239
6267
  "1",
6240
6268
  "3",
@@ -6261,7 +6289,7 @@ var DEPLOYMENT_KEYS = /* @__PURE__ */ new Set([
6261
6289
  "assetClasses",
6262
6290
  "tickers"
6263
6291
  ]);
6264
- var STRATEGY_KEYS = /* @__PURE__ */ new Set(["version", "enabled", "selection", "config"]);
6292
+ var STRATEGY_KEYS = /* @__PURE__ */ new Set(["generation", "enabled", "selection", "config"]);
6265
6293
  var SELECTION_KEYS = /* @__PURE__ */ new Set(["tickers"]);
6266
6294
  var FORBIDDEN_CONFIG_KEYS = /* @__PURE__ */ new Set([
6267
6295
  "ACCOUNT_ID",
@@ -6270,60 +6298,165 @@ var FORBIDDEN_CONFIG_KEYS = /* @__PURE__ */ new Set([
6270
6298
  "ENABLE"
6271
6299
  ]);
6272
6300
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
6273
- var readPackageManifest = async (projectRoot) => {
6274
- const candidates = [
6275
- process.env.TRADEJS_RUNTIME_PACKAGE_MANIFEST,
6276
- import_node_path.default.join(projectRoot, "runtime-package-manifest.json"),
6277
- "/app/runtime-package-manifest.json"
6278
- ].filter((candidate) => Boolean(candidate));
6279
- for (const candidate of candidates) {
6280
- try {
6281
- return JSON.parse(
6282
- await (0, import_promises.readFile)(candidate, "utf8")
6283
- );
6284
- } catch {
6285
- }
6301
+ var normalizeForCanonicalJson = (value) => {
6302
+ if (Array.isArray(value)) return value.map(normalizeForCanonicalJson);
6303
+ if (isRecord(value)) {
6304
+ return Object.fromEntries(
6305
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nestedValue]) => [
6306
+ key,
6307
+ normalizeForCanonicalJson(nestedValue)
6308
+ ])
6309
+ );
6286
6310
  }
6287
- return { packages: {} };
6311
+ return value;
6288
6312
  };
6289
- var resolveInstalledPackageVersion = async (projectRoot, packageName, manifest) => {
6290
- if (!packageName || packageName === "runtime") return null;
6291
- const manifestVersion = manifest.packages?.[packageName];
6292
- if (manifestVersion) return manifestVersion;
6313
+ var revision = (prefix, value) => `${prefix}:${(0, import_node_crypto4.createHash)("sha256").update(JSON.stringify(normalizeForCanonicalJson(value))).digest("hex").slice(0, 16)}`;
6314
+ var computeStrategyRevision = ({
6315
+ strategyName,
6316
+ strategyPackage,
6317
+ strategyPackageVersion,
6318
+ strategyDependencyVersions,
6319
+ runtimePackageVersion,
6320
+ strategyConfig
6321
+ }) => revision("sr1", {
6322
+ schema: "tradejs-strategy-revision/v1",
6323
+ strategyName,
6324
+ strategyPackage,
6325
+ strategyPackageVersion,
6326
+ strategyDependencyVersions,
6327
+ runtimePackageVersion,
6328
+ strategyConfig
6329
+ });
6330
+ var computeDeploymentCompositionId = (value) => revision("dc1", {
6331
+ schema: "tradejs-deployment-composition/v1",
6332
+ ...value,
6333
+ assetClasses: value.assetClasses ? [...value.assetClasses].sort((left, right) => left.localeCompare(right)) : void 0,
6334
+ strategies: [...value.strategies].sort(
6335
+ (left, right) => left.strategyName.localeCompare(right.strategyName)
6336
+ ).map((strategy) => ({
6337
+ ...strategy,
6338
+ selection: strategy.selection ? {
6339
+ tickers: [...strategy.selection.tickers].sort(
6340
+ (left, right) => left.localeCompare(right)
6341
+ )
6342
+ } : void 0
6343
+ }))
6344
+ });
6345
+ var readRuntimePackageManifest = async (projectRoot) => {
6346
+ const manifestPath = process.env.TRADEJS_RUNTIME_PACKAGE_MANIFEST?.trim() || import_node_path.default.join(projectRoot, "runtime-package-manifest.json");
6347
+ let value;
6293
6348
  try {
6294
- const packageJsonPath = import_node_path.default.join(
6295
- projectRoot,
6296
- "node_modules",
6297
- ...packageName.split("/"),
6298
- "package.json"
6349
+ value = JSON.parse(await (0, import_promises.readFile)(manifestPath, "utf8"));
6350
+ } catch (error) {
6351
+ throw new Error(
6352
+ `Unable to read runtime package manifest ${manifestPath}: ${String(error)}`
6299
6353
  );
6354
+ }
6355
+ if (!isRecord(value) || Object.keys(value).some(
6356
+ (key) => !["schema", "projectSha", "packages"].includes(key)
6357
+ ) || value.schema !== RUNTIME_PACKAGE_MANIFEST_SCHEMA || typeof value.projectSha !== "string" || !/^[a-f0-9]{40}$/.test(value.projectSha) || !isRecord(value.packages) || Object.keys(value.packages).length === 0 || Object.entries(value.packages).some(
6358
+ ([packageName, version]) => !packageName.trim() || typeof version !== "string" || !version.trim()
6359
+ )) {
6360
+ throw new Error(`Invalid runtime package manifest: ${manifestPath}`);
6361
+ }
6362
+ return value;
6363
+ };
6364
+ var readInstalledPackageMetadata = async ({
6365
+ projectRoot,
6366
+ packageName,
6367
+ projectPackage
6368
+ }) => {
6369
+ const packageJsonPath = projectPackage ? import_node_path.default.join(projectRoot, "package.json") : import_node_path.default.join(
6370
+ projectRoot,
6371
+ "node_modules",
6372
+ ...packageName.split("/"),
6373
+ "package.json"
6374
+ );
6375
+ try {
6300
6376
  const packageJson = JSON.parse(await (0, import_promises.readFile)(packageJsonPath, "utf8"));
6301
- return packageJson.version ?? null;
6302
- } catch {
6303
- return null;
6377
+ if (packageJson.name !== void 0 && packageJson.name !== packageName || typeof packageJson.version !== "string" || !packageJson.version.trim()) {
6378
+ throw new Error("name or version is invalid");
6379
+ }
6380
+ const dependencyNames = [
6381
+ ...isRecord(packageJson.dependencies) ? Object.keys(packageJson.dependencies) : [],
6382
+ ...isRecord(packageJson.peerDependencies) ? Object.keys(packageJson.peerDependencies) : []
6383
+ ];
6384
+ return {
6385
+ version: packageJson.version,
6386
+ runtimeDependencies: [...new Set(dependencyNames)].filter((name) => name.startsWith("@tradejs/")).sort((left, right) => left.localeCompare(right))
6387
+ };
6388
+ } catch (error) {
6389
+ throw new Error(
6390
+ `Installed package manifest not found for ${packageName}: ${String(error)}`
6391
+ );
6304
6392
  }
6305
6393
  };
6306
- var resolveStrategyPackageName = async ({
6394
+ var resolveVerifiedPackageVersion = async ({
6395
+ projectRoot,
6396
+ packageName,
6397
+ manifest,
6398
+ projectPackage = false
6399
+ }) => {
6400
+ const declaredVersion = manifest.packages[packageName];
6401
+ if (!declaredVersion) {
6402
+ throw new Error(`Runtime package manifest is missing ${packageName}`);
6403
+ }
6404
+ const installed = await readInstalledPackageMetadata({
6405
+ projectRoot,
6406
+ packageName,
6407
+ projectPackage
6408
+ });
6409
+ if (declaredVersion !== installed.version) {
6410
+ throw new Error(
6411
+ `Runtime package manifest mismatch for ${packageName}: declared=${declaredVersion} installed=${installed.version}`
6412
+ );
6413
+ }
6414
+ return installed.version;
6415
+ };
6416
+ var resolveVerifiedStrategyDependencyVersions = async ({
6417
+ projectRoot,
6418
+ strategyPackage,
6419
+ manifest
6420
+ }) => {
6421
+ const metadata = await readInstalledPackageMetadata({
6422
+ projectRoot,
6423
+ packageName: strategyPackage.name,
6424
+ projectPackage: strategyPackage.projectPackage
6425
+ });
6426
+ return Object.fromEntries(
6427
+ await Promise.all(
6428
+ metadata.runtimeDependencies.map(async (packageName) => [
6429
+ packageName,
6430
+ await resolveVerifiedPackageVersion({
6431
+ projectRoot,
6432
+ packageName,
6433
+ manifest
6434
+ })
6435
+ ])
6436
+ )
6437
+ );
6438
+ };
6439
+ var resolveStrategyPackage = async ({
6307
6440
  pluginSource,
6308
6441
  projectRoot
6309
6442
  }) => {
6310
6443
  if (!pluginSource) return null;
6311
6444
  if (!pluginSource.startsWith(".") && !import_node_path.default.isAbsolute(pluginSource)) {
6312
- return pluginSource;
6445
+ return { name: pluginSource, projectPackage: false };
6313
6446
  }
6314
6447
  try {
6315
6448
  const packageJson = JSON.parse(
6316
6449
  await (0, import_promises.readFile)(import_node_path.default.join(projectRoot, "package.json"), "utf8")
6317
6450
  );
6318
- return typeof packageJson.name === "string" && packageJson.name.trim() ? packageJson.name : null;
6451
+ return typeof packageJson.name === "string" && packageJson.name.trim() ? { name: packageJson.name, projectPackage: true } : null;
6319
6452
  } catch {
6320
6453
  return null;
6321
6454
  }
6322
6455
  };
6323
- var verifyStringArray = (value) => value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
6324
- var verifyStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => SELECTION_KEYS.has(key)) && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every(
6325
- (ticker) => typeof ticker === "string" && ticker.trim().length > 0
6326
- );
6456
+ var verifyStringSet = (value) => value === void 0 || Array.isArray(value) && value.length > 0 && value.every(
6457
+ (item) => typeof item === "string" && item.length > 0 && item === item.trim()
6458
+ ) && new Set(value).size === value.length;
6459
+ var verifyStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => SELECTION_KEYS.has(key)) && value.tickers !== void 0 && verifyStringSet(value.tickers);
6327
6460
  var cloneSelection = (selection) => selection ? { tickers: [...selection.tickers] } : void 0;
6328
6461
  var resolveStrategySelection = ({
6329
6462
  deployment,
@@ -6332,13 +6465,13 @@ var resolveStrategySelection = ({
6332
6465
  strategy.selection ?? (deployment.tickers ? { tickers: deployment.tickers } : void 0)
6333
6466
  );
6334
6467
  var verifyDeploymentDeclaration = (deploymentId, value) => {
6335
- if (!deploymentId.trim() || !isRecord(value) || Object.keys(value).some((key) => !DEPLOYMENT_KEYS.has(key)) || typeof value.connectorName !== "string" || !value.connectorName.trim() || typeof value.accountId !== "string" || !value.accountId.trim() || value.label !== void 0 && typeof value.label !== "string" || value.provider !== void 0 && typeof value.provider !== "string" || value.enabled !== void 0 && typeof value.enabled !== "boolean" || !verifyStringArray(value.assetClasses) || !verifyStringArray(value.tickers) || !isRecord(value.strategies) || !Object.keys(value.strategies).length) {
6468
+ if (!deploymentId.trim() || !isRecord(value) || Object.keys(value).some((key) => !DEPLOYMENT_KEYS.has(key)) || typeof value.connectorName !== "string" || !value.connectorName.trim() || typeof value.accountId !== "string" || !value.accountId.trim() || value.label !== void 0 && typeof value.label !== "string" || value.provider !== void 0 && typeof value.provider !== "string" || value.enabled !== void 0 && typeof value.enabled !== "boolean" || !verifyStringSet(value.assetClasses) || !verifyStringSet(value.tickers) || !isRecord(value.strategies) || !Object.keys(value.strategies).length) {
6336
6469
  throw new Error(`Invalid runtime deployment declaration: ${deploymentId}`);
6337
6470
  }
6338
6471
  for (const [strategyName, strategyValue] of Object.entries(
6339
6472
  value.strategies
6340
6473
  )) {
6341
- if (!strategyName.trim() || !isRecord(strategyValue) || Object.keys(strategyValue).some((key) => !STRATEGY_KEYS.has(key)) || !Number.isSafeInteger(strategyValue.version) || Number(strategyValue.version) <= 0 || typeof strategyValue.enabled !== "boolean" || !verifyStrategySelection(strategyValue.selection) || !isRecord(strategyValue.config) || Object.keys(strategyValue.config).some(
6474
+ if (!strategyName.trim() || !isRecord(strategyValue) || Object.keys(strategyValue).some((key) => !STRATEGY_KEYS.has(key)) || strategyValue.generation !== void 0 && (typeof strategyValue.generation !== "string" || !strategyValue.generation.trim()) || typeof strategyValue.enabled !== "boolean" || !verifyStrategySelection(strategyValue.selection) || !isRecord(strategyValue.config) || Object.keys(strategyValue.config).some(
6342
6475
  (key) => FORBIDDEN_CONFIG_KEYS.has(key)
6343
6476
  ) || !INTERVALS.has(String(strategyValue.config.INTERVAL)) || !["crypto", "tradfi"].includes(String(strategyValue.config.UNIVERSE))) {
6344
6477
  throw new Error(
@@ -6357,55 +6490,180 @@ var verifyRuntimeDeclaration = (value) => {
6357
6490
  }
6358
6491
  return value;
6359
6492
  };
6360
- var toRuntimeDeployment = ({
6361
- id,
6493
+ var loadRuntimeDeclaration = async (projectRoot) => {
6494
+ const projectConfig = await loadTradejsConfig(projectRoot);
6495
+ if (!projectConfig.runtime) {
6496
+ throw new Error("Runtime declaration is required in tradejs.config.ts");
6497
+ }
6498
+ return verifyRuntimeDeclaration(projectConfig.runtime);
6499
+ };
6500
+ var resolveStrategyComposition = async ({
6501
+ strategyName,
6362
6502
  declaration,
6503
+ deployment,
6504
+ projectRoot,
6505
+ packageManifest
6506
+ }) => {
6507
+ const [strategyEntry, strategyCreator, pluginSource] = await Promise.all([
6508
+ getStrategyEntry(strategyName, projectRoot),
6509
+ getStrategyCreator(strategyName, projectRoot),
6510
+ getStrategyPluginSource(strategyName, projectRoot)
6511
+ ]);
6512
+ if (!strategyEntry || !strategyCreator) {
6513
+ throw new Error(`Unknown strategy: ${strategyName}`);
6514
+ }
6515
+ if (typeof strategyEntry.parseConfig !== "function") {
6516
+ throw new Error(`Strategy config parser is missing: ${strategyName}`);
6517
+ }
6518
+ const strategyPackage = await resolveStrategyPackage({
6519
+ pluginSource: pluginSource ?? null,
6520
+ projectRoot
6521
+ });
6522
+ if (!strategyPackage) {
6523
+ throw new Error(`Installed strategy package not found: ${strategyName}`);
6524
+ }
6525
+ const [
6526
+ strategyPackageVersion,
6527
+ strategyDependencyVersions,
6528
+ runtimePackageVersion
6529
+ ] = await Promise.all([
6530
+ resolveVerifiedPackageVersion({
6531
+ projectRoot,
6532
+ packageName: strategyPackage.name,
6533
+ projectPackage: strategyPackage.projectPackage,
6534
+ manifest: packageManifest
6535
+ }),
6536
+ resolveVerifiedStrategyDependencyVersions({
6537
+ projectRoot,
6538
+ strategyPackage,
6539
+ manifest: packageManifest
6540
+ }),
6541
+ resolveVerifiedPackageVersion({
6542
+ projectRoot,
6543
+ packageName: "@tradejs/node",
6544
+ manifest: packageManifest
6545
+ })
6546
+ ]);
6547
+ const parsedConfig = strategyEntry.parseConfig(declaration.config);
6548
+ if (!isRecord(parsedConfig)) {
6549
+ throw new Error(
6550
+ `Strategy config parser returned a non-object: ${strategyName}`
6551
+ );
6552
+ }
6553
+ const strategyConfig = parsedConfig;
6554
+ const selection = resolveStrategySelection({
6555
+ deployment,
6556
+ strategy: declaration
6557
+ });
6558
+ return {
6559
+ strategyName,
6560
+ strategyRevision: computeStrategyRevision({
6561
+ strategyName,
6562
+ strategyPackage: strategyPackage.name,
6563
+ strategyPackageVersion,
6564
+ strategyDependencyVersions,
6565
+ runtimePackageVersion,
6566
+ strategyConfig
6567
+ }),
6568
+ ...declaration.generation ? { generation: declaration.generation } : {},
6569
+ enabled: declaration.enabled,
6570
+ interval: String(strategyConfig.INTERVAL),
6571
+ universe: strategyConfig.UNIVERSE,
6572
+ strategyPackage: strategyPackage.name,
6573
+ strategyPackageVersion,
6574
+ strategyDependencyVersions,
6575
+ runtimePackageVersion,
6576
+ strategyCreator,
6577
+ sourceStrategyConfig: declaration.config,
6578
+ strategyConfig,
6579
+ ...selection ? { selection } : {}
6580
+ };
6581
+ };
6582
+ var resolveRuntimeComposition = async ({
6583
+ projectRoot
6584
+ }) => {
6585
+ const [runtime, packageManifest] = await Promise.all([
6586
+ loadRuntimeDeclaration(projectRoot),
6587
+ readRuntimePackageManifest(projectRoot)
6588
+ ]);
6589
+ const deployments = await Promise.all(
6590
+ Object.entries(runtime.deployments).map(
6591
+ async ([deploymentId, declaration]) => {
6592
+ const strategies2 = await Promise.all(
6593
+ Object.entries(declaration.strategies).map(
6594
+ ([strategyName, strategyDeclaration]) => resolveStrategyComposition({
6595
+ strategyName,
6596
+ declaration: strategyDeclaration,
6597
+ deployment: declaration,
6598
+ projectRoot,
6599
+ packageManifest
6600
+ })
6601
+ )
6602
+ );
6603
+ const provider = (declaration.provider || declaration.connectorName).trim().toLowerCase();
6604
+ return {
6605
+ deploymentId,
6606
+ deploymentCompositionId: computeDeploymentCompositionId({
6607
+ deploymentId,
6608
+ connectorName: declaration.connectorName.trim(),
6609
+ provider,
6610
+ accountId: declaration.accountId.trim(),
6611
+ enabled: declaration.enabled ?? true,
6612
+ ...declaration.assetClasses ? { assetClasses: declaration.assetClasses } : {},
6613
+ strategies: strategies2.map((strategy) => ({
6614
+ strategyName: strategy.strategyName,
6615
+ strategyRevision: strategy.strategyRevision,
6616
+ enabled: strategy.enabled,
6617
+ ...strategy.selection ? { selection: strategy.selection } : {}
6618
+ }))
6619
+ }),
6620
+ declaration,
6621
+ strategies: strategies2
6622
+ };
6623
+ }
6624
+ )
6625
+ );
6626
+ return {
6627
+ deployments: deployments.sort(
6628
+ (left, right) => left.deploymentId.localeCompare(right.deploymentId)
6629
+ )
6630
+ };
6631
+ };
6632
+ var toRuntimeDeployment = ({
6633
+ composition,
6363
6634
  controls
6364
6635
  }) => {
6636
+ const { declaration, deploymentId } = composition;
6365
6637
  const deploymentEnabled = declaration.enabled ?? true;
6366
6638
  return {
6367
- id,
6368
- label: declaration.label?.trim() || id,
6639
+ id: deploymentId,
6640
+ deploymentCompositionId: composition.deploymentCompositionId,
6641
+ label: declaration.label?.trim() || deploymentId,
6369
6642
  connectorName: declaration.connectorName.trim(),
6370
6643
  provider: (declaration.provider || declaration.connectorName).trim().toLowerCase(),
6371
6644
  accountId: declaration.accountId.trim(),
6372
6645
  enabled: deploymentEnabled,
6373
- strategies: Object.entries(declaration.strategies).map(
6374
- ([strategyName, strategy]) => {
6375
- const selection = resolveStrategySelection({
6376
- deployment: declaration,
6377
- strategy
6378
- });
6379
- return {
6380
- strategyName,
6381
- version: strategy.version,
6382
- enabled: strategy.enabled,
6383
- controlState: deploymentEnabled && strategy.enabled && !controls.deployments[id]?.[strategyName]?.entriesPaused ? "active" : "entries_paused",
6384
- ...selection ? { selection } : {}
6385
- };
6386
- }
6387
- ),
6646
+ strategies: composition.strategies.map((strategy) => ({
6647
+ strategyName: strategy.strategyName,
6648
+ strategyRevision: strategy.strategyRevision,
6649
+ enabled: strategy.enabled,
6650
+ controlState: deploymentEnabled && strategy.enabled && !controls.deployments[deploymentId]?.[strategy.strategyName]?.entriesPaused ? "active" : "entries_paused",
6651
+ ...strategy.selection ? { selection: strategy.selection } : {}
6652
+ })),
6388
6653
  ...declaration.assetClasses ? { assetClasses: declaration.assetClasses } : {},
6389
6654
  ...declaration.tickers ? { tickers: declaration.tickers } : {}
6390
6655
  };
6391
6656
  };
6392
- var loadRuntimeDeclaration = async (projectRoot) => {
6393
- const projectConfig = await loadTradejsConfig(projectRoot);
6394
- if (!projectConfig.runtime) {
6395
- throw new Error("Runtime declaration is required in tradejs.config.ts");
6396
- }
6397
- return verifyRuntimeDeclaration(projectConfig.runtime);
6398
- };
6399
6657
  var listRuntimeDeployments = async ({
6400
6658
  userName,
6401
6659
  projectRoot
6402
6660
  }) => {
6403
- const [runtime, controls] = await Promise.all([
6404
- loadRuntimeDeclaration(projectRoot),
6661
+ const [composition, controls] = await Promise.all([
6662
+ resolveRuntimeComposition({ projectRoot }),
6405
6663
  (0, import_runtimeControls.getRuntimeControls)(userName)
6406
6664
  ]);
6407
- return Object.entries(runtime.deployments).map(
6408
- ([id, declaration]) => toRuntimeDeployment({ id, declaration, controls })
6665
+ return composition.deployments.map(
6666
+ (deploymentComposition) => toRuntimeDeployment({ composition: deploymentComposition, controls })
6409
6667
  ).sort((left, right) => left.label.localeCompare(right.label));
6410
6668
  };
6411
6669
  var getRuntimeDeployment = async ({
@@ -6440,87 +6698,37 @@ var loadResolvedRuntimeStrategies = async ({
6440
6698
  accountId,
6441
6699
  interval
6442
6700
  }) => {
6443
- const [runtime, controls, packageManifest] = await Promise.all([
6444
- loadRuntimeDeclaration(projectRoot),
6445
- (0, import_runtimeControls.getRuntimeControls)(userName),
6446
- readPackageManifest(projectRoot)
6701
+ const [composition, controls] = await Promise.all([
6702
+ resolveRuntimeComposition({ projectRoot }),
6703
+ (0, import_runtimeControls.getRuntimeControls)(userName)
6447
6704
  ]);
6448
- const declaration = runtime.deployments[deploymentId];
6449
- if (!declaration) {
6705
+ const deploymentComposition = composition.deployments.find(
6706
+ (candidate) => candidate.deploymentId === deploymentId
6707
+ );
6708
+ if (!deploymentComposition) {
6450
6709
  throw new Error(`Runtime deployment not found: ${deploymentId}`);
6451
6710
  }
6452
6711
  const deployment = toRuntimeDeployment({
6453
- id: deploymentId,
6454
- declaration,
6712
+ composition: deploymentComposition,
6455
6713
  controls
6456
6714
  });
6457
6715
  const strategies2 = await Promise.all(
6458
- Object.entries(declaration.strategies).map(
6459
- async ([strategyName, strategyDeclaration]) => {
6460
- const strategyCreator = await getStrategyCreator(
6461
- strategyName,
6462
- projectRoot
6463
- );
6464
- if (!strategyCreator) {
6465
- throw new Error(`Unknown strategy: ${strategyName}`);
6466
- }
6467
- const pluginSource = await getStrategyPluginSource(strategyName, projectRoot) ?? null;
6468
- const strategyPackage = await resolveStrategyPackageName({
6469
- pluginSource,
6470
- projectRoot
6471
- });
6472
- const [strategyPackageVersion, runtimePackageVersion] = await Promise.all([
6473
- resolveInstalledPackageVersion(
6474
- projectRoot,
6475
- strategyPackage,
6476
- packageManifest
6477
- ),
6478
- resolveInstalledPackageVersion(
6479
- projectRoot,
6480
- "@tradejs/node",
6481
- packageManifest
6482
- )
6483
- ]);
6484
- if (!strategyPackage || !strategyPackageVersion) {
6485
- throw new Error(
6486
- `Installed strategy package not found: ${strategyName}`
6487
- );
6488
- }
6489
- if (!runtimePackageVersion) {
6490
- throw new Error("Installed @tradejs/node package version not found");
6491
- }
6492
- const strategyView = deployment.strategies.find(
6493
- (candidate) => candidate.strategyName === strategyName
6494
- );
6495
- const selection = resolveStrategySelection({
6496
- deployment: declaration,
6497
- strategy: strategyDeclaration
6498
- });
6499
- const strategyConfig = strategyDeclaration.config;
6500
- const strategyUniverse = strategyConfig.UNIVERSE;
6501
- const resolvedAccountId = await resolveAccountId({
6502
- userName,
6503
- deployment,
6504
- universe: strategyUniverse
6505
- });
6506
- return {
6507
- strategyName,
6508
- version: strategyDeclaration.version,
6509
- enabled: strategyDeclaration.enabled,
6510
- controlState: strategyView?.controlState ?? "entries_paused",
6511
- interval: String(strategyConfig.INTERVAL),
6512
- universe: strategyUniverse,
6513
- accountId: resolvedAccountId,
6514
- strategyPackage,
6515
- strategyPackageVersion,
6516
- runtimePackageVersion,
6517
- strategyCreator,
6518
- sourceStrategyConfig: strategyConfig,
6519
- strategyConfig,
6520
- ...selection ? { selection } : {}
6521
- };
6522
- }
6523
- )
6716
+ deploymentComposition.strategies.map(async (strategy) => {
6717
+ const strategyView = deployment.strategies.find(
6718
+ (candidate) => candidate.strategyName === strategy.strategyName
6719
+ );
6720
+ const resolvedAccountId = await resolveAccountId({
6721
+ userName,
6722
+ deployment,
6723
+ universe: strategy.universe
6724
+ });
6725
+ return {
6726
+ ...strategy,
6727
+ deploymentCompositionId: deploymentComposition.deploymentCompositionId,
6728
+ accountId: resolvedAccountId,
6729
+ controlState: strategyView?.controlState ?? "entries_paused"
6730
+ };
6731
+ })
6524
6732
  );
6525
6733
  const filtered = strategies2.filter(
6526
6734
  (candidate) => (!universe || candidate.universe === universe) && (!interval || String(candidate.interval) === String(interval)) && (!accountId || candidate.accountId === accountId)
@@ -6539,31 +6747,55 @@ var getRuntimeStrategyPackageMetadata = async ({
6539
6747
  strategyName,
6540
6748
  projectRoot
6541
6749
  }) => {
6542
- const packageManifest = await readPackageManifest(projectRoot);
6543
- const pluginSource = await getStrategyPluginSource(strategyName, projectRoot) ?? null;
6544
- const strategyPackage = await resolveStrategyPackageName({
6545
- pluginSource,
6750
+ const [packageManifest, pluginSource] = await Promise.all([
6751
+ readRuntimePackageManifest(projectRoot),
6752
+ getStrategyPluginSource(strategyName, projectRoot)
6753
+ ]);
6754
+ const strategyPackage = await resolveStrategyPackage({
6755
+ pluginSource: pluginSource ?? null,
6546
6756
  projectRoot
6547
6757
  });
6548
- return {
6549
- strategyPackage,
6550
- strategyPackageVersion: await resolveInstalledPackageVersion(
6758
+ if (!strategyPackage) {
6759
+ throw new Error(`Installed strategy package not found: ${strategyName}`);
6760
+ }
6761
+ const [
6762
+ strategyPackageVersion,
6763
+ strategyDependencyVersions,
6764
+ runtimePackageVersion
6765
+ ] = await Promise.all([
6766
+ resolveVerifiedPackageVersion({
6767
+ projectRoot,
6768
+ packageName: strategyPackage.name,
6769
+ projectPackage: strategyPackage.projectPackage,
6770
+ manifest: packageManifest
6771
+ }),
6772
+ resolveVerifiedStrategyDependencyVersions({
6551
6773
  projectRoot,
6552
6774
  strategyPackage,
6553
- packageManifest
6554
- ),
6555
- runtimePackageVersion: await resolveInstalledPackageVersion(
6775
+ manifest: packageManifest
6776
+ }),
6777
+ resolveVerifiedPackageVersion({
6556
6778
  projectRoot,
6557
- "@tradejs/node",
6558
- packageManifest
6559
- )
6779
+ packageName: "@tradejs/node",
6780
+ manifest: packageManifest
6781
+ })
6782
+ ]);
6783
+ return {
6784
+ strategyPackage: strategyPackage.name,
6785
+ strategyPackageVersion,
6786
+ strategyDependencyVersions,
6787
+ runtimePackageVersion
6560
6788
  };
6561
6789
  };
6562
6790
  // Annotate the CommonJS export names for ESM import in node:
6563
6791
  0 && (module.exports = {
6792
+ RUNTIME_PACKAGE_MANIFEST_SCHEMA,
6793
+ computeDeploymentCompositionId,
6794
+ computeStrategyRevision,
6564
6795
  getRuntimeDeployment,
6565
6796
  getRuntimeStrategyPackageMetadata,
6566
6797
  listRuntimeDeployments,
6567
6798
  loadResolvedRuntimeStrategies,
6799
+ resolveRuntimeComposition,
6568
6800
  verifyRuntimeDeclaration
6569
6801
  });