tradeblocks-mcp 3.0.2 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -80
- package/dist/{chunk-LDKTV7GW.js → chunk-27S67XW3.js} +24 -52
- package/dist/chunk-27S67XW3.js.map +1 -0
- package/dist/{chunk-FGZH632F.js → chunk-2E63THNI.js} +13 -11
- package/dist/chunk-2E63THNI.js.map +1 -0
- package/dist/{chunk-QTTR7AAW.js → chunk-2I3S2ZLT.js} +325 -84
- package/dist/chunk-2I3S2ZLT.js.map +1 -0
- package/dist/{chunk-4BLCXNQ6.js → chunk-4HZLVUOZ.js} +179 -183
- package/dist/chunk-4HZLVUOZ.js.map +1 -0
- package/dist/{chunk-XXYOUIZY.js → chunk-NWNSKALN.js} +63 -80
- package/dist/chunk-NWNSKALN.js.map +1 -0
- package/dist/{chunk-PRAYH3RT.js → chunk-WNTYA7ER.js} +29 -12
- package/dist/chunk-WNTYA7ER.js.map +1 -0
- package/dist/{chunk-BKQ4PM4Y.js → chunk-YZA4RS76.js} +24 -18
- package/dist/chunk-YZA4RS76.js.map +1 -0
- package/dist/{chunk-W2PP3LEH.js → chunk-ZTJXC3LS.js} +17 -8
- package/dist/chunk-ZTJXC3LS.js.map +1 -0
- package/dist/daily-log-processor-MZW2XBZY.js +9 -0
- package/dist/{daily-logs-store-D3QC2XPV.js → daily-logs-store-3C3OTGPK.js} +2 -2
- package/dist/iv-solver-worker.js +9 -1
- package/dist/market-provider-6U33TQUT.js +16 -0
- package/dist/{proto-3HZTCWK4.js → proto-V23GIZG2.js} +2 -2
- package/dist/{sync-PO4IPCYV.js → sync-3UBC37VW.js} +7 -7
- package/dist/test-exports.js +876 -483
- package/dist/test-exports.js.map +1 -1
- package/dist/trade-processor-DKDCWGKD.js +9 -0
- package/dist/{trades-store-LOL3FQSF.js → trades-store-R3NL25T2.js} +2 -2
- package/package.json +2 -6
- package/server/{chunk-CSDVJPBB.js → chunk-536NSFED.js} +29 -12
- package/server/chunk-536NSFED.js.map +1 -0
- package/server/{chunk-WA5AAPCH.js → chunk-A3UKD64A.js} +17 -8
- package/server/chunk-A3UKD64A.js.map +1 -0
- package/server/{chunk-PNKG7RY7.js → chunk-OMUDNJBJ.js} +63 -80
- package/server/chunk-OMUDNJBJ.js.map +1 -0
- package/server/{chunk-72GKJE2U.js → chunk-RJDJHZ5Y.js} +934 -335
- package/server/chunk-RJDJHZ5Y.js.map +1 -0
- package/server/{chunk-NZO6PT64.js → chunk-RM4B2VKS.js} +167 -177
- package/server/chunk-RM4B2VKS.js.map +1 -0
- package/server/{chunk-5EBXHT6C.js → chunk-SY6GDNVI.js} +24 -18
- package/server/chunk-SY6GDNVI.js.map +1 -0
- package/server/{chunk-FBNDMCT5.js → chunk-T66KH2XH.js} +13 -11
- package/server/chunk-T66KH2XH.js.map +1 -0
- package/server/{chunk-NRFXAJF7.js → chunk-W5E7FHC4.js} +24 -52
- package/server/chunk-W5E7FHC4.js.map +1 -0
- package/server/{config-6IZXEFEX.js → config-DK7KOMNL.js} +1 -1
- package/server/config-DK7KOMNL.js.map +1 -0
- package/server/daily-log-processor-B2VPU2FQ.js +10 -0
- package/server/{daily-logs-store-NU7M4L5C.js → daily-logs-store-YFNXTB7J.js} +2 -2
- package/server/http-server.js +2 -5
- package/server/index.js +2497 -2029
- package/server/index.js.map +1 -1
- package/server/iv-solver-worker.js +9 -1
- package/server/market-provider-L56RFHAC.js +17 -0
- package/server/{proto-DWRZJO4E.js → proto-YZ4TLX2N.js} +2 -2
- package/server/{sync-QFI5L7S7.js → sync-CENKDN53.js} +7 -7
- package/server/trade-processor-3PI4LHZI.js +10 -0
- package/server/{trades-store-VY26MWER.js → trades-store-RTTEYMXH.js} +2 -2
- package/src/auth/clients-store.ts +4 -4
- package/src/auth/code-store.ts +1 -1
- package/src/auth/config.ts +11 -12
- package/src/auth/login-page.ts +8 -10
- package/src/auth/provider.ts +35 -30
- package/src/auth/token.ts +17 -15
- package/src/db/backtest-schemas.ts +38 -8
- package/src/db/connection.ts +107 -40
- package/src/db/data-root.ts +22 -0
- package/src/db/index.ts +37 -5
- package/src/db/json-adapters.ts +22 -31
- package/src/db/json-migration.ts +11 -15
- package/src/db/json-store.ts +5 -3
- package/src/db/market-datasets.ts +48 -15
- package/src/db/market-schemas.ts +11 -5
- package/src/db/market-views.ts +119 -32
- package/src/db/parquet-writer.ts +7 -7
- package/src/db/profile-schemas.ts +39 -22
- package/src/db/schemas.ts +2 -2
- package/src/http-server.ts +7 -12
- package/src/index.ts +8 -9
- package/src/market/ingestor/index.ts +1 -4
- package/src/market/ingestor/market-ingestor.ts +140 -67
- package/src/market/ingestor/types.ts +1 -3
- package/src/market/stores/chain-sql.ts +2 -8
- package/src/market/stores/chain-store.ts +1 -4
- package/src/market/stores/duckdb-chain-store.ts +3 -14
- package/src/market/stores/duckdb-enriched-store.ts +3 -13
- package/src/market/stores/duckdb-quote-store.ts +10 -27
- package/src/market/stores/duckdb-spot-store.ts +4 -20
- package/src/market/stores/enriched-sql.ts +3 -9
- package/src/market/stores/enriched-store.ts +2 -2
- package/src/market/stores/parquet-chain-store.ts +5 -22
- package/src/market/stores/parquet-enriched-store.ts +4 -16
- package/src/market/stores/parquet-oi-daily-store.ts +3 -14
- package/src/market/stores/parquet-quote-store.ts +9 -29
- package/src/market/stores/parquet-spot-store.ts +14 -33
- package/src/market/stores/quote-store.ts +2 -10
- package/src/market/stores/spot-sql.ts +3 -15
- package/src/market/stores/spot-store.ts +1 -1
- package/src/market/tickers/defaults.json +6 -6
- package/src/market/tickers/loader.ts +2 -7
- package/src/market/tickers/registry.ts +5 -15
- package/src/market/tickers/schemas.ts +2 -6
- package/src/models/strategy-profile.ts +39 -39
- package/src/sync/block-sync.ts +44 -65
- package/src/sync/index.ts +1 -4
- package/src/sync/metadata.ts +14 -20
- package/src/test-exports.ts +139 -123
- package/src/tools/analysis.ts +180 -159
- package/src/tools/batch-exit-analysis.ts +100 -59
- package/src/tools/blocks/analysis.ts +116 -101
- package/src/tools/blocks/comparison.ts +281 -364
- package/src/tools/blocks/core.ts +208 -253
- package/src/tools/blocks/health.ts +571 -563
- package/src/tools/blocks/index.ts +2 -0
- package/src/tools/blocks/paired-comparison.ts +425 -0
- package/src/tools/blocks/similarity.ts +316 -283
- package/src/tools/edge-decay.ts +124 -197
- package/src/tools/exit-analysis.ts +130 -77
- package/src/tools/greeks-attribution.ts +84 -35
- package/src/tools/guides.ts +4 -6
- package/src/tools/imports.ts +11 -14
- package/src/tools/market-data.ts +1067 -757
- package/src/tools/market-enrichment.ts +3 -3
- package/src/tools/market-fetch.ts +148 -67
- package/src/tools/market-imports.ts +12 -12
- package/src/tools/middleware/sync-middleware.ts +5 -6
- package/src/tools/performance.ts +185 -302
- package/src/tools/profile-analysis.ts +52 -66
- package/src/tools/profiles.ts +106 -69
- package/src/tools/regime-advisor.ts +20 -45
- package/src/tools/replay.ts +81 -77
- package/src/tools/reports/discrepancies.ts +298 -328
- package/src/tools/reports/fields.ts +7 -25
- package/src/tools/reports/helpers.ts +18 -49
- package/src/tools/reports/predictive.ts +27 -70
- package/src/tools/reports/slippage-trends.ts +315 -345
- package/src/tools/reports/slippage.ts +1 -4
- package/src/tools/reports/strategy-matches.ts +399 -441
- package/src/tools/schema.ts +43 -40
- package/src/tools/shared/filters.ts +3 -9
- package/src/tools/snapshot.ts +9 -30
- package/src/tools/sql.ts +15 -14
- package/src/tools/tickers.ts +1 -4
- package/src/utils/batch-exit-analysis.ts +31 -42
- package/src/utils/black-scholes.ts +39 -29
- package/src/utils/block-loader.ts +69 -83
- package/src/utils/calibration-probe.ts +3 -4
- package/src/utils/chain-loader.ts +3 -3
- package/src/utils/csv-discovery.ts +16 -22
- package/src/utils/data-quality.ts +24 -36
- package/src/utils/exit-triggers.ts +91 -96
- package/src/utils/field-timing.ts +94 -79
- package/src/utils/filter-predicates.ts +13 -9
- package/src/utils/flatfile-importer.ts +94 -64
- package/src/utils/greeks-decomposition.ts +152 -100
- package/src/utils/iv-solver-pool.ts +55 -25
- package/src/utils/iv-solver-worker.ts +5 -5
- package/src/utils/market-enricher.ts +528 -497
- package/src/utils/market-importer.ts +31 -12
- package/src/utils/market-provider.ts +21 -23
- package/src/utils/massive-tier.ts +5 -7
- package/src/utils/migrate-option-data-helpers.ts +2 -8
- package/src/utils/option-quote-greeks.ts +25 -31
- package/src/utils/option-time.ts +4 -8
- package/src/utils/output-formatter.ts +1 -4
- package/src/utils/provider-capabilities.ts +1 -4
- package/src/utils/providers/massive.ts +59 -93
- package/src/utils/providers/thetadata/backfill.ts +14 -23
- package/src/utils/providers/thetadata/client.ts +12 -8
- package/src/utils/providers/thetadata/decode.ts +2 -20
- package/src/utils/providers/thetadata/endpoints.ts +32 -40
- package/src/utils/providers/thetadata/join.ts +11 -10
- package/src/utils/providers/thetadata/proto.ts +12 -10
- package/src/utils/providers/thetadata/quote-mid-greeks.ts +5 -5
- package/src/utils/providers/thetadata.ts +11 -10
- package/src/utils/quote-enricher.ts +4 -4
- package/src/utils/quote-parquet-projection.ts +3 -11
- package/src/utils/sample-date-selector.ts +3 -5
- package/src/utils/schema-metadata.ts +102 -70
- package/src/utils/ticker.ts +5 -9
- package/src/utils/trade-replay.ts +77 -68
- package/dist/chunk-4BLCXNQ6.js.map +0 -1
- package/dist/chunk-BKQ4PM4Y.js.map +0 -1
- package/dist/chunk-FGZH632F.js.map +0 -1
- package/dist/chunk-LDKTV7GW.js.map +0 -1
- package/dist/chunk-PRAYH3RT.js.map +0 -1
- package/dist/chunk-QTTR7AAW.js.map +0 -1
- package/dist/chunk-W2PP3LEH.js.map +0 -1
- package/dist/chunk-XXYOUIZY.js.map +0 -1
- package/dist/daily-log-processor-6MWJ23JK.js +0 -9
- package/dist/market-provider-VDRJUEF2.js +0 -16
- package/dist/trade-processor-NHU4VWRX.js +0 -9
- package/manifest.json +0 -141
- package/server/chunk-5EBXHT6C.js.map +0 -1
- package/server/chunk-72GKJE2U.js.map +0 -1
- package/server/chunk-CSDVJPBB.js.map +0 -1
- package/server/chunk-FBNDMCT5.js.map +0 -1
- package/server/chunk-NRFXAJF7.js.map +0 -1
- package/server/chunk-NZO6PT64.js.map +0 -1
- package/server/chunk-PNKG7RY7.js.map +0 -1
- package/server/chunk-WA5AAPCH.js.map +0 -1
- package/server/config-6IZXEFEX.js.map +0 -1
- package/server/daily-log-processor-Y3PVSVBM.js +0 -10
- package/server/market-provider-VOYYVYWT.js +0 -17
- package/server/trade-processor-JWVS37KM.js +0 -10
- /package/dist/{daily-log-processor-6MWJ23JK.js.map → daily-log-processor-MZW2XBZY.js.map} +0 -0
- /package/dist/{daily-logs-store-D3QC2XPV.js.map → daily-logs-store-3C3OTGPK.js.map} +0 -0
- /package/dist/{market-provider-VDRJUEF2.js.map → market-provider-6U33TQUT.js.map} +0 -0
- /package/dist/{proto-3HZTCWK4.js.map → proto-V23GIZG2.js.map} +0 -0
- /package/dist/{sync-PO4IPCYV.js.map → sync-3UBC37VW.js.map} +0 -0
- /package/dist/{trade-processor-NHU4VWRX.js.map → trade-processor-DKDCWGKD.js.map} +0 -0
- /package/dist/{trades-store-LOL3FQSF.js.map → trades-store-R3NL25T2.js.map} +0 -0
- /package/server/{daily-log-processor-Y3PVSVBM.js.map → daily-log-processor-B2VPU2FQ.js.map} +0 -0
- /package/server/{daily-logs-store-NU7M4L5C.js.map → daily-logs-store-YFNXTB7J.js.map} +0 -0
- /package/server/{market-provider-VOYYVYWT.js.map → market-provider-L56RFHAC.js.map} +0 -0
- /package/server/{proto-DWRZJO4E.js.map → proto-YZ4TLX2N.js.map} +0 -0
- /package/server/{sync-QFI5L7S7.js.map → sync-CENKDN53.js.map} +0 -0
- /package/server/{trade-processor-JWVS37KM.js.map → trade-processor-3PI4LHZI.js.map} +0 -0
- /package/server/{trades-store-VY26MWER.js.map → trades-store-RTTEYMXH.js.map} +0 -0
|
@@ -3,19 +3,19 @@ import {
|
|
|
3
3
|
REPORTING_TRADE_COLUMN_ALIASES,
|
|
4
4
|
convertTatRowToReportingTrade,
|
|
5
5
|
isTatFormat
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RJDJHZ5Y.js";
|
|
7
7
|
|
|
8
8
|
// src/sync/index.ts
|
|
9
9
|
import { existsSync as existsSync2 } from "fs";
|
|
10
10
|
import * as fs9 from "fs/promises";
|
|
11
|
-
import * as
|
|
11
|
+
import * as path12 from "path";
|
|
12
12
|
|
|
13
13
|
// src/db/connection.ts
|
|
14
14
|
import { DuckDBInstance } from "@duckdb/node-api";
|
|
15
15
|
import { execFile } from "child_process";
|
|
16
16
|
import * as fs4 from "fs/promises";
|
|
17
17
|
import * as os from "os";
|
|
18
|
-
import * as
|
|
18
|
+
import * as path8 from "path";
|
|
19
19
|
import { promisify } from "util";
|
|
20
20
|
|
|
21
21
|
// src/db/schemas.ts
|
|
@@ -211,12 +211,13 @@ async function ensureMarketDataTables(conn) {
|
|
|
211
211
|
|
|
212
212
|
// src/db/parquet-writer.ts
|
|
213
213
|
import * as fs from "fs/promises";
|
|
214
|
-
import * as
|
|
214
|
+
import * as path3 from "path";
|
|
215
215
|
|
|
216
216
|
// src/db/market-datasets.ts
|
|
217
|
-
import * as
|
|
217
|
+
import * as path2 from "path";
|
|
218
218
|
|
|
219
219
|
// src/db/data-root.ts
|
|
220
|
+
import path from "path";
|
|
220
221
|
var KEY = "__tradeblocks_data_root__";
|
|
221
222
|
function setDataRoot(dir) {
|
|
222
223
|
globalThis[KEY] = dir;
|
|
@@ -236,26 +237,38 @@ var PARTITIONED_DATASETS = {
|
|
|
236
237
|
option_quote_minutes: "option_quote_minutes"
|
|
237
238
|
};
|
|
238
239
|
function resolveMarketDir(dataDir) {
|
|
239
|
-
return
|
|
240
|
+
return path2.join(getDataRoot(dataDir), "market");
|
|
240
241
|
}
|
|
241
242
|
function resolveCanonicalMarketFile(dataDir, dataset) {
|
|
242
|
-
return
|
|
243
|
+
return path2.join(resolveMarketDir(dataDir), SINGLE_FILE_DATASETS[dataset]);
|
|
243
244
|
}
|
|
244
245
|
function resolveCanonicalMarketPartitionDir(dataDir, dataset) {
|
|
245
|
-
return
|
|
246
|
+
return path2.join(resolveMarketDir(dataDir), PARTITIONED_DATASETS[dataset]);
|
|
246
247
|
}
|
|
247
248
|
var DATASETS_V3 = {
|
|
248
249
|
spot: { subdir: "spot", partitionKeys: ["ticker", "date"], filename: "data.parquet" },
|
|
249
250
|
enriched: { subdir: "enriched", partitionKeys: ["ticker"], filename: "data.parquet" },
|
|
250
251
|
enriched_context: { subdir: "enriched/context", partitionKeys: [], filename: "data.parquet" },
|
|
251
|
-
option_chain: {
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
option_chain: {
|
|
253
|
+
subdir: "option_chain",
|
|
254
|
+
partitionKeys: ["underlying", "date"],
|
|
255
|
+
filename: "data.parquet"
|
|
256
|
+
},
|
|
257
|
+
option_quote_minutes: {
|
|
258
|
+
subdir: "option_quote_minutes",
|
|
259
|
+
partitionKeys: ["underlying", "date"],
|
|
260
|
+
filename: "data.parquet"
|
|
261
|
+
},
|
|
262
|
+
option_oi_daily: {
|
|
263
|
+
subdir: "option_oi_daily",
|
|
264
|
+
partitionKeys: ["underlying", "date"],
|
|
265
|
+
filename: "data.parquet"
|
|
266
|
+
}
|
|
254
267
|
};
|
|
255
268
|
async function writeSpotPartition(conn, args) {
|
|
256
269
|
const def = DATASETS_V3.spot;
|
|
257
270
|
return writeParquetPartition(conn, {
|
|
258
|
-
baseDir:
|
|
271
|
+
baseDir: path2.join(resolveMarketDir(args.dataDir), def.subdir),
|
|
259
272
|
partitions: { ticker: args.ticker, date: args.date },
|
|
260
273
|
// order matches def.partitionKeys
|
|
261
274
|
selectQuery: args.selectQuery,
|
|
@@ -266,7 +279,7 @@ async function writeSpotPartition(conn, args) {
|
|
|
266
279
|
async function writeChainPartition(conn, args) {
|
|
267
280
|
const def = DATASETS_V3.option_chain;
|
|
268
281
|
return writeParquetPartition(conn, {
|
|
269
|
-
baseDir:
|
|
282
|
+
baseDir: path2.join(resolveMarketDir(args.dataDir), def.subdir),
|
|
270
283
|
partitions: { underlying: args.underlying, date: args.date },
|
|
271
284
|
selectQuery: args.selectQuery,
|
|
272
285
|
compression: args.compression,
|
|
@@ -277,7 +290,7 @@ async function writeQuoteMinutesPartition(conn, args) {
|
|
|
277
290
|
const def = DATASETS_V3.option_quote_minutes;
|
|
278
291
|
const sortedSelect = `SELECT * FROM (${args.selectQuery}) AS q ORDER BY q.ticker, q.time`;
|
|
279
292
|
return writeParquetPartition(conn, {
|
|
280
|
-
baseDir:
|
|
293
|
+
baseDir: path2.join(resolveMarketDir(args.dataDir), def.subdir),
|
|
281
294
|
partitions: { underlying: args.underlying, date: args.date },
|
|
282
295
|
selectQuery: sortedSelect,
|
|
283
296
|
compression: args.compression,
|
|
@@ -288,7 +301,7 @@ async function writeOiDailyPartition(conn, args) {
|
|
|
288
301
|
const def = DATASETS_V3.option_oi_daily;
|
|
289
302
|
const sortedSelect = `SELECT * FROM (${args.selectQuery}) AS q ORDER BY q.ticker`;
|
|
290
303
|
return writeParquetPartition(conn, {
|
|
291
|
-
baseDir:
|
|
304
|
+
baseDir: path2.join(resolveMarketDir(args.dataDir), def.subdir),
|
|
292
305
|
partitions: { underlying: args.underlying, date: args.date },
|
|
293
306
|
selectQuery: sortedSelect,
|
|
294
307
|
compression: args.compression,
|
|
@@ -310,7 +323,7 @@ async function writeParquetAtomic(conn, opts) {
|
|
|
310
323
|
const tempPath = `${targetPath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
311
324
|
try {
|
|
312
325
|
await conn.run(`CREATE TEMP TABLE "${stagingName}" AS ${selectQuery}`);
|
|
313
|
-
await fs.mkdir(
|
|
326
|
+
await fs.mkdir(path3.dirname(targetPath), { recursive: true });
|
|
314
327
|
await conn.run(
|
|
315
328
|
`COPY "${stagingName}" TO '${tempPath}' (FORMAT PARQUET, COMPRESSION ${compression})`
|
|
316
329
|
);
|
|
@@ -341,9 +354,7 @@ async function writeParquetPartition(conn, opts) {
|
|
|
341
354
|
const filename = isLegacy ? "data.parquet" : opts.filename ?? "data.parquet";
|
|
342
355
|
for (const [k, v] of Object.entries(partitions)) {
|
|
343
356
|
if (!PARTITION_KEY_RE.test(k)) {
|
|
344
|
-
throw new Error(
|
|
345
|
-
`writeParquetPartition: unsafe partition key: ${JSON.stringify(k)}`
|
|
346
|
-
);
|
|
357
|
+
throw new Error(`writeParquetPartition: unsafe partition key: ${JSON.stringify(k)}`);
|
|
347
358
|
}
|
|
348
359
|
if (!PARTITION_VALUE_RE.test(v)) {
|
|
349
360
|
throw new Error(
|
|
@@ -351,10 +362,8 @@ async function writeParquetPartition(conn, opts) {
|
|
|
351
362
|
);
|
|
352
363
|
}
|
|
353
364
|
}
|
|
354
|
-
const partitionSegments = Object.entries(partitions).map(
|
|
355
|
-
|
|
356
|
-
);
|
|
357
|
-
const targetPath = path2.join(opts.baseDir, ...partitionSegments, filename);
|
|
365
|
+
const partitionSegments = Object.entries(partitions).map(([k, v]) => `${k}=${v}`);
|
|
366
|
+
const targetPath = path3.join(opts.baseDir, ...partitionSegments, filename);
|
|
358
367
|
return writeParquetAtomic(conn, {
|
|
359
368
|
targetPath,
|
|
360
369
|
selectQuery: opts.selectQuery,
|
|
@@ -364,18 +373,18 @@ async function writeParquetPartition(conn, opts) {
|
|
|
364
373
|
|
|
365
374
|
// src/db/json-adapters.ts
|
|
366
375
|
import * as fs3 from "fs/promises";
|
|
367
|
-
import * as
|
|
376
|
+
import * as path5 from "path";
|
|
368
377
|
import { z } from "zod";
|
|
369
378
|
|
|
370
379
|
// src/db/json-store.ts
|
|
371
380
|
import * as fs2 from "fs/promises";
|
|
372
|
-
import * as
|
|
381
|
+
import * as path4 from "path";
|
|
373
382
|
function isEnoent(err) {
|
|
374
383
|
return typeof err === "object" && err !== null && err.code === "ENOENT";
|
|
375
384
|
}
|
|
376
385
|
async function writeJsonFile(filePath, data) {
|
|
377
386
|
const tmpPath = filePath + ".tmp";
|
|
378
|
-
await fs2.mkdir(
|
|
387
|
+
await fs2.mkdir(path4.dirname(filePath), { recursive: true });
|
|
379
388
|
await fs2.writeFile(tmpPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
380
389
|
await fs2.rename(tmpPath, filePath);
|
|
381
390
|
}
|
|
@@ -404,7 +413,7 @@ async function deleteJsonFile(filePath) {
|
|
|
404
413
|
async function listJsonFiles(dirPath, suffix = ".json") {
|
|
405
414
|
try {
|
|
406
415
|
const entries = await fs2.readdir(dirPath, { withFileTypes: true });
|
|
407
|
-
return entries.filter((e) => e.isFile() && e.name.endsWith(suffix)).map((e) =>
|
|
416
|
+
return entries.filter((e) => e.isFile() && e.name.endsWith(suffix)).map((e) => path4.join(dirPath, e.name)).sort();
|
|
408
417
|
} catch (err) {
|
|
409
418
|
if (isEnoent(err)) {
|
|
410
419
|
return [];
|
|
@@ -432,7 +441,7 @@ function jsonToProfile(json) {
|
|
|
432
441
|
};
|
|
433
442
|
}
|
|
434
443
|
function profilePath(blockId, strategyName, blocksDir) {
|
|
435
|
-
return
|
|
444
|
+
return path5.join(blocksDir, blockId, "profiles", toFileSlug(strategyName) + ".json");
|
|
436
445
|
}
|
|
437
446
|
async function upsertProfileJson(profile, blocksDir) {
|
|
438
447
|
const filePath = profilePath(profile.blockId, profile.strategyName, blocksDir);
|
|
@@ -454,7 +463,7 @@ async function getProfileJson(blockId, strategyName, blocksDir) {
|
|
|
454
463
|
}
|
|
455
464
|
async function listProfilesJson(blocksDir, blockId) {
|
|
456
465
|
if (blockId) {
|
|
457
|
-
const profileDir =
|
|
466
|
+
const profileDir = path5.join(blocksDir, blockId, "profiles");
|
|
458
467
|
const files = await listJsonFiles(profileDir);
|
|
459
468
|
const profiles2 = [];
|
|
460
469
|
for (const file of files) {
|
|
@@ -494,7 +503,7 @@ function jsonToSyncMeta(json) {
|
|
|
494
503
|
};
|
|
495
504
|
}
|
|
496
505
|
function syncMetaPath(blockId, blocksDir) {
|
|
497
|
-
return
|
|
506
|
+
return path5.join(blocksDir, blockId, ".sync-meta.json");
|
|
498
507
|
}
|
|
499
508
|
async function getSyncMetadataJson(blockId, blocksDir) {
|
|
500
509
|
const filePath = syncMetaPath(blockId, blocksDir);
|
|
@@ -532,7 +541,7 @@ function marketMetaKey(source, ticker, targetTable) {
|
|
|
532
541
|
return `${source}|${ticker}|${targetTable}`;
|
|
533
542
|
}
|
|
534
543
|
function marketMetaFilePath(dataDir) {
|
|
535
|
-
return
|
|
544
|
+
return path5.join(getDataRoot(dataDir), "market-meta", "sync-metadata.json");
|
|
536
545
|
}
|
|
537
546
|
async function upsertMarketImportMetadataJson(metadata, dataDir) {
|
|
538
547
|
const filePath = marketMetaFilePath(dataDir);
|
|
@@ -548,7 +557,7 @@ function flatLogKey(entry) {
|
|
|
548
557
|
return `${entry.date}|${entry.asset_class}|${entry.underlying}`;
|
|
549
558
|
}
|
|
550
559
|
function flatLogFilePath(dataDir) {
|
|
551
|
-
return
|
|
560
|
+
return path5.join(getDataRoot(dataDir), "market-meta", "flat-import-log.json");
|
|
552
561
|
}
|
|
553
562
|
async function upsertFlatImportLogJson(entry, dataDir) {
|
|
554
563
|
const filePath = flatLogFilePath(dataDir);
|
|
@@ -574,16 +583,14 @@ var EnrichmentWatermarksSchema = z.object({
|
|
|
574
583
|
watermarks: z.record(z.string().regex(/^[A-Z0-9._-]+$/), TickerEntrySchema)
|
|
575
584
|
});
|
|
576
585
|
function watermarksFilePath(dataDir) {
|
|
577
|
-
return
|
|
586
|
+
return path5.join(getDataRoot(dataDir), "market-meta", "enrichment-watermarks.json");
|
|
578
587
|
}
|
|
579
588
|
async function loadEnrichmentWatermarks(dataDir) {
|
|
580
589
|
const raw = await readJsonFile(watermarksFilePath(dataDir));
|
|
581
590
|
if (raw === null) return { version: 1, watermarks: {} };
|
|
582
591
|
const parsed = EnrichmentWatermarksSchema.safeParse(raw);
|
|
583
592
|
if (!parsed.success) {
|
|
584
|
-
throw new Error(
|
|
585
|
-
`enrichment-watermarks.json is malformed: ${parsed.error.message}`
|
|
586
|
-
);
|
|
593
|
+
throw new Error(`enrichment-watermarks.json is malformed: ${parsed.error.message}`);
|
|
587
594
|
}
|
|
588
595
|
return parsed.data;
|
|
589
596
|
}
|
|
@@ -624,13 +631,27 @@ async function ensureProfilesSchema(conn) {
|
|
|
624
631
|
await conn.run(`
|
|
625
632
|
ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS position_sizing JSON
|
|
626
633
|
`);
|
|
627
|
-
await conn.run(
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
await conn.run(
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
await conn.run(
|
|
634
|
+
await conn.run(
|
|
635
|
+
`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS underlying VARCHAR`
|
|
636
|
+
);
|
|
637
|
+
await conn.run(
|
|
638
|
+
`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS re_entry BOOLEAN`
|
|
639
|
+
);
|
|
640
|
+
await conn.run(
|
|
641
|
+
`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS cap_profits BOOLEAN`
|
|
642
|
+
);
|
|
643
|
+
await conn.run(
|
|
644
|
+
`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS cap_losses BOOLEAN`
|
|
645
|
+
);
|
|
646
|
+
await conn.run(
|
|
647
|
+
`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS require_two_prices_pt BOOLEAN`
|
|
648
|
+
);
|
|
649
|
+
await conn.run(
|
|
650
|
+
`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS close_on_completion BOOLEAN`
|
|
651
|
+
);
|
|
652
|
+
await conn.run(
|
|
653
|
+
`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS ignore_margin_req BOOLEAN`
|
|
654
|
+
);
|
|
634
655
|
const strategyCols = [
|
|
635
656
|
{ name: "slippage_entry", type: "DOUBLE" },
|
|
636
657
|
{ name: "slippage_exit", type: "DOUBLE" },
|
|
@@ -644,7 +665,9 @@ async function ensureProfilesSchema(conn) {
|
|
|
644
665
|
{ name: "default_to_date", type: "VARCHAR" }
|
|
645
666
|
];
|
|
646
667
|
for (const col of strategyCols) {
|
|
647
|
-
await conn.run(
|
|
668
|
+
await conn.run(
|
|
669
|
+
`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS ${col.name} ${col.type}`
|
|
670
|
+
);
|
|
648
671
|
}
|
|
649
672
|
await migrateExpectedRegimes(conn);
|
|
650
673
|
}
|
|
@@ -867,7 +890,7 @@ async function deleteProfile(conn, blockId, strategyName, baseDir) {
|
|
|
867
890
|
|
|
868
891
|
// src/db/market-views.ts
|
|
869
892
|
import { existsSync, readdirSync } from "fs";
|
|
870
|
-
import * as
|
|
893
|
+
import * as path6 from "path";
|
|
871
894
|
|
|
872
895
|
// src/utils/quote-parquet-projection.ts
|
|
873
896
|
var describeCache = /* @__PURE__ */ new Map();
|
|
@@ -976,12 +999,12 @@ function hasParquetPartitions(dir, partitionKey = "date") {
|
|
|
976
999
|
const prefix = `${partitionKey}=`;
|
|
977
1000
|
return readdirSync(dir).some((entry) => {
|
|
978
1001
|
if (!entry.startsWith(prefix)) return false;
|
|
979
|
-
const partDir =
|
|
1002
|
+
const partDir = path6.join(dir, entry);
|
|
980
1003
|
try {
|
|
981
1004
|
const entries = readdirSync(partDir);
|
|
982
1005
|
for (const sub of entries) {
|
|
983
1006
|
if (sub.endsWith(".parquet")) return true;
|
|
984
|
-
const nested =
|
|
1007
|
+
const nested = path6.join(partDir, sub);
|
|
985
1008
|
try {
|
|
986
1009
|
if (readdirSync(nested).some((f) => f.endsWith(".parquet"))) return true;
|
|
987
1010
|
} catch {
|
|
@@ -1001,20 +1024,24 @@ function hasEnrichedTickerFiles(dir) {
|
|
|
1001
1024
|
try {
|
|
1002
1025
|
return readdirSync(dir).some((entry) => {
|
|
1003
1026
|
if (!entry.startsWith("ticker=")) return false;
|
|
1004
|
-
return existsSync(
|
|
1027
|
+
return existsSync(path6.join(dir, entry, "data.parquet"));
|
|
1005
1028
|
});
|
|
1006
1029
|
} catch {
|
|
1007
1030
|
return false;
|
|
1008
1031
|
}
|
|
1009
1032
|
}
|
|
1010
1033
|
function hasEnrichedContextFile(dir) {
|
|
1011
|
-
return existsSync(
|
|
1034
|
+
return existsSync(path6.join(dir, "context", "data.parquet"));
|
|
1012
1035
|
}
|
|
1013
1036
|
async function createMarketParquetViews(conn, dataDir) {
|
|
1014
1037
|
const viewsCreated = [];
|
|
1015
1038
|
const tablesKept = [];
|
|
1016
1039
|
const hiveViews = [
|
|
1017
|
-
{
|
|
1040
|
+
{
|
|
1041
|
+
name: "option_chain",
|
|
1042
|
+
subdir: resolveCanonicalMarketPartitionDir(dataDir, "option_chain"),
|
|
1043
|
+
partitionKey: "underlying"
|
|
1044
|
+
}
|
|
1018
1045
|
];
|
|
1019
1046
|
for (const { name, subdir, partitionKey } of hiveViews) {
|
|
1020
1047
|
const dirPath = subdir;
|
|
@@ -1085,7 +1112,7 @@ async function createMarketParquetViews(conn, dataDir) {
|
|
|
1085
1112
|
await conn.run("DROP TABLE IF EXISTS market.option_delta_index");
|
|
1086
1113
|
} catch {
|
|
1087
1114
|
}
|
|
1088
|
-
const spotDir =
|
|
1115
|
+
const spotDir = path6.join(resolveMarketDir(dataDir), "spot");
|
|
1089
1116
|
if (hasParquetPartitions(spotDir, "ticker")) {
|
|
1090
1117
|
try {
|
|
1091
1118
|
await conn.run("DROP VIEW IF EXISTS market.spot");
|
|
@@ -1107,7 +1134,7 @@ async function createMarketParquetViews(conn, dataDir) {
|
|
|
1107
1134
|
}
|
|
1108
1135
|
tablesKept.push("spot");
|
|
1109
1136
|
}
|
|
1110
|
-
const enrichedDir =
|
|
1137
|
+
const enrichedDir = path6.join(resolveMarketDir(dataDir), "enriched");
|
|
1111
1138
|
if (hasEnrichedTickerFiles(enrichedDir)) {
|
|
1112
1139
|
try {
|
|
1113
1140
|
await conn.run("DROP VIEW IF EXISTS market.enriched");
|
|
@@ -1140,7 +1167,7 @@ async function createMarketParquetViews(conn, dataDir) {
|
|
|
1140
1167
|
}
|
|
1141
1168
|
await conn.run(
|
|
1142
1169
|
`CREATE OR REPLACE VIEW market.enriched_context AS
|
|
1143
|
-
SELECT * FROM read_parquet('${
|
|
1170
|
+
SELECT * FROM read_parquet('${path6.join(enrichedDir, "context", "data.parquet")}')`
|
|
1144
1171
|
);
|
|
1145
1172
|
viewsCreated.push("enriched_context");
|
|
1146
1173
|
} else {
|
|
@@ -1205,7 +1232,7 @@ async function createMarketParquetViews(conn, dataDir) {
|
|
|
1205
1232
|
}
|
|
1206
1233
|
|
|
1207
1234
|
// src/db/json-migration.ts
|
|
1208
|
-
import * as
|
|
1235
|
+
import * as path7 from "path";
|
|
1209
1236
|
function toDate2(value) {
|
|
1210
1237
|
if (value instanceof Date) return value;
|
|
1211
1238
|
if (typeof value === "object" && value !== null && "micros" in value) {
|
|
@@ -1282,12 +1309,7 @@ async function migrateProfiles(conn, blocksDir) {
|
|
|
1282
1309
|
createdAt: createdAt.toISOString(),
|
|
1283
1310
|
updatedAt: updatedAt.toISOString()
|
|
1284
1311
|
};
|
|
1285
|
-
const filePath =
|
|
1286
|
-
blocksDir,
|
|
1287
|
-
blockId,
|
|
1288
|
-
"profiles",
|
|
1289
|
-
toFileSlug(strategyName) + ".json"
|
|
1290
|
-
);
|
|
1312
|
+
const filePath = path7.join(blocksDir, blockId, "profiles", toFileSlug(strategyName) + ".json");
|
|
1291
1313
|
await writeJsonFile(filePath, profileJson);
|
|
1292
1314
|
}
|
|
1293
1315
|
return rows.length;
|
|
@@ -1320,7 +1342,7 @@ async function migrateSyncMetadata(conn, blocksDir) {
|
|
|
1320
1342
|
return rows.length;
|
|
1321
1343
|
}
|
|
1322
1344
|
async function migrateMarketImportMetadata(conn, dataDir) {
|
|
1323
|
-
const existingFile = await readJsonFile(
|
|
1345
|
+
const existingFile = await readJsonFile(path7.join(dataDir, "market-meta", "sync-metadata.json"));
|
|
1324
1346
|
if (existingFile !== null) return 0;
|
|
1325
1347
|
let rows;
|
|
1326
1348
|
try {
|
|
@@ -1346,7 +1368,9 @@ async function migrateMarketImportMetadata(conn, dataDir) {
|
|
|
1346
1368
|
return rows.length;
|
|
1347
1369
|
}
|
|
1348
1370
|
async function migrateFlatImportLog(conn, dataDir) {
|
|
1349
|
-
const existingFile = await readJsonFile(
|
|
1371
|
+
const existingFile = await readJsonFile(
|
|
1372
|
+
path7.join(dataDir, "market-meta", "flat-import-log.json")
|
|
1373
|
+
);
|
|
1350
1374
|
if (existingFile !== null) return 0;
|
|
1351
1375
|
let rows;
|
|
1352
1376
|
try {
|
|
@@ -1490,7 +1514,7 @@ async function tryRecoverLockByTerminatingStaleProcess(errorMessage, dbPath, for
|
|
|
1490
1514
|
return false;
|
|
1491
1515
|
}
|
|
1492
1516
|
const normalizedDbPath = dbPath.replace(/\\/g, "/");
|
|
1493
|
-
const normalizedDbDir =
|
|
1517
|
+
const normalizedDbDir = path8.dirname(normalizedDbPath);
|
|
1494
1518
|
const isTradeblocksProcess = command.includes("tradeblocks-mcp") || command.includes("/mcp-server/server/index.js") || command.includes("packages/mcp-server/server/index.js") || command.includes("\\mcp-server\\server\\index.js") || command.includes("packages\\mcp-server\\server\\index.js");
|
|
1495
1519
|
const normalizedCommand = command.replace(/\\/g, "/");
|
|
1496
1520
|
const targetsSameDb = normalizedCommand.includes(normalizedDbPath) || normalizedCommand.includes(normalizedDbDir);
|
|
@@ -1524,16 +1548,16 @@ function resolveMarketDbPath(dataDir) {
|
|
|
1524
1548
|
const args = process.argv;
|
|
1525
1549
|
for (let i = 0; i < args.length; i++) {
|
|
1526
1550
|
if (args[i] === "--market-db" && args[i + 1]) {
|
|
1527
|
-
return
|
|
1551
|
+
return path8.resolve(args[i + 1]);
|
|
1528
1552
|
}
|
|
1529
1553
|
}
|
|
1530
1554
|
if (process.env.MARKET_DB_PATH) {
|
|
1531
|
-
return
|
|
1555
|
+
return path8.resolve(process.env.MARKET_DB_PATH);
|
|
1532
1556
|
}
|
|
1533
|
-
return
|
|
1557
|
+
return path8.join(dataDir, "market.duckdb");
|
|
1534
1558
|
}
|
|
1535
1559
|
async function attachMarketDb(conn, marketDbPath, mode) {
|
|
1536
|
-
await fs4.mkdir(
|
|
1560
|
+
await fs4.mkdir(path8.dirname(marketDbPath), { recursive: true });
|
|
1537
1561
|
const readOnlyClause = mode === "read_only" ? " (READ_ONLY)" : "";
|
|
1538
1562
|
const escapedPath = marketDbPath.replace(/'/g, "''");
|
|
1539
1563
|
try {
|
|
@@ -1580,15 +1604,18 @@ async function openReadWriteConnection(dbPath, threads, memoryLimit) {
|
|
|
1580
1604
|
await ensureReportingDataTable(connection);
|
|
1581
1605
|
await ensureMutableMarketTables(connection);
|
|
1582
1606
|
await ensureProfilesSchema(connection);
|
|
1583
|
-
const dataDir =
|
|
1607
|
+
const dataDir = path8.dirname(dbPath);
|
|
1584
1608
|
const dataRoot = getDataRoot(dataDir);
|
|
1585
1609
|
await createMarketParquetViews(connection, dataRoot);
|
|
1586
1610
|
await ensureMarketDataTables(connection);
|
|
1587
1611
|
try {
|
|
1588
|
-
const blocksDir = (await import("./sync-
|
|
1612
|
+
const blocksDir = (await import("./sync-CENKDN53.js")).getBlocksDir(dataRoot);
|
|
1589
1613
|
await migrateMetadataToJson(connection, dataRoot, blocksDir);
|
|
1590
1614
|
} catch (err) {
|
|
1591
|
-
console.warn(
|
|
1615
|
+
console.warn(
|
|
1616
|
+
"[json-migration] Migration failed (non-fatal):",
|
|
1617
|
+
err instanceof Error ? err.message : err
|
|
1618
|
+
);
|
|
1592
1619
|
}
|
|
1593
1620
|
connectionMode = "read_write";
|
|
1594
1621
|
return connection;
|
|
@@ -1628,7 +1655,7 @@ async function getConnection(dataDir) {
|
|
|
1628
1655
|
if (connection) {
|
|
1629
1656
|
return connection;
|
|
1630
1657
|
}
|
|
1631
|
-
const dbPath =
|
|
1658
|
+
const dbPath = path8.join(dataDir, "analytics.duckdb");
|
|
1632
1659
|
const threads = process.env.DUCKDB_THREADS || defaultThreads();
|
|
1633
1660
|
const memoryLimit = process.env.DUCKDB_MEMORY_LIMIT || defaultMemoryLimit();
|
|
1634
1661
|
storedDbPath = dbPath;
|
|
@@ -1643,7 +1670,11 @@ async function getConnection(dataDir) {
|
|
|
1643
1670
|
} catch (error) {
|
|
1644
1671
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1645
1672
|
if (isLockError(errorMessage)) {
|
|
1646
|
-
const recovered = await tryRecoverLockByTerminatingStaleProcess(
|
|
1673
|
+
const recovered = await tryRecoverLockByTerminatingStaleProcess(
|
|
1674
|
+
errorMessage,
|
|
1675
|
+
dbPath,
|
|
1676
|
+
forceRecovery
|
|
1677
|
+
);
|
|
1647
1678
|
if (recovered) {
|
|
1648
1679
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
1649
1680
|
await new Promise((r) => setTimeout(r, 500 * (attempt + 1)));
|
|
@@ -1701,7 +1732,7 @@ async function closeConnection() {
|
|
|
1701
1732
|
async function upgradeToReadWrite(dataDir, options) {
|
|
1702
1733
|
if (connectionMode === "read_write" && connection) return connection;
|
|
1703
1734
|
await closeConnection();
|
|
1704
|
-
const dbPath = storedDbPath ||
|
|
1735
|
+
const dbPath = storedDbPath || path8.join(dataDir, "analytics.duckdb");
|
|
1705
1736
|
const threads = storedThreads || process.env.DUCKDB_THREADS || defaultThreads();
|
|
1706
1737
|
const memoryLimit = storedMemoryLimit || process.env.DUCKDB_MEMORY_LIMIT || defaultMemoryLimit();
|
|
1707
1738
|
if (!storedMarketDbPath) {
|
|
@@ -1755,7 +1786,7 @@ function getCurrentConnection() {
|
|
|
1755
1786
|
|
|
1756
1787
|
// src/sync/block-sync.ts
|
|
1757
1788
|
import * as fs8 from "fs/promises";
|
|
1758
|
-
import * as
|
|
1789
|
+
import * as path11 from "path";
|
|
1759
1790
|
|
|
1760
1791
|
// src/sync/hasher.ts
|
|
1761
1792
|
import * as crypto from "crypto";
|
|
@@ -1813,18 +1844,13 @@ async function deleteSyncMetadata(conn, blockId, blocksDir) {
|
|
|
1813
1844
|
await deleteSyncMetadataJson(blockId, blocksDir);
|
|
1814
1845
|
return;
|
|
1815
1846
|
}
|
|
1816
|
-
await conn.run(
|
|
1817
|
-
`DELETE FROM trades._sync_metadata WHERE block_id = $1`,
|
|
1818
|
-
[blockId]
|
|
1819
|
-
);
|
|
1847
|
+
await conn.run(`DELETE FROM trades._sync_metadata WHERE block_id = $1`, [blockId]);
|
|
1820
1848
|
}
|
|
1821
1849
|
async function getAllSyncedBlockIds(conn, blocksDir) {
|
|
1822
1850
|
if (isParquetMode() && blocksDir) {
|
|
1823
1851
|
return getAllSyncedBlockIdsJson(blocksDir);
|
|
1824
1852
|
}
|
|
1825
|
-
const reader = await conn.runAndReadAll(
|
|
1826
|
-
`SELECT block_id FROM trades._sync_metadata`
|
|
1827
|
-
);
|
|
1853
|
+
const reader = await conn.runAndReadAll(`SELECT block_id FROM trades._sync_metadata`);
|
|
1828
1854
|
const rows = reader.getRows();
|
|
1829
1855
|
return rows.map((row) => row[0]);
|
|
1830
1856
|
}
|
|
@@ -1876,11 +1902,11 @@ function marketTickerDateKey(ticker, date) {
|
|
|
1876
1902
|
|
|
1877
1903
|
// src/utils/block-loader.ts
|
|
1878
1904
|
import * as fs7 from "fs/promises";
|
|
1879
|
-
import * as
|
|
1905
|
+
import * as path10 from "path";
|
|
1880
1906
|
|
|
1881
1907
|
// src/utils/csv-discovery.ts
|
|
1882
1908
|
import * as fs6 from "fs/promises";
|
|
1883
|
-
import * as
|
|
1909
|
+
import * as path9 from "path";
|
|
1884
1910
|
function parseCSVLine(line) {
|
|
1885
1911
|
const result = [];
|
|
1886
1912
|
let current = "";
|
|
@@ -1961,12 +1987,8 @@ async function detectCsvType(filePath) {
|
|
|
1961
1987
|
const reportingAliases = Object.keys(REPORTING_TRADE_COLUMN_ALIASES).map(
|
|
1962
1988
|
(k) => k.toLowerCase()
|
|
1963
1989
|
);
|
|
1964
|
-
const hasReportingColumns = reportingAliases.some(
|
|
1965
|
-
|
|
1966
|
-
);
|
|
1967
|
-
const hasActualPl = headers.some(
|
|
1968
|
-
(h) => h.includes("actual") && h.includes("p")
|
|
1969
|
-
);
|
|
1990
|
+
const hasReportingColumns = reportingAliases.some((alias) => headers.includes(alias));
|
|
1991
|
+
const hasActualPl = headers.some((h) => h.includes("actual") && h.includes("p"));
|
|
1970
1992
|
const hasReportedStyle = headers.includes("trade id") || headers.some((h) => h.includes("reported"));
|
|
1971
1993
|
if (hasActualPl || hasReportingColumns || hasReportedStyle) {
|
|
1972
1994
|
if (!hasPl || hasActualPl) {
|
|
@@ -2009,7 +2031,7 @@ async function discoverCsvFiles(folderPath) {
|
|
|
2009
2031
|
if (csvFile === "tradelog.csv" || csvFile === "dailylog.csv" || csvFile === "reportinglog.csv" || csvFile === mappings.reportinglog) {
|
|
2010
2032
|
continue;
|
|
2011
2033
|
}
|
|
2012
|
-
const csvPath =
|
|
2034
|
+
const csvPath = path9.join(folderPath, csvFile);
|
|
2013
2035
|
const detectedType = await detectCsvType(csvPath);
|
|
2014
2036
|
if (detectedType) {
|
|
2015
2037
|
if (detectedType === "tradelog" && !mappings.tradelog) {
|
|
@@ -2198,7 +2220,7 @@ function convertToDailyLogEntry(raw, blockId) {
|
|
|
2198
2220
|
}
|
|
2199
2221
|
}
|
|
2200
2222
|
async function loadTrades(blockPath, filename = "tradelog.csv", blockId) {
|
|
2201
|
-
const tradelogPath =
|
|
2223
|
+
const tradelogPath = path10.join(blockPath, filename);
|
|
2202
2224
|
const content = await fs7.readFile(tradelogPath, "utf-8");
|
|
2203
2225
|
const records = parseCSV(content);
|
|
2204
2226
|
const trades = [];
|
|
@@ -2216,7 +2238,7 @@ async function loadTrades(blockPath, filename = "tradelog.csv", blockId) {
|
|
|
2216
2238
|
return trades;
|
|
2217
2239
|
}
|
|
2218
2240
|
async function loadDailyLogs(blockPath, blockId, filename = "dailylog.csv") {
|
|
2219
|
-
const dailylogPath =
|
|
2241
|
+
const dailylogPath = path10.join(blockPath, filename);
|
|
2220
2242
|
try {
|
|
2221
2243
|
await fs7.access(dailylogPath);
|
|
2222
2244
|
const content = await fs7.readFile(dailylogPath, "utf-8");
|
|
@@ -2228,9 +2250,7 @@ async function loadDailyLogs(blockPath, blockId, filename = "dailylog.csv") {
|
|
|
2228
2250
|
entries.push(entry);
|
|
2229
2251
|
}
|
|
2230
2252
|
}
|
|
2231
|
-
entries.sort(
|
|
2232
|
-
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
|
|
2233
|
-
);
|
|
2253
|
+
entries.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
|
|
2234
2254
|
return entries.length > 0 ? entries : void 0;
|
|
2235
2255
|
} catch {
|
|
2236
2256
|
return void 0;
|
|
@@ -2238,10 +2258,10 @@ async function loadDailyLogs(blockPath, blockId, filename = "dailylog.csv") {
|
|
|
2238
2258
|
}
|
|
2239
2259
|
async function loadBlock(baseDir, blockId) {
|
|
2240
2260
|
const blocksDir = resolveBlocksBaseDir(baseDir);
|
|
2241
|
-
const blockPath =
|
|
2261
|
+
const blockPath = path10.join(blocksDir, blockId);
|
|
2242
2262
|
const { mappings } = await discoverCsvFiles(blockPath);
|
|
2243
2263
|
const tradelogFilename = mappings.tradelog || "tradelog.csv";
|
|
2244
|
-
const tradelogPath =
|
|
2264
|
+
const tradelogPath = path10.join(blockPath, tradelogFilename);
|
|
2245
2265
|
try {
|
|
2246
2266
|
await fs7.access(tradelogPath);
|
|
2247
2267
|
} catch {
|
|
@@ -2411,7 +2431,7 @@ async function listBlocks(baseDir) {
|
|
|
2411
2431
|
}
|
|
2412
2432
|
blocks.push(info);
|
|
2413
2433
|
} else if (!stats) {
|
|
2414
|
-
const blockPath =
|
|
2434
|
+
const blockPath = path10.join(blocksDir, blockId);
|
|
2415
2435
|
try {
|
|
2416
2436
|
const { mappings } = await discoverCsvFiles(blockPath);
|
|
2417
2437
|
if (mappings.tradelog) {
|
|
@@ -2439,14 +2459,12 @@ async function listBlocks(baseDir) {
|
|
|
2439
2459
|
}
|
|
2440
2460
|
function normalizeRecordHeaders(raw) {
|
|
2441
2461
|
const normalized = { ...raw };
|
|
2442
|
-
Object.entries(REPORTING_TRADE_COLUMN_ALIASES).forEach(
|
|
2443
|
-
([alias
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
delete normalized[alias];
|
|
2447
|
-
}
|
|
2462
|
+
Object.entries(REPORTING_TRADE_COLUMN_ALIASES).forEach(([alias, canonical]) => {
|
|
2463
|
+
if (normalized[alias] !== void 0) {
|
|
2464
|
+
normalized[canonical] = normalized[alias];
|
|
2465
|
+
delete normalized[alias];
|
|
2448
2466
|
}
|
|
2449
|
-
);
|
|
2467
|
+
});
|
|
2450
2468
|
return normalized;
|
|
2451
2469
|
}
|
|
2452
2470
|
function convertToReportingTrade(raw) {
|
|
@@ -2481,10 +2499,10 @@ function convertToReportingTrade(raw) {
|
|
|
2481
2499
|
}
|
|
2482
2500
|
async function loadReportingLog(baseDir, blockId) {
|
|
2483
2501
|
const blocksDir = resolveBlocksBaseDir(baseDir);
|
|
2484
|
-
const blockPath =
|
|
2502
|
+
const blockPath = path10.join(blocksDir, blockId);
|
|
2485
2503
|
const { mappings } = await discoverCsvFiles(blockPath);
|
|
2486
2504
|
const filename = mappings.reportinglog || "reportinglog.csv";
|
|
2487
|
-
const reportingLogPath =
|
|
2505
|
+
const reportingLogPath = path10.join(blockPath, filename);
|
|
2488
2506
|
try {
|
|
2489
2507
|
await fs7.access(reportingLogPath);
|
|
2490
2508
|
} catch {
|
|
@@ -2499,9 +2517,7 @@ async function loadReportingLog(baseDir, blockId) {
|
|
|
2499
2517
|
trades.push(trade);
|
|
2500
2518
|
}
|
|
2501
2519
|
}
|
|
2502
|
-
trades.sort(
|
|
2503
|
-
(a, b) => new Date(a.dateOpened).getTime() - new Date(b.dateOpened).getTime()
|
|
2504
|
-
);
|
|
2520
|
+
trades.sort((a, b) => new Date(a.dateOpened).getTime() - new Date(b.dateOpened).getTime());
|
|
2505
2521
|
return trades;
|
|
2506
2522
|
}
|
|
2507
2523
|
function toKebabCase(str) {
|
|
@@ -2541,9 +2557,7 @@ function validateCsvColumns(records, csvType) {
|
|
|
2541
2557
|
}
|
|
2542
2558
|
const dateOpenedAliases = ["Date Opened", "date_opened"];
|
|
2543
2559
|
const plAliases = ["P/L", "pl"];
|
|
2544
|
-
const hasDateOpened = dateOpenedAliases.some(
|
|
2545
|
-
(col) => headers.includes(col)
|
|
2546
|
-
);
|
|
2560
|
+
const hasDateOpened = dateOpenedAliases.some((col) => headers.includes(col));
|
|
2547
2561
|
const hasPl = plAliases.some((col) => headers.includes(col));
|
|
2548
2562
|
const missing = [];
|
|
2549
2563
|
if (!hasDateOpened) missing.push("Date Opened");
|
|
@@ -2583,11 +2597,9 @@ async function importCsv(baseDir, options) {
|
|
|
2583
2597
|
const name = blockName;
|
|
2584
2598
|
const blockId = toKebabCase(name);
|
|
2585
2599
|
if (!blockId) {
|
|
2586
|
-
throw new Error(
|
|
2587
|
-
"Could not derive a valid block ID from the filename or provided name"
|
|
2588
|
-
);
|
|
2600
|
+
throw new Error("Could not derive a valid block ID from the filename or provided name");
|
|
2589
2601
|
}
|
|
2590
|
-
const blockPath =
|
|
2602
|
+
const blockPath = path10.join(blocksDir, blockId);
|
|
2591
2603
|
try {
|
|
2592
2604
|
await fs7.access(blockPath);
|
|
2593
2605
|
throw new Error(
|
|
@@ -2600,7 +2612,7 @@ async function importCsv(baseDir, options) {
|
|
|
2600
2612
|
}
|
|
2601
2613
|
await fs7.mkdir(blockPath, { recursive: true });
|
|
2602
2614
|
const targetFilename = csvType === "tradelog" ? "tradelog.csv" : csvType === "dailylog" ? "dailylog.csv" : "reportinglog.csv";
|
|
2603
|
-
const targetPath =
|
|
2615
|
+
const targetPath = path10.join(blockPath, targetFilename);
|
|
2604
2616
|
await fs7.copyFile(csvPath, targetPath);
|
|
2605
2617
|
let dateRange = {
|
|
2606
2618
|
start: null,
|
|
@@ -2744,10 +2756,7 @@ async function insertTradeBatch(conn, blockId, records, startIdx, batchSize) {
|
|
|
2744
2756
|
for (let rowIdx = 0; rowIdx < batch.length; rowIdx++) {
|
|
2745
2757
|
const record = batch[rowIdx];
|
|
2746
2758
|
const baseParam = rowIdx * columnsPerRow + 1;
|
|
2747
|
-
const rowPlaceholders = Array.from(
|
|
2748
|
-
{ length: columnsPerRow },
|
|
2749
|
-
(_, i) => `$${baseParam + i}`
|
|
2750
|
-
);
|
|
2759
|
+
const rowPlaceholders = Array.from({ length: columnsPerRow }, (_, i) => `$${baseParam + i}`);
|
|
2751
2760
|
placeholders.push(`(${rowPlaceholders.join(", ")})`);
|
|
2752
2761
|
const premium = parseFloat(record["Premium"]);
|
|
2753
2762
|
const numContracts = parseInt(record["No. of Contracts"], 10);
|
|
@@ -2815,10 +2824,7 @@ async function insertReportingBatch(conn, blockId, trades, tickers, startIdx, ba
|
|
|
2815
2824
|
for (let rowIdx = 0; rowIdx < batch.length; rowIdx++) {
|
|
2816
2825
|
const trade = batch[rowIdx];
|
|
2817
2826
|
const baseParam = rowIdx * columnsPerRow + 1;
|
|
2818
|
-
const rowPlaceholders = Array.from(
|
|
2819
|
-
{ length: columnsPerRow },
|
|
2820
|
-
(_, i) => `$${baseParam + i}`
|
|
2821
|
-
);
|
|
2827
|
+
const rowPlaceholders = Array.from({ length: columnsPerRow }, (_, i) => `$${baseParam + i}`);
|
|
2822
2828
|
placeholders.push(`(${rowPlaceholders.join(", ")})`);
|
|
2823
2829
|
params.push(
|
|
2824
2830
|
blockId,
|
|
@@ -2852,7 +2858,7 @@ function versionedHash(hash) {
|
|
|
2852
2858
|
return `${hash}:${PARSE_VERSION}`;
|
|
2853
2859
|
}
|
|
2854
2860
|
async function syncBlockInternal(conn, blockId, blockPath) {
|
|
2855
|
-
const blocksDir =
|
|
2861
|
+
const blocksDir = path11.dirname(blockPath);
|
|
2856
2862
|
try {
|
|
2857
2863
|
const existingMetadata = await getSyncMetadata(conn, blockId, blocksDir);
|
|
2858
2864
|
const tradelogFilename = await findTradelogFile(blockPath);
|
|
@@ -2860,14 +2866,8 @@ async function syncBlockInternal(conn, blockId, blockPath) {
|
|
|
2860
2866
|
if (existingMetadata) {
|
|
2861
2867
|
await conn.run("BEGIN TRANSACTION");
|
|
2862
2868
|
try {
|
|
2863
|
-
await conn.run(
|
|
2864
|
-
|
|
2865
|
-
[blockId]
|
|
2866
|
-
);
|
|
2867
|
-
await conn.run(
|
|
2868
|
-
"DELETE FROM trades.reporting_data WHERE block_id = $1",
|
|
2869
|
-
[blockId]
|
|
2870
|
-
);
|
|
2869
|
+
await conn.run("DELETE FROM trades.trade_data WHERE block_id = $1", [blockId]);
|
|
2870
|
+
await conn.run("DELETE FROM trades.reporting_data WHERE block_id = $1", [blockId]);
|
|
2871
2871
|
await deleteSyncMetadata(conn, blockId, blocksDir);
|
|
2872
2872
|
await conn.run("COMMIT");
|
|
2873
2873
|
return { blockId, status: "deleted" };
|
|
@@ -2882,12 +2882,12 @@ async function syncBlockInternal(conn, blockId, blockPath) {
|
|
|
2882
2882
|
error: "No tradelog CSV found in block"
|
|
2883
2883
|
};
|
|
2884
2884
|
}
|
|
2885
|
-
const tradelogPath =
|
|
2885
|
+
const tradelogPath = path11.join(blockPath, tradelogFilename);
|
|
2886
2886
|
const tradelogHash = versionedHash(await hashFileContent(tradelogPath));
|
|
2887
2887
|
if (existingMetadata && existingMetadata.tradelog_hash === tradelogHash) {
|
|
2888
2888
|
const optionalLogs = await findOptionalLogFiles(blockPath);
|
|
2889
2889
|
if (optionalLogs.reportinglog) {
|
|
2890
|
-
const reportinglogPath =
|
|
2890
|
+
const reportinglogPath = path11.join(blockPath, optionalLogs.reportinglog);
|
|
2891
2891
|
const reportinglogHash = versionedHash(await hashFileContent(reportinglogPath));
|
|
2892
2892
|
if (existingMetadata.reportinglog_hash !== reportinglogHash) {
|
|
2893
2893
|
} else {
|
|
@@ -2902,10 +2902,7 @@ async function syncBlockInternal(conn, blockId, blockPath) {
|
|
|
2902
2902
|
}
|
|
2903
2903
|
await conn.run("BEGIN TRANSACTION");
|
|
2904
2904
|
try {
|
|
2905
|
-
await conn.run(
|
|
2906
|
-
"DELETE FROM trades.trade_data WHERE block_id = $1",
|
|
2907
|
-
[blockId]
|
|
2908
|
-
);
|
|
2905
|
+
await conn.run("DELETE FROM trades.trade_data WHERE block_id = $1", [blockId]);
|
|
2909
2906
|
const csvContent = await fs8.readFile(tradelogPath, "utf-8");
|
|
2910
2907
|
const records = parseCSV2(csvContent);
|
|
2911
2908
|
const batchSize = 500;
|
|
@@ -2917,26 +2914,23 @@ async function syncBlockInternal(conn, blockId, blockPath) {
|
|
|
2917
2914
|
let reportinglogHash = null;
|
|
2918
2915
|
if (optionalLogs.dailylog) {
|
|
2919
2916
|
try {
|
|
2920
|
-
dailylogHash = versionedHash(
|
|
2921
|
-
|
|
2922
|
-
)
|
|
2917
|
+
dailylogHash = versionedHash(
|
|
2918
|
+
await hashFileContent(path11.join(blockPath, optionalLogs.dailylog))
|
|
2919
|
+
);
|
|
2923
2920
|
} catch {
|
|
2924
2921
|
}
|
|
2925
2922
|
}
|
|
2926
2923
|
if (optionalLogs.reportinglog) {
|
|
2927
2924
|
try {
|
|
2928
|
-
reportinglogHash = versionedHash(
|
|
2929
|
-
|
|
2930
|
-
)
|
|
2925
|
+
reportinglogHash = versionedHash(
|
|
2926
|
+
await hashFileContent(path11.join(blockPath, optionalLogs.reportinglog))
|
|
2927
|
+
);
|
|
2931
2928
|
} catch {
|
|
2932
2929
|
}
|
|
2933
2930
|
}
|
|
2934
|
-
await conn.run(
|
|
2935
|
-
"DELETE FROM trades.reporting_data WHERE block_id = $1",
|
|
2936
|
-
[blockId]
|
|
2937
|
-
);
|
|
2931
|
+
await conn.run("DELETE FROM trades.reporting_data WHERE block_id = $1", [blockId]);
|
|
2938
2932
|
if (optionalLogs.reportinglog && reportinglogHash) {
|
|
2939
|
-
const reportingPath =
|
|
2933
|
+
const reportingPath = path11.join(blockPath, optionalLogs.reportinglog);
|
|
2940
2934
|
const reportingContent = await fs8.readFile(reportingPath, "utf-8");
|
|
2941
2935
|
const reportingRecords = parseCSV2(reportingContent);
|
|
2942
2936
|
const reportingTrades = [];
|
|
@@ -2949,7 +2943,14 @@ async function syncBlockInternal(conn, blockId, blockPath) {
|
|
|
2949
2943
|
}
|
|
2950
2944
|
}
|
|
2951
2945
|
for (let i = 0; i < reportingTrades.length; i += batchSize) {
|
|
2952
|
-
await insertReportingBatch(
|
|
2946
|
+
await insertReportingBatch(
|
|
2947
|
+
conn,
|
|
2948
|
+
blockId,
|
|
2949
|
+
reportingTrades,
|
|
2950
|
+
reportingTickers,
|
|
2951
|
+
i,
|
|
2952
|
+
batchSize
|
|
2953
|
+
);
|
|
2953
2954
|
}
|
|
2954
2955
|
}
|
|
2955
2956
|
const newMetadata = {
|
|
@@ -2972,14 +2973,8 @@ async function syncBlockInternal(conn, blockId, blockPath) {
|
|
|
2972
2973
|
if (existingMetadata) {
|
|
2973
2974
|
try {
|
|
2974
2975
|
await conn.run("BEGIN TRANSACTION");
|
|
2975
|
-
await conn.run(
|
|
2976
|
-
|
|
2977
|
-
[blockId]
|
|
2978
|
-
);
|
|
2979
|
-
await conn.run(
|
|
2980
|
-
"DELETE FROM trades.reporting_data WHERE block_id = $1",
|
|
2981
|
-
[blockId]
|
|
2982
|
-
);
|
|
2976
|
+
await conn.run("DELETE FROM trades.trade_data WHERE block_id = $1", [blockId]);
|
|
2977
|
+
await conn.run("DELETE FROM trades.reporting_data WHERE block_id = $1", [blockId]);
|
|
2983
2978
|
await deleteSyncMetadata(conn, blockId, blocksDir);
|
|
2984
2979
|
await conn.run("COMMIT");
|
|
2985
2980
|
} catch {
|
|
@@ -3009,10 +3004,11 @@ async function detectBlockChanges(conn, baseDir) {
|
|
|
3009
3004
|
for (const entry of entries) {
|
|
3010
3005
|
if (!entry.isDirectory()) continue;
|
|
3011
3006
|
if (entry.name.startsWith(".") || entry.name.startsWith("_")) continue;
|
|
3012
|
-
if (entry.name.endsWith(".tmp") || entry.name.endsWith(".duckdb") || entry.name.endsWith(".duckdb.tmp"))
|
|
3007
|
+
if (entry.name.endsWith(".tmp") || entry.name.endsWith(".duckdb") || entry.name.endsWith(".duckdb.tmp"))
|
|
3008
|
+
continue;
|
|
3013
3009
|
const blockId = entry.name;
|
|
3014
3010
|
folderNames.add(blockId);
|
|
3015
|
-
const blockPath =
|
|
3011
|
+
const blockPath = path11.join(baseDir, blockId);
|
|
3016
3012
|
if (!syncedBlockIds.has(blockId)) {
|
|
3017
3013
|
const tradelog = await findTradelogFile(blockPath);
|
|
3018
3014
|
if (tradelog) {
|
|
@@ -3026,7 +3022,7 @@ async function detectBlockChanges(conn, baseDir) {
|
|
|
3026
3022
|
continue;
|
|
3027
3023
|
}
|
|
3028
3024
|
try {
|
|
3029
|
-
const tradelogPath =
|
|
3025
|
+
const tradelogPath = path11.join(blockPath, tradelogFilename);
|
|
3030
3026
|
const currentHash = versionedHash(await hashFileContent(tradelogPath));
|
|
3031
3027
|
const metadata = await getSyncMetadata(conn, blockId, baseDir);
|
|
3032
3028
|
if (!metadata || metadata.tradelog_hash !== currentHash) {
|
|
@@ -3034,7 +3030,7 @@ async function detectBlockChanges(conn, baseDir) {
|
|
|
3034
3030
|
} else {
|
|
3035
3031
|
const optionalLogs = await findOptionalLogFiles(blockPath);
|
|
3036
3032
|
if (optionalLogs.reportinglog) {
|
|
3037
|
-
const reportinglogPath =
|
|
3033
|
+
const reportinglogPath = path11.join(blockPath, optionalLogs.reportinglog);
|
|
3038
3034
|
const reportingHash = versionedHash(await hashFileContent(reportinglogPath));
|
|
3039
3035
|
if (metadata.reportinglog_hash !== reportingHash) {
|
|
3040
3036
|
toSync.push(blockId);
|
|
@@ -3058,14 +3054,8 @@ async function cleanupDeletedBlocks(conn, deletedBlockIds, blocksDir) {
|
|
|
3058
3054
|
for (const blockId of deletedBlockIds) {
|
|
3059
3055
|
await conn.run("BEGIN TRANSACTION");
|
|
3060
3056
|
try {
|
|
3061
|
-
await conn.run(
|
|
3062
|
-
|
|
3063
|
-
[blockId]
|
|
3064
|
-
);
|
|
3065
|
-
await conn.run(
|
|
3066
|
-
"DELETE FROM trades.reporting_data WHERE block_id = $1",
|
|
3067
|
-
[blockId]
|
|
3068
|
-
);
|
|
3057
|
+
await conn.run("DELETE FROM trades.trade_data WHERE block_id = $1", [blockId]);
|
|
3058
|
+
await conn.run("DELETE FROM trades.reporting_data WHERE block_id = $1", [blockId]);
|
|
3069
3059
|
await deleteSyncMetadata(conn, blockId, blocksDir);
|
|
3070
3060
|
await conn.run("COMMIT");
|
|
3071
3061
|
} catch (err) {
|
|
@@ -3082,7 +3072,7 @@ function setBlocksDir(dir) {
|
|
|
3082
3072
|
}
|
|
3083
3073
|
function getBlocksDir(baseDir) {
|
|
3084
3074
|
if (_blocksDir) return _blocksDir;
|
|
3085
|
-
const nestedBlocksDir =
|
|
3075
|
+
const nestedBlocksDir = path12.join(baseDir, "blocks");
|
|
3086
3076
|
return existsSync2(nestedBlocksDir) ? nestedBlocksDir : baseDir;
|
|
3087
3077
|
}
|
|
3088
3078
|
async function syncAllBlocks(baseDir) {
|
|
@@ -3101,7 +3091,7 @@ async function syncAllBlocks(baseDir) {
|
|
|
3101
3091
|
}
|
|
3102
3092
|
}
|
|
3103
3093
|
for (const blockId of toSync) {
|
|
3104
|
-
const blockPath =
|
|
3094
|
+
const blockPath = path12.join(blocksDir, blockId);
|
|
3105
3095
|
const result = await syncBlockInternal(conn, blockId, blockPath);
|
|
3106
3096
|
results.push(result);
|
|
3107
3097
|
if (result.status === "error" && result.error) {
|
|
@@ -3120,7 +3110,7 @@ async function syncAllBlocks(baseDir) {
|
|
|
3120
3110
|
async function syncBlock(blockId, baseDir) {
|
|
3121
3111
|
const conn = await getConnection(baseDir);
|
|
3122
3112
|
const blocksDir = getBlocksDir(baseDir);
|
|
3123
|
-
const blockPath =
|
|
3113
|
+
const blockPath = path12.join(blocksDir, blockId);
|
|
3124
3114
|
try {
|
|
3125
3115
|
await fs9.access(blockPath);
|
|
3126
3116
|
} catch {
|
|
@@ -3183,4 +3173,4 @@ export {
|
|
|
3183
3173
|
loadReportingLog,
|
|
3184
3174
|
importCsv
|
|
3185
3175
|
};
|
|
3186
|
-
//# sourceMappingURL=chunk-
|
|
3176
|
+
//# sourceMappingURL=chunk-RM4B2VKS.js.map
|