@tradejs/infra 1.0.8 → 1.0.9

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.
@@ -122,6 +122,31 @@ var parseJsonOrDeleteKey = async (redis, key, raw, fallback) => {
122
122
  return fallback;
123
123
  }
124
124
  };
125
+ var parseHashMap = (value) => {
126
+ if (!value) {
127
+ return {};
128
+ }
129
+ if (Array.isArray(value)) {
130
+ const result = {};
131
+ for (let index = 0; index < value.length; index += 2) {
132
+ const field = value[index];
133
+ const fieldValue = value[index + 1];
134
+ if (field == null || fieldValue == null) {
135
+ continue;
136
+ }
137
+ result[String(field)] = toResultString(fieldValue) ?? "";
138
+ }
139
+ return result;
140
+ }
141
+ if (typeof value === "object") {
142
+ return Object.fromEntries(
143
+ Object.entries(value).map(
144
+ ([field, fieldValue]) => [field, toResultString(fieldValue) ?? ""]
145
+ )
146
+ );
147
+ }
148
+ return {};
149
+ };
125
150
  var getKeys = async (prefix) => {
126
151
  if (redisUnavailable) return [];
127
152
  const redis = await getReadyRedis();
@@ -258,6 +283,96 @@ var setData = async (key, data, options = {}) => {
258
283
  }
259
284
  }
260
285
  };
286
+ var setHashJsonField = async (key, field, data, options = {}) => {
287
+ if (redisUnavailable) return;
288
+ const { expire } = { ...DEFAULT_OPTIONS, ...options };
289
+ const redis = await getReadyRedis();
290
+ if (!redis) return;
291
+ try {
292
+ await redis.call("HSET", key, field, toJson(data));
293
+ if (expire) {
294
+ await redis.expire(key, expire);
295
+ }
296
+ } catch (e) {
297
+ if (e instanceof Error && isRedisConnectivityError(e)) {
298
+ markRedisUnavailable(e);
299
+ return;
300
+ }
301
+ logger.log("error", "failed HSET %s[%s]: %s", key, field, String(e));
302
+ }
303
+ };
304
+ var getHashJsonValues = async (key) => {
305
+ if (redisUnavailable) return [];
306
+ const redis = await getReadyRedis();
307
+ if (!redis) return [];
308
+ try {
309
+ const raw = await redis.call("HGETALL", key);
310
+ const values = Object.values(parseHashMap(raw));
311
+ const parsed = [];
312
+ for (const value of values) {
313
+ if (!value) {
314
+ continue;
315
+ }
316
+ try {
317
+ parsed.push(JSON.parse(value));
318
+ } catch (e) {
319
+ logger.log(
320
+ "error",
321
+ "failed JSON.parse(HGETALL %s value): %s",
322
+ key,
323
+ String(e)
324
+ );
325
+ }
326
+ }
327
+ return parsed;
328
+ } catch (e) {
329
+ if (e instanceof Error && isRedisConnectivityError(e)) {
330
+ markRedisUnavailable(e);
331
+ return [];
332
+ }
333
+ logger.log("error", "failed HGETALL %s: %s", key, String(e));
334
+ return [];
335
+ }
336
+ };
337
+ var incrHashFields = async (key, increments, options = {}) => {
338
+ if (redisUnavailable) return;
339
+ const { expire } = { ...DEFAULT_OPTIONS, ...options };
340
+ const redis = await getReadyRedis();
341
+ if (!redis) return;
342
+ try {
343
+ for (const [field, increment] of Object.entries(increments)) {
344
+ if (!Number.isFinite(increment) || increment === 0) {
345
+ continue;
346
+ }
347
+ await redis.call("HINCRBY", key, field, Math.trunc(increment));
348
+ }
349
+ if (expire) {
350
+ await redis.expire(key, expire);
351
+ }
352
+ } catch (e) {
353
+ if (e instanceof Error && isRedisConnectivityError(e)) {
354
+ markRedisUnavailable(e);
355
+ return;
356
+ }
357
+ logger.log("error", "failed HINCRBY %s: %s", key, String(e));
358
+ }
359
+ };
360
+ var getHashData = async (key) => {
361
+ if (redisUnavailable) return {};
362
+ const redis = await getReadyRedis();
363
+ if (!redis) return {};
364
+ try {
365
+ const raw = await redis.call("HGETALL", key);
366
+ return parseHashMap(raw);
367
+ } catch (e) {
368
+ if (e instanceof Error && isRedisConnectivityError(e)) {
369
+ markRedisUnavailable(e);
370
+ return {};
371
+ }
372
+ logger.log("error", "failed HGETALL %s: %s", key, String(e));
373
+ return {};
374
+ }
375
+ };
261
376
  var createScreenshotSessionToken = async (userName) => {
262
377
  const token = randomBytes(24).toString("hex");
263
378
  await setData(
@@ -311,8 +426,14 @@ var redisKeys = {
311
426
  storeSignal: (symbol, signalId) => `store:signals:${symbol}:${signalId}`,
312
427
  runtimeSignals: (userName) => `users:${userName}:runtime:signals:`,
313
428
  runtimeSignal: (userName, signalId) => `users:${userName}:runtime:signals:${signalId}`,
429
+ runtimeSignalBuckets: (userName) => `users:${userName}:runtime:signals:days:`,
430
+ runtimeSignalBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signals:days:${dayKey}:${strategyName}`,
314
431
  runtimeSignalEvaluations: (userName) => `users:${userName}:runtime:signal-evaluations:`,
315
432
  runtimeSignalEvaluation: (userName, evaluationId) => `users:${userName}:runtime:signal-evaluations:${evaluationId}`,
433
+ runtimeSignalEvaluationBuckets: (userName) => `users:${userName}:runtime:signal-evaluations:days:`,
434
+ runtimeSignalEvaluationBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signal-evaluations:days:${dayKey}:${strategyName}`,
435
+ runtimeSignalEvaluationStatsBuckets: (userName) => `users:${userName}:runtime:signal-evaluation-stats:days:`,
436
+ runtimeSignalEvaluationStatsBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signal-evaluation-stats:days:${dayKey}:${strategyName}`,
316
437
  runtimeTrades: (userName) => `users:${userName}:runtime:trade-records:`,
317
438
  runtimeTrade: (userName, orderId) => `users:${userName}:runtime:trade-records:${orderId}`,
318
439
  runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
@@ -339,6 +460,10 @@ export {
339
460
  RedisWriteBlockedError,
340
461
  delKeyWithOptions,
341
462
  setData,
463
+ setHashJsonField,
464
+ getHashJsonValues,
465
+ incrHashFields,
466
+ getHashData,
342
467
  createScreenshotSessionToken,
343
468
  consumeScreenshotSessionToken,
344
469
  redisKeys
package/dist/redis.d.mts CHANGED
@@ -17,6 +17,10 @@ declare class RedisWriteBlockedError extends Error {
17
17
  }
18
18
  declare const delKeyWithOptions: (key: string, options?: DelKeyOptions) => Promise<boolean>;
19
19
  declare const setData: <T>(key: string, data: T, options?: Options) => Promise<void>;
20
+ declare const setHashJsonField: <T>(key: string, field: string, data: T, options?: Options) => Promise<void>;
21
+ declare const getHashJsonValues: <T>(key: string) => Promise<T[]>;
22
+ declare const incrHashFields: (key: string, increments: Record<string, number>, options?: Options) => Promise<void>;
23
+ declare const getHashData: (key: string) => Promise<Record<string, string>>;
20
24
  declare const createScreenshotSessionToken: (userName: string) => Promise<string | null>;
21
25
  declare const consumeScreenshotSessionToken: (token: string) => Promise<string | null>;
22
26
  declare const redisKeys: {
@@ -42,8 +46,14 @@ declare const redisKeys: {
42
46
  storeSignal: (symbol: string, signalId: string) => string;
43
47
  runtimeSignals: (userName: string) => string;
44
48
  runtimeSignal: (userName: string, signalId: string) => string;
49
+ runtimeSignalBuckets: (userName: string) => string;
50
+ runtimeSignalBucket: (userName: string, dayKey: string, strategyName: string) => string;
45
51
  runtimeSignalEvaluations: (userName: string) => string;
46
52
  runtimeSignalEvaluation: (userName: string, evaluationId: string) => string;
53
+ runtimeSignalEvaluationBuckets: (userName: string) => string;
54
+ runtimeSignalEvaluationBucket: (userName: string, dayKey: string, strategyName: string) => string;
55
+ runtimeSignalEvaluationStatsBuckets: (userName: string) => string;
56
+ runtimeSignalEvaluationStatsBucket: (userName: string, dayKey: string, strategyName: string) => string;
47
57
  runtimeTrades: (userName: string) => string;
48
58
  runtimeTrade: (userName: string, orderId: string) => string;
49
59
  runtimeActiveTrades: (userName: string) => string;
@@ -63,4 +73,4 @@ declare const redisKeys: {
63
73
  mlResult: (strategyName: string, signalId: string) => string;
64
74
  };
65
75
 
66
- export { RedisWriteBlockedError, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getKeys, redisKeys, setData };
76
+ export { RedisWriteBlockedError, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getHashData, getHashJsonValues, getKeys, incrHashFields, redisKeys, setData, setHashJsonField };
package/dist/redis.d.ts CHANGED
@@ -17,6 +17,10 @@ declare class RedisWriteBlockedError extends Error {
17
17
  }
18
18
  declare const delKeyWithOptions: (key: string, options?: DelKeyOptions) => Promise<boolean>;
19
19
  declare const setData: <T>(key: string, data: T, options?: Options) => Promise<void>;
20
+ declare const setHashJsonField: <T>(key: string, field: string, data: T, options?: Options) => Promise<void>;
21
+ declare const getHashJsonValues: <T>(key: string) => Promise<T[]>;
22
+ declare const incrHashFields: (key: string, increments: Record<string, number>, options?: Options) => Promise<void>;
23
+ declare const getHashData: (key: string) => Promise<Record<string, string>>;
20
24
  declare const createScreenshotSessionToken: (userName: string) => Promise<string | null>;
21
25
  declare const consumeScreenshotSessionToken: (token: string) => Promise<string | null>;
22
26
  declare const redisKeys: {
@@ -42,8 +46,14 @@ declare const redisKeys: {
42
46
  storeSignal: (symbol: string, signalId: string) => string;
43
47
  runtimeSignals: (userName: string) => string;
44
48
  runtimeSignal: (userName: string, signalId: string) => string;
49
+ runtimeSignalBuckets: (userName: string) => string;
50
+ runtimeSignalBucket: (userName: string, dayKey: string, strategyName: string) => string;
45
51
  runtimeSignalEvaluations: (userName: string) => string;
46
52
  runtimeSignalEvaluation: (userName: string, evaluationId: string) => string;
53
+ runtimeSignalEvaluationBuckets: (userName: string) => string;
54
+ runtimeSignalEvaluationBucket: (userName: string, dayKey: string, strategyName: string) => string;
55
+ runtimeSignalEvaluationStatsBuckets: (userName: string) => string;
56
+ runtimeSignalEvaluationStatsBucket: (userName: string, dayKey: string, strategyName: string) => string;
47
57
  runtimeTrades: (userName: string) => string;
48
58
  runtimeTrade: (userName: string, orderId: string) => string;
49
59
  runtimeActiveTrades: (userName: string) => string;
@@ -63,4 +73,4 @@ declare const redisKeys: {
63
73
  mlResult: (strategyName: string, signalId: string) => string;
64
74
  };
65
75
 
66
- export { RedisWriteBlockedError, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getKeys, redisKeys, setData };
76
+ export { RedisWriteBlockedError, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getHashData, getHashJsonValues, getKeys, incrHashFields, redisKeys, setData, setHashJsonField };
package/dist/redis.js CHANGED
@@ -36,9 +36,13 @@ __export(redis_exports, {
36
36
  delKey: () => delKey,
37
37
  delKeyWithOptions: () => delKeyWithOptions,
38
38
  getData: () => getData,
39
+ getHashData: () => getHashData,
40
+ getHashJsonValues: () => getHashJsonValues,
39
41
  getKeys: () => getKeys,
42
+ incrHashFields: () => incrHashFields,
40
43
  redisKeys: () => redisKeys,
41
- setData: () => setData
44
+ setData: () => setData,
45
+ setHashJsonField: () => setHashJsonField
42
46
  });
43
47
  module.exports = __toCommonJS(redis_exports);
44
48
  var import_crypto = require("crypto");
@@ -164,6 +168,31 @@ var parseJsonOrDeleteKey = async (redis, key, raw, fallback) => {
164
168
  return fallback;
165
169
  }
166
170
  };
171
+ var parseHashMap = (value) => {
172
+ if (!value) {
173
+ return {};
174
+ }
175
+ if (Array.isArray(value)) {
176
+ const result = {};
177
+ for (let index = 0; index < value.length; index += 2) {
178
+ const field = value[index];
179
+ const fieldValue = value[index + 1];
180
+ if (field == null || fieldValue == null) {
181
+ continue;
182
+ }
183
+ result[String(field)] = toResultString(fieldValue) ?? "";
184
+ }
185
+ return result;
186
+ }
187
+ if (typeof value === "object") {
188
+ return Object.fromEntries(
189
+ Object.entries(value).map(
190
+ ([field, fieldValue]) => [field, toResultString(fieldValue) ?? ""]
191
+ )
192
+ );
193
+ }
194
+ return {};
195
+ };
167
196
  var getKeys = async (prefix) => {
168
197
  if (redisUnavailable) return [];
169
198
  const redis = await getReadyRedis();
@@ -300,6 +329,96 @@ var setData = async (key, data, options = {}) => {
300
329
  }
301
330
  }
302
331
  };
332
+ var setHashJsonField = async (key, field, data, options = {}) => {
333
+ if (redisUnavailable) return;
334
+ const { expire } = { ...DEFAULT_OPTIONS, ...options };
335
+ const redis = await getReadyRedis();
336
+ if (!redis) return;
337
+ try {
338
+ await redis.call("HSET", key, field, toJson(data));
339
+ if (expire) {
340
+ await redis.expire(key, expire);
341
+ }
342
+ } catch (e) {
343
+ if (e instanceof Error && isRedisConnectivityError(e)) {
344
+ markRedisUnavailable(e);
345
+ return;
346
+ }
347
+ logger.log("error", "failed HSET %s[%s]: %s", key, field, String(e));
348
+ }
349
+ };
350
+ var getHashJsonValues = async (key) => {
351
+ if (redisUnavailable) return [];
352
+ const redis = await getReadyRedis();
353
+ if (!redis) return [];
354
+ try {
355
+ const raw = await redis.call("HGETALL", key);
356
+ const values = Object.values(parseHashMap(raw));
357
+ const parsed = [];
358
+ for (const value of values) {
359
+ if (!value) {
360
+ continue;
361
+ }
362
+ try {
363
+ parsed.push(JSON.parse(value));
364
+ } catch (e) {
365
+ logger.log(
366
+ "error",
367
+ "failed JSON.parse(HGETALL %s value): %s",
368
+ key,
369
+ String(e)
370
+ );
371
+ }
372
+ }
373
+ return parsed;
374
+ } catch (e) {
375
+ if (e instanceof Error && isRedisConnectivityError(e)) {
376
+ markRedisUnavailable(e);
377
+ return [];
378
+ }
379
+ logger.log("error", "failed HGETALL %s: %s", key, String(e));
380
+ return [];
381
+ }
382
+ };
383
+ var incrHashFields = async (key, increments, options = {}) => {
384
+ if (redisUnavailable) return;
385
+ const { expire } = { ...DEFAULT_OPTIONS, ...options };
386
+ const redis = await getReadyRedis();
387
+ if (!redis) return;
388
+ try {
389
+ for (const [field, increment] of Object.entries(increments)) {
390
+ if (!Number.isFinite(increment) || increment === 0) {
391
+ continue;
392
+ }
393
+ await redis.call("HINCRBY", key, field, Math.trunc(increment));
394
+ }
395
+ if (expire) {
396
+ await redis.expire(key, expire);
397
+ }
398
+ } catch (e) {
399
+ if (e instanceof Error && isRedisConnectivityError(e)) {
400
+ markRedisUnavailable(e);
401
+ return;
402
+ }
403
+ logger.log("error", "failed HINCRBY %s: %s", key, String(e));
404
+ }
405
+ };
406
+ var getHashData = async (key) => {
407
+ if (redisUnavailable) return {};
408
+ const redis = await getReadyRedis();
409
+ if (!redis) return {};
410
+ try {
411
+ const raw = await redis.call("HGETALL", key);
412
+ return parseHashMap(raw);
413
+ } catch (e) {
414
+ if (e instanceof Error && isRedisConnectivityError(e)) {
415
+ markRedisUnavailable(e);
416
+ return {};
417
+ }
418
+ logger.log("error", "failed HGETALL %s: %s", key, String(e));
419
+ return {};
420
+ }
421
+ };
303
422
  var createScreenshotSessionToken = async (userName) => {
304
423
  const token = (0, import_crypto.randomBytes)(24).toString("hex");
305
424
  await setData(
@@ -353,8 +472,14 @@ var redisKeys = {
353
472
  storeSignal: (symbol, signalId) => `store:signals:${symbol}:${signalId}`,
354
473
  runtimeSignals: (userName) => `users:${userName}:runtime:signals:`,
355
474
  runtimeSignal: (userName, signalId) => `users:${userName}:runtime:signals:${signalId}`,
475
+ runtimeSignalBuckets: (userName) => `users:${userName}:runtime:signals:days:`,
476
+ runtimeSignalBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signals:days:${dayKey}:${strategyName}`,
356
477
  runtimeSignalEvaluations: (userName) => `users:${userName}:runtime:signal-evaluations:`,
357
478
  runtimeSignalEvaluation: (userName, evaluationId) => `users:${userName}:runtime:signal-evaluations:${evaluationId}`,
479
+ runtimeSignalEvaluationBuckets: (userName) => `users:${userName}:runtime:signal-evaluations:days:`,
480
+ runtimeSignalEvaluationBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signal-evaluations:days:${dayKey}:${strategyName}`,
481
+ runtimeSignalEvaluationStatsBuckets: (userName) => `users:${userName}:runtime:signal-evaluation-stats:days:`,
482
+ runtimeSignalEvaluationStatsBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signal-evaluation-stats:days:${dayKey}:${strategyName}`,
358
483
  runtimeTrades: (userName) => `users:${userName}:runtime:trade-records:`,
359
484
  runtimeTrade: (userName, orderId) => `users:${userName}:runtime:trade-records:${orderId}`,
360
485
  runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
@@ -381,7 +506,11 @@ var redisKeys = {
381
506
  delKey,
382
507
  delKeyWithOptions,
383
508
  getData,
509
+ getHashData,
510
+ getHashJsonValues,
384
511
  getKeys,
512
+ incrHashFields,
385
513
  redisKeys,
386
- setData
514
+ setData,
515
+ setHashJsonField
387
516
  });
package/dist/redis.mjs CHANGED
@@ -5,10 +5,14 @@ import {
5
5
  delKey,
6
6
  delKeyWithOptions,
7
7
  getData,
8
+ getHashData,
9
+ getHashJsonValues,
8
10
  getKeys,
11
+ incrHashFields,
9
12
  redisKeys,
10
- setData
11
- } from "./chunk-DSTV67R5.mjs";
13
+ setData,
14
+ setHashJsonField
15
+ } from "./chunk-MLVWC2I2.mjs";
12
16
  export {
13
17
  RedisWriteBlockedError,
14
18
  consumeScreenshotSessionToken,
@@ -16,7 +20,11 @@ export {
16
20
  delKey,
17
21
  delKeyWithOptions,
18
22
  getData,
23
+ getHashData,
24
+ getHashJsonValues,
19
25
  getKeys,
26
+ incrHashFields,
20
27
  redisKeys,
21
- setData
28
+ setData,
29
+ setHashJsonField
22
30
  };
@@ -558,8 +558,14 @@ var redisKeys = {
558
558
  storeSignal: (symbol, signalId) => `store:signals:${symbol}:${signalId}`,
559
559
  runtimeSignals: (userName) => `users:${userName}:runtime:signals:`,
560
560
  runtimeSignal: (userName, signalId) => `users:${userName}:runtime:signals:${signalId}`,
561
+ runtimeSignalBuckets: (userName) => `users:${userName}:runtime:signals:days:`,
562
+ runtimeSignalBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signals:days:${dayKey}:${strategyName}`,
561
563
  runtimeSignalEvaluations: (userName) => `users:${userName}:runtime:signal-evaluations:`,
562
564
  runtimeSignalEvaluation: (userName, evaluationId) => `users:${userName}:runtime:signal-evaluations:${evaluationId}`,
565
+ runtimeSignalEvaluationBuckets: (userName) => `users:${userName}:runtime:signal-evaluations:days:`,
566
+ runtimeSignalEvaluationBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signal-evaluations:days:${dayKey}:${strategyName}`,
567
+ runtimeSignalEvaluationStatsBuckets: (userName) => `users:${userName}:runtime:signal-evaluation-stats:days:`,
568
+ runtimeSignalEvaluationStatsBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signal-evaluation-stats:days:${dayKey}:${strategyName}`,
563
569
  runtimeTrades: (userName) => `users:${userName}:runtime:trade-records:`,
564
570
  runtimeTrade: (userName, orderId) => `users:${userName}:runtime:trade-records:${orderId}`,
565
571
  runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
@@ -2,7 +2,7 @@ import {
2
2
  getData,
3
3
  redisKeys,
4
4
  setData
5
- } from "./chunk-DSTV67R5.mjs";
5
+ } from "./chunk-MLVWC2I2.mjs";
6
6
  import {
7
7
  DEFAULT_AI_RESPONSE_LANGUAGE,
8
8
  normalizeAiResponseLanguage
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/infra",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "Server-only infrastructure adapters for the TradeJS open-source framework: Redis, Timescale, ML, logging, and IO.",
5
5
  "keywords": [
6
6
  "tradejs",
@@ -83,7 +83,7 @@
83
83
  "dependencies": {
84
84
  "@grpc/grpc-js": "^1.10.7",
85
85
  "@grpc/proto-loader": "^0.8.0",
86
- "@tradejs/types": "^1.0.8",
86
+ "@tradejs/types": "^1.0.9",
87
87
  "chalk": "4.1.2",
88
88
  "ioredis": "5.8.0",
89
89
  "pg": "8.16.3",