wenay-common2 1.0.46 → 1.0.49
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 +51 -37
- package/lib/Common/Color.d.ts +3 -0
- package/lib/Common/Color.js +4 -0
- package/lib/Common/ObserveAll2/index.d.ts +2 -0
- package/lib/Common/ObserveAll2/index.js +18 -0
- package/lib/Common/ObserveAll2/reactive2.d.ts +33 -0
- package/lib/Common/ObserveAll2/reactive2.js +254 -0
- package/lib/Common/ObserveAll2/store.d.ts +98 -0
- package/lib/Common/ObserveAll2/store.js +381 -0
- package/lib/Common/Time.d.ts +8 -0
- package/lib/Common/Time.js +41 -14
- package/lib/Common/async/PromiseArrayListen.d.ts +3 -3
- package/lib/Common/async/PromiseArrayListen.js +10 -13
- package/lib/Common/async/createIterableObject.js +1 -1
- package/lib/Common/async/waitRun.d.ts +11 -4
- package/lib/Common/async/waitRun.js +74 -44
- package/lib/Common/core/Decorator.d.ts +3 -1
- package/lib/Common/core/Decorator.js +5 -2
- package/lib/Common/core/common.d.ts +25 -7
- package/lib/Common/core/common.js +114 -34
- package/lib/Common/data/ByteStream.d.ts +1 -1
- package/lib/Common/data/ByteStream.js +21 -8
- package/lib/Common/data/List.d.ts +5 -0
- package/lib/Common/data/List.js +13 -4
- package/lib/Common/data/ListNodeAnd.js +2 -2
- package/lib/Common/data/objectPath.d.ts +4 -0
- package/lib/Common/data/objectPath.js +8 -3
- package/lib/Common/events/Listen.d.ts +1 -55
- package/lib/Common/events/Listen.js +15 -154
- package/lib/Common/events/Listen2.d.ts +1 -0
- package/lib/Common/events/Listen2.js +17 -0
- package/lib/Common/events/Listen3.d.ts +197 -0
- package/lib/Common/events/Listen3.js +249 -0
- package/lib/Common/events/SocketBuffer.d.ts +14 -9
- package/lib/Common/events/SocketServerHook.d.ts +26 -13
- package/lib/Common/events/SocketServerHook.js +2 -1
- package/lib/Common/events/UseListenTransform.d.ts +10 -5
- package/lib/Common/events/event.d.ts +12 -0
- package/lib/Common/events/event.js +10 -6
- package/lib/Common/events/joinListens.d.ts +2 -0
- package/lib/Common/events/joinListens.js +13 -12
- package/lib/Common/funcTimeWait.d.ts +28 -0
- package/lib/Common/funcTimeWait.js +18 -1
- package/lib/Common/isProxy.d.ts +1 -0
- package/lib/Common/isProxy.js +2 -0
- package/lib/Common/node_console.d.ts +2 -0
- package/lib/Common/node_console.js +3 -76
- package/lib/Common/rcp/createRpcServerAutoWithProtocolDetection.d.ts +2 -0
- package/lib/Common/rcp/createRpcServerAutoWithProtocolDetection.js +63 -30
- package/lib/Common/rcp/listen-deep.d.ts +13 -5
- package/lib/Common/rcp/listen-socket.d.ts +21 -3
- package/lib/Common/rcp/listen-socket.js +126 -17
- package/lib/Common/rcp/oldCommonsServer.d.ts +1 -1
- package/lib/Common/rcp/oldCommonsServer.js +15 -1
- package/lib/Common/rcp/old/320/241ommonsServerMini.js +1 -0
- package/lib/Common/rcp/rpc-caps.d.ts +10 -0
- package/lib/Common/rcp/rpc-caps.js +16 -0
- package/lib/Common/rcp/rpc-client.d.ts +23 -1
- package/lib/Common/rcp/rpc-client.js +306 -25
- package/lib/Common/rcp/rpc-clientHub.d.ts +7 -1
- package/lib/Common/rcp/rpc-clientHub.js +25 -2
- package/lib/Common/rcp/rpc-index.d.ts +3 -0
- package/lib/Common/rcp/rpc-index.js +3 -0
- package/lib/Common/rcp/rpc-inproc.d.ts +17 -0
- package/lib/Common/rcp/rpc-inproc.js +30 -0
- package/lib/Common/rcp/rpc-off.d.ts +10 -0
- package/lib/Common/rcp/rpc-off.js +22 -0
- package/lib/Common/rcp/rpc-protocol.d.ts +6 -0
- package/lib/Common/rcp/rpc-protocol.js +4 -2
- package/lib/Common/rcp/rpc-server-auto.d.ts +14 -3
- package/lib/Common/rcp/rpc-server-auto.js +81 -6
- package/lib/Common/rcp/rpc-server.d.ts +17 -2
- package/lib/Common/rcp/rpc-server.js +127 -31
- package/lib/Common/rcp/rpc-shape.d.ts +17 -0
- package/lib/Common/rcp/rpc-shape.js +42 -0
- package/lib/Common/rcp/rpc-walk.js +29 -11
- package/lib/Exchange/Bars.d.ts +3 -0
- package/lib/Exchange/Bars.js +4 -1
- package/lib/Exchange/CParams.d.ts +2 -0
- package/lib/Exchange/CParams.js +21 -14
- package/lib/Exchange/MarketData.d.ts +6 -0
- package/lib/Exchange/MarketData.js +4 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -1
- package/lib/server/WebHook3.js +22 -9
- package/package.json +3 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.endCallback = void 0;
|
|
4
|
+
exports.makeOff = makeOff;
|
|
5
|
+
const rpc_walk_1 = require("./rpc-walk");
|
|
6
|
+
exports.endCallback = rpc_walk_1.rpcEndCallback;
|
|
7
|
+
function makeOff(promise, stop, extra) {
|
|
8
|
+
let done = false;
|
|
9
|
+
function off() {
|
|
10
|
+
if (done)
|
|
11
|
+
return;
|
|
12
|
+
done = true;
|
|
13
|
+
stop();
|
|
14
|
+
}
|
|
15
|
+
const handle = off;
|
|
16
|
+
handle.then = promise.then.bind(promise);
|
|
17
|
+
handle.catch = promise.catch.bind(promise);
|
|
18
|
+
handle.finally = promise.finally.bind(promise);
|
|
19
|
+
if (extra)
|
|
20
|
+
Object.assign(handle, extra);
|
|
21
|
+
return handle;
|
|
22
|
+
}
|
|
@@ -6,7 +6,13 @@ export declare const Pkt: {
|
|
|
6
6
|
readonly STRICT: 4;
|
|
7
7
|
readonly CB_END: 5;
|
|
8
8
|
readonly PIPE: 6;
|
|
9
|
+
readonly HELLO: 7;
|
|
10
|
+
readonly SHAPE: 8;
|
|
11
|
+
readonly CBV: 9;
|
|
12
|
+
readonly CAPS: 10;
|
|
9
13
|
};
|
|
14
|
+
export declare const RPC_STOP = "___STOP";
|
|
15
|
+
export declare const IS_RPC_LISTEN: unique symbol;
|
|
10
16
|
export type SocketTmpl = {
|
|
11
17
|
emit: (e: string, d: any) => void;
|
|
12
18
|
on: (e: string, cb: (d: any) => void) => void;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Pkt = void 0;
|
|
4
|
-
exports.Pkt = { CALL: 0, RESP: 1, CB: 2, MAP: 3, STRICT: 4, CB_END: 5, PIPE: 6 };
|
|
3
|
+
exports.IS_RPC_LISTEN = exports.RPC_STOP = exports.Pkt = void 0;
|
|
4
|
+
exports.Pkt = { CALL: 0, RESP: 1, CB: 2, MAP: 3, STRICT: 4, CB_END: 5, PIPE: 6, HELLO: 7, SHAPE: 8, CBV: 9, CAPS: 10 };
|
|
5
|
+
exports.RPC_STOP = "___STOP";
|
|
6
|
+
exports.IS_RPC_LISTEN = Symbol.for("isRpcListen");
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { funcListenCallbackBase } from "../events/Listen";
|
|
2
|
-
import { type PromiseServerHooks, type RpcLimits } from "./rpc-server";
|
|
2
|
+
import { type PromiseServerHooks, type RpcLimits, type RpcServerAuth, type RpcOpt } from "./rpc-server";
|
|
3
3
|
import { DeepSocketListen } from "./listen-deep";
|
|
4
4
|
import { SocketTmpl } from "./rpc-protocol";
|
|
5
5
|
type ListenCallbackBase<T extends any[] = any[]> = ReturnType<typeof funcListenCallbackBase<T>>;
|
|
6
|
-
export declare function createRpcServerAuto<T extends object>({ socket, object: target, socketKey: key, debug, hooks, disconnectListen, limits }: {
|
|
6
|
+
export declare function createRpcServerAuto<T extends object>({ socket, object: target, socketKey: key, debug, hooks, disconnectListen, limits, auth, maxPerListen, throttle, opt }: {
|
|
7
7
|
socket: SocketTmpl;
|
|
8
8
|
object: T;
|
|
9
9
|
socketKey: string;
|
|
@@ -11,5 +11,16 @@ export declare function createRpcServerAuto<T extends object>({ socket, object:
|
|
|
11
11
|
hooks?: Omit<PromiseServerHooks<DeepSocketListen<T>>, "resolveTransform">;
|
|
12
12
|
disconnectListen?: ListenCallbackBase<any>;
|
|
13
13
|
limits?: RpcLimits;
|
|
14
|
-
|
|
14
|
+
auth?: RpcServerAuth;
|
|
15
|
+
maxPerListen?: number;
|
|
16
|
+
throttle?: number;
|
|
17
|
+
opt?: RpcOpt;
|
|
18
|
+
}): {
|
|
19
|
+
api: {
|
|
20
|
+
subscriptions: () => {
|
|
21
|
+
key: string;
|
|
22
|
+
consumers: number;
|
|
23
|
+
}[];
|
|
24
|
+
};
|
|
25
|
+
};
|
|
15
26
|
export {};
|
|
@@ -4,25 +4,100 @@ exports.createRpcServerAuto = createRpcServerAuto;
|
|
|
4
4
|
const Listen_1 = require("../events/Listen");
|
|
5
5
|
const listen_socket_1 = require("./listen-socket");
|
|
6
6
|
const rpc_server_1 = require("./rpc-server");
|
|
7
|
-
|
|
7
|
+
const rpc_protocol_1 = require("./rpc-protocol");
|
|
8
|
+
function createRpcServerAuto({ socket, object: target, socketKey: key, debug, hooks, disconnectListen, limits, auth, maxPerListen, throttle, opt }) {
|
|
8
9
|
const cache = new WeakMap();
|
|
10
|
+
const registry = new Map();
|
|
11
|
+
function unsubscribeAllActive() {
|
|
12
|
+
for (const { subs } of registry.values()) {
|
|
13
|
+
subs.forEach(w => w.removeCallback());
|
|
14
|
+
subs.clear();
|
|
15
|
+
}
|
|
16
|
+
registry.clear();
|
|
17
|
+
}
|
|
9
18
|
function getListenSocket(parent, disconnectListen) {
|
|
10
19
|
let result = cache.get(parent);
|
|
11
20
|
if (!result) {
|
|
12
|
-
|
|
21
|
+
const subs = new Map();
|
|
22
|
+
function subscribe(z) {
|
|
23
|
+
if (typeof z !== "function")
|
|
24
|
+
return Promise.reject(new TypeError("Listen callback expects a function"));
|
|
25
|
+
if (maxPerListen != null && subs.size >= maxPerListen)
|
|
26
|
+
return Promise.resolve();
|
|
27
|
+
if (!registry.has(parent))
|
|
28
|
+
registry.set(parent, { subs });
|
|
29
|
+
subs.get(z)?.removeCallback();
|
|
30
|
+
const w = (0, listen_socket_1.listenSocket)(parent, { addListenClose: disconnectListen, throttle });
|
|
31
|
+
subs.set(z, w);
|
|
32
|
+
const done = w.callback(z);
|
|
33
|
+
done.then(() => {
|
|
34
|
+
if (subs.get(z) == w)
|
|
35
|
+
subs.delete(z);
|
|
36
|
+
if (subs.size == 0)
|
|
37
|
+
registry.delete(parent);
|
|
38
|
+
});
|
|
39
|
+
return done;
|
|
40
|
+
}
|
|
41
|
+
function subscribeOnce(z) {
|
|
42
|
+
if (typeof z !== "function")
|
|
43
|
+
return Promise.reject(new TypeError("Listen once expects a function"));
|
|
44
|
+
if (maxPerListen != null && subs.size >= maxPerListen)
|
|
45
|
+
return Promise.resolve();
|
|
46
|
+
if (!registry.has(parent))
|
|
47
|
+
registry.set(parent, { subs });
|
|
48
|
+
subs.get(z)?.removeCallback();
|
|
49
|
+
const w = (0, listen_socket_1.listenSocket)(parent, { addListenClose: disconnectListen, throttle });
|
|
50
|
+
let fired = false;
|
|
51
|
+
const oneShot = (...a) => {
|
|
52
|
+
if (fired)
|
|
53
|
+
return;
|
|
54
|
+
fired = true;
|
|
55
|
+
try {
|
|
56
|
+
z(...a);
|
|
57
|
+
z(rpc_protocol_1.RPC_STOP);
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
w.removeCallback();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
subs.set(z, w);
|
|
64
|
+
const done = w.callback(oneShot);
|
|
65
|
+
done.then(() => { if (subs.get(z) == w)
|
|
66
|
+
subs.delete(z); if (subs.size == 0)
|
|
67
|
+
registry.delete(parent); });
|
|
68
|
+
return done;
|
|
69
|
+
}
|
|
70
|
+
function unsubscribeAll() {
|
|
71
|
+
subs.forEach(w => w.removeCallback());
|
|
72
|
+
subs.clear();
|
|
73
|
+
registry.delete(parent);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
result = { callback: subscribe, removeCallback: unsubscribeAll, on: subscribe, once: subscribeOnce, close: () => parent.close?.() };
|
|
77
|
+
result[rpc_protocol_1.IS_RPC_LISTEN] = true;
|
|
13
78
|
cache.set(parent, result);
|
|
14
79
|
}
|
|
15
80
|
return result;
|
|
16
81
|
}
|
|
82
|
+
const api = {
|
|
83
|
+
subscriptions: () => Array.from(registry, ([parent, e], i) => ({
|
|
84
|
+
key: parent?.constructor?.name ? `${parent.constructor.name}#${i}` : `listen#${i}`,
|
|
85
|
+
consumers: e.subs.size,
|
|
86
|
+
})),
|
|
87
|
+
};
|
|
17
88
|
(0, rpc_server_1.createRpcServer)({
|
|
18
|
-
socket, object: target, socketKey: key, debug, limits,
|
|
89
|
+
socket, object: target, socketKey: key, debug, limits, auth, opt,
|
|
19
90
|
hooks: {
|
|
20
91
|
...hooks,
|
|
92
|
+
onDispose: () => { unsubscribeAllActive(); hooks?.onDispose?.(); },
|
|
21
93
|
resolveTransform: (obj) => {
|
|
22
|
-
if (
|
|
23
|
-
return obj;
|
|
24
|
-
|
|
94
|
+
if ((0, Listen_1.isListenCallback)(obj))
|
|
95
|
+
return getListenSocket(obj, disconnectListen);
|
|
96
|
+
if ((0, Listen_1.isListenOn)(obj))
|
|
97
|
+
return getListenSocket((0, Listen_1.getListenByOn)(obj), disconnectListen);
|
|
98
|
+
return obj;
|
|
25
99
|
},
|
|
26
100
|
},
|
|
27
101
|
});
|
|
102
|
+
return { api };
|
|
28
103
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type RpcLimits } from "./rpc-limits";
|
|
2
2
|
import { type SocketTmpl } from "./rpc-protocol";
|
|
3
|
+
import { type RpcOpt } from "./rpc-caps";
|
|
3
4
|
type Func = (...args: any[]) => any;
|
|
4
5
|
type PromiseServerHooks<T> = {
|
|
5
6
|
onRequest?: (ctx: {
|
|
@@ -15,13 +16,27 @@ type PromiseServerHooks<T> = {
|
|
|
15
16
|
error?: any;
|
|
16
17
|
}) => void | Promise<void>;
|
|
17
18
|
resolveTransform?: (value: any) => any;
|
|
19
|
+
onDispose?: () => void;
|
|
18
20
|
};
|
|
19
|
-
|
|
21
|
+
type RpcServerAuth = {
|
|
22
|
+
resolveAuth: (token: any) => {
|
|
23
|
+
object?: any;
|
|
24
|
+
ack?: any;
|
|
25
|
+
} | Promise<{
|
|
26
|
+
object?: any;
|
|
27
|
+
ack?: any;
|
|
28
|
+
}>;
|
|
29
|
+
gate?: boolean;
|
|
30
|
+
};
|
|
31
|
+
export declare function createRpcServer<T extends object>({ socket, object: target, socketKey: key, debug, hooks, limits, auth, opt }: {
|
|
20
32
|
socket: SocketTmpl;
|
|
21
33
|
object: T;
|
|
22
34
|
socketKey: string;
|
|
23
35
|
debug?: boolean;
|
|
24
36
|
hooks?: PromiseServerHooks<T>;
|
|
25
37
|
limits?: RpcLimits;
|
|
38
|
+
auth?: RpcServerAuth;
|
|
39
|
+
opt?: RpcOpt;
|
|
26
40
|
}): void;
|
|
27
|
-
export type { PromiseServerHooks, RpcLimits };
|
|
41
|
+
export type { PromiseServerHooks, RpcLimits, RpcServerAuth };
|
|
42
|
+
export type { RpcOpt } from "./rpc-caps";
|
|
@@ -4,12 +4,14 @@ exports.createRpcServer = createRpcServer;
|
|
|
4
4
|
const rpc_dynamic_1 = require("./rpc-dynamic");
|
|
5
5
|
const rpc_limits_1 = require("./rpc-limits");
|
|
6
6
|
const rpc_walk_1 = require("./rpc-walk");
|
|
7
|
+
const rpc_shape_1 = require("./rpc-shape");
|
|
7
8
|
const rpc_protocol_1 = require("./rpc-protocol");
|
|
8
|
-
|
|
9
|
+
const rpc_caps_1 = require("./rpc-caps");
|
|
10
|
+
const myThrow_1 = require("../../toError/myThrow");
|
|
11
|
+
const SERVERS = new WeakMap();
|
|
12
|
+
function createServer(socket, key, target, hooks, limits, auth, opt) {
|
|
9
13
|
const lim = (0, rpc_limits_1.resolveLimits)(limits);
|
|
10
|
-
const
|
|
11
|
-
const contexts = [];
|
|
12
|
-
const routeMap = {};
|
|
14
|
+
const IS_RPC_PIPE = Symbol.for("isRpcPipe");
|
|
13
15
|
function transformTree(obj) {
|
|
14
16
|
let current = obj;
|
|
15
17
|
if (hooks?.resolveTransform && !(0, rpc_dynamic_1.isNoStrict)(current)) {
|
|
@@ -18,6 +20,8 @@ function createServer(socket, key, target, hooks, limits) {
|
|
|
18
20
|
if (current == null || typeof current != "object" || (0, rpc_dynamic_1.isNoStrict)(current))
|
|
19
21
|
return current;
|
|
20
22
|
const out = {};
|
|
23
|
+
if (current[rpc_protocol_1.IS_RPC_LISTEN])
|
|
24
|
+
out[rpc_protocol_1.IS_RPC_LISTEN] = true;
|
|
21
25
|
for (const k of Object.keys(current)) {
|
|
22
26
|
if (!(0, rpc_limits_1.isSafeKey)(k))
|
|
23
27
|
continue;
|
|
@@ -26,27 +30,11 @@ function createServer(socket, key, target, hooks, limits) {
|
|
|
26
30
|
out[k] = v;
|
|
27
31
|
continue;
|
|
28
32
|
}
|
|
29
|
-
out[k] = typeof v == "function" ?
|
|
33
|
+
out[k] = typeof v == "function" ? (hooks?.resolveTransform ? hooks.resolveTransform(v) : v)
|
|
34
|
+
: v != null && typeof v == "object" ? transformTree(v) : v;
|
|
30
35
|
}
|
|
31
36
|
return out;
|
|
32
37
|
}
|
|
33
|
-
const resolved = transformTree(target);
|
|
34
|
-
function index(obj, prefix) {
|
|
35
|
-
for (const k of Object.keys(obj)) {
|
|
36
|
-
if (!(0, rpc_limits_1.isSafeKey)(k))
|
|
37
|
-
continue;
|
|
38
|
-
const v = obj[k];
|
|
39
|
-
const path = prefix ? prefix + "." + k : k;
|
|
40
|
-
if (typeof v == "function") {
|
|
41
|
-
routeMap[path] = methods.length;
|
|
42
|
-
methods.push(v);
|
|
43
|
-
contexts.push(obj);
|
|
44
|
-
}
|
|
45
|
-
else if (v && typeof v == "object" && !(0, rpc_dynamic_1.isNoStrict)(v))
|
|
46
|
-
index(v, path);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
index(resolved, "");
|
|
50
38
|
function serialize(obj) {
|
|
51
39
|
const out = {};
|
|
52
40
|
for (const k of Object.keys(obj)) {
|
|
@@ -73,13 +61,110 @@ function createServer(socket, key, target, hooks, limits) {
|
|
|
73
61
|
}
|
|
74
62
|
return out;
|
|
75
63
|
}
|
|
76
|
-
|
|
64
|
+
let methods = [];
|
|
65
|
+
let contexts = [];
|
|
66
|
+
let routeMap = {};
|
|
67
|
+
let listenPaths = [];
|
|
68
|
+
let strictSchema = {};
|
|
69
|
+
let currentTarget = target;
|
|
70
|
+
function buildDispatch(t) {
|
|
71
|
+
const m = [], cx = [], rm = {}, lp = [];
|
|
72
|
+
const resolved = transformTree(t);
|
|
73
|
+
(function index(obj, prefix) {
|
|
74
|
+
for (const k of Object.keys(obj)) {
|
|
75
|
+
if (!(0, rpc_limits_1.isSafeKey)(k))
|
|
76
|
+
continue;
|
|
77
|
+
const v = obj[k];
|
|
78
|
+
const path = prefix ? prefix + "." + k : k;
|
|
79
|
+
if (typeof v == "function") {
|
|
80
|
+
rm[path] = m.length;
|
|
81
|
+
m.push(v);
|
|
82
|
+
cx.push(obj);
|
|
83
|
+
}
|
|
84
|
+
else if (v && typeof v == "object" && !(0, rpc_dynamic_1.isNoStrict)(v)) {
|
|
85
|
+
if (v[rpc_protocol_1.IS_RPC_LISTEN])
|
|
86
|
+
lp.push(path);
|
|
87
|
+
index(v, path);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
})(resolved, "");
|
|
91
|
+
methods = m;
|
|
92
|
+
contexts = cx;
|
|
93
|
+
routeMap = rm;
|
|
94
|
+
listenPaths = lp;
|
|
95
|
+
strictSchema = serialize(resolved);
|
|
96
|
+
currentTarget = t;
|
|
97
|
+
}
|
|
98
|
+
buildDispatch(target);
|
|
77
99
|
const send = (d) => socket.emit(key, d);
|
|
78
|
-
const
|
|
79
|
-
|
|
100
|
+
const serverCaps = (0, rpc_caps_1.optToCaps)(opt);
|
|
101
|
+
let peerCaps = 0;
|
|
102
|
+
const compactOn = () => (0, rpc_caps_1.hasCap)(serverCaps & peerCaps, rpc_caps_1.Caps.COMPACT);
|
|
103
|
+
const cbShapes = (0, rpc_shape_1.createCbShapeServer)();
|
|
104
|
+
const sendCb = (cbId, cbArgs) => {
|
|
105
|
+
if (compactOn() && cbArgs.length == 1 && (0, rpc_shape_1.isPlainObject)(cbArgs[0])) {
|
|
106
|
+
const obj = cbArgs[0];
|
|
107
|
+
const r = cbShapes.offer(cbId, obj);
|
|
108
|
+
if (r.mode == "register") {
|
|
109
|
+
send([rpc_protocol_1.Pkt.SHAPE, cbId, r.shapeId, r.keys]);
|
|
110
|
+
send([rpc_protocol_1.Pkt.CBV, cbId, r.shapeId, r.keys.map(k => (0, rpc_walk_1.packResult)(obj[k]))]);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (r.mode == "compact") {
|
|
114
|
+
send([rpc_protocol_1.Pkt.CBV, cbId, r.shapeId, r.keys.map(k => (0, rpc_walk_1.packResult)(obj[k]))]);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
send([rpc_protocol_1.Pkt.CB, cbId, cbArgs.map(rpc_walk_1.packResult)]);
|
|
119
|
+
};
|
|
120
|
+
const sendCbEnd = (cbId) => { cbShapes.drop(cbId); send([rpc_protocol_1.Pkt.CB_END, cbId]); };
|
|
121
|
+
let authed = !auth?.gate;
|
|
122
|
+
let authAck = undefined;
|
|
123
|
+
const sendMap = () => send(authAck !== undefined
|
|
124
|
+
? [rpc_protocol_1.Pkt.MAP, routeMap, strictSchema, listenPaths, authAck]
|
|
125
|
+
: [rpc_protocol_1.Pkt.MAP, routeMap, strictSchema, listenPaths]);
|
|
126
|
+
sendMap();
|
|
127
|
+
if (serverCaps)
|
|
128
|
+
send([rpc_protocol_1.Pkt.CAPS, serverCaps]);
|
|
129
|
+
let detached = false;
|
|
130
|
+
let byKey = SERVERS.get(socket);
|
|
131
|
+
if (!byKey) {
|
|
132
|
+
byKey = new Map();
|
|
133
|
+
SERVERS.set(socket, byKey);
|
|
134
|
+
}
|
|
135
|
+
const detachPrev = byKey.get(key);
|
|
136
|
+
if (detachPrev) {
|
|
137
|
+
detachPrev();
|
|
138
|
+
console.warn(`[RPC] createRpcServer: повторная инициализация на socket+key "${key}" — предыдущий сервер отцеплен`);
|
|
139
|
+
}
|
|
140
|
+
byKey.set(key, () => { detached = true; hooks?.onDispose?.(); });
|
|
80
141
|
socket.on(key, async (msg) => {
|
|
142
|
+
if (detached)
|
|
143
|
+
return;
|
|
81
144
|
if (msg == rpc_protocol_1.Pkt.STRICT) {
|
|
82
|
-
|
|
145
|
+
sendMap();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (Array.isArray(msg) && msg[0] === rpc_protocol_1.Pkt.CAPS) {
|
|
149
|
+
peerCaps = typeof msg[1] === "number" ? msg[1] : rpc_caps_1.Caps.COMPACT;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (Array.isArray(msg) && msg[0] === rpc_protocol_1.Pkt.HELLO) {
|
|
153
|
+
if (!auth?.resolveAuth) {
|
|
154
|
+
send([rpc_protocol_1.Pkt.MAP, routeMap, strictSchema, listenPaths, null]);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const r = await auth.resolveAuth(msg[1]);
|
|
159
|
+
if (r && r.object !== undefined)
|
|
160
|
+
buildDispatch(r.object);
|
|
161
|
+
authAck = r && r.ack !== undefined ? r.ack : { ok: true };
|
|
162
|
+
authed = authAck?.ok !== false;
|
|
163
|
+
sendMap();
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
send([rpc_protocol_1.Pkt.MAP, routeMap, strictSchema, listenPaths, { ok: false, reason: e?.message ?? String(e) }]);
|
|
167
|
+
}
|
|
83
168
|
return;
|
|
84
169
|
}
|
|
85
170
|
if (!Array.isArray(msg) || (msg[0] !== rpc_protocol_1.Pkt.CALL && msg[0] !== rpc_protocol_1.Pkt.PIPE))
|
|
@@ -91,6 +176,11 @@ function createServer(socket, key, target, hooks, limits) {
|
|
|
91
176
|
hooks?.onInvalid?.({ reason: "invalid_payload", key: ref, request: rawArgsOrSteps, error: "reqId is not a valid number" });
|
|
92
177
|
return;
|
|
93
178
|
}
|
|
179
|
+
if (!authed) {
|
|
180
|
+
if (wait)
|
|
181
|
+
send([rpc_protocol_1.Pkt.RESP, reqId, null, (0, rpc_walk_1.errToObj)(new myThrow_1.MyError("Unauthorized", "E_UNAUTHORIZED"))]);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
94
184
|
if (typeof ref !== "number" && !Array.isArray(ref)) {
|
|
95
185
|
hooks?.onInvalid?.({ reason: "invalid_payload", key: ref, request: rawArgsOrSteps, error: "ref must be number or string[]" });
|
|
96
186
|
if (wait)
|
|
@@ -116,13 +206,19 @@ function createServer(socket, key, target, hooks, limits) {
|
|
|
116
206
|
send([rpc_protocol_1.Pkt.RESP, reqId, null, (0, rpc_walk_1.errToObj)(new Error("Forbidden path segment"))]);
|
|
117
207
|
return;
|
|
118
208
|
}
|
|
209
|
+
if (ref.length > lim.maxPathLen) {
|
|
210
|
+
hooks?.onInvalid?.({ reason: "invalid_payload", key: ref, request: rawArgsOrSteps, error: "path too long" });
|
|
211
|
+
if (wait)
|
|
212
|
+
send([rpc_protocol_1.Pkt.RESP, reqId, null, (0, rpc_walk_1.errToObj)(new rpc_limits_1.PayloadLimitError("path too long"))]);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
119
215
|
const idx = routeMap[ref.join(".")];
|
|
120
216
|
if (idx !== undefined) {
|
|
121
217
|
fn = methods[idx];
|
|
122
218
|
ctx = contexts[idx];
|
|
123
219
|
}
|
|
124
220
|
else {
|
|
125
|
-
let curr =
|
|
221
|
+
let curr = currentTarget;
|
|
126
222
|
for (let i = 0; i < ref.length - 1; i++) {
|
|
127
223
|
const seg = ref[i];
|
|
128
224
|
if (curr == null || typeof curr !== "object" || !(seg in curr)) {
|
|
@@ -178,7 +274,7 @@ function createServer(socket, key, target, hooks, limits) {
|
|
|
178
274
|
else if (step.type === 'call') {
|
|
179
275
|
if (typeof current !== "function")
|
|
180
276
|
throw new Error("Attempted to call a non-function in pipe");
|
|
181
|
-
const stepArgs = (0, rpc_walk_1.unpack)(step.args,
|
|
277
|
+
const stepArgs = (0, rpc_walk_1.unpack)(step.args, sendCb, sendCbEnd, lim);
|
|
182
278
|
current = current(...stepArgs);
|
|
183
279
|
}
|
|
184
280
|
}
|
|
@@ -189,7 +285,7 @@ function createServer(socket, key, target, hooks, limits) {
|
|
|
189
285
|
send([rpc_protocol_1.Pkt.RESP, reqId, (0, rpc_walk_1.packResult)(current)]);
|
|
190
286
|
}
|
|
191
287
|
else {
|
|
192
|
-
const args = (0, rpc_walk_1.unpack)(rawArgsOrSteps,
|
|
288
|
+
const args = (0, rpc_walk_1.unpack)(rawArgsOrSteps, sendCb, sendCbEnd, lim);
|
|
193
289
|
const res = await fn.apply(ctx, args);
|
|
194
290
|
if (wait)
|
|
195
291
|
send([rpc_protocol_1.Pkt.RESP, reqId, (0, rpc_walk_1.packResult)(res)]);
|
|
@@ -201,10 +297,10 @@ function createServer(socket, key, target, hooks, limits) {
|
|
|
201
297
|
}
|
|
202
298
|
});
|
|
203
299
|
}
|
|
204
|
-
function createRpcServer({ socket, object: target, socketKey: key, debug = false, hooks, limits }) {
|
|
300
|
+
function createRpcServer({ socket, object: target, socketKey: key, debug = false, hooks, limits, auth, opt }) {
|
|
205
301
|
if (debug) {
|
|
206
302
|
const origOn = socket.on.bind(socket);
|
|
207
303
|
socket.on = (e, cb) => origOn(e, (d) => { console.log("[RPC IN]", typeof d == "object" ? JSON.stringify(d) : d); cb(d); });
|
|
208
304
|
}
|
|
209
|
-
createServer(socket, key, target, hooks, limits);
|
|
305
|
+
createServer(socket, key, target, hooks, limits, auth, opt);
|
|
210
306
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function isPlainObject(v: any): boolean;
|
|
2
|
+
export declare function createCbShapeServer(threshold?: number, maxShapes?: number): {
|
|
3
|
+
offer: (cbId: number, obj: any) => {
|
|
4
|
+
mode: "compact";
|
|
5
|
+
shapeId: number;
|
|
6
|
+
keys: string[];
|
|
7
|
+
} | {
|
|
8
|
+
mode: "register";
|
|
9
|
+
shapeId: number;
|
|
10
|
+
keys: string[];
|
|
11
|
+
} | {
|
|
12
|
+
mode: "full";
|
|
13
|
+
shapeId?: undefined;
|
|
14
|
+
keys?: undefined;
|
|
15
|
+
};
|
|
16
|
+
drop: (cbId: number) => void;
|
|
17
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isPlainObject = isPlainObject;
|
|
4
|
+
exports.createCbShapeServer = createCbShapeServer;
|
|
5
|
+
const THRESHOLD = 5;
|
|
6
|
+
const MAX_SHAPES = 5;
|
|
7
|
+
function isPlainObject(v) {
|
|
8
|
+
if (v == null || typeof v != "object")
|
|
9
|
+
return false;
|
|
10
|
+
if (Array.isArray(v) || v instanceof Date || v instanceof Map || v instanceof Set || v instanceof RegExp)
|
|
11
|
+
return false;
|
|
12
|
+
const p = Object.getPrototypeOf(v);
|
|
13
|
+
return p == null || p == Object.prototype;
|
|
14
|
+
}
|
|
15
|
+
function createCbShapeServer(threshold = THRESHOLD, maxShapes = MAX_SHAPES) {
|
|
16
|
+
const byCb = new Map();
|
|
17
|
+
function offer(cbId, obj) {
|
|
18
|
+
const keys = Object.keys(obj);
|
|
19
|
+
const sig = keys.slice().sort().join("\x00");
|
|
20
|
+
let st = byCb.get(cbId);
|
|
21
|
+
if (!st) {
|
|
22
|
+
st = { shapes: [], nextId: 0 };
|
|
23
|
+
byCb.set(cbId, st);
|
|
24
|
+
}
|
|
25
|
+
const sh = st.shapes.find(s => s.sig == sig);
|
|
26
|
+
if (sh) {
|
|
27
|
+
sh.count++;
|
|
28
|
+
if (sh.shapeId >= 0)
|
|
29
|
+
return { mode: "compact", shapeId: sh.shapeId, keys: sh.keys };
|
|
30
|
+
if (sh.count >= threshold) {
|
|
31
|
+
sh.shapeId = st.nextId++;
|
|
32
|
+
return { mode: "register", shapeId: sh.shapeId, keys: sh.keys };
|
|
33
|
+
}
|
|
34
|
+
return { mode: "full" };
|
|
35
|
+
}
|
|
36
|
+
if (st.shapes.length < maxShapes)
|
|
37
|
+
st.shapes.push({ sig, keys, count: 1, shapeId: -1 });
|
|
38
|
+
return { mode: "full" };
|
|
39
|
+
}
|
|
40
|
+
function drop(cbId) { byCb.delete(cbId); }
|
|
41
|
+
return { offer, drop };
|
|
42
|
+
}
|
|
@@ -8,6 +8,7 @@ exports.rpcEndCallback = rpcEndCallback;
|
|
|
8
8
|
exports.unpack = unpack;
|
|
9
9
|
exports.unpackResult = unpackResult;
|
|
10
10
|
const rpc_limits_1 = require("./rpc-limits");
|
|
11
|
+
const rpc_protocol_1 = require("./rpc-protocol");
|
|
11
12
|
const FN_MARKER = "$_f";
|
|
12
13
|
const DATE_MARKER = "$_d";
|
|
13
14
|
const MAP_MARKER = "$_m";
|
|
@@ -15,17 +16,19 @@ const SET_MARKER = "$_s";
|
|
|
15
16
|
const REGEXP_MARKER = "$_r";
|
|
16
17
|
const BIGINT_MARKER = "$_b";
|
|
17
18
|
const ALL_MARKERS = new Set([FN_MARKER, DATE_MARKER, MAP_MARKER, SET_MARKER, REGEXP_MARKER, BIGINT_MARKER]);
|
|
19
|
+
const deepSerialize = (v) => walk(v, serializeLeaf);
|
|
20
|
+
const deepDeserialize = (v, lim) => walk(v, l => deserializeLeaf(l, undefined, lim), lim);
|
|
18
21
|
const DESERIALIZERS = {
|
|
19
22
|
[DATE_MARKER]: (v) => new Date(v),
|
|
20
|
-
[MAP_MARKER]: (v) => new Map(v),
|
|
21
|
-
[SET_MARKER]: (v) => new Set(v),
|
|
23
|
+
[MAP_MARKER]: (v, lim) => new Map(v.map(([k, val]) => [deepDeserialize(k, lim), deepDeserialize(val, lim)])),
|
|
24
|
+
[SET_MARKER]: (v, lim) => new Set(v.map((x) => deepDeserialize(x, lim))),
|
|
22
25
|
[REGEXP_MARKER]: (v) => new RegExp(v.source, v.flags),
|
|
23
26
|
[BIGINT_MARKER]: (v) => BigInt(v),
|
|
24
27
|
};
|
|
25
28
|
const SERIALIZERS = [
|
|
26
29
|
(v) => v instanceof Date ? [DATE_MARKER, v.valueOf()] : null,
|
|
27
|
-
(v) => v instanceof Map ? [MAP_MARKER, Array.from(v.entries())] : null,
|
|
28
|
-
(v) => v instanceof Set ? [SET_MARKER, Array.from(v.values())] : null,
|
|
30
|
+
(v) => v instanceof Map ? [MAP_MARKER, Array.from(v.entries(), ([k, val]) => [deepSerialize(k), deepSerialize(val)])] : null,
|
|
31
|
+
(v) => v instanceof Set ? [SET_MARKER, Array.from(v.values(), (x) => deepSerialize(x))] : null,
|
|
29
32
|
(v) => v instanceof RegExp ? [REGEXP_MARKER, { source: v.source, flags: v.flags }] : null,
|
|
30
33
|
(v) => typeof v === "bigint" ? [BIGINT_MARKER, v.toString()] : null,
|
|
31
34
|
];
|
|
@@ -40,7 +43,8 @@ function walk(val, onLeaf, lim, depth = 0) {
|
|
|
40
43
|
return onLeaf(val);
|
|
41
44
|
if (val instanceof Date || val instanceof Map || val instanceof Set || val instanceof RegExp)
|
|
42
45
|
return onLeaf(val);
|
|
43
|
-
|
|
46
|
+
const ks0 = Object.keys(val);
|
|
47
|
+
if (ks0.length === 1 && ALL_MARKERS.has(ks0[0]))
|
|
44
48
|
return onLeaf(val);
|
|
45
49
|
if (Array.isArray(val)) {
|
|
46
50
|
if (lim && val.length > lim.maxArrayLen)
|
|
@@ -56,7 +60,7 @@ function walk(val, onLeaf, lim, depth = 0) {
|
|
|
56
60
|
o[k] = walk(val[k], onLeaf, lim, depth + 1);
|
|
57
61
|
return o;
|
|
58
62
|
}
|
|
59
|
-
function deserializeLeaf(leaf, onCallback) {
|
|
63
|
+
function deserializeLeaf(leaf, onCallback, lim) {
|
|
60
64
|
if (leaf == null || typeof leaf !== "object")
|
|
61
65
|
return leaf;
|
|
62
66
|
const key = Object.keys(leaf)[0];
|
|
@@ -66,7 +70,7 @@ function deserializeLeaf(leaf, onCallback) {
|
|
|
66
70
|
return onCallback?.(leaf[FN_MARKER]) ?? leaf;
|
|
67
71
|
}
|
|
68
72
|
const deserialize = DESERIALIZERS[key];
|
|
69
|
-
return deserialize ? deserialize(leaf[key]) : leaf;
|
|
73
|
+
return deserialize ? deserialize(leaf[key], lim) : leaf;
|
|
70
74
|
}
|
|
71
75
|
function serializeLeaf(leaf) {
|
|
72
76
|
for (const serializer of SERIALIZERS) {
|
|
@@ -95,6 +99,8 @@ function rpcEndCallback(fn) {
|
|
|
95
99
|
_stopRegistry.get(fn)?.();
|
|
96
100
|
}
|
|
97
101
|
function unpack(args, sender, onEnd, lim) {
|
|
102
|
+
if (lim && args.length > lim.maxArgs)
|
|
103
|
+
throw new rpc_limits_1.PayloadLimitError("too many args");
|
|
98
104
|
let cbCount = 0;
|
|
99
105
|
return args.map(v => walk(v, leaf => {
|
|
100
106
|
if (leaf != null && typeof leaf == "object" && leaf[FN_MARKER] !== undefined) {
|
|
@@ -104,7 +110,7 @@ function unpack(args, sender, onEnd, lim) {
|
|
|
104
110
|
if (typeof id !== "number" || !Number.isFinite(id))
|
|
105
111
|
throw new rpc_limits_1.PayloadLimitError("invalid callback id");
|
|
106
112
|
const wrapper = (...a) => {
|
|
107
|
-
if (a[0] ==
|
|
113
|
+
if (a[0] == rpc_protocol_1.RPC_STOP) {
|
|
108
114
|
onEnd(id);
|
|
109
115
|
return;
|
|
110
116
|
}
|
|
@@ -113,13 +119,25 @@ function unpack(args, sender, onEnd, lim) {
|
|
|
113
119
|
_stopRegistry.set(wrapper, () => onEnd(id));
|
|
114
120
|
return wrapper;
|
|
115
121
|
}
|
|
116
|
-
return deserializeLeaf(leaf);
|
|
122
|
+
return deserializeLeaf(leaf, undefined, lim);
|
|
117
123
|
}, lim));
|
|
118
124
|
}
|
|
119
125
|
function unpackResult(value, lim) {
|
|
120
|
-
return walk(value, leaf => deserializeLeaf(leaf), lim);
|
|
126
|
+
return walk(value, leaf => deserializeLeaf(leaf, undefined, lim), lim);
|
|
121
127
|
}
|
|
122
|
-
const errToObj = (e) =>
|
|
128
|
+
const errToObj = (e) => {
|
|
129
|
+
if (!(e instanceof Error))
|
|
130
|
+
return e;
|
|
131
|
+
const o = { name: e.name, message: e.message, stack: e.stack };
|
|
132
|
+
const { code, data, cause } = e;
|
|
133
|
+
if (code !== undefined)
|
|
134
|
+
o.code = code;
|
|
135
|
+
if (data !== undefined)
|
|
136
|
+
o.data = packResult(data);
|
|
137
|
+
if (cause !== undefined)
|
|
138
|
+
o.cause = (0, exports.errToObj)(cause);
|
|
139
|
+
return o;
|
|
140
|
+
};
|
|
123
141
|
exports.errToObj = errToObj;
|
|
124
142
|
const resolveCA = (path, args) => {
|
|
125
143
|
const last = path[path.length - 1];
|
package/lib/Exchange/Bars.d.ts
CHANGED
|
@@ -131,6 +131,8 @@ export declare abstract class CBarsMutableBase extends CBarsBase {
|
|
|
131
131
|
updateLast(bar: CBar): void;
|
|
132
132
|
AddTick(tick: ITick): boolean;
|
|
133
133
|
AddTicks(ticks: readonly ITick[]): boolean;
|
|
134
|
+
addTick(tick: ITick): boolean;
|
|
135
|
+
addTicks(ticks: readonly ITick[]): boolean;
|
|
134
136
|
}
|
|
135
137
|
export declare class CBarsMutable extends CBarsMutableBase {
|
|
136
138
|
readonly Mutable = true;
|
|
@@ -141,6 +143,7 @@ export declare class CBarsMutableExt extends CBarsMutable implements IBarsExt {
|
|
|
141
143
|
}
|
|
142
144
|
export declare function CreateRandomBars(tf: TF, startTime: const_Date, endTime: const_Date, startPrice?: number, volatility?: number | `${number}%`, ticksize?: number): CBars;
|
|
143
145
|
export declare function CreateRandomBars(tf: TF, startTime: const_Date, barsCount: number, startPrice?: number, volatility?: number | `${number}%`, ticksize?: number): CBars;
|
|
146
|
+
export declare const createRandomBars: typeof CreateRandomBars;
|
|
144
147
|
export type TimeValue<T> = {
|
|
145
148
|
readonly time: const_Date;
|
|
146
149
|
readonly value: T;
|
package/lib/Exchange/Bars.js
CHANGED
|
@@ -36,7 +36,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
36
36
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.CTimeSeries = exports.CTimeSeriesBase = exports.CBarsMutableExt = exports.CBarsMutable = exports.CBarsMutableBase = exports.CBars = exports.CBarsBase = exports.IBars = exports.CTick = exports.CBar = exports.CBarBase = exports.OHLC = void 0;
|
|
39
|
+
exports.CTimeSeries = exports.CTimeSeriesBase = exports.createRandomBars = exports.CBarsMutableExt = exports.CBarsMutable = exports.CBarsMutableBase = exports.CBars = exports.CBarsBase = exports.IBars = exports.CTick = exports.CBar = exports.CBarBase = exports.OHLC = void 0;
|
|
40
40
|
exports.CreateRandomBars = CreateRandomBars;
|
|
41
41
|
exports.findBarsShallow = findBarsShallow;
|
|
42
42
|
const lib = __importStar(require("../Common/core/common"));
|
|
@@ -357,6 +357,8 @@ class CBarsMutableBase extends CBarsBase {
|
|
|
357
357
|
AddTicks(ticks) { for (let tick of ticks)
|
|
358
358
|
if (!this.AddTick(tick))
|
|
359
359
|
return false; return true; }
|
|
360
|
+
addTick(tick) { return this.AddTick(tick); }
|
|
361
|
+
addTicks(ticks) { return this.AddTicks(ticks); }
|
|
360
362
|
}
|
|
361
363
|
exports.CBarsMutableBase = CBarsMutableBase;
|
|
362
364
|
class CBarsMutable extends CBarsMutableBase {
|
|
@@ -403,6 +405,7 @@ function CreateRandomBars(tf, startTime, endTimeOrCount, startPrice = 100, volat
|
|
|
403
405
|
}
|
|
404
406
|
return new CBars(tf, bars);
|
|
405
407
|
}
|
|
408
|
+
exports.createRandomBars = CreateRandomBars;
|
|
406
409
|
class CTimeSeriesBase {
|
|
407
410
|
time(i) { return this.points[i]?.time ?? (() => { throw "Wrong index i=" + i + " of " + this.length; })(); }
|
|
408
411
|
value(i) { return this.points[i]?.value ?? (() => { throw "Wrong index i=" + i + " of " + this.length; })(); }
|