@discomedia/utils 1.0.46 → 1.0.51
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 +10 -1
- package/dist/index-frontend.cjs +151 -11
- package/dist/index-frontend.cjs.map +1 -1
- package/dist/index-frontend.mjs +151 -11
- package/dist/index-frontend.mjs.map +1 -1
- package/dist/index.cjs +151 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +151 -11
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +4 -4
- package/dist/test.js +292 -46
- package/dist/test.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/llm-config.d.ts.map +1 -1
- package/dist/types/llm-images.d.ts +6 -3
- package/dist/types/llm-images.d.ts.map +1 -1
- package/dist/types/llm-openai.d.ts.map +1 -1
- package/dist/types/market-time.d.ts +34 -0
- package/dist/types/market-time.d.ts.map +1 -1
- package/dist/types/types/llm-types.d.ts +10 -4
- package/dist/types/types/llm-types.d.ts.map +1 -1
- package/dist/types-frontend/index.d.ts +1 -0
- package/dist/types-frontend/index.d.ts.map +1 -1
- package/dist/types-frontend/llm-config.d.ts.map +1 -1
- package/dist/types-frontend/llm-images.d.ts +6 -3
- package/dist/types-frontend/llm-images.d.ts.map +1 -1
- package/dist/types-frontend/llm-openai.d.ts.map +1 -1
- package/dist/types-frontend/market-time.d.ts +34 -0
- package/dist/types-frontend/market-time.d.ts.map +1 -1
- package/dist/types-frontend/types/llm-types.d.ts +10 -4
- package/dist/types-frontend/types/llm-types.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.51",
|
|
7
7
|
"author": "Disco Media",
|
|
8
8
|
"description": "Utility functions used in Disco Media apps",
|
|
9
9
|
"always-build-npm": true,
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"dotenv": "^17.2.3",
|
|
36
|
-
"openai": "^6.
|
|
36
|
+
"openai": "^6.15.0",
|
|
37
37
|
"p-limit": "^7.2.0",
|
|
38
38
|
"tslib": "^2.8.1",
|
|
39
39
|
"ws": "^8.18.3"
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
46
46
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
47
47
|
"@types/ws": "^8.18.1",
|
|
48
|
-
"lightweight-charts": "^5.0
|
|
49
|
-
"rollup": "^4.53.
|
|
48
|
+
"lightweight-charts": "^5.1.0",
|
|
49
|
+
"rollup": "^4.53.5",
|
|
50
50
|
"typescript": "^5.9.3"
|
|
51
51
|
}
|
|
52
52
|
}
|
package/dist/test.js
CHANGED
|
@@ -447,9 +447,10 @@ function getLastFullTradingDateImpl(currentDate = new Date()) {
|
|
|
447
447
|
if (calendar.isEarlyCloseDay(prevMarketDay)) {
|
|
448
448
|
prevCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
449
449
|
}
|
|
450
|
-
const
|
|
451
|
-
const
|
|
452
|
-
const
|
|
450
|
+
const prevNYDate = toNYTime(prevMarketDay);
|
|
451
|
+
const year = prevNYDate.getUTCFullYear();
|
|
452
|
+
const month = prevNYDate.getUTCMonth();
|
|
453
|
+
const day = prevNYDate.getUTCDate();
|
|
453
454
|
const closeHour = Math.floor(prevCloseMinutes / 60);
|
|
454
455
|
const closeMinute = prevCloseMinutes % 60;
|
|
455
456
|
return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));
|
|
@@ -963,6 +964,61 @@ function countTradingDays(startDate, endDate = new Date()) {
|
|
|
963
964
|
minutes: Math.round(minutes),
|
|
964
965
|
};
|
|
965
966
|
}
|
|
967
|
+
/**
|
|
968
|
+
* Returns the trading day N days back from a reference date, along with its market open time.
|
|
969
|
+
* Trading days are counted as full or half trading days (days that end count as 1 full trading day).
|
|
970
|
+
*
|
|
971
|
+
* @param options - Object with:
|
|
972
|
+
* - referenceDate: Date to count back from (default: now)
|
|
973
|
+
* - days: Number of trading days to go back (must be >= 1)
|
|
974
|
+
* @returns Object containing:
|
|
975
|
+
* - date: Trading date in YYYY-MM-DD format
|
|
976
|
+
* - marketOpenISO: Market open time as ISO string (e.g., "2025-11-15T13:30:00.000Z")
|
|
977
|
+
* - unixTimestamp: Market open time as Unix timestamp in seconds
|
|
978
|
+
* @example
|
|
979
|
+
* ```typescript
|
|
980
|
+
* // Get the trading day 1 day back (most recent full trading day)
|
|
981
|
+
* const result = getTradingDaysBack({ days: 1 });
|
|
982
|
+
* console.log(result.date); // "2025-11-01"
|
|
983
|
+
* console.log(result.marketOpenISO); // "2025-11-01T13:30:00.000Z"
|
|
984
|
+
* console.log(result.unixTimestamp); // 1730466600
|
|
985
|
+
*
|
|
986
|
+
* // Get the trading day 5 days back from a specific date
|
|
987
|
+
* const result2 = getTradingDaysBack({
|
|
988
|
+
* referenceDate: new Date('2025-11-15T12:00:00-05:00'),
|
|
989
|
+
* days: 5
|
|
990
|
+
* });
|
|
991
|
+
* ```
|
|
992
|
+
*/
|
|
993
|
+
function getTradingDaysBack(options) {
|
|
994
|
+
const calendar = new MarketCalendar();
|
|
995
|
+
const refDate = options.referenceDate || new Date();
|
|
996
|
+
const daysBack = options.days;
|
|
997
|
+
if (daysBack < 1) {
|
|
998
|
+
throw new Error('days must be at least 1');
|
|
999
|
+
}
|
|
1000
|
+
// Start from the last full trading date relative to reference
|
|
1001
|
+
let targetDate = getLastFullTradingDateImpl(refDate);
|
|
1002
|
+
// Go back the specified number of days (we're already at day 1, so go back days-1 more)
|
|
1003
|
+
for (let i = 1; i < daysBack; i++) {
|
|
1004
|
+
targetDate = calendar.getPreviousMarketDay(targetDate);
|
|
1005
|
+
}
|
|
1006
|
+
// Get market open time for this date
|
|
1007
|
+
const marketTimes = getMarketTimes(targetDate);
|
|
1008
|
+
if (!marketTimes.open) {
|
|
1009
|
+
throw new Error(`No market open time for target date`);
|
|
1010
|
+
}
|
|
1011
|
+
// Format the date string (YYYY-MM-DD) in NY time
|
|
1012
|
+
const nyDate = toNYTime(marketTimes.open);
|
|
1013
|
+
const dateStr = `${nyDate.getUTCFullYear()}-${String(nyDate.getUTCMonth() + 1).padStart(2, '0')}-${String(nyDate.getUTCDate()).padStart(2, '0')}`;
|
|
1014
|
+
const marketOpenISO = marketTimes.open.toISOString();
|
|
1015
|
+
const unixTimestamp = Math.floor(marketTimes.open.getTime() / 1000);
|
|
1016
|
+
return {
|
|
1017
|
+
date: dateStr,
|
|
1018
|
+
marketOpenISO,
|
|
1019
|
+
unixTimestamp,
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
966
1022
|
// Export MARKET_TIMES for compatibility
|
|
967
1023
|
const MARKET_TIMES = {
|
|
968
1024
|
TIMEZONE: MARKET_CONFIG.TIMEZONE,
|
|
@@ -1085,6 +1141,10 @@ function isOpenRouterModel(model) {
|
|
|
1085
1141
|
'openai/gpt-5-mini',
|
|
1086
1142
|
'openai/gpt-5-nano',
|
|
1087
1143
|
'openai/gpt-5.1',
|
|
1144
|
+
'openai/gpt-5.2',
|
|
1145
|
+
'openai/gpt-5.2-pro',
|
|
1146
|
+
'openai/gpt-5.1-codex',
|
|
1147
|
+
'openai/gpt-5.1-codex-max',
|
|
1088
1148
|
'openai/gpt-oss-120b',
|
|
1089
1149
|
'z.ai/glm-4.5',
|
|
1090
1150
|
'z.ai/glm-4.5-air',
|
|
@@ -2450,7 +2510,7 @@ const safeJSON = (text) => {
|
|
|
2450
2510
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2451
2511
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2452
2512
|
|
|
2453
|
-
const VERSION = '6.
|
|
2513
|
+
const VERSION = '6.15.0'; // x-release-please-version
|
|
2454
2514
|
|
|
2455
2515
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2456
2516
|
const isRunningInBrowser = () => {
|
|
@@ -8291,6 +8351,19 @@ class Responses extends APIResource {
|
|
|
8291
8351
|
cancel(responseID, options) {
|
|
8292
8352
|
return this._client.post(path `/responses/${responseID}/cancel`, options);
|
|
8293
8353
|
}
|
|
8354
|
+
/**
|
|
8355
|
+
* Compact conversation
|
|
8356
|
+
*
|
|
8357
|
+
* @example
|
|
8358
|
+
* ```ts
|
|
8359
|
+
* const compactedResponse = await client.responses.compact({
|
|
8360
|
+
* model: 'gpt-5.2',
|
|
8361
|
+
* });
|
|
8362
|
+
* ```
|
|
8363
|
+
*/
|
|
8364
|
+
compact(body, options) {
|
|
8365
|
+
return this._client.post('/responses/compact', { body, ...options });
|
|
8366
|
+
}
|
|
8294
8367
|
}
|
|
8295
8368
|
Responses.InputItems = InputItems;
|
|
8296
8369
|
Responses.InputTokens = InputTokens;
|
|
@@ -9433,6 +9506,22 @@ const openAiModelCosts = {
|
|
|
9433
9506
|
inputCost: 1.25 / 1_000_000,
|
|
9434
9507
|
outputCost: 10 / 1_000_000,
|
|
9435
9508
|
},
|
|
9509
|
+
'gpt-5.2': {
|
|
9510
|
+
inputCost: 1.5 / 1_000_000,
|
|
9511
|
+
outputCost: 12 / 1_000_000,
|
|
9512
|
+
},
|
|
9513
|
+
'gpt-5.2-pro': {
|
|
9514
|
+
inputCost: 3 / 1_000_000,
|
|
9515
|
+
outputCost: 24 / 1_000_000,
|
|
9516
|
+
},
|
|
9517
|
+
'gpt-5.1-codex': {
|
|
9518
|
+
inputCost: 1.1 / 1_000_000,
|
|
9519
|
+
outputCost: 8.8 / 1_000_000,
|
|
9520
|
+
},
|
|
9521
|
+
'gpt-5.1-codex-max': {
|
|
9522
|
+
inputCost: 1.8 / 1_000_000,
|
|
9523
|
+
outputCost: 14.4 / 1_000_000,
|
|
9524
|
+
},
|
|
9436
9525
|
'o4-mini': {
|
|
9437
9526
|
inputCost: 1.1 / 1_000_000,
|
|
9438
9527
|
outputCost: 4.4 / 1_000_000,
|
|
@@ -9453,6 +9542,7 @@ const deepseekModelCosts = {
|
|
|
9453
9542
|
/** Image generation costs in USD per image. Based on OpenAI pricing as of Feb 2025. */
|
|
9454
9543
|
const openAiImageCosts = {
|
|
9455
9544
|
'gpt-image-1': 0.0075, // $0.0075 per image for gpt-image-1
|
|
9545
|
+
'gpt-image-1.5': 0.0075, // Assumes parity pricing with gpt-image-1 until OpenAI publishes updated rates
|
|
9456
9546
|
};
|
|
9457
9547
|
/**
|
|
9458
9548
|
* Calculates the cost of generating images using OpenAI's Images API.
|
|
@@ -9462,10 +9552,12 @@ const openAiImageCosts = {
|
|
|
9462
9552
|
* @returns The cost of generating the images in USD.
|
|
9463
9553
|
*/
|
|
9464
9554
|
function calculateImageCost(model, imageCount) {
|
|
9465
|
-
if (typeof imageCount !== 'number' || imageCount <= 0) {
|
|
9555
|
+
if (typeof model !== 'string' || typeof imageCount !== 'number' || imageCount <= 0) {
|
|
9466
9556
|
return 0;
|
|
9467
9557
|
}
|
|
9468
9558
|
const costPerImage = openAiImageCosts[model];
|
|
9559
|
+
if (!costPerImage)
|
|
9560
|
+
return 0;
|
|
9469
9561
|
return imageCount * costPerImage;
|
|
9470
9562
|
}
|
|
9471
9563
|
/**
|
|
@@ -9894,6 +9986,10 @@ const isSupportedModel = (model) => {
|
|
|
9894
9986
|
'gpt-5-mini',
|
|
9895
9987
|
'gpt-5-nano',
|
|
9896
9988
|
'gpt-5.1',
|
|
9989
|
+
'gpt-5.2',
|
|
9990
|
+
'gpt-5.2-pro',
|
|
9991
|
+
'gpt-5.1-codex',
|
|
9992
|
+
'gpt-5.1-codex-max',
|
|
9897
9993
|
'o4-mini',
|
|
9898
9994
|
'o3',
|
|
9899
9995
|
].includes(model);
|
|
@@ -9906,7 +10002,21 @@ const isSupportedModel = (model) => {
|
|
|
9906
10002
|
function supportsTemperature(model) {
|
|
9907
10003
|
// Reasoning models don't support temperature
|
|
9908
10004
|
// GPT-5 models also do not support temperature
|
|
9909
|
-
const reasoningAndGPT5Models = [
|
|
10005
|
+
const reasoningAndGPT5Models = [
|
|
10006
|
+
'o1',
|
|
10007
|
+
'o1-mini',
|
|
10008
|
+
'o3-mini',
|
|
10009
|
+
'o4-mini',
|
|
10010
|
+
'o3',
|
|
10011
|
+
'gpt-5',
|
|
10012
|
+
'gpt-5-mini',
|
|
10013
|
+
'gpt-5-nano',
|
|
10014
|
+
'gpt-5.1',
|
|
10015
|
+
'gpt-5.2',
|
|
10016
|
+
'gpt-5.2-pro',
|
|
10017
|
+
'gpt-5.1-codex',
|
|
10018
|
+
'gpt-5.1-codex-max',
|
|
10019
|
+
];
|
|
9910
10020
|
return !reasoningAndGPT5Models.includes(model);
|
|
9911
10021
|
}
|
|
9912
10022
|
/**
|
|
@@ -9924,7 +10034,16 @@ function isReasoningModel(model) {
|
|
|
9924
10034
|
* @returns True if the model is a GPT-5 model, false otherwise.
|
|
9925
10035
|
*/
|
|
9926
10036
|
function isGPT5Model(model) {
|
|
9927
|
-
const gpt5Models = [
|
|
10037
|
+
const gpt5Models = [
|
|
10038
|
+
'gpt-5',
|
|
10039
|
+
'gpt-5-mini',
|
|
10040
|
+
'gpt-5-nano',
|
|
10041
|
+
'gpt-5.1',
|
|
10042
|
+
'gpt-5.2',
|
|
10043
|
+
'gpt-5.2-pro',
|
|
10044
|
+
'gpt-5.1-codex',
|
|
10045
|
+
'gpt-5.1-codex-max',
|
|
10046
|
+
];
|
|
9928
10047
|
return gpt5Models.includes(model);
|
|
9929
10048
|
}
|
|
9930
10049
|
/**
|
|
@@ -10165,6 +10284,20 @@ async function makeLLMCall(input, options = {}) {
|
|
|
10165
10284
|
return await makeResponsesAPICall(processedInput, responsesOptions);
|
|
10166
10285
|
}
|
|
10167
10286
|
|
|
10287
|
+
const DEFAULT_IMAGE_MODEL = 'gpt-image-1.5';
|
|
10288
|
+
const resolveImageModel = (model) => model ?? DEFAULT_IMAGE_MODEL;
|
|
10289
|
+
const MULTIMODAL_VISION_MODELS = new Set([
|
|
10290
|
+
'gpt-4o-mini',
|
|
10291
|
+
'gpt-4o',
|
|
10292
|
+
'gpt-5',
|
|
10293
|
+
'gpt-5-mini',
|
|
10294
|
+
'gpt-5-nano',
|
|
10295
|
+
'gpt-5.1',
|
|
10296
|
+
'gpt-5.2',
|
|
10297
|
+
'gpt-5.2-pro',
|
|
10298
|
+
'gpt-5.1-codex',
|
|
10299
|
+
'gpt-5.1-codex-max',
|
|
10300
|
+
]);
|
|
10168
10301
|
/**
|
|
10169
10302
|
* Makes a call to the OpenAI Images API to generate images based on a text prompt.
|
|
10170
10303
|
*
|
|
@@ -10201,7 +10334,12 @@ async function makeLLMCall(input, options = {}) {
|
|
|
10201
10334
|
* @throws Error if the API call fails or invalid parameters are provided
|
|
10202
10335
|
*/
|
|
10203
10336
|
async function makeImagesCall(prompt, options = {}) {
|
|
10204
|
-
const { size = 'auto', outputFormat = 'webp', compression = 50, quality = 'high', count = 1, background = 'auto', moderation = 'auto', apiKey } = options;
|
|
10337
|
+
const { model, size = 'auto', outputFormat = 'webp', compression = 50, quality = 'high', count = 1, background = 'auto', moderation = 'auto', apiKey, visionModel, } = options;
|
|
10338
|
+
const imageModel = resolveImageModel(model);
|
|
10339
|
+
const supportedVisionModel = visionModel && MULTIMODAL_VISION_MODELS.has(visionModel) ? visionModel : undefined;
|
|
10340
|
+
if (visionModel && !supportedVisionModel) {
|
|
10341
|
+
console.warn(`Vision model ${visionModel} is not recognized as a multimodal OpenAI model. Ignoring for image usage metadata.`);
|
|
10342
|
+
}
|
|
10205
10343
|
// Get API key
|
|
10206
10344
|
const effectiveApiKey = apiKey || process.env.OPENAI_API_KEY;
|
|
10207
10345
|
if (!effectiveApiKey) {
|
|
@@ -10222,7 +10360,7 @@ async function makeImagesCall(prompt, options = {}) {
|
|
|
10222
10360
|
});
|
|
10223
10361
|
// Build the request parameters using OpenAI's type
|
|
10224
10362
|
const requestParams = {
|
|
10225
|
-
model:
|
|
10363
|
+
model: imageModel,
|
|
10226
10364
|
prompt,
|
|
10227
10365
|
n: count || 1,
|
|
10228
10366
|
size: size || 'auto',
|
|
@@ -10246,7 +10384,7 @@ async function makeImagesCall(prompt, options = {}) {
|
|
|
10246
10384
|
throw new Error('No images returned from OpenAI Images API');
|
|
10247
10385
|
}
|
|
10248
10386
|
// Calculate cost
|
|
10249
|
-
const cost = calculateImageCost(
|
|
10387
|
+
const cost = calculateImageCost(imageModel, count || 1);
|
|
10250
10388
|
// Return the response with enhanced usage information
|
|
10251
10389
|
const enhancedResponse = {
|
|
10252
10390
|
...response,
|
|
@@ -10259,8 +10397,9 @@ async function makeImagesCall(prompt, options = {}) {
|
|
|
10259
10397
|
total_tokens: 0,
|
|
10260
10398
|
}),
|
|
10261
10399
|
provider: 'openai',
|
|
10262
|
-
model:
|
|
10400
|
+
model: imageModel,
|
|
10263
10401
|
cost,
|
|
10402
|
+
...(supportedVisionModel ? { visionModel: supportedVisionModel } : {}),
|
|
10264
10403
|
},
|
|
10265
10404
|
};
|
|
10266
10405
|
return enhancedResponse;
|
|
@@ -19387,6 +19526,7 @@ const disco = {
|
|
|
19387
19526
|
getNYTimeZone: getNYTimeZone,
|
|
19388
19527
|
getTradingDate: getTradingDate,
|
|
19389
19528
|
getTradingStartAndEndDates: getTradingStartAndEndDates,
|
|
19529
|
+
getTradingDaysBack: getTradingDaysBack,
|
|
19390
19530
|
isMarketDay: isMarketDay,
|
|
19391
19531
|
isWithinMarketHours: isWithinMarketHours,
|
|
19392
19532
|
countTradingDays: countTradingDays,
|
|
@@ -19401,47 +19541,151 @@ const disco = {
|
|
|
19401
19541
|
};
|
|
19402
19542
|
|
|
19403
19543
|
// Test file for context functionality
|
|
19404
|
-
|
|
19405
|
-
|
|
19406
|
-
|
|
19407
|
-
|
|
19408
|
-
|
|
19409
|
-
|
|
19410
|
-
|
|
19411
|
-
|
|
19412
|
-
|
|
19413
|
-
|
|
19414
|
-
|
|
19415
|
-
|
|
19416
|
-
|
|
19417
|
-
|
|
19418
|
-
|
|
19419
|
-
|
|
19420
|
-
|
|
19544
|
+
function testGetTradingDaysBack() {
|
|
19545
|
+
const testCases = [
|
|
19546
|
+
{
|
|
19547
|
+
label: '1 day back from Friday after close',
|
|
19548
|
+
referenceDate: '2025-07-11T18:00:00-04:00',
|
|
19549
|
+
days: 1,
|
|
19550
|
+
expected: {
|
|
19551
|
+
date: '2025-07-11',
|
|
19552
|
+
marketOpenISO: '2025-07-11T13:30:00.000Z',
|
|
19553
|
+
},
|
|
19554
|
+
},
|
|
19555
|
+
{
|
|
19556
|
+
label: '1 day back from Friday during market',
|
|
19557
|
+
referenceDate: '2025-07-11T10:00:00-04:00',
|
|
19558
|
+
days: 1,
|
|
19559
|
+
expected: {
|
|
19560
|
+
date: '2025-07-10',
|
|
19561
|
+
marketOpenISO: '2025-07-10T13:30:00.000Z',
|
|
19562
|
+
},
|
|
19563
|
+
},
|
|
19564
|
+
{
|
|
19565
|
+
label: '2 days back from Friday after close',
|
|
19566
|
+
referenceDate: '2025-07-11T18:00:00-04:00',
|
|
19567
|
+
days: 2,
|
|
19568
|
+
expected: {
|
|
19569
|
+
date: '2025-07-10',
|
|
19570
|
+
marketOpenISO: '2025-07-10T13:30:00.000Z',
|
|
19571
|
+
},
|
|
19572
|
+
},
|
|
19573
|
+
{
|
|
19574
|
+
label: '5 days back from Friday after close',
|
|
19575
|
+
referenceDate: '2025-07-11T18:00:00-04:00',
|
|
19576
|
+
days: 5,
|
|
19577
|
+
expected: {
|
|
19578
|
+
date: '2025-07-07',
|
|
19579
|
+
marketOpenISO: '2025-07-07T13:30:00.000Z',
|
|
19580
|
+
},
|
|
19581
|
+
},
|
|
19582
|
+
{
|
|
19583
|
+
label: '6 days back from Friday after close (skips weekend and July 4)',
|
|
19584
|
+
referenceDate: '2025-07-11T18:00:00-04:00',
|
|
19585
|
+
days: 6,
|
|
19586
|
+
expected: {
|
|
19587
|
+
date: '2025-07-03',
|
|
19588
|
+
marketOpenISO: '2025-07-03T13:30:00.000Z',
|
|
19589
|
+
},
|
|
19590
|
+
},
|
|
19591
|
+
{
|
|
19592
|
+
label: '1 day back from Monday after close (should be Monday)',
|
|
19593
|
+
referenceDate: '2025-07-14T18:00:00-04:00',
|
|
19594
|
+
days: 1,
|
|
19595
|
+
expected: {
|
|
19596
|
+
date: '2025-07-14',
|
|
19597
|
+
marketOpenISO: '2025-07-14T13:30:00.000Z',
|
|
19598
|
+
},
|
|
19599
|
+
},
|
|
19600
|
+
{
|
|
19601
|
+
label: '1 day back from Saturday (should be Friday)',
|
|
19602
|
+
referenceDate: '2025-07-12T12:00:00-04:00',
|
|
19603
|
+
days: 1,
|
|
19604
|
+
expected: {
|
|
19605
|
+
date: '2025-07-11',
|
|
19606
|
+
marketOpenISO: '2025-07-11T13:30:00.000Z',
|
|
19607
|
+
},
|
|
19608
|
+
},
|
|
19609
|
+
{
|
|
19610
|
+
label: '3 days back from Monday (skips weekend)',
|
|
19611
|
+
referenceDate: '2025-07-14T18:00:00-04:00',
|
|
19612
|
+
days: 3,
|
|
19613
|
+
expected: {
|
|
19614
|
+
date: '2025-07-10',
|
|
19615
|
+
marketOpenISO: '2025-07-10T13:30:00.000Z',
|
|
19616
|
+
},
|
|
19617
|
+
},
|
|
19618
|
+
{
|
|
19619
|
+
label: '1 day back from day after holiday (July 7, after July 4)',
|
|
19620
|
+
referenceDate: '2025-07-07T18:00:00-04:00',
|
|
19621
|
+
days: 1,
|
|
19622
|
+
expected: {
|
|
19623
|
+
date: '2025-07-07',
|
|
19624
|
+
marketOpenISO: '2025-07-07T13:30:00.000Z',
|
|
19625
|
+
},
|
|
19626
|
+
},
|
|
19627
|
+
{
|
|
19628
|
+
label: '2 days back from day after holiday (skips July 4)',
|
|
19629
|
+
referenceDate: '2025-07-07T18:00:00-04:00',
|
|
19630
|
+
days: 2,
|
|
19631
|
+
expected: {
|
|
19632
|
+
date: '2025-07-03',
|
|
19633
|
+
marketOpenISO: '2025-07-03T13:30:00.000Z',
|
|
19634
|
+
},
|
|
19635
|
+
},
|
|
19636
|
+
{
|
|
19637
|
+
label: 'Early close day (July 3) - 1 day back from July 7',
|
|
19638
|
+
referenceDate: '2025-07-07T18:00:00-04:00',
|
|
19639
|
+
days: 2,
|
|
19640
|
+
expected: {
|
|
19641
|
+
date: '2025-07-03',
|
|
19642
|
+
marketOpenISO: '2025-07-03T13:30:00.000Z', // Still opens at normal time
|
|
19643
|
+
},
|
|
19644
|
+
},
|
|
19645
|
+
];
|
|
19646
|
+
console.log('\n=== Testing getTradingDaysBack ===\n');
|
|
19647
|
+
for (const { label, referenceDate, days, expected } of testCases) {
|
|
19421
19648
|
try {
|
|
19422
|
-
const
|
|
19423
|
-
const
|
|
19424
|
-
|
|
19425
|
-
|
|
19649
|
+
const refDate = new Date(referenceDate);
|
|
19650
|
+
const result = disco.time.getTradingDaysBack({ referenceDate: refDate, days });
|
|
19651
|
+
const dateMatches = result.date === expected.date;
|
|
19652
|
+
const isoMatches = result.marketOpenISO === expected.marketOpenISO;
|
|
19653
|
+
const unixValid = typeof result.unixTimestamp === 'number' && result.unixTimestamp > 0;
|
|
19654
|
+
// Verify unix timestamp matches ISO
|
|
19655
|
+
const dateFromUnix = new Date(result.unixTimestamp * 1000).toISOString();
|
|
19656
|
+
const unixMatches = dateFromUnix === result.marketOpenISO;
|
|
19657
|
+
const allPass = dateMatches && isoMatches && unixValid && unixMatches;
|
|
19658
|
+
console.log(`${allPass ? '✅' : '❌'} ${label}`);
|
|
19659
|
+
if (!allPass) {
|
|
19660
|
+
console.log(` Expected: ${JSON.stringify(expected)}`);
|
|
19661
|
+
console.log(` Got: ${JSON.stringify(result)}`);
|
|
19662
|
+
if (!dateMatches)
|
|
19663
|
+
console.log(` ❌ Date mismatch`);
|
|
19664
|
+
if (!isoMatches)
|
|
19665
|
+
console.log(` ❌ ISO mismatch`);
|
|
19666
|
+
if (!unixValid)
|
|
19667
|
+
console.log(` ❌ Unix timestamp invalid`);
|
|
19668
|
+
if (!unixMatches)
|
|
19669
|
+
console.log(` ❌ Unix timestamp doesn't match ISO`);
|
|
19426
19670
|
}
|
|
19427
|
-
console.log(`Response: ${JSON.stringify(json.response)}`);
|
|
19428
19671
|
}
|
|
19429
|
-
catch (
|
|
19430
|
-
console.
|
|
19672
|
+
catch (error) {
|
|
19673
|
+
console.log(`❌ ${label}`);
|
|
19674
|
+
console.log(` Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
19431
19675
|
}
|
|
19432
|
-
|
|
19676
|
+
}
|
|
19677
|
+
const totalTests = testCases.length;
|
|
19678
|
+
const passedTests = testCases.filter((tc) => {
|
|
19433
19679
|
try {
|
|
19434
|
-
const
|
|
19435
|
-
const
|
|
19436
|
-
|
|
19437
|
-
throw new Error('No response from LLM');
|
|
19438
|
-
}
|
|
19439
|
-
console.log(`Response: ${tool.response}`);
|
|
19680
|
+
const refDate = new Date(tc.referenceDate);
|
|
19681
|
+
const result = disco.time.getTradingDaysBack({ referenceDate: refDate, days: tc.days });
|
|
19682
|
+
return result.date === tc.expected.date && result.marketOpenISO === tc.expected.marketOpenISO;
|
|
19440
19683
|
}
|
|
19441
|
-
catch
|
|
19442
|
-
|
|
19684
|
+
catch {
|
|
19685
|
+
return false;
|
|
19443
19686
|
}
|
|
19444
|
-
}
|
|
19687
|
+
}).length;
|
|
19688
|
+
console.log(`\n=== Summary: ${passedTests}/${totalTests} tests passed ===\n`);
|
|
19445
19689
|
}
|
|
19446
19690
|
// testGetTradingDate();
|
|
19447
19691
|
// testGetTradingStartAndEndDates();
|
|
@@ -19458,5 +19702,7 @@ async function testLLM() {
|
|
|
19458
19702
|
// testWebSocketConnectAndDisconnect();
|
|
19459
19703
|
// testGetAssetsShortableFilter();
|
|
19460
19704
|
// testMarketDataAPI();
|
|
19461
|
-
testLLM();
|
|
19705
|
+
// testLLM();
|
|
19706
|
+
// testImageModelDefaults();
|
|
19707
|
+
testGetTradingDaysBack();
|
|
19462
19708
|
//# sourceMappingURL=test.js.map
|