@antines/protocol 0.1.0
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/header.d.ts +18 -0
- package/dist/header.d.ts.map +1 -0
- package/dist/header.js +67 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/layout.d.ts +8 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +88 -0
- package/dist/serialize.d.ts +12 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/serialize.js +225 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +33 -0
- package/package.json +33 -0
package/dist/header.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Direction, MessageType, type Header } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Encode a Header into a 32-byte buffer.
|
|
4
|
+
*/
|
|
5
|
+
export declare function encodeHeader(h: Header): ArrayBuffer;
|
|
6
|
+
/**
|
|
7
|
+
* Decode a 32-byte buffer into a Header.
|
|
8
|
+
*/
|
|
9
|
+
export declare function decodeHeader(buf: ArrayBuffer): Header;
|
|
10
|
+
/**
|
|
11
|
+
* Read a header from an ArrayBuffer-like source.
|
|
12
|
+
*/
|
|
13
|
+
export declare function readHeader(buffer: ArrayBuffer): Header;
|
|
14
|
+
/**
|
|
15
|
+
* Create a new Header with sensible defaults.
|
|
16
|
+
*/
|
|
17
|
+
export declare function newHeader(direction: Direction, msgType: MessageType, requestId: number, handlerId: number, statusCode: number, payloadLen: number): Header;
|
|
18
|
+
//# sourceMappingURL=header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../src/header.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAsB,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAErF;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,WAAW,CAgBnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAwBrD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,MAAM,CAaR"}
|
package/dist/header.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Direction, MessageType, MAGIC, HEADER_SIZE } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Encode a Header into a 32-byte buffer.
|
|
4
|
+
*/
|
|
5
|
+
export function encodeHeader(h) {
|
|
6
|
+
const buf = new ArrayBuffer(HEADER_SIZE);
|
|
7
|
+
const dv = new DataView(buf);
|
|
8
|
+
dv.setUint32(0, h.magic, true); // offset 0: magic
|
|
9
|
+
dv.setUint8(4, h.version); // offset 4: version
|
|
10
|
+
dv.setUint8(5, h.direction); // offset 5: direction
|
|
11
|
+
dv.setUint8(6, h.msgType); // offset 6: msgType
|
|
12
|
+
dv.setUint8(7, h.flags); // offset 7: flags
|
|
13
|
+
dv.setUint32(8, h.requestId, true); // offset 8: requestId
|
|
14
|
+
dv.setUint32(12, h.handlerId, true); // offset 12: handlerId
|
|
15
|
+
dv.setUint32(16, h.payloadLen, true); // offset 16: payloadLen
|
|
16
|
+
dv.setUint32(20, h.statusCode, true); // offset 20: statusCode
|
|
17
|
+
// offset 24-31: reserved (zeros)
|
|
18
|
+
return buf;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Decode a 32-byte buffer into a Header.
|
|
22
|
+
*/
|
|
23
|
+
export function decodeHeader(buf) {
|
|
24
|
+
if (buf.byteLength < HEADER_SIZE) {
|
|
25
|
+
throw new Error(`Header too small: ${buf.byteLength} bytes`);
|
|
26
|
+
}
|
|
27
|
+
const dv = new DataView(buf);
|
|
28
|
+
const magic = dv.getUint32(0, true);
|
|
29
|
+
if (magic !== MAGIC) {
|
|
30
|
+
throw new Error(`Invalid magic: 0x${magic.toString(16)}`);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
magic,
|
|
34
|
+
version: dv.getUint8(4),
|
|
35
|
+
direction: dv.getUint8(5),
|
|
36
|
+
msgType: dv.getUint8(6),
|
|
37
|
+
flags: dv.getUint8(7),
|
|
38
|
+
requestId: dv.getUint32(8, true),
|
|
39
|
+
handlerId: dv.getUint32(12, true),
|
|
40
|
+
payloadLen: dv.getUint32(16, true),
|
|
41
|
+
statusCode: dv.getUint32(20, true),
|
|
42
|
+
reserved: new Uint8Array(buf, 24, 8),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Read a header from an ArrayBuffer-like source.
|
|
47
|
+
*/
|
|
48
|
+
export function readHeader(buffer) {
|
|
49
|
+
return decodeHeader(buffer);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a new Header with sensible defaults.
|
|
53
|
+
*/
|
|
54
|
+
export function newHeader(direction, msgType, requestId, handlerId, statusCode, payloadLen) {
|
|
55
|
+
return {
|
|
56
|
+
magic: MAGIC,
|
|
57
|
+
version: 0x01,
|
|
58
|
+
direction,
|
|
59
|
+
msgType,
|
|
60
|
+
flags: 0,
|
|
61
|
+
requestId,
|
|
62
|
+
handlerId,
|
|
63
|
+
payloadLen,
|
|
64
|
+
statusCode,
|
|
65
|
+
reserved: new Uint8Array(8),
|
|
66
|
+
};
|
|
67
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { calculateLayout } from "./layout.js";
|
|
2
|
+
export { encodeHeader, decodeHeader, readHeader, newHeader } from "./header.js";
|
|
3
|
+
export { serializeOutput, deserializeInput } from "./serialize.js";
|
|
4
|
+
export { FieldType, FieldCategory, Direction, MessageType, MAGIC, HEADER_SIZE, SENTINEL_ABSENT, } from "./types.js";
|
|
5
|
+
export type { FieldLayout, CompiledLayout, Header } from "./types.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,EACL,SAAS,EACT,aAAa,EACb,SAAS,EACT,WAAW,EACX,KAAK,EACL,WAAW,EACX,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { calculateLayout } from "./layout.js";
|
|
2
|
+
export { encodeHeader, decodeHeader, readHeader, newHeader } from "./header.js";
|
|
3
|
+
export { serializeOutput, deserializeInput } from "./serialize.js";
|
|
4
|
+
export { FieldType, FieldCategory, Direction, MessageType, MAGIC, HEADER_SIZE, SENTINEL_ABSENT, } from "./types.js";
|
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ObjectIR } from "@antines/schema";
|
|
2
|
+
import { type CompiledLayout } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Calculate the wire format layout from a SchemaIR object schema.
|
|
5
|
+
* Mirrors Go's CalculateLayout.
|
|
6
|
+
*/
|
|
7
|
+
export declare function calculateLayout(s: ObjectIR): CompiledLayout;
|
|
8
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAA8C,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAwC7F;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,QAAQ,GAAG,cAAc,CAkD3D"}
|
package/dist/layout.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { FieldType, FieldCategory } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a SchemaIR node to its wire type, category, and fixed size.
|
|
4
|
+
* Mirrors Go's fieldTypeAndSize.
|
|
5
|
+
*/
|
|
6
|
+
function fieldTypeAndSize(s) {
|
|
7
|
+
switch (s.type) {
|
|
8
|
+
case "string":
|
|
9
|
+
return [FieldType.String, FieldCategory.Variable, 0];
|
|
10
|
+
case "number":
|
|
11
|
+
return [FieldType.Number, FieldCategory.Fixed, 8];
|
|
12
|
+
case "boolean":
|
|
13
|
+
return [FieldType.Boolean, FieldCategory.Fixed, 1];
|
|
14
|
+
case "enum":
|
|
15
|
+
return [FieldType.Enum, FieldCategory.Fixed, 2];
|
|
16
|
+
case "date":
|
|
17
|
+
return [FieldType.Date, FieldCategory.Fixed, 8];
|
|
18
|
+
case "array":
|
|
19
|
+
return [FieldType.Array, FieldCategory.Variable, 0];
|
|
20
|
+
case "object":
|
|
21
|
+
return [FieldType.Object, FieldCategory.Variable, 0];
|
|
22
|
+
case "nullable": {
|
|
23
|
+
if (!s.inner)
|
|
24
|
+
throw new Error("nullable: missing inner schema");
|
|
25
|
+
const [innerType, innerCat, innerSize] = fieldTypeAndSize(s.inner);
|
|
26
|
+
if (innerCat === FieldCategory.Fixed) {
|
|
27
|
+
return [innerType, FieldCategory.Fixed, innerSize + 1];
|
|
28
|
+
}
|
|
29
|
+
return [innerType, FieldCategory.Variable, 0];
|
|
30
|
+
}
|
|
31
|
+
case "optional": {
|
|
32
|
+
if (!s.inner)
|
|
33
|
+
throw new Error("optional: missing inner schema");
|
|
34
|
+
// In object field context: bitmask handles optionality, unwrap to inner type
|
|
35
|
+
return fieldTypeAndSize(s.inner);
|
|
36
|
+
}
|
|
37
|
+
default:
|
|
38
|
+
throw new Error(`unknown schema type: ${s.type}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Calculate the wire format layout from a SchemaIR object schema.
|
|
43
|
+
* Mirrors Go's CalculateLayout.
|
|
44
|
+
*/
|
|
45
|
+
export function calculateLayout(s) {
|
|
46
|
+
const fields = [];
|
|
47
|
+
let fixedSize = 0;
|
|
48
|
+
let bitmaskBit = 0;
|
|
49
|
+
let variableCount = 0;
|
|
50
|
+
const fieldNames = s.fieldOrder ?? Object.keys(s.fields);
|
|
51
|
+
for (const name of fieldNames) {
|
|
52
|
+
const f = s.fields[name];
|
|
53
|
+
if (!f)
|
|
54
|
+
continue;
|
|
55
|
+
const [ft, cat, size] = fieldTypeAndSize(f.schema);
|
|
56
|
+
const fl = {
|
|
57
|
+
name,
|
|
58
|
+
fieldType: ft,
|
|
59
|
+
category: cat,
|
|
60
|
+
offset: 0,
|
|
61
|
+
size: 0,
|
|
62
|
+
bitmaskBit: -1,
|
|
63
|
+
isOptional: f.optional,
|
|
64
|
+
isNullable: f.nullable,
|
|
65
|
+
};
|
|
66
|
+
if (cat === FieldCategory.Fixed) {
|
|
67
|
+
fl.offset = fixedSize;
|
|
68
|
+
fl.size = size;
|
|
69
|
+
fixedSize += size;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
fl.offset = variableCount;
|
|
73
|
+
variableCount++;
|
|
74
|
+
}
|
|
75
|
+
if (f.optional) {
|
|
76
|
+
fl.bitmaskBit = bitmaskBit;
|
|
77
|
+
bitmaskBit++;
|
|
78
|
+
}
|
|
79
|
+
fields.push(fl);
|
|
80
|
+
}
|
|
81
|
+
const bitmaskSize = bitmaskBit > 0 ? Math.ceil(bitmaskBit / 8) : 0;
|
|
82
|
+
return {
|
|
83
|
+
fields,
|
|
84
|
+
fixedSize,
|
|
85
|
+
bitmaskSize,
|
|
86
|
+
variableCount,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type CompiledLayout } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Serialize JS data (Record) into the positional wire format.
|
|
4
|
+
* Mirrors Go's SerializeInput — used by JS worker to send results.
|
|
5
|
+
*/
|
|
6
|
+
export declare function serializeOutput(layout: CompiledLayout, data: Record<string, unknown>): ArrayBuffer;
|
|
7
|
+
/**
|
|
8
|
+
* Deserialize the positional wire format into JS data (Record).
|
|
9
|
+
* Mirrors Go's DeserializeOutput — used by JS worker to receive dispatches.
|
|
10
|
+
*/
|
|
11
|
+
export declare function deserializeInput(layout: CompiledLayout, data: ArrayBuffer): Record<string, unknown>;
|
|
12
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EAEpB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,WAAW,CAyFb;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,WAAW,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA0CzB"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { FieldType, FieldCategory, SENTINEL_ABSENT, } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Serialize JS data (Record) into the positional wire format.
|
|
4
|
+
* Mirrors Go's SerializeInput — used by JS worker to send results.
|
|
5
|
+
*/
|
|
6
|
+
export function serializeOutput(layout, data) {
|
|
7
|
+
const bitmaskSize = layout.bitmaskSize;
|
|
8
|
+
const fixedSize = layout.fixedSize;
|
|
9
|
+
const varCount = layout.variableCount;
|
|
10
|
+
// pre-allocate with max possible size
|
|
11
|
+
const offsetTableSize = varCount * 8;
|
|
12
|
+
const headerSize = bitmaskSize + fixedSize + offsetTableSize;
|
|
13
|
+
const buf = new ArrayBuffer(headerSize);
|
|
14
|
+
const view = new DataView(buf);
|
|
15
|
+
const bitmask = new Uint8Array(bitmaskSize);
|
|
16
|
+
const variableOffsets = new Uint32Array(varCount);
|
|
17
|
+
variableOffsets.fill(SENTINEL_ABSENT);
|
|
18
|
+
const variableData = [];
|
|
19
|
+
let variableDataTotal = 0;
|
|
20
|
+
let varIdx = 0;
|
|
21
|
+
for (const f of layout.fields) {
|
|
22
|
+
const val = data[f.name];
|
|
23
|
+
if (val === undefined || val === null) {
|
|
24
|
+
if (f.isOptional) {
|
|
25
|
+
if (f.category === FieldCategory.Variable) {
|
|
26
|
+
varIdx++;
|
|
27
|
+
}
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (f.isOptional && f.bitmaskBit >= 0 && val !== undefined && val !== null) {
|
|
32
|
+
const byteIdx = Math.floor(f.bitmaskBit / 8);
|
|
33
|
+
const bitIdx = f.bitmaskBit % 8;
|
|
34
|
+
bitmask[byteIdx] |= 1 << bitIdx;
|
|
35
|
+
}
|
|
36
|
+
if (f.category === FieldCategory.Fixed) {
|
|
37
|
+
const offset = bitmaskSize + f.offset;
|
|
38
|
+
encodeFixedField(f, val, view, offset);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const enc = encodeVariableField(f, val);
|
|
42
|
+
variableOffsets[varIdx] = variableDataTotal;
|
|
43
|
+
variableData.push(enc);
|
|
44
|
+
variableDataTotal += enc.byteLength;
|
|
45
|
+
varIdx++;
|
|
46
|
+
}
|
|
47
|
+
const totalSize = headerSize + variableDataTotal;
|
|
48
|
+
const finalBuf = new ArrayBuffer(totalSize);
|
|
49
|
+
const finalView = new DataView(finalBuf);
|
|
50
|
+
for (let i = 0; i < bitmaskSize; i++) {
|
|
51
|
+
finalView.setUint8(i, bitmask[i] ?? 0);
|
|
52
|
+
}
|
|
53
|
+
if (fixedSize > 0) {
|
|
54
|
+
const fixedSrc = new Uint8Array(buf, bitmaskSize, fixedSize);
|
|
55
|
+
const fixedDst = new Uint8Array(finalBuf, bitmaskSize, fixedSize);
|
|
56
|
+
fixedDst.set(fixedSrc);
|
|
57
|
+
}
|
|
58
|
+
let variableStart = bitmaskSize + fixedSize;
|
|
59
|
+
for (let i = 0; i < varCount; i++) {
|
|
60
|
+
const start = variableOffsets[i];
|
|
61
|
+
const offset = variableStart + i * 8;
|
|
62
|
+
let length = 0;
|
|
63
|
+
if (start !== SENTINEL_ABSENT) {
|
|
64
|
+
if (i + 1 < varCount && variableOffsets[i + 1] !== SENTINEL_ABSENT) {
|
|
65
|
+
length = variableOffsets[i + 1] - start;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
length = variableDataTotal - start;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
finalView.setUint32(offset, start, true);
|
|
72
|
+
finalView.setUint32(offset + 4, length, true);
|
|
73
|
+
}
|
|
74
|
+
if (variableDataTotal > 0) {
|
|
75
|
+
const varDst = new Uint8Array(finalBuf, variableStart + varCount * 8);
|
|
76
|
+
let pos = 0;
|
|
77
|
+
for (const chunk of variableData) {
|
|
78
|
+
varDst.set(chunk, pos);
|
|
79
|
+
pos += chunk.byteLength;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return finalBuf;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Deserialize the positional wire format into JS data (Record).
|
|
86
|
+
* Mirrors Go's DeserializeOutput — used by JS worker to receive dispatches.
|
|
87
|
+
*/
|
|
88
|
+
export function deserializeInput(layout, data) {
|
|
89
|
+
const result = {};
|
|
90
|
+
const view = new DataView(data);
|
|
91
|
+
const bitmaskSize = layout.bitmaskSize;
|
|
92
|
+
const fixedSize = layout.fixedSize;
|
|
93
|
+
const varCount = layout.variableCount;
|
|
94
|
+
let varIdx = 0;
|
|
95
|
+
for (const f of layout.fields) {
|
|
96
|
+
if (f.isOptional && f.bitmaskBit >= 0) {
|
|
97
|
+
const byteIdx = Math.floor(f.bitmaskBit / 8);
|
|
98
|
+
const bitIdx = f.bitmaskBit % 8;
|
|
99
|
+
if (byteIdx >= bitmaskSize || ((view.getUint8(byteIdx) >> bitIdx) & 1) === 0) {
|
|
100
|
+
if (f.category === FieldCategory.Variable) {
|
|
101
|
+
varIdx++;
|
|
102
|
+
}
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (f.category === FieldCategory.Fixed) {
|
|
107
|
+
const offset = bitmaskSize + f.offset;
|
|
108
|
+
result[f.name] = decodeFixedField(f, view, offset);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const tableOffset = bitmaskSize + fixedSize + varIdx * 8;
|
|
112
|
+
const start = view.getUint32(tableOffset, true);
|
|
113
|
+
const length = view.getUint32(tableOffset + 4, true);
|
|
114
|
+
if (start !== SENTINEL_ABSENT) {
|
|
115
|
+
if (length > 0) {
|
|
116
|
+
const variableStart = bitmaskSize + fixedSize + varCount * 8;
|
|
117
|
+
const fieldBuf = data.slice(variableStart + start, variableStart + start + length);
|
|
118
|
+
result[f.name] = decodeVariableField(f, fieldBuf);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
result[f.name] = zeroValueForWire(f);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
varIdx++;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
// ---- Fixed field encoding ----
|
|
130
|
+
function encodeFixedField(f, val, view, offset) {
|
|
131
|
+
switch (f.fieldType) {
|
|
132
|
+
case FieldType.Number: {
|
|
133
|
+
const num = typeof val === "number" ? val : 0;
|
|
134
|
+
view.setFloat64(offset, num, true);
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
case FieldType.Boolean: {
|
|
138
|
+
view.setUint8(offset, val ? 1 : 0);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case FieldType.Enum: {
|
|
142
|
+
const idx = typeof val === "number" ? val : 0;
|
|
143
|
+
view.setUint16(offset, idx, true);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case FieldType.Date: {
|
|
147
|
+
let ms;
|
|
148
|
+
if (typeof val === "string") {
|
|
149
|
+
ms = new Date(val).getTime();
|
|
150
|
+
}
|
|
151
|
+
else if (val instanceof Date) {
|
|
152
|
+
ms = val.getTime();
|
|
153
|
+
}
|
|
154
|
+
else if (typeof val === "number") {
|
|
155
|
+
ms = val;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
ms = 0;
|
|
159
|
+
}
|
|
160
|
+
view.setBigUint64(offset, BigInt(ms), true);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function decodeFixedField(f, view, offset) {
|
|
166
|
+
switch (f.fieldType) {
|
|
167
|
+
case FieldType.Number:
|
|
168
|
+
return view.getFloat64(offset, true);
|
|
169
|
+
case FieldType.Boolean:
|
|
170
|
+
return view.getUint8(offset) !== 0;
|
|
171
|
+
case FieldType.Enum:
|
|
172
|
+
return view.getUint16(offset, true);
|
|
173
|
+
case FieldType.Date: {
|
|
174
|
+
const ms = Number(view.getBigUint64(offset, true));
|
|
175
|
+
return new Date(ms);
|
|
176
|
+
}
|
|
177
|
+
default:
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// ---- Variable field encoding ----
|
|
182
|
+
function encodeVariableField(f, val) {
|
|
183
|
+
switch (f.fieldType) {
|
|
184
|
+
case FieldType.String: {
|
|
185
|
+
const str = typeof val === "string" ? val : String(val ?? "");
|
|
186
|
+
return new TextEncoder().encode(str);
|
|
187
|
+
}
|
|
188
|
+
case FieldType.Array:
|
|
189
|
+
case FieldType.Object: {
|
|
190
|
+
const json = JSON.stringify(val ?? {});
|
|
191
|
+
return new TextEncoder().encode(json);
|
|
192
|
+
}
|
|
193
|
+
default:
|
|
194
|
+
return new TextEncoder().encode(String(val ?? ""));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function decodeVariableField(f, buf) {
|
|
198
|
+
switch (f.fieldType) {
|
|
199
|
+
case FieldType.String:
|
|
200
|
+
return new TextDecoder().decode(buf);
|
|
201
|
+
case FieldType.Array:
|
|
202
|
+
case FieldType.Object: {
|
|
203
|
+
try {
|
|
204
|
+
return JSON.parse(new TextDecoder().decode(buf));
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
return new TextDecoder().decode(buf);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
default:
|
|
211
|
+
return new TextDecoder().decode(buf);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function zeroValueForWire(f) {
|
|
215
|
+
switch (f.fieldType) {
|
|
216
|
+
case FieldType.String:
|
|
217
|
+
return "";
|
|
218
|
+
case FieldType.Array:
|
|
219
|
+
return [];
|
|
220
|
+
case FieldType.Object:
|
|
221
|
+
return {};
|
|
222
|
+
default:
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export declare enum FieldType {
|
|
2
|
+
String = 0,
|
|
3
|
+
Number = 1,
|
|
4
|
+
Boolean = 2,
|
|
5
|
+
Enum = 3,
|
|
6
|
+
Date = 4,
|
|
7
|
+
Array = 5,
|
|
8
|
+
Object = 6
|
|
9
|
+
}
|
|
10
|
+
export declare enum FieldCategory {
|
|
11
|
+
Fixed = 0,
|
|
12
|
+
Variable = 1
|
|
13
|
+
}
|
|
14
|
+
export interface FieldLayout {
|
|
15
|
+
name: string;
|
|
16
|
+
fieldType: FieldType;
|
|
17
|
+
category: FieldCategory;
|
|
18
|
+
offset: number;
|
|
19
|
+
size: number;
|
|
20
|
+
bitmaskBit: number;
|
|
21
|
+
isOptional: boolean;
|
|
22
|
+
isNullable: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface CompiledLayout {
|
|
25
|
+
fields: FieldLayout[];
|
|
26
|
+
fixedSize: number;
|
|
27
|
+
bitmaskSize: number;
|
|
28
|
+
variableCount: number;
|
|
29
|
+
}
|
|
30
|
+
export declare enum Direction {
|
|
31
|
+
GoToJS = 0,
|
|
32
|
+
JSToGo = 1
|
|
33
|
+
}
|
|
34
|
+
export declare enum MessageType {
|
|
35
|
+
Dispatch = 0,
|
|
36
|
+
Result = 1,
|
|
37
|
+
Ping = 2,
|
|
38
|
+
Error = 3
|
|
39
|
+
}
|
|
40
|
+
export interface Header {
|
|
41
|
+
magic: number;
|
|
42
|
+
version: number;
|
|
43
|
+
direction: Direction;
|
|
44
|
+
msgType: MessageType;
|
|
45
|
+
flags: number;
|
|
46
|
+
requestId: number;
|
|
47
|
+
handlerId: number;
|
|
48
|
+
payloadLen: number;
|
|
49
|
+
statusCode: number;
|
|
50
|
+
reserved: Uint8Array;
|
|
51
|
+
}
|
|
52
|
+
export declare const MAGIC = 1095652435;
|
|
53
|
+
export declare const HEADER_SIZE = 32;
|
|
54
|
+
export declare const SENTINEL_ABSENT = 4294967295;
|
|
55
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,oBAAY,SAAS;IACnB,MAAM,IAAI;IACV,MAAM,IAAI;IACV,OAAO,IAAI;IACX,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;IACT,MAAM,IAAI;CACX;AAGD,oBAAY,aAAa;IACvB,KAAK,IAAI;IACT,QAAQ,IAAI;CACb;AAGD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB;AAGD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAGD,oBAAY,SAAS;IACnB,MAAM,IAAO;IACb,MAAM,IAAO;CACd;AAED,oBAAY,WAAW;IACrB,QAAQ,IAAO;IACf,MAAM,IAAO;IACb,IAAI,IAAO;IACX,KAAK,IAAO;CACb;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,UAAU,CAAC;CACtB;AAED,eAAO,MAAM,KAAK,aAAa,CAAC;AAChC,eAAO,MAAM,WAAW,KAAK,CAAC;AAC9B,eAAO,MAAM,eAAe,aAAa,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Mirrors Go's FieldType
|
|
2
|
+
export var FieldType;
|
|
3
|
+
(function (FieldType) {
|
|
4
|
+
FieldType[FieldType["String"] = 0] = "String";
|
|
5
|
+
FieldType[FieldType["Number"] = 1] = "Number";
|
|
6
|
+
FieldType[FieldType["Boolean"] = 2] = "Boolean";
|
|
7
|
+
FieldType[FieldType["Enum"] = 3] = "Enum";
|
|
8
|
+
FieldType[FieldType["Date"] = 4] = "Date";
|
|
9
|
+
FieldType[FieldType["Array"] = 5] = "Array";
|
|
10
|
+
FieldType[FieldType["Object"] = 6] = "Object";
|
|
11
|
+
})(FieldType || (FieldType = {}));
|
|
12
|
+
// Mirrors Go's FieldCategory
|
|
13
|
+
export var FieldCategory;
|
|
14
|
+
(function (FieldCategory) {
|
|
15
|
+
FieldCategory[FieldCategory["Fixed"] = 0] = "Fixed";
|
|
16
|
+
FieldCategory[FieldCategory["Variable"] = 1] = "Variable";
|
|
17
|
+
})(FieldCategory || (FieldCategory = {}));
|
|
18
|
+
// Mirrors Go's Header
|
|
19
|
+
export var Direction;
|
|
20
|
+
(function (Direction) {
|
|
21
|
+
Direction[Direction["GoToJS"] = 0] = "GoToJS";
|
|
22
|
+
Direction[Direction["JSToGo"] = 1] = "JSToGo";
|
|
23
|
+
})(Direction || (Direction = {}));
|
|
24
|
+
export var MessageType;
|
|
25
|
+
(function (MessageType) {
|
|
26
|
+
MessageType[MessageType["Dispatch"] = 0] = "Dispatch";
|
|
27
|
+
MessageType[MessageType["Result"] = 1] = "Result";
|
|
28
|
+
MessageType[MessageType["Ping"] = 2] = "Ping";
|
|
29
|
+
MessageType[MessageType["Error"] = 3] = "Error";
|
|
30
|
+
})(MessageType || (MessageType = {}));
|
|
31
|
+
export const MAGIC = 0x414e5453;
|
|
32
|
+
export const HEADER_SIZE = 32;
|
|
33
|
+
export const SENTINEL_ABSENT = 0xffffffff;
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@antines/protocol",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": ["dist"],
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"check-types": "tsc --noEmit",
|
|
17
|
+
"lint": "oxlint"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@antines/schema": "0.1.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^25.9.1"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/antines-labs/antinesjs.git",
|
|
31
|
+
"directory": "packages/protocol"
|
|
32
|
+
}
|
|
33
|
+
}
|