libshv-js 3.6.1 → 3.6.2
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/.github/workflows/check-version-bump.yml +3 -3
- package/.github/workflows/lint.yml +4 -4
- package/.github/workflows/publish.yml +3 -3
- package/.github/workflows/test.yml +1 -1
- package/eslint.config.js +102 -0
- package/package.json +10 -5
- package/src/chainpack.ts +35 -38
- package/src/cpcontext.ts +0 -1
- package/src/cpon.ts +53 -60
- package/src/json.ts +1 -1
- package/src/rpcvalue.ts +7 -4
- package/src/ws-client.ts +17 -19
- package/src/zod.ts +2 -1
- package/.xo-config.json +0 -42
|
@@ -14,9 +14,9 @@ on:
|
|
|
14
14
|
jobs:
|
|
15
15
|
check-version-bump:
|
|
16
16
|
name: Check version bump
|
|
17
|
-
runs-on: ubuntu-
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
20
|
- name: Check if version bumped
|
|
21
|
-
uses: del-systems/check-if-version-bumped@v2
|
|
21
|
+
uses: del-systems/check-if-version-bumped@v2
|
|
22
22
|
|
|
@@ -14,9 +14,9 @@ on:
|
|
|
14
14
|
jobs:
|
|
15
15
|
type-check:
|
|
16
16
|
name: Type check
|
|
17
|
-
runs-on: ubuntu-
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
20
|
- name: Install tsc
|
|
21
21
|
run: npm install
|
|
22
22
|
- name: Run tsc
|
|
@@ -24,9 +24,9 @@ jobs:
|
|
|
24
24
|
|
|
25
25
|
xo:
|
|
26
26
|
name: xo
|
|
27
|
-
runs-on: ubuntu-
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
28
|
steps:
|
|
29
|
-
- uses: actions/checkout@
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
30
|
- name: Install tsc
|
|
31
31
|
run: npm install
|
|
32
32
|
- name: Run linters
|
|
@@ -8,14 +8,14 @@ on:
|
|
|
8
8
|
jobs:
|
|
9
9
|
test:
|
|
10
10
|
name: Publish new version
|
|
11
|
-
runs-on: ubuntu-
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
12
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
14
|
|
|
15
15
|
- name: Setup node
|
|
16
16
|
uses: actions/setup-node@v4
|
|
17
17
|
with:
|
|
18
|
-
node-version: '
|
|
18
|
+
node-version: '22.x'
|
|
19
19
|
registry-url: 'https://registry.npmjs.org'
|
|
20
20
|
|
|
21
21
|
- name: Publish
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import xo from "eslint-config-xo";
|
|
2
|
+
import typescriptEslintParser from "@typescript-eslint/parser";
|
|
3
|
+
import eslint from '@eslint/js';
|
|
4
|
+
import tseslint from 'typescript-eslint';
|
|
5
|
+
import unicornPlugin from 'eslint-plugin-unicorn';
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
eslint.configs.recommended,
|
|
9
|
+
eslint.configs.recommended,
|
|
10
|
+
...tseslint.configs.recommendedTypeChecked,
|
|
11
|
+
...tseslint.configs.stylisticTypeChecked,
|
|
12
|
+
unicornPlugin.configs.recommended,
|
|
13
|
+
...xo,
|
|
14
|
+
{
|
|
15
|
+
languageOptions: {
|
|
16
|
+
parser: typescriptEslintParser,
|
|
17
|
+
parserOptions: {
|
|
18
|
+
project: "./tsconfig.json",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
rules: {
|
|
22
|
+
"@stylistic/indent": ["error", 4],
|
|
23
|
+
"@stylistic/indent-binary-ops": ["error", 4],
|
|
24
|
+
"@stylistic/max-len": ["off"],
|
|
25
|
+
"@stylistic/multiline-ternary": ["off"],
|
|
26
|
+
"@stylistic/function-paren-newline": ["off"],
|
|
27
|
+
"@typescript-eslint/no-misused-promises": ["error", {
|
|
28
|
+
checksVoidReturn: false
|
|
29
|
+
}],
|
|
30
|
+
"@typescript-eslint/no-unsafe-assignment": ["off"],
|
|
31
|
+
"@typescript-eslint/no-unsafe-call": ["off"],
|
|
32
|
+
"@typescript-eslint/no-unsafe-enum-comparison": ["off"],
|
|
33
|
+
"@typescript-eslint/consistent-type-definitions": ["error",
|
|
34
|
+
"type"
|
|
35
|
+
],
|
|
36
|
+
"@typescript-eslint/array-type": ["error", {
|
|
37
|
+
default: "array-simple"
|
|
38
|
+
}],
|
|
39
|
+
"@typescript-eslint/naming-convention": ["error",
|
|
40
|
+
{
|
|
41
|
+
"selector": "variableLike",
|
|
42
|
+
"format": ["camelCase"]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"selector": "variableLike",
|
|
46
|
+
"format": null,
|
|
47
|
+
"modifiers": ["unused"]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"format": ["camelCase", "UPPER_CASE"],
|
|
51
|
+
"selector": "variable",
|
|
52
|
+
"modifiers": ["const"]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"format": ["PascalCase"],
|
|
56
|
+
"selector": "variable",
|
|
57
|
+
"modifiers": ["const"],
|
|
58
|
+
"filter": "Validation$|Zod$"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"@typescript-eslint/prefer-promise-reject-errors": "off",
|
|
62
|
+
"@typescript-eslint/promise-function-async": "off",
|
|
63
|
+
"@typescript-eslint/strict-boolean-expressions": ["error",
|
|
64
|
+
{
|
|
65
|
+
"allowString": false,
|
|
66
|
+
"allowNumber": false,
|
|
67
|
+
"allowNullableObject": false
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"@typescript-eslint/triple-slash-reference": "off",
|
|
71
|
+
"capitalized-comments": "off",
|
|
72
|
+
"@stylistic/object-curly-newline": ["error", {
|
|
73
|
+
"ImportDeclaration": "never"
|
|
74
|
+
}],
|
|
75
|
+
"n/file-extension-in-import": "off",
|
|
76
|
+
"promise-function-async": "off",
|
|
77
|
+
"camelcase": "off",
|
|
78
|
+
"default-case": "off",
|
|
79
|
+
"import/extensions": "off",
|
|
80
|
+
"import/no-unassigned-import": "off",
|
|
81
|
+
"no-dupe-class-members": "off",
|
|
82
|
+
"no-negated-condition": "off",
|
|
83
|
+
"no-unused-vars": "off",
|
|
84
|
+
"no-useless-constructor": "off",
|
|
85
|
+
"no-void": ["error", {
|
|
86
|
+
allowAsStatement: true
|
|
87
|
+
}],
|
|
88
|
+
"no-warning-comments": "off",
|
|
89
|
+
"prefer-promise-reject-errors": "off",
|
|
90
|
+
"unicorn/consistent-function-scoping": "off",
|
|
91
|
+
"unicorn/explicit-length-check": "off",
|
|
92
|
+
"unicorn/filename-case": "off",
|
|
93
|
+
"unicorn/no-negated-condition": "off",
|
|
94
|
+
"unicorn/no-useless-undefined": ["error", {
|
|
95
|
+
checkArguments: false
|
|
96
|
+
}],
|
|
97
|
+
"unicorn/prefer-top-level-await": "off",
|
|
98
|
+
"unicorn/switch-case-braces": "off",
|
|
99
|
+
"unicorn/prevent-abbreviations": "off",
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
);
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "libshv-js",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.2",
|
|
4
4
|
"description": "Typescript implementation of libshv",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
7
|
-
"lint": "
|
|
7
|
+
"lint": "eslint --format unix src/",
|
|
8
8
|
"fix": "npm run lint -- --fix"
|
|
9
9
|
},
|
|
10
10
|
"author": "Elektroline",
|
|
@@ -28,10 +28,15 @@
|
|
|
28
28
|
"./zod.ts": "./src/zod.ts"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"zod": "^3.
|
|
31
|
+
"zod": "^3.24.2"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"typescript": "^
|
|
35
|
-
"
|
|
34
|
+
"@typescript-eslint/parser": "^8.27.0",
|
|
35
|
+
"eslint": "^9.22.0",
|
|
36
|
+
"eslint-config-xo": "^0.46.0",
|
|
37
|
+
"eslint-formatter-unix": "^8.40.0",
|
|
38
|
+
"eslint-plugin-unicorn": "^57.0.0",
|
|
39
|
+
"typescript": "^5.8.2",
|
|
40
|
+
"typescript-eslint": "^8.27.0"
|
|
36
41
|
}
|
|
37
42
|
}
|
package/src/chainpack.ts
CHANGED
|
@@ -155,9 +155,9 @@ class ChainPackReader {
|
|
|
155
155
|
bi >>= 2n;
|
|
156
156
|
|
|
157
157
|
let offset = 0;
|
|
158
|
-
if (hasTzOffset) {
|
|
158
|
+
if (hasTzOffset !== 0n) {
|
|
159
159
|
offset = Number(bi & 0x7Fn);
|
|
160
|
-
if (offset & 0x40) {
|
|
160
|
+
if ((offset & 0x40) !== 0) {
|
|
161
161
|
// sign extension
|
|
162
162
|
offset -= 128;
|
|
163
163
|
}
|
|
@@ -172,7 +172,7 @@ class ChainPackReader {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
let msec = Number(bi);
|
|
175
|
-
if (hasNotMsec) {
|
|
175
|
+
if (hasNotMsec !== 0n) {
|
|
176
176
|
msec *= 1000;
|
|
177
177
|
}
|
|
178
178
|
|
|
@@ -216,7 +216,6 @@ class ChainPackReader {
|
|
|
216
216
|
case PackingSchema.CString: {
|
|
217
217
|
// variation of CponReader.readCString()
|
|
218
218
|
const pctx = new PackContext();
|
|
219
|
-
// eslint-disable-next-line no-constant-condition
|
|
220
219
|
while (true) {
|
|
221
220
|
let b = this.ctx.getByte();
|
|
222
221
|
if (b === '\\'.codePointAt(0)) {
|
|
@@ -317,7 +316,6 @@ class ChainPackReader {
|
|
|
317
316
|
|
|
318
317
|
readList() {
|
|
319
318
|
const lst = [];
|
|
320
|
-
// eslint-disable-next-line no-constant-condition
|
|
321
319
|
while (true) {
|
|
322
320
|
const b = this.ctx.peekByte();
|
|
323
321
|
if (b as PackingSchema === PackingSchema.Term) {
|
|
@@ -343,14 +341,13 @@ class ChainPackReader {
|
|
|
343
341
|
return this.implReadMap('imap');
|
|
344
342
|
}
|
|
345
343
|
|
|
346
|
-
private implReadMap(
|
|
347
|
-
private implReadMap(
|
|
348
|
-
private implReadMap(
|
|
349
|
-
private implReadMap(
|
|
344
|
+
private implReadMap(mapType: 'map'): ShvMap;
|
|
345
|
+
private implReadMap(mapType: 'imap'): IMap;
|
|
346
|
+
private implReadMap(mapType: 'metamap'): MetaMap;
|
|
347
|
+
private implReadMap(mapType: 'map' | 'imap' | 'metamap') {
|
|
350
348
|
const map: ShvMap | IMap | MetaMap = {
|
|
351
|
-
[shvMapType]:
|
|
349
|
+
[shvMapType]: mapType,
|
|
352
350
|
};
|
|
353
|
-
// eslint-disable-next-line no-constant-condition
|
|
354
351
|
while (true) {
|
|
355
352
|
const b = this.ctx.peekByte();
|
|
356
353
|
if (b as PackingSchema === PackingSchema.Term) {
|
|
@@ -384,55 +381,55 @@ class ChainPackWriter {
|
|
|
384
381
|
this.ctx = new PackContext();
|
|
385
382
|
}
|
|
386
383
|
|
|
387
|
-
write(
|
|
388
|
-
if (
|
|
389
|
-
this.writeMeta(
|
|
390
|
-
|
|
384
|
+
write(rpcVal: RpcValue) {
|
|
385
|
+
if (rpcVal instanceof RpcValueWithMetaData) {
|
|
386
|
+
this.writeMeta(rpcVal.meta);
|
|
387
|
+
rpcVal = rpcVal.value;
|
|
391
388
|
}
|
|
392
389
|
|
|
393
390
|
switch (true) {
|
|
394
|
-
case
|
|
391
|
+
case rpcVal === undefined:
|
|
395
392
|
this.ctx.putByte(PackingSchema.Null);
|
|
396
393
|
break;
|
|
397
|
-
case typeof
|
|
398
|
-
this.ctx.putByte(
|
|
394
|
+
case typeof rpcVal === 'boolean':
|
|
395
|
+
this.ctx.putByte(rpcVal ? PackingSchema.True : PackingSchema.False);
|
|
399
396
|
break;
|
|
400
|
-
case typeof
|
|
401
|
-
this.writeJSString(
|
|
397
|
+
case typeof rpcVal === 'string':
|
|
398
|
+
this.writeJSString(rpcVal);
|
|
402
399
|
break;
|
|
403
|
-
case
|
|
404
|
-
this.writeBlob(
|
|
400
|
+
case rpcVal instanceof ArrayBuffer:
|
|
401
|
+
this.writeBlob(rpcVal);
|
|
405
402
|
break;
|
|
406
|
-
case
|
|
407
|
-
this.writeUInt(
|
|
403
|
+
case rpcVal instanceof UInt:
|
|
404
|
+
this.writeUInt(rpcVal);
|
|
408
405
|
break;
|
|
409
|
-
case typeof
|
|
410
|
-
this.writeInt(
|
|
406
|
+
case typeof rpcVal === 'number':
|
|
407
|
+
this.writeInt(rpcVal);
|
|
411
408
|
break;
|
|
412
|
-
case
|
|
413
|
-
this.writeDecimal(
|
|
409
|
+
case rpcVal instanceof Decimal:
|
|
410
|
+
this.writeDecimal(rpcVal);
|
|
414
411
|
break;
|
|
415
|
-
case Array.isArray(
|
|
416
|
-
this.writeList(
|
|
412
|
+
case Array.isArray(rpcVal):
|
|
413
|
+
this.writeList(rpcVal);
|
|
417
414
|
break;
|
|
418
|
-
case
|
|
419
|
-
this.writeDateTime(
|
|
415
|
+
case rpcVal instanceof Date:
|
|
416
|
+
this.writeDateTime(rpcVal);
|
|
420
417
|
break;
|
|
421
|
-
case
|
|
418
|
+
case rpcVal instanceof Double:
|
|
422
419
|
throw new Error('writing doubles not implemented');
|
|
423
|
-
case typeof
|
|
424
|
-
switch (
|
|
420
|
+
case typeof rpcVal === 'object':
|
|
421
|
+
switch (rpcVal[shvMapType]) {
|
|
425
422
|
case 'imap':
|
|
426
|
-
this.writeIMap(
|
|
423
|
+
this.writeIMap(rpcVal);
|
|
427
424
|
break;
|
|
428
425
|
case 'map':
|
|
429
|
-
this.writeMap(
|
|
426
|
+
this.writeMap(rpcVal);
|
|
430
427
|
break;
|
|
431
428
|
}
|
|
432
429
|
|
|
433
430
|
break;
|
|
434
431
|
default:
|
|
435
|
-
console.log('Can\'t serialize',
|
|
432
|
+
console.log('Can\'t serialize', rpcVal);
|
|
436
433
|
throw new Error('Can\'t serialize');
|
|
437
434
|
}
|
|
438
435
|
}
|
package/src/cpcontext.ts
CHANGED
package/src/cpon.ts
CHANGED
|
@@ -7,7 +7,7 @@ export const stringifyDate = (dt: DateTime) => {
|
|
|
7
7
|
let utcOffset = dt.utc_offset;
|
|
8
8
|
const localMsec = epochMsec + (60_000 * (utcOffset ?? 0));
|
|
9
9
|
let res = new Date(localMsec).toISOString();
|
|
10
|
-
const rtrim = (localMsec % 1000) ? 1 : 5;
|
|
10
|
+
const rtrim = ((localMsec % 1000) !== 0) ? 1 : 5;
|
|
11
11
|
res = res.slice(0, Math.max(0, res.length - rtrim));
|
|
12
12
|
|
|
13
13
|
if (utcOffset === undefined || utcOffset === 0) {
|
|
@@ -21,7 +21,7 @@ export const stringifyDate = (dt: DateTime) => {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
res += (Math.trunc(utcOffset / 60)).toString().padStart(2, '0');
|
|
24
|
-
if (utcOffset % 60) {
|
|
24
|
+
if ((utcOffset % 60) !== 0) {
|
|
25
25
|
res += (utcOffset % 60).toString().padStart(2, '0');
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -85,8 +85,9 @@ const utf8ToString = (bytearray: ArrayBuffer) => {
|
|
|
85
85
|
|
|
86
86
|
class CponReader {
|
|
87
87
|
ctx: UnpackContext;
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
|
|
89
|
+
constructor(unpackContext: UnpackContext) {
|
|
90
|
+
this.ctx = unpackContext;
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
read(): RpcValue {
|
|
@@ -188,7 +189,6 @@ class CponReader {
|
|
|
188
189
|
const KEY_DELIM = ':'.codePointAt(0)!;
|
|
189
190
|
const FIELD_DELIM = ','.codePointAt(0)!;
|
|
190
191
|
/* eslint-disable max-depth */
|
|
191
|
-
// eslint-disable-next-line no-constant-condition
|
|
192
192
|
while (true) {
|
|
193
193
|
let b = this.ctx.peekByte();
|
|
194
194
|
if (b < 1) {
|
|
@@ -202,7 +202,6 @@ class CponReader {
|
|
|
202
202
|
b = this.ctx.getByte();
|
|
203
203
|
if (b === STAR) {
|
|
204
204
|
// multiline_comment_entered;
|
|
205
|
-
// eslint-disable-next-line no-constant-condition
|
|
206
205
|
while (true) {
|
|
207
206
|
b = this.ctx.getByte();
|
|
208
207
|
if (b === STAR) {
|
|
@@ -214,7 +213,6 @@ class CponReader {
|
|
|
214
213
|
}
|
|
215
214
|
} else if (b === SLASH) {
|
|
216
215
|
// to end of line comment entered;
|
|
217
|
-
// eslint-disable-next-line no-constant-condition
|
|
218
216
|
while (true) {
|
|
219
217
|
b = this.ctx.getByte();
|
|
220
218
|
if (b === LF) {
|
|
@@ -354,7 +352,6 @@ class CponReader {
|
|
|
354
352
|
readCString() {
|
|
355
353
|
const pctx = new PackContext();
|
|
356
354
|
this.ctx.getByte(); // eat '"'
|
|
357
|
-
// eslint-disable-next-line no-constant-condition
|
|
358
355
|
while (true) {
|
|
359
356
|
let b = this.ctx.getByte();
|
|
360
357
|
if (b === '\\'.codePointAt(0)) {
|
|
@@ -402,7 +399,6 @@ class CponReader {
|
|
|
402
399
|
readBlobEsc() {
|
|
403
400
|
const pctx = new PackContext();
|
|
404
401
|
this.ctx.getByte(); // eat '"'
|
|
405
|
-
// eslint-disable-next-line no-constant-condition
|
|
406
402
|
while (true) {
|
|
407
403
|
let b = this.ctx.getByte();
|
|
408
404
|
if (b === '\\'.codePointAt(0)) {
|
|
@@ -445,7 +441,6 @@ class CponReader {
|
|
|
445
441
|
readBlobHex() {
|
|
446
442
|
const pctx = new PackContext();
|
|
447
443
|
this.ctx.getByte(); // eat '"'
|
|
448
|
-
// eslint-disable-next-line no-constant-condition
|
|
449
444
|
while (true) {
|
|
450
445
|
const b = this.ctx.getByte();
|
|
451
446
|
if (b === '"'.codePointAt(0)) {
|
|
@@ -463,7 +458,6 @@ class CponReader {
|
|
|
463
458
|
readList() {
|
|
464
459
|
const lst = [];
|
|
465
460
|
this.ctx.getByte(); // eat '['
|
|
466
|
-
// eslint-disable-next-line no-constant-condition
|
|
467
461
|
while (true) {
|
|
468
462
|
this.skipWhitespace();
|
|
469
463
|
const b = this.ctx.peekByte();
|
|
@@ -494,7 +488,7 @@ class CponReader {
|
|
|
494
488
|
readInt() {
|
|
495
489
|
let base = 10;
|
|
496
490
|
let val = 0;
|
|
497
|
-
let neg =
|
|
491
|
+
let neg = false;
|
|
498
492
|
let n = 0;
|
|
499
493
|
for (; ; n++) {
|
|
500
494
|
const b = this.ctx.peekByte();
|
|
@@ -509,7 +503,7 @@ class CponReader {
|
|
|
509
503
|
|
|
510
504
|
this.ctx.getByte();
|
|
511
505
|
if (b === 45) {
|
|
512
|
-
neg =
|
|
506
|
+
neg = true;
|
|
513
507
|
}
|
|
514
508
|
} else if (b === 120) { // 'x'
|
|
515
509
|
if (n === 1 && val !== 0) {
|
|
@@ -575,7 +569,6 @@ class CponReader {
|
|
|
575
569
|
mantisa = Number(this.readInt());
|
|
576
570
|
b = this.ctx.peekByte();
|
|
577
571
|
(() => {
|
|
578
|
-
// eslint-disable-next-line no-constant-condition
|
|
579
572
|
while (true) {
|
|
580
573
|
switch (b) {
|
|
581
574
|
case 'u'.codePointAt(0): {
|
|
@@ -636,15 +629,14 @@ class CponReader {
|
|
|
636
629
|
return isNeg ? -mantisa : mantisa;
|
|
637
630
|
}
|
|
638
631
|
|
|
639
|
-
private implReadMap(
|
|
640
|
-
private implReadMap(
|
|
641
|
-
private implReadMap(
|
|
642
|
-
private implReadMap(
|
|
632
|
+
private implReadMap(mapType: 'map', terminator: number): ShvMap;
|
|
633
|
+
private implReadMap(mapType: 'imap', terminator: number): IMap;
|
|
634
|
+
private implReadMap(mapType: 'metamap', terminator: number): MetaMap;
|
|
635
|
+
private implReadMap(mapType: 'map' | 'imap' | 'metamap', terminator: number) {
|
|
643
636
|
const map: MetaMap | ShvMap | IMap = {
|
|
644
|
-
[shvMapType]:
|
|
637
|
+
[shvMapType]: mapType,
|
|
645
638
|
};
|
|
646
639
|
this.ctx.getByte(); // eat start
|
|
647
|
-
// eslint-disable-next-line no-constant-condition
|
|
648
640
|
while (true) {
|
|
649
641
|
this.skipWhitespace();
|
|
650
642
|
const b = this.ctx.peekByte();
|
|
@@ -681,60 +673,61 @@ class CponReader {
|
|
|
681
673
|
class CponWriter {
|
|
682
674
|
ctx: PackContext;
|
|
683
675
|
nestLevel = 0;
|
|
676
|
+
|
|
684
677
|
constructor(private readonly indentString?: string) {
|
|
685
678
|
this.ctx = new PackContext();
|
|
686
679
|
}
|
|
687
680
|
|
|
688
|
-
write(
|
|
689
|
-
if (
|
|
690
|
-
this.writeMeta(
|
|
691
|
-
|
|
681
|
+
write(rpcVal: RpcValue) {
|
|
682
|
+
if (rpcVal instanceof RpcValueWithMetaData) {
|
|
683
|
+
this.writeMeta(rpcVal.meta);
|
|
684
|
+
rpcVal = rpcVal.value;
|
|
692
685
|
}
|
|
693
686
|
|
|
694
687
|
switch (true) {
|
|
695
|
-
case
|
|
688
|
+
case rpcVal === undefined:
|
|
696
689
|
this.ctx.writeStringUtf8('null');
|
|
697
690
|
break;
|
|
698
|
-
case typeof
|
|
699
|
-
this.writeBool(
|
|
691
|
+
case typeof rpcVal === 'boolean':
|
|
692
|
+
this.writeBool(rpcVal);
|
|
700
693
|
break;
|
|
701
|
-
case typeof
|
|
702
|
-
this.writeJSString(
|
|
694
|
+
case typeof rpcVal === 'string':
|
|
695
|
+
this.writeJSString(rpcVal);
|
|
703
696
|
break;
|
|
704
|
-
case
|
|
705
|
-
this.writeBlob(
|
|
697
|
+
case rpcVal instanceof ArrayBuffer:
|
|
698
|
+
this.writeBlob(rpcVal);
|
|
706
699
|
break;
|
|
707
|
-
case
|
|
708
|
-
this.writeUInt(
|
|
700
|
+
case rpcVal instanceof UInt:
|
|
701
|
+
this.writeUInt(rpcVal);
|
|
709
702
|
break;
|
|
710
|
-
case typeof
|
|
711
|
-
this.writeInt(
|
|
703
|
+
case typeof rpcVal === 'number':
|
|
704
|
+
this.writeInt(rpcVal);
|
|
712
705
|
break;
|
|
713
|
-
case
|
|
714
|
-
this.writeDouble(
|
|
706
|
+
case rpcVal instanceof Double:
|
|
707
|
+
this.writeDouble(rpcVal);
|
|
715
708
|
break;
|
|
716
|
-
case
|
|
717
|
-
this.writeDecimal(
|
|
709
|
+
case rpcVal instanceof Decimal:
|
|
710
|
+
this.writeDecimal(rpcVal);
|
|
718
711
|
break;
|
|
719
|
-
case Array.isArray(
|
|
720
|
-
this.writeList(
|
|
712
|
+
case Array.isArray(rpcVal):
|
|
713
|
+
this.writeList(rpcVal);
|
|
721
714
|
break;
|
|
722
|
-
case
|
|
723
|
-
this.writeDateTime(
|
|
715
|
+
case rpcVal instanceof Date:
|
|
716
|
+
this.writeDateTime(rpcVal);
|
|
724
717
|
break;
|
|
725
|
-
case typeof
|
|
726
|
-
switch (
|
|
718
|
+
case typeof rpcVal === 'object':
|
|
719
|
+
switch (rpcVal[shvMapType]) {
|
|
727
720
|
case 'imap':
|
|
728
|
-
this.writeIMap(
|
|
721
|
+
this.writeIMap(rpcVal);
|
|
729
722
|
break;
|
|
730
723
|
case 'map':
|
|
731
|
-
this.writeMap(
|
|
724
|
+
this.writeMap(rpcVal);
|
|
732
725
|
break;
|
|
733
726
|
}
|
|
734
727
|
|
|
735
728
|
break;
|
|
736
729
|
default:
|
|
737
|
-
console.log('Can\'t serialize rpc value',
|
|
730
|
+
console.log('Can\'t serialize rpc value', rpcVal);
|
|
738
731
|
throw new Error('Can\'t serialize rpc value');
|
|
739
732
|
}
|
|
740
733
|
}
|
|
@@ -745,25 +738,25 @@ class CponWriter {
|
|
|
745
738
|
const charcode = str.codePointAt(i)!;
|
|
746
739
|
switch (charcode) {
|
|
747
740
|
case 0:
|
|
748
|
-
this.ctx.writeStringUtf8(
|
|
741
|
+
this.ctx.writeStringUtf8(String.raw`\0`);
|
|
749
742
|
break;
|
|
750
743
|
case '\\'.codePointAt(0):
|
|
751
744
|
this.ctx.writeStringUtf8('\\\\');
|
|
752
745
|
break;
|
|
753
746
|
case '\t'.codePointAt(0):
|
|
754
|
-
this.ctx.writeStringUtf8(
|
|
747
|
+
this.ctx.writeStringUtf8(String.raw`\t`);
|
|
755
748
|
break;
|
|
756
749
|
case '\b'.codePointAt(0):
|
|
757
|
-
this.ctx.writeStringUtf8(
|
|
750
|
+
this.ctx.writeStringUtf8(String.raw`\b`);
|
|
758
751
|
break;
|
|
759
752
|
case '\r'.codePointAt(0):
|
|
760
|
-
this.ctx.writeStringUtf8(
|
|
753
|
+
this.ctx.writeStringUtf8(String.raw`\r`);
|
|
761
754
|
break;
|
|
762
755
|
case '\n'.codePointAt(0):
|
|
763
|
-
this.ctx.writeStringUtf8(
|
|
756
|
+
this.ctx.writeStringUtf8(String.raw`\n`);
|
|
764
757
|
break;
|
|
765
758
|
case '"'.codePointAt(0):
|
|
766
|
-
this.ctx.writeStringUtf8(
|
|
759
|
+
this.ctx.writeStringUtf8(String.raw`\"`);
|
|
767
760
|
break;
|
|
768
761
|
default:
|
|
769
762
|
this.ctx.writeCharCodeUtf8(charcode);
|
|
@@ -782,16 +775,16 @@ class CponWriter {
|
|
|
782
775
|
this.ctx.writeStringUtf8('\\\\');
|
|
783
776
|
break;
|
|
784
777
|
case '\t'.codePointAt(0):
|
|
785
|
-
this.ctx.writeStringUtf8(
|
|
778
|
+
this.ctx.writeStringUtf8(String.raw`\t`);
|
|
786
779
|
break;
|
|
787
780
|
case '\r'.codePointAt(0):
|
|
788
|
-
this.ctx.writeStringUtf8(
|
|
781
|
+
this.ctx.writeStringUtf8(String.raw`\r`);
|
|
789
782
|
break;
|
|
790
783
|
case '\n'.codePointAt(0):
|
|
791
|
-
this.ctx.writeStringUtf8(
|
|
784
|
+
this.ctx.writeStringUtf8(String.raw`\n`);
|
|
792
785
|
break;
|
|
793
786
|
case '"'.codePointAt(0):
|
|
794
|
-
this.ctx.writeStringUtf8(
|
|
787
|
+
this.ctx.writeStringUtf8(String.raw`\"`);
|
|
795
788
|
break;
|
|
796
789
|
default:
|
|
797
790
|
if (b >= 32 && b < 127) {
|
|
@@ -910,8 +903,8 @@ class CponWriter {
|
|
|
910
903
|
}
|
|
911
904
|
|
|
912
905
|
writeDecimal(val: Decimal) {
|
|
913
|
-
let mantisa = val
|
|
914
|
-
const exponent = val
|
|
906
|
+
let {mantisa} = val;
|
|
907
|
+
const {exponent} = val;
|
|
915
908
|
if (mantisa < 0) {
|
|
916
909
|
mantisa = -mantisa;
|
|
917
910
|
this.ctx.putByte('-'.codePointAt(0)!);
|
package/src/json.ts
CHANGED
|
@@ -2,7 +2,6 @@ import {UnpackContext} from './cpcontext';
|
|
|
2
2
|
import {CponReader, stringifyDate} from './cpon';
|
|
3
3
|
import {Decimal, Double, isIMap, isShvMap, makeIMap, makeMap, makeMetaMap, RpcValueWithMetaData, UInt, type RpcValue} from './rpcvalue';
|
|
4
4
|
|
|
5
|
-
// eslint-disable-next-line @typescript-eslint/ban-types -- Zod needs the default argument, otherwise it'll infer as UInt<unknown>
|
|
6
5
|
const decodeMap = (x: object) => makeMap(Object.fromEntries(Object.entries(x).map(([key, value]) => [key, decodeValueJson(value)])));
|
|
7
6
|
|
|
8
7
|
const decodeValueJson = (x: unknown): RpcValue => {
|
|
@@ -123,6 +122,7 @@ const encodeValueJson = (x: RpcValue): unknown => {
|
|
|
123
122
|
case x instanceof Date:
|
|
124
123
|
return [JSON_TAG_TYPE, 'DateTime', stringifyDate(x)];
|
|
125
124
|
case x === undefined:
|
|
125
|
+
// eslint-disable-next-line unicorn/no-null
|
|
126
126
|
return null;
|
|
127
127
|
case x instanceof Decimal:
|
|
128
128
|
case x instanceof UInt:
|
package/src/rpcvalue.ts
CHANGED
|
@@ -14,7 +14,7 @@ class UInt<T extends number = number> {
|
|
|
14
14
|
this.value = u;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
[Symbol.toPrimitive](
|
|
17
|
+
[Symbol.toPrimitive]() {
|
|
18
18
|
return this.value;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -34,6 +34,7 @@ class Double {
|
|
|
34
34
|
class Decimal {
|
|
35
35
|
mantisa: number;
|
|
36
36
|
exponent: number;
|
|
37
|
+
|
|
37
38
|
constructor(mantisa: number, exponent: number) {
|
|
38
39
|
if (!Number.isInteger(exponent)) {
|
|
39
40
|
throw new TypeError(`Decimal: exponent must be integral (${exponent})`);
|
|
@@ -49,9 +50,9 @@ export type Bool = boolean;
|
|
|
49
50
|
export type Blob = ArrayBuffer;
|
|
50
51
|
export type ShvString = string;
|
|
51
52
|
export type DateTime = Date & {utc_offset?: number};
|
|
52
|
-
const withOffset = (date: Date,
|
|
53
|
-
const clonedDate: DateTime = new Date(date
|
|
54
|
-
clonedDate.utc_offset =
|
|
53
|
+
const withOffset = (date: Date, utcOffset?: number) => {
|
|
54
|
+
const clonedDate: DateTime = new Date(date);
|
|
55
|
+
clonedDate.utc_offset = utcOffset;
|
|
55
56
|
return clonedDate;
|
|
56
57
|
};
|
|
57
58
|
|
|
@@ -59,12 +60,14 @@ export type List = RpcValue[];
|
|
|
59
60
|
|
|
60
61
|
const shvMapType = Symbol('shvMapType');
|
|
61
62
|
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- I can't get rid of this yet
|
|
62
64
|
type IMap<T extends Record<number, RpcValue> = Record<number, any>> = {
|
|
63
65
|
[Key in keyof T]: T[Key];
|
|
64
66
|
} & {
|
|
65
67
|
[shvMapType]: 'imap';
|
|
66
68
|
};
|
|
67
69
|
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- I can't get rid of this yet
|
|
68
71
|
type ShvMap<T extends Record<string, RpcValue> = Record<string, any>> = {
|
|
69
72
|
[Key in keyof T]: T[Key];
|
|
70
73
|
} & {
|
package/src/ws-client.ts
CHANGED
|
@@ -122,15 +122,12 @@ class NotImplemented extends RpcError {}
|
|
|
122
122
|
class WsClient {
|
|
123
123
|
private requestId = 1;
|
|
124
124
|
private pingTimerId = -1;
|
|
125
|
-
|
|
126
125
|
private rpcHandlers: Array<{
|
|
127
126
|
resolve: RpcResponseResolver;
|
|
128
127
|
timeout_handle: number;
|
|
129
128
|
}> = [];
|
|
130
|
-
|
|
131
129
|
private readonly subscriptions: Subscription[] = [];
|
|
132
130
|
private readonly websocket: WebSocket;
|
|
133
|
-
|
|
134
131
|
private readonly options: WsClientOptions;
|
|
135
132
|
private readonly timeout: number;
|
|
136
133
|
|
|
@@ -172,6 +169,7 @@ class WsClient {
|
|
|
172
169
|
handler.resolve((() => {
|
|
173
170
|
if (RPC_MESSAGE_ERROR in rpcMsg.value) {
|
|
174
171
|
const code = rpcMsg.value[RPC_MESSAGE_ERROR][ERROR_CODE] as unknown;
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
175
173
|
const ErrorTypeCtor = (() => {
|
|
176
174
|
switch (code) {
|
|
177
175
|
case ErrorCode.InvalidRequest: return InvalidRequest;
|
|
@@ -199,7 +197,7 @@ class WsClient {
|
|
|
199
197
|
|
|
200
198
|
return new ProtocolError('Response included neither result nor error');
|
|
201
199
|
})());
|
|
202
|
-
// eslint-disable-next-line @typescript-eslint/no-array-delete
|
|
200
|
+
// eslint-disable-next-line @typescript-eslint/no-array-delete
|
|
203
201
|
delete this.rpcHandlers[Number(requestId)];
|
|
204
202
|
}
|
|
205
203
|
}
|
|
@@ -217,16 +215,16 @@ class WsClient {
|
|
|
217
215
|
}
|
|
218
216
|
}
|
|
219
217
|
|
|
220
|
-
callRpcMethod(
|
|
221
|
-
callRpcMethod(
|
|
222
|
-
callRpcMethod(
|
|
223
|
-
callRpcMethod(
|
|
224
|
-
callRpcMethod(
|
|
218
|
+
callRpcMethod(shvPath: '.broker/currentClient', method: 'accessGrantForMethodCall', params: [string, string]): Promise<ResultOrError<string>>;
|
|
219
|
+
callRpcMethod(shvPath: string | undefined, method: 'dir', params?: RpcValue): Promise<ResultOrError<DirResult>>;
|
|
220
|
+
callRpcMethod(shvPath: string | undefined, method: 'ls', params?: RpcValue): Promise<ResultOrError<LsResult>>;
|
|
221
|
+
callRpcMethod(shvPath: string | undefined, method: string, params?: RpcValue): Promise<ResultOrError>;
|
|
222
|
+
callRpcMethod(shvPath: string | undefined, method: string, params?: RpcValue): Promise<ResultOrError> {
|
|
225
223
|
const rqId = this.requestId++;
|
|
226
224
|
const rq: RpcRequest = new RpcValueWithMetaData(makeMetaMap({
|
|
227
225
|
[RPC_MESSAGE_REQUEST_ID]: rqId,
|
|
228
226
|
[RPC_MESSAGE_METHOD]: method ?? '',
|
|
229
|
-
[RPC_MESSAGE_SHV_PATH]:
|
|
227
|
+
[RPC_MESSAGE_SHV_PATH]: shvPath ?? '',
|
|
230
228
|
}), makeIMap({
|
|
231
229
|
[RPC_MESSAGE_PARAMS]: params,
|
|
232
230
|
}));
|
|
@@ -234,7 +232,7 @@ class WsClient {
|
|
|
234
232
|
this.sendRpcMessage(rq);
|
|
235
233
|
|
|
236
234
|
const promise = new Promise<ResultOrError>(resolve => {
|
|
237
|
-
this.rpcHandlers[rqId] = {resolve, timeout_handle:
|
|
235
|
+
this.rpcHandlers[rqId] = {resolve, timeout_handle: globalThis.setTimeout(() => {
|
|
238
236
|
resolve(new MethodCallTimeout(makeIMap({
|
|
239
237
|
[ERROR_CODE]: ErrorCode.MethodCallTimeout,
|
|
240
238
|
[ERROR_MESSAGE]: `Shv call timeout after: ${this.timeout} msec.`,
|
|
@@ -246,10 +244,10 @@ class WsClient {
|
|
|
246
244
|
return promise;
|
|
247
245
|
}
|
|
248
246
|
|
|
249
|
-
sendRpcMessage(
|
|
250
|
-
if (this.websocket
|
|
251
|
-
this.logDebug('sending rpc message:', toCpon(
|
|
252
|
-
const msgData = new Uint8Array(toChainPack(
|
|
247
|
+
sendRpcMessage(rpcMsg: RpcMessage) {
|
|
248
|
+
if (this.websocket.readyState === WebSocket.OPEN) {
|
|
249
|
+
this.logDebug('sending rpc message:', toCpon(rpcMsg));
|
|
250
|
+
const msgData = new Uint8Array(toChainPack(rpcMsg));
|
|
253
251
|
|
|
254
252
|
const wr = new ChainPackWriter();
|
|
255
253
|
wr.writeUIntData(msgData.length + 1);
|
|
@@ -354,7 +352,7 @@ class WsClient {
|
|
|
354
352
|
options.onWorkflows(response);
|
|
355
353
|
|
|
356
354
|
this.close();
|
|
357
|
-
}).catch((
|
|
355
|
+
}).catch(() => {
|
|
358
356
|
options.onWorkflowsFailed();
|
|
359
357
|
});
|
|
360
358
|
});
|
|
@@ -375,7 +373,7 @@ class WsClient {
|
|
|
375
373
|
options.onConnectionFailure(error);
|
|
376
374
|
};
|
|
377
375
|
|
|
378
|
-
const handleLoginResponse = (response:
|
|
376
|
+
const handleLoginResponse = (response: unknown) => {
|
|
379
377
|
if (response instanceof Error) {
|
|
380
378
|
handleConnectionError(response);
|
|
381
379
|
return;
|
|
@@ -383,7 +381,7 @@ class WsClient {
|
|
|
383
381
|
|
|
384
382
|
this.logDebug('SUCCESS: connected to shv broker');
|
|
385
383
|
options.onConnected();
|
|
386
|
-
this.pingTimerId =
|
|
384
|
+
this.pingTimerId = globalThis.setInterval(() => {
|
|
387
385
|
this.sendPing();
|
|
388
386
|
}, options.pingInterval ?? DEFAULT_PING_INTERVAL);
|
|
389
387
|
};
|
|
@@ -427,7 +425,7 @@ class WsClient {
|
|
|
427
425
|
this.logDebug('DISCONNECTED');
|
|
428
426
|
this.subscriptions.length = 0;
|
|
429
427
|
options.onDisconnected();
|
|
430
|
-
|
|
428
|
+
globalThis.clearInterval(this.pingTimerId);
|
|
431
429
|
});
|
|
432
430
|
}
|
|
433
431
|
}
|
package/src/zod.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
import {z, type ZodType} from 'zod';
|
|
2
3
|
import {Decimal, Double, type IMap, isIMap, isMetaMap, isShvMap, type MetaMap, type RpcValue, type RpcValueType, RpcValueWithMetaData, type ShvMap, UInt} from './rpcvalue';
|
|
3
4
|
|
|
@@ -6,7 +7,7 @@ export const recmap = <T extends ZodType<any, any, any>>(schema: T) => z.custom<
|
|
|
6
7
|
export const imap = <T extends Record<string, ZodType<any, any, any>>>(schema?: T) => z.custom<IMap<{[K in keyof T]: z.infer<T[K]>}>>((data: RpcValue) => isIMap(data) && (schema === undefined || z.object(schema).safeParse(data).success));
|
|
7
8
|
export const metamap = <T extends Record<string | number, ZodType<any, any, any>>>(schema?: T) => z.custom<MetaMap<{[K in keyof T]: z.infer<T[K]>}>>((data: RpcValue) => isMetaMap(data) && (schema === undefined || z.object(schema).safeParse(data).success));
|
|
8
9
|
export const int = () => z.number();
|
|
9
|
-
|
|
10
|
+
|
|
10
11
|
export const uint = () => z.instanceof(UInt<number>);
|
|
11
12
|
export const double = () => z.instanceof(Double);
|
|
12
13
|
export const decimal = () => z.instanceof(Decimal);
|
package/.xo-config.json
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"space": 4,
|
|
3
|
-
"rules": {
|
|
4
|
-
"@typescript-eslint/naming-convention": ["error",
|
|
5
|
-
{
|
|
6
|
-
"selector": "variable",
|
|
7
|
-
"format": ["camelCase"]
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
"format": ["camelCase", "UPPER_CASE"],
|
|
11
|
-
"selector": "variable",
|
|
12
|
-
"modifiers": ["const"]
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"format": ["PascalCase"],
|
|
16
|
-
"selector": "variable",
|
|
17
|
-
"modifiers": ["const"],
|
|
18
|
-
"filter": "Ctor$|Validation$|Zod$"
|
|
19
|
-
}
|
|
20
|
-
],
|
|
21
|
-
"@typescript-eslint/prefer-promise-reject-errors": "off",
|
|
22
|
-
"@typescript-eslint/promise-function-async": "off",
|
|
23
|
-
"@typescript-eslint/triple-slash-reference": "off",
|
|
24
|
-
"capitalized-comments": "off",
|
|
25
|
-
"object-curly-newline": ["error", {
|
|
26
|
-
"ImportDeclaration": "never"
|
|
27
|
-
}],
|
|
28
|
-
"n/file-extension-in-import": "off",
|
|
29
|
-
"promise-function-async": "off",
|
|
30
|
-
"default-case": "off",
|
|
31
|
-
"import/extensions": "off",
|
|
32
|
-
"import/no-unassigned-import": "off",
|
|
33
|
-
"no-warning-comments": "off",
|
|
34
|
-
"prefer-promise-reject-errors": "off",
|
|
35
|
-
"unicorn/explicit-length-check": "off",
|
|
36
|
-
"unicorn/filename-case": "off",
|
|
37
|
-
"unicorn/no-negated-condition": "off",
|
|
38
|
-
"unicorn/prefer-top-level-await": "off",
|
|
39
|
-
"unicorn/switch-case-braces": "off",
|
|
40
|
-
"unicorn/prevent-abbreviations": "off"
|
|
41
|
-
}
|
|
42
|
-
}
|