@tradejs/infra 3.1.29-beta.261 → 3.1.29-beta.263
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/dist/{chunk-GTZOMAFK.mjs → chunk-BACJCS7N.mjs} +73 -1
- package/dist/jev.d.mts +3 -1
- package/dist/jev.d.ts +3 -1
- package/dist/jev.js +11 -6
- package/dist/jev.mjs +10 -6
- package/dist/redis.d.mts +28 -2
- package/dist/redis.d.ts +28 -2
- package/dist/redis.js +76 -1
- package/dist/redis.mjs +7 -1
- package/dist/runtimeControls.js +0 -1
- package/dist/runtimeControls.mjs +1 -1
- package/dist/runtimeDeploymentEvents.js +0 -1
- package/dist/runtimeDeploymentEvents.mjs +1 -1
- package/dist/runtimeHeartbeats.js +0 -1
- package/dist/runtimeHeartbeats.mjs +1 -1
- package/dist/runtimeStrategyConfigs.js +0 -1
- package/dist/runtimeStrategyConfigs.mjs +1 -1
- package/dist/tradingAccounts.js +0 -1
- package/dist/tradingAccounts.mjs +1 -1
- package/dist/userSettings.js +0 -1
- package/dist/userSettings.mjs +1 -1
- package/package.json +4 -3
|
@@ -83,6 +83,76 @@ var closeRedisConnection = async () => {
|
|
|
83
83
|
redisConnectionWarningShown = false;
|
|
84
84
|
redis.disconnect();
|
|
85
85
|
};
|
|
86
|
+
var mcpStorage = {
|
|
87
|
+
async get(id) {
|
|
88
|
+
const value = await (await requireReadyRedis()).get(`tradejs:mcp:v1:${id}`);
|
|
89
|
+
return value === null ? null : JSON.parse(value);
|
|
90
|
+
},
|
|
91
|
+
async put(id, value, ttlSeconds, onlyAbsent = false) {
|
|
92
|
+
const redis = await requireReadyRedis();
|
|
93
|
+
const key = `tradejs:mcp:v1:${id}`;
|
|
94
|
+
const result = onlyAbsent ? await redis.set(key, JSON.stringify(value), "EX", ttlSeconds, "NX") : await redis.set(key, JSON.stringify(value), "EX", ttlSeconds);
|
|
95
|
+
return result === "OK";
|
|
96
|
+
},
|
|
97
|
+
async take(id) {
|
|
98
|
+
const value = await (await requireReadyRedis()).getdel(`tradejs:mcp:v1:${id}`);
|
|
99
|
+
return value === null ? null : JSON.parse(value);
|
|
100
|
+
},
|
|
101
|
+
async remove(id) {
|
|
102
|
+
return await (await requireReadyRedis()).del(`tradejs:mcp:v1:${id}`) > 0;
|
|
103
|
+
},
|
|
104
|
+
async compare(id, previous, next, ttlSeconds) {
|
|
105
|
+
const result = await (await requireReadyRedis()).eval(
|
|
106
|
+
"if redis.call('GET',KEYS[1]) ~= ARGV[1] then return 0 end; redis.call('SET',KEYS[1],ARGV[2],'EX',ARGV[3]); return 1",
|
|
107
|
+
1,
|
|
108
|
+
`tradejs:mcp:v1:${id}`,
|
|
109
|
+
JSON.stringify(previous),
|
|
110
|
+
JSON.stringify(next),
|
|
111
|
+
ttlSeconds
|
|
112
|
+
);
|
|
113
|
+
return result === 1;
|
|
114
|
+
},
|
|
115
|
+
async release(id, previous) {
|
|
116
|
+
return await (await requireReadyRedis()).eval(
|
|
117
|
+
"if redis.call('GET',KEYS[1]) ~= ARGV[1] then return 0 end; return redis.call('DEL',KEYS[1])",
|
|
118
|
+
1,
|
|
119
|
+
`tradejs:mcp:v1:${id}`,
|
|
120
|
+
JSON.stringify(previous)
|
|
121
|
+
) === 1;
|
|
122
|
+
},
|
|
123
|
+
async rateLimit(id, maximum, seconds) {
|
|
124
|
+
const count = await (await requireReadyRedis()).eval(
|
|
125
|
+
"local n=redis.call('INCR',KEYS[1]); if n==1 then redis.call('EXPIRE',KEYS[1],ARGV[1]) end; return n",
|
|
126
|
+
1,
|
|
127
|
+
`tradejs:mcp:v1:rate:${id}`,
|
|
128
|
+
seconds
|
|
129
|
+
);
|
|
130
|
+
return Number(count) <= maximum;
|
|
131
|
+
},
|
|
132
|
+
async scan(prefix, cursor = "0", count = 100) {
|
|
133
|
+
const [nextCursor, keys] = await (await requireReadyRedis()).scan(cursor, "MATCH", `tradejs:mcp:v1:${prefix}*`, "COUNT", count);
|
|
134
|
+
return {
|
|
135
|
+
cursor: nextCursor,
|
|
136
|
+
ids: keys.map((key) => key.slice("tradejs:mcp:v1:".length))
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
var scanDataKeys = async (prefix, cursor = "0") => {
|
|
141
|
+
if (!/^\d+$/.test(cursor)) throw new Error("Invalid storage cursor");
|
|
142
|
+
const literalPrefix = [...prefix].map(
|
|
143
|
+
(character) => ["*", "?", "[", "]", "\\"].includes(character) ? `\\${character}` : character
|
|
144
|
+
).join("");
|
|
145
|
+
const [nextCursor, keys] = await (await requireReadyRedis()).scan(cursor, "MATCH", `${literalPrefix}*`, "COUNT", 100);
|
|
146
|
+
return { cursor: nextCursor, keys };
|
|
147
|
+
};
|
|
148
|
+
var scanHashJson = async (key, cursor = "0") => {
|
|
149
|
+
if (!/^\d+$/.test(cursor)) throw new Error("Invalid storage cursor");
|
|
150
|
+
const [next, pairs] = await (await requireReadyRedis()).hscan(key, cursor, "COUNT", 50);
|
|
151
|
+
const values = [];
|
|
152
|
+
for (let index = 1; index < pairs.length; index += 2)
|
|
153
|
+
values.push(JSON.parse(pairs[index]));
|
|
154
|
+
return { cursor: next, values };
|
|
155
|
+
};
|
|
86
156
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
87
157
|
var getRedisStatus = (redis) => String(redis.status ?? "ready");
|
|
88
158
|
var waitForRedisReady = async (redis) => {
|
|
@@ -649,7 +719,6 @@ var redisKeys = {
|
|
|
649
719
|
runtimeClosedTradeBucket: (userName, dayKey) => `users:${userName}:runtime:closed-trade-records:days:${dayKey}`,
|
|
650
720
|
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
651
721
|
runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
|
|
652
|
-
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
653
722
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
654
723
|
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
655
724
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
|
@@ -672,6 +741,9 @@ var redisKeys = {
|
|
|
672
741
|
|
|
673
742
|
export {
|
|
674
743
|
closeRedisConnection,
|
|
744
|
+
mcpStorage,
|
|
745
|
+
scanDataKeys,
|
|
746
|
+
scanHashJson,
|
|
675
747
|
publishData,
|
|
676
748
|
getKeys,
|
|
677
749
|
getData,
|
package/dist/jev.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { JevProviderConfig, JevResponse } from '@tradejs/types';
|
|
2
2
|
|
|
3
|
+
/** Provider criteria are zero-based: ten strength levels use raw scores 0–9. */
|
|
4
|
+
declare const jevScoreMaximum: (dimension: string) => 4 | 9;
|
|
3
5
|
declare const jevStableJson: (value: unknown) => string;
|
|
4
6
|
declare const jevHash: (value: unknown) => string;
|
|
5
7
|
declare const jevFileHash: (contents: string) => string;
|
|
@@ -13,4 +15,4 @@ declare const requestJev: (provider: JevProviderConfig, apiKey: string, state: u
|
|
|
13
15
|
}) => Promise<JevResponse>;
|
|
14
16
|
declare const validateJevResponse: (body: unknown, expected: string[]) => JevResponse;
|
|
15
17
|
|
|
16
|
-
export { jevFileHash, jevHash, jevStableJson, readJevArtifact, requestJev, validateJevResponse, writeJevArtifact };
|
|
18
|
+
export { jevFileHash, jevHash, jevScoreMaximum, jevStableJson, readJevArtifact, requestJev, validateJevResponse, writeJevArtifact };
|
package/dist/jev.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { JevProviderConfig, JevResponse } from '@tradejs/types';
|
|
2
2
|
|
|
3
|
+
/** Provider criteria are zero-based: ten strength levels use raw scores 0–9. */
|
|
4
|
+
declare const jevScoreMaximum: (dimension: string) => 4 | 9;
|
|
3
5
|
declare const jevStableJson: (value: unknown) => string;
|
|
4
6
|
declare const jevHash: (value: unknown) => string;
|
|
5
7
|
declare const jevFileHash: (contents: string) => string;
|
|
@@ -13,4 +15,4 @@ declare const requestJev: (provider: JevProviderConfig, apiKey: string, state: u
|
|
|
13
15
|
}) => Promise<JevResponse>;
|
|
14
16
|
declare const validateJevResponse: (body: unknown, expected: string[]) => JevResponse;
|
|
15
17
|
|
|
16
|
-
export { jevFileHash, jevHash, jevStableJson, readJevArtifact, requestJev, validateJevResponse, writeJevArtifact };
|
|
18
|
+
export { jevFileHash, jevHash, jevScoreMaximum, jevStableJson, readJevArtifact, requestJev, validateJevResponse, writeJevArtifact };
|
package/dist/jev.js
CHANGED
|
@@ -32,6 +32,7 @@ var jev_exports = {};
|
|
|
32
32
|
__export(jev_exports, {
|
|
33
33
|
jevFileHash: () => jevFileHash,
|
|
34
34
|
jevHash: () => jevHash,
|
|
35
|
+
jevScoreMaximum: () => jevScoreMaximum,
|
|
35
36
|
jevStableJson: () => jevStableJson,
|
|
36
37
|
readJevArtifact: () => readJevArtifact,
|
|
37
38
|
requestJev: () => requestJev,
|
|
@@ -42,6 +43,7 @@ module.exports = __toCommonJS(jev_exports);
|
|
|
42
43
|
var import_node_crypto = require("crypto");
|
|
43
44
|
var import_promises = __toESM(require("fs/promises"));
|
|
44
45
|
var import_node_path = __toESM(require("path"));
|
|
46
|
+
var jevScoreMaximum = (dimension) => dimension === "signalStrength" ? 9 : 4;
|
|
45
47
|
var jevStableJson = (value) => {
|
|
46
48
|
if (Array.isArray(value)) return `[${value.map(jevStableJson).join(",")}]`;
|
|
47
49
|
if (value && typeof value === "object")
|
|
@@ -154,26 +156,28 @@ var validateJevResponse = (body, expected) => {
|
|
|
154
156
|
const result = body;
|
|
155
157
|
if (!result || typeof result.model !== "string" || !result.model || !result.answers)
|
|
156
158
|
throw new Error("Invalid Jev response");
|
|
157
|
-
if (!expected.length || expected.length >
|
|
159
|
+
if (!expected.length || expected.length > 9 || Object.keys(result.answers).sort().join(",") !== [...expected].sort().join(","))
|
|
158
160
|
throw new Error("Invalid Jev answer set");
|
|
159
161
|
for (const key of expected) {
|
|
160
162
|
const answer = result.answers[key];
|
|
161
|
-
|
|
163
|
+
const maximum = jevScoreMaximum(key);
|
|
164
|
+
const levels = Array.from({ length: maximum + 1 }, (_, index) => index);
|
|
165
|
+
if (!answer || answer.type !== "score" || !Number.isFinite(answer.score) || answer.score < 0 || answer.score > maximum || !Number.isFinite(answer.confidence) || answer.confidence < 0 || answer.confidence > 1)
|
|
162
166
|
throw new Error(`Invalid Jev ${key} answer`);
|
|
163
167
|
const probabilities = answer.probabilities;
|
|
164
|
-
if (!probabilities || Object.keys(probabilities).length !==
|
|
168
|
+
if (!probabilities || Object.keys(probabilities).length !== levels.length || levels.some(
|
|
165
169
|
(level) => !Number.isFinite(probabilities[level]) || probabilities[level] < 0 || probabilities[level] > 1
|
|
166
170
|
))
|
|
167
171
|
throw new Error(`Invalid Jev ${key} probabilities`);
|
|
168
172
|
const roundingHalfUnit = 5e-3;
|
|
169
173
|
const epsilon = 1e-9;
|
|
170
|
-
if (Math.abs(Object.values(probabilities).reduce((a, b) => a + b, 0) - 1) >
|
|
174
|
+
if (Math.abs(Object.values(probabilities).reduce((a, b) => a + b, 0) - 1) > levels.length * roundingHalfUnit + epsilon)
|
|
171
175
|
throw new Error("Jev probabilities must sum to one");
|
|
172
|
-
const mean =
|
|
176
|
+
const mean = levels.reduce(
|
|
173
177
|
(sum, level) => sum + level * probabilities[level],
|
|
174
178
|
0
|
|
175
179
|
);
|
|
176
|
-
if (Math.abs(mean - answer.score) > (
|
|
180
|
+
if (Math.abs(mean - answer.score) > levels.reduce((sum, level) => sum + level, 1) * roundingHalfUnit + epsilon)
|
|
177
181
|
throw new Error("Jev score disagrees with probabilities");
|
|
178
182
|
}
|
|
179
183
|
return result;
|
|
@@ -182,6 +186,7 @@ var validateJevResponse = (body, expected) => {
|
|
|
182
186
|
0 && (module.exports = {
|
|
183
187
|
jevFileHash,
|
|
184
188
|
jevHash,
|
|
189
|
+
jevScoreMaximum,
|
|
185
190
|
jevStableJson,
|
|
186
191
|
readJevArtifact,
|
|
187
192
|
requestJev,
|
package/dist/jev.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { createHash, randomUUID } from "crypto";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
4
|
import path from "path";
|
|
5
|
+
var jevScoreMaximum = (dimension) => dimension === "signalStrength" ? 9 : 4;
|
|
5
6
|
var jevStableJson = (value) => {
|
|
6
7
|
if (Array.isArray(value)) return `[${value.map(jevStableJson).join(",")}]`;
|
|
7
8
|
if (value && typeof value === "object")
|
|
@@ -114,26 +115,28 @@ var validateJevResponse = (body, expected) => {
|
|
|
114
115
|
const result = body;
|
|
115
116
|
if (!result || typeof result.model !== "string" || !result.model || !result.answers)
|
|
116
117
|
throw new Error("Invalid Jev response");
|
|
117
|
-
if (!expected.length || expected.length >
|
|
118
|
+
if (!expected.length || expected.length > 9 || Object.keys(result.answers).sort().join(",") !== [...expected].sort().join(","))
|
|
118
119
|
throw new Error("Invalid Jev answer set");
|
|
119
120
|
for (const key of expected) {
|
|
120
121
|
const answer = result.answers[key];
|
|
121
|
-
|
|
122
|
+
const maximum = jevScoreMaximum(key);
|
|
123
|
+
const levels = Array.from({ length: maximum + 1 }, (_, index) => index);
|
|
124
|
+
if (!answer || answer.type !== "score" || !Number.isFinite(answer.score) || answer.score < 0 || answer.score > maximum || !Number.isFinite(answer.confidence) || answer.confidence < 0 || answer.confidence > 1)
|
|
122
125
|
throw new Error(`Invalid Jev ${key} answer`);
|
|
123
126
|
const probabilities = answer.probabilities;
|
|
124
|
-
if (!probabilities || Object.keys(probabilities).length !==
|
|
127
|
+
if (!probabilities || Object.keys(probabilities).length !== levels.length || levels.some(
|
|
125
128
|
(level) => !Number.isFinite(probabilities[level]) || probabilities[level] < 0 || probabilities[level] > 1
|
|
126
129
|
))
|
|
127
130
|
throw new Error(`Invalid Jev ${key} probabilities`);
|
|
128
131
|
const roundingHalfUnit = 5e-3;
|
|
129
132
|
const epsilon = 1e-9;
|
|
130
|
-
if (Math.abs(Object.values(probabilities).reduce((a, b) => a + b, 0) - 1) >
|
|
133
|
+
if (Math.abs(Object.values(probabilities).reduce((a, b) => a + b, 0) - 1) > levels.length * roundingHalfUnit + epsilon)
|
|
131
134
|
throw new Error("Jev probabilities must sum to one");
|
|
132
|
-
const mean =
|
|
135
|
+
const mean = levels.reduce(
|
|
133
136
|
(sum, level) => sum + level * probabilities[level],
|
|
134
137
|
0
|
|
135
138
|
);
|
|
136
|
-
if (Math.abs(mean - answer.score) > (
|
|
139
|
+
if (Math.abs(mean - answer.score) > levels.reduce((sum, level) => sum + level, 1) * roundingHalfUnit + epsilon)
|
|
137
140
|
throw new Error("Jev score disagrees with probabilities");
|
|
138
141
|
}
|
|
139
142
|
return result;
|
|
@@ -141,6 +144,7 @@ var validateJevResponse = (body, expected) => {
|
|
|
141
144
|
export {
|
|
142
145
|
jevFileHash,
|
|
143
146
|
jevHash,
|
|
147
|
+
jevScoreMaximum,
|
|
144
148
|
jevStableJson,
|
|
145
149
|
readJevArtifact,
|
|
146
150
|
requestJev,
|
package/dist/redis.d.mts
CHANGED
|
@@ -4,6 +4,33 @@ declare global {
|
|
|
4
4
|
var __redis__: Redis | undefined;
|
|
5
5
|
}
|
|
6
6
|
declare const closeRedisConnection: () => Promise<void>;
|
|
7
|
+
/** Fail-closed storage for MCP credentials, grants, jobs and worker leases.
|
|
8
|
+
* Values use native Redis strings so consumption and compare-and-set are atomic.
|
|
9
|
+
* Never pass a caller-supplied Redis key to this adapter.
|
|
10
|
+
*/
|
|
11
|
+
declare const mcpStorage: {
|
|
12
|
+
get<T>(id: string): Promise<T | null>;
|
|
13
|
+
put(id: string, value: unknown, ttlSeconds: number, onlyAbsent?: boolean): Promise<boolean>;
|
|
14
|
+
take<T>(id: string): Promise<T | null>;
|
|
15
|
+
remove(id: string): Promise<boolean>;
|
|
16
|
+
compare(id: string, previous: unknown, next: unknown, ttlSeconds: number): Promise<boolean>;
|
|
17
|
+
release(id: string, previous: unknown): Promise<boolean>;
|
|
18
|
+
rateLimit(id: string, maximum: number, seconds: number): Promise<boolean>;
|
|
19
|
+
scan(prefix: string, cursor?: string, count?: number): Promise<{
|
|
20
|
+
cursor: string;
|
|
21
|
+
ids: string[];
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
/** One bounded SCAN page. Cursor is opaque; an empty page is not end-of-data. */
|
|
25
|
+
declare const scanDataKeys: (prefix: string, cursor?: string) => Promise<{
|
|
26
|
+
cursor: string;
|
|
27
|
+
keys: string[];
|
|
28
|
+
}>;
|
|
29
|
+
/** HSCAN preserves large runtime buckets without materializing the complete hash. */
|
|
30
|
+
declare const scanHashJson: (key: string, cursor?: string) => Promise<{
|
|
31
|
+
cursor: string;
|
|
32
|
+
values: unknown[];
|
|
33
|
+
}>;
|
|
7
34
|
interface Options {
|
|
8
35
|
expire?: number;
|
|
9
36
|
}
|
|
@@ -94,7 +121,6 @@ declare const redisKeys: {
|
|
|
94
121
|
runtimeClosedTradeBucket: (userName: string, dayKey: string) => string;
|
|
95
122
|
runtimeActiveTrades: (userName: string) => string;
|
|
96
123
|
runtimeActiveTrade: (userName: string, symbol: string, scopeId?: string) => string;
|
|
97
|
-
aiChatHistory: (userName: string, symbolKey: string) => string;
|
|
98
124
|
analysis: (symbol: string, signalId: string) => string;
|
|
99
125
|
screenshotSessionToken: (token: string) => string;
|
|
100
126
|
backtestResults: (userName: string, config: string, timestamp: string) => string;
|
|
@@ -115,4 +141,4 @@ declare const redisKeys: {
|
|
|
115
141
|
mlResult: (strategyName: string, signalId: string) => string;
|
|
116
142
|
};
|
|
117
143
|
|
|
118
|
-
export { RedisWriteBlockedError, closeRedisConnection, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyStrict, delKeyWithOptions, getData, getDataStrict, getHashData, getHashJsonField, getHashJsonValues, getKeys, incrHashFields, incrementKey, publishData, redisKeys, setData, setDataIfAbsent, setDataStrict, setHashJsonField, setHashJsonFields };
|
|
144
|
+
export { RedisWriteBlockedError, closeRedisConnection, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyStrict, delKeyWithOptions, getData, getDataStrict, getHashData, getHashJsonField, getHashJsonValues, getKeys, incrHashFields, incrementKey, mcpStorage, publishData, redisKeys, scanDataKeys, scanHashJson, setData, setDataIfAbsent, setDataStrict, setHashJsonField, setHashJsonFields };
|
package/dist/redis.d.ts
CHANGED
|
@@ -4,6 +4,33 @@ declare global {
|
|
|
4
4
|
var __redis__: Redis | undefined;
|
|
5
5
|
}
|
|
6
6
|
declare const closeRedisConnection: () => Promise<void>;
|
|
7
|
+
/** Fail-closed storage for MCP credentials, grants, jobs and worker leases.
|
|
8
|
+
* Values use native Redis strings so consumption and compare-and-set are atomic.
|
|
9
|
+
* Never pass a caller-supplied Redis key to this adapter.
|
|
10
|
+
*/
|
|
11
|
+
declare const mcpStorage: {
|
|
12
|
+
get<T>(id: string): Promise<T | null>;
|
|
13
|
+
put(id: string, value: unknown, ttlSeconds: number, onlyAbsent?: boolean): Promise<boolean>;
|
|
14
|
+
take<T>(id: string): Promise<T | null>;
|
|
15
|
+
remove(id: string): Promise<boolean>;
|
|
16
|
+
compare(id: string, previous: unknown, next: unknown, ttlSeconds: number): Promise<boolean>;
|
|
17
|
+
release(id: string, previous: unknown): Promise<boolean>;
|
|
18
|
+
rateLimit(id: string, maximum: number, seconds: number): Promise<boolean>;
|
|
19
|
+
scan(prefix: string, cursor?: string, count?: number): Promise<{
|
|
20
|
+
cursor: string;
|
|
21
|
+
ids: string[];
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
/** One bounded SCAN page. Cursor is opaque; an empty page is not end-of-data. */
|
|
25
|
+
declare const scanDataKeys: (prefix: string, cursor?: string) => Promise<{
|
|
26
|
+
cursor: string;
|
|
27
|
+
keys: string[];
|
|
28
|
+
}>;
|
|
29
|
+
/** HSCAN preserves large runtime buckets without materializing the complete hash. */
|
|
30
|
+
declare const scanHashJson: (key: string, cursor?: string) => Promise<{
|
|
31
|
+
cursor: string;
|
|
32
|
+
values: unknown[];
|
|
33
|
+
}>;
|
|
7
34
|
interface Options {
|
|
8
35
|
expire?: number;
|
|
9
36
|
}
|
|
@@ -94,7 +121,6 @@ declare const redisKeys: {
|
|
|
94
121
|
runtimeClosedTradeBucket: (userName: string, dayKey: string) => string;
|
|
95
122
|
runtimeActiveTrades: (userName: string) => string;
|
|
96
123
|
runtimeActiveTrade: (userName: string, symbol: string, scopeId?: string) => string;
|
|
97
|
-
aiChatHistory: (userName: string, symbolKey: string) => string;
|
|
98
124
|
analysis: (symbol: string, signalId: string) => string;
|
|
99
125
|
screenshotSessionToken: (token: string) => string;
|
|
100
126
|
backtestResults: (userName: string, config: string, timestamp: string) => string;
|
|
@@ -115,4 +141,4 @@ declare const redisKeys: {
|
|
|
115
141
|
mlResult: (strategyName: string, signalId: string) => string;
|
|
116
142
|
};
|
|
117
143
|
|
|
118
|
-
export { RedisWriteBlockedError, closeRedisConnection, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyStrict, delKeyWithOptions, getData, getDataStrict, getHashData, getHashJsonField, getHashJsonValues, getKeys, incrHashFields, incrementKey, publishData, redisKeys, setData, setDataIfAbsent, setDataStrict, setHashJsonField, setHashJsonFields };
|
|
144
|
+
export { RedisWriteBlockedError, closeRedisConnection, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyStrict, delKeyWithOptions, getData, getDataStrict, getHashData, getHashJsonField, getHashJsonValues, getKeys, incrHashFields, incrementKey, mcpStorage, publishData, redisKeys, scanDataKeys, scanHashJson, setData, setDataIfAbsent, setDataStrict, setHashJsonField, setHashJsonFields };
|
package/dist/redis.js
CHANGED
|
@@ -45,8 +45,11 @@ __export(redis_exports, {
|
|
|
45
45
|
getKeys: () => getKeys,
|
|
46
46
|
incrHashFields: () => incrHashFields,
|
|
47
47
|
incrementKey: () => incrementKey,
|
|
48
|
+
mcpStorage: () => mcpStorage,
|
|
48
49
|
publishData: () => publishData,
|
|
49
50
|
redisKeys: () => redisKeys,
|
|
51
|
+
scanDataKeys: () => scanDataKeys,
|
|
52
|
+
scanHashJson: () => scanHashJson,
|
|
50
53
|
setData: () => setData,
|
|
51
54
|
setDataIfAbsent: () => setDataIfAbsent,
|
|
52
55
|
setDataStrict: () => setDataStrict,
|
|
@@ -138,6 +141,76 @@ var closeRedisConnection = async () => {
|
|
|
138
141
|
redisConnectionWarningShown = false;
|
|
139
142
|
redis.disconnect();
|
|
140
143
|
};
|
|
144
|
+
var mcpStorage = {
|
|
145
|
+
async get(id) {
|
|
146
|
+
const value = await (await requireReadyRedis()).get(`tradejs:mcp:v1:${id}`);
|
|
147
|
+
return value === null ? null : JSON.parse(value);
|
|
148
|
+
},
|
|
149
|
+
async put(id, value, ttlSeconds, onlyAbsent = false) {
|
|
150
|
+
const redis = await requireReadyRedis();
|
|
151
|
+
const key = `tradejs:mcp:v1:${id}`;
|
|
152
|
+
const result = onlyAbsent ? await redis.set(key, JSON.stringify(value), "EX", ttlSeconds, "NX") : await redis.set(key, JSON.stringify(value), "EX", ttlSeconds);
|
|
153
|
+
return result === "OK";
|
|
154
|
+
},
|
|
155
|
+
async take(id) {
|
|
156
|
+
const value = await (await requireReadyRedis()).getdel(`tradejs:mcp:v1:${id}`);
|
|
157
|
+
return value === null ? null : JSON.parse(value);
|
|
158
|
+
},
|
|
159
|
+
async remove(id) {
|
|
160
|
+
return await (await requireReadyRedis()).del(`tradejs:mcp:v1:${id}`) > 0;
|
|
161
|
+
},
|
|
162
|
+
async compare(id, previous, next, ttlSeconds) {
|
|
163
|
+
const result = await (await requireReadyRedis()).eval(
|
|
164
|
+
"if redis.call('GET',KEYS[1]) ~= ARGV[1] then return 0 end; redis.call('SET',KEYS[1],ARGV[2],'EX',ARGV[3]); return 1",
|
|
165
|
+
1,
|
|
166
|
+
`tradejs:mcp:v1:${id}`,
|
|
167
|
+
JSON.stringify(previous),
|
|
168
|
+
JSON.stringify(next),
|
|
169
|
+
ttlSeconds
|
|
170
|
+
);
|
|
171
|
+
return result === 1;
|
|
172
|
+
},
|
|
173
|
+
async release(id, previous) {
|
|
174
|
+
return await (await requireReadyRedis()).eval(
|
|
175
|
+
"if redis.call('GET',KEYS[1]) ~= ARGV[1] then return 0 end; return redis.call('DEL',KEYS[1])",
|
|
176
|
+
1,
|
|
177
|
+
`tradejs:mcp:v1:${id}`,
|
|
178
|
+
JSON.stringify(previous)
|
|
179
|
+
) === 1;
|
|
180
|
+
},
|
|
181
|
+
async rateLimit(id, maximum, seconds) {
|
|
182
|
+
const count = await (await requireReadyRedis()).eval(
|
|
183
|
+
"local n=redis.call('INCR',KEYS[1]); if n==1 then redis.call('EXPIRE',KEYS[1],ARGV[1]) end; return n",
|
|
184
|
+
1,
|
|
185
|
+
`tradejs:mcp:v1:rate:${id}`,
|
|
186
|
+
seconds
|
|
187
|
+
);
|
|
188
|
+
return Number(count) <= maximum;
|
|
189
|
+
},
|
|
190
|
+
async scan(prefix, cursor = "0", count = 100) {
|
|
191
|
+
const [nextCursor, keys] = await (await requireReadyRedis()).scan(cursor, "MATCH", `tradejs:mcp:v1:${prefix}*`, "COUNT", count);
|
|
192
|
+
return {
|
|
193
|
+
cursor: nextCursor,
|
|
194
|
+
ids: keys.map((key) => key.slice("tradejs:mcp:v1:".length))
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
var scanDataKeys = async (prefix, cursor = "0") => {
|
|
199
|
+
if (!/^\d+$/.test(cursor)) throw new Error("Invalid storage cursor");
|
|
200
|
+
const literalPrefix = [...prefix].map(
|
|
201
|
+
(character) => ["*", "?", "[", "]", "\\"].includes(character) ? `\\${character}` : character
|
|
202
|
+
).join("");
|
|
203
|
+
const [nextCursor, keys] = await (await requireReadyRedis()).scan(cursor, "MATCH", `${literalPrefix}*`, "COUNT", 100);
|
|
204
|
+
return { cursor: nextCursor, keys };
|
|
205
|
+
};
|
|
206
|
+
var scanHashJson = async (key, cursor = "0") => {
|
|
207
|
+
if (!/^\d+$/.test(cursor)) throw new Error("Invalid storage cursor");
|
|
208
|
+
const [next, pairs] = await (await requireReadyRedis()).hscan(key, cursor, "COUNT", 50);
|
|
209
|
+
const values = [];
|
|
210
|
+
for (let index = 1; index < pairs.length; index += 2)
|
|
211
|
+
values.push(JSON.parse(pairs[index]));
|
|
212
|
+
return { cursor: next, values };
|
|
213
|
+
};
|
|
141
214
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
142
215
|
var getRedisStatus = (redis) => String(redis.status ?? "ready");
|
|
143
216
|
var waitForRedisReady = async (redis) => {
|
|
@@ -704,7 +777,6 @@ var redisKeys = {
|
|
|
704
777
|
runtimeClosedTradeBucket: (userName, dayKey) => `users:${userName}:runtime:closed-trade-records:days:${dayKey}`,
|
|
705
778
|
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
706
779
|
runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
|
|
707
|
-
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
708
780
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
709
781
|
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
710
782
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
|
@@ -741,8 +813,11 @@ var redisKeys = {
|
|
|
741
813
|
getKeys,
|
|
742
814
|
incrHashFields,
|
|
743
815
|
incrementKey,
|
|
816
|
+
mcpStorage,
|
|
744
817
|
publishData,
|
|
745
818
|
redisKeys,
|
|
819
|
+
scanDataKeys,
|
|
820
|
+
scanHashJson,
|
|
746
821
|
setData,
|
|
747
822
|
setDataIfAbsent,
|
|
748
823
|
setDataStrict,
|
package/dist/redis.mjs
CHANGED
|
@@ -14,14 +14,17 @@ import {
|
|
|
14
14
|
getKeys,
|
|
15
15
|
incrHashFields,
|
|
16
16
|
incrementKey,
|
|
17
|
+
mcpStorage,
|
|
17
18
|
publishData,
|
|
18
19
|
redisKeys,
|
|
20
|
+
scanDataKeys,
|
|
21
|
+
scanHashJson,
|
|
19
22
|
setData,
|
|
20
23
|
setDataIfAbsent,
|
|
21
24
|
setDataStrict,
|
|
22
25
|
setHashJsonField,
|
|
23
26
|
setHashJsonFields
|
|
24
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-BACJCS7N.mjs";
|
|
25
28
|
export {
|
|
26
29
|
RedisWriteBlockedError,
|
|
27
30
|
closeRedisConnection,
|
|
@@ -38,8 +41,11 @@ export {
|
|
|
38
41
|
getKeys,
|
|
39
42
|
incrHashFields,
|
|
40
43
|
incrementKey,
|
|
44
|
+
mcpStorage,
|
|
41
45
|
publishData,
|
|
42
46
|
redisKeys,
|
|
47
|
+
scanDataKeys,
|
|
48
|
+
scanHashJson,
|
|
43
49
|
setData,
|
|
44
50
|
setDataIfAbsent,
|
|
45
51
|
setDataStrict,
|
package/dist/runtimeControls.js
CHANGED
|
@@ -304,7 +304,6 @@ var redisKeys = {
|
|
|
304
304
|
runtimeClosedTradeBucket: (userName, dayKey) => `users:${userName}:runtime:closed-trade-records:days:${dayKey}`,
|
|
305
305
|
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
306
306
|
runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
|
|
307
|
-
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
308
307
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
309
308
|
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
310
309
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
package/dist/runtimeControls.mjs
CHANGED
|
@@ -328,7 +328,6 @@ var redisKeys = {
|
|
|
328
328
|
runtimeClosedTradeBucket: (userName, dayKey) => `users:${userName}:runtime:closed-trade-records:days:${dayKey}`,
|
|
329
329
|
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
330
330
|
runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
|
|
331
|
-
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
332
331
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
333
332
|
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
334
333
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
|
@@ -285,7 +285,6 @@ var redisKeys = {
|
|
|
285
285
|
runtimeClosedTradeBucket: (userName, dayKey) => `users:${userName}:runtime:closed-trade-records:days:${dayKey}`,
|
|
286
286
|
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
287
287
|
runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
|
|
288
|
-
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
289
288
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
290
289
|
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
291
290
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
|
@@ -323,7 +323,6 @@ var redisKeys = {
|
|
|
323
323
|
runtimeClosedTradeBucket: (userName, dayKey) => `users:${userName}:runtime:closed-trade-records:days:${dayKey}`,
|
|
324
324
|
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
325
325
|
runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
|
|
326
|
-
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
327
326
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
328
327
|
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
329
328
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
package/dist/tradingAccounts.js
CHANGED
|
@@ -353,7 +353,6 @@ var redisKeys = {
|
|
|
353
353
|
runtimeClosedTradeBucket: (userName, dayKey) => `users:${userName}:runtime:closed-trade-records:days:${dayKey}`,
|
|
354
354
|
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
355
355
|
runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
|
|
356
|
-
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
357
356
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
358
357
|
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
359
358
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
package/dist/tradingAccounts.mjs
CHANGED
package/dist/userSettings.js
CHANGED
|
@@ -286,7 +286,6 @@ var redisKeys = {
|
|
|
286
286
|
runtimeClosedTradeBucket: (userName, dayKey) => `users:${userName}:runtime:closed-trade-records:days:${dayKey}`,
|
|
287
287
|
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
288
288
|
runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
|
|
289
|
-
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
290
289
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
291
290
|
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
292
291
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
package/dist/userSettings.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/infra",
|
|
3
|
-
"version": "3.1.29-beta.
|
|
3
|
+
"version": "3.1.29-beta.263",
|
|
4
4
|
"description": "MIT-licensed server infrastructure adapters for TradeJS: Redis, Timescale, ML, logging, and IO.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"coinbase",
|
|
17
17
|
"ai",
|
|
18
18
|
"claude",
|
|
19
|
-
"codex"
|
|
19
|
+
"codex",
|
|
20
|
+
"jev"
|
|
20
21
|
],
|
|
21
22
|
"repository": {
|
|
22
23
|
"type": "git",
|
|
@@ -140,7 +141,7 @@
|
|
|
140
141
|
"dependencies": {
|
|
141
142
|
"@grpc/grpc-js": "^1.14.4",
|
|
142
143
|
"@grpc/proto-loader": "^0.8.1",
|
|
143
|
-
"@tradejs/types": "^3.1.29-beta.
|
|
144
|
+
"@tradejs/types": "^3.1.29-beta.263",
|
|
144
145
|
"chalk": "4.1.2",
|
|
145
146
|
"date-fns": "^3.6.0",
|
|
146
147
|
"ioredis": "5.11.1",
|