@prisma/param-graph 7.3.0-integration-parameterization.15 → 7.4.0-dev.22
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/index.d.ts +6 -1
- package/dist/index.js +14 -6
- package/dist/index.mjs +6 -1
- package/dist/param-graph.d.ts +76 -91
- package/dist/param-graph.js +134 -2
- package/dist/param-graph.mjs +133 -2
- package/dist/serialization.d.ts +113 -0
- package/dist/serialization.js +276 -0
- package/dist/serialization.mjs +251 -0
- package/dist/serialization.test.d.ts +1 -0
- package/dist/serialization.test.js +169 -0
- package/dist/serialization.test.mjs +168 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.js +16 -0
- package/dist/types.mjs +0 -0
- package/package.json +3 -2
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary serialization for ParamGraph.
|
|
3
|
+
*
|
|
4
|
+
* This module handles compact binary encoding/decoding of the param graph structure.
|
|
5
|
+
* The format uses a hybrid approach: JSON string array for field names + binary blob
|
|
6
|
+
* for structural data (nodes, edges, roots).
|
|
7
|
+
*
|
|
8
|
+
* ## Serialized Representation
|
|
9
|
+
*
|
|
10
|
+
* ```
|
|
11
|
+
* SerializedParamGraph {
|
|
12
|
+
* strings: string[] // String table (field names, enum names, root keys)
|
|
13
|
+
* graph: string // Base64url-encoded binary blob
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ## Why Hybrid?
|
|
18
|
+
*
|
|
19
|
+
* - **Strings stay as JSON**: V8's JSON.parse is highly optimized for string arrays
|
|
20
|
+
* - **Structure goes binary**: Indices, flags, masks benefit from compact encoding
|
|
21
|
+
* - **Best of both**: Fast parsing + compact size where it matters
|
|
22
|
+
*
|
|
23
|
+
* ## Variable-Length Encoding
|
|
24
|
+
*
|
|
25
|
+
* All integer values (except fixed-size fields like `scalarMask` and `flags`) use
|
|
26
|
+
* unsigned LEB128 (Little Endian Base 128) variable-length encoding:
|
|
27
|
+
*
|
|
28
|
+
* - Values 0-127: 1 byte
|
|
29
|
+
* - Values 128-16383: 2 bytes
|
|
30
|
+
* - Values 16384-2097151: 3 bytes
|
|
31
|
+
* - And so on...
|
|
32
|
+
*
|
|
33
|
+
* Optional values use value+1 encoding: 0 means "none/undefined", N+1 means actual value N.
|
|
34
|
+
*
|
|
35
|
+
* ## Binary Blob Layout
|
|
36
|
+
*
|
|
37
|
+
* ```
|
|
38
|
+
* ┌───────────────────────────────────────────────────────────────────┐
|
|
39
|
+
* │ HEADER │
|
|
40
|
+
* ├───────────────────────────────────────────────────────────────────┤
|
|
41
|
+
* │ inputNodeCount: varuint │
|
|
42
|
+
* │ outputNodeCount: varuint │
|
|
43
|
+
* │ rootCount: varuint │
|
|
44
|
+
* └───────────────────────────────────────────────────────────────────┘
|
|
45
|
+
*
|
|
46
|
+
* ┌───────────────────────────────────────────────────────────────────┐
|
|
47
|
+
* │ INPUT NODES (repeated inputNodeCount times) │
|
|
48
|
+
* ├───────────────────────────────────────────────────────────────────┤
|
|
49
|
+
* │ edgeCount: varuint │
|
|
50
|
+
* │ edges[] │
|
|
51
|
+
* └───────────────────────────────────────────────────────────────────┘
|
|
52
|
+
*
|
|
53
|
+
* ┌───────────────────────────────────────────────────────────────────┐
|
|
54
|
+
* │ INPUT EDGE │
|
|
55
|
+
* ├───────────────────────────────────────────────────────────────────┤
|
|
56
|
+
* │ fieldIndex: varuint │
|
|
57
|
+
* │ scalarMask: u16 │
|
|
58
|
+
* │ childNodeId: varuint (0=none, N+1=actual) │
|
|
59
|
+
* │ enumNameIndex: varuint (0=none, N+1=actual) │
|
|
60
|
+
* │ flags: u8 │
|
|
61
|
+
* └───────────────────────────────────────────────────────────────────┘
|
|
62
|
+
*
|
|
63
|
+
* ┌───────────────────────────────────────────────────────────────────┐
|
|
64
|
+
* │ OUTPUT NODES (repeated outputNodeCount times) │
|
|
65
|
+
* ├───────────────────────────────────────────────────────────────────┤
|
|
66
|
+
* │ edgeCount: varuint │
|
|
67
|
+
* │ edges[] │
|
|
68
|
+
* └───────────────────────────────────────────────────────────────────┘
|
|
69
|
+
*
|
|
70
|
+
* ┌───────────────────────────────────────────────────────────────────┐
|
|
71
|
+
* │ OUTPUT EDGE │
|
|
72
|
+
* ├───────────────────────────────────────────────────────────────────┤
|
|
73
|
+
* │ fieldIndex: varuint │
|
|
74
|
+
* │ argsNodeId: varuint (0=none, N+1=actual) │
|
|
75
|
+
* │ outputNodeId: varuint (0=none, N+1=actual) │
|
|
76
|
+
* └───────────────────────────────────────────────────────────────────┘
|
|
77
|
+
*
|
|
78
|
+
* ┌───────────────────────────────────────────────────────────────────┐
|
|
79
|
+
* │ ROOTS (repeated rootCount times) │
|
|
80
|
+
* ├───────────────────────────────────────────────────────────────────┤
|
|
81
|
+
* │ keyIndex: varuint │
|
|
82
|
+
* │ argsNodeId: varuint (0=none, N+1=actual) │
|
|
83
|
+
* │ outputNodeId: varuint (0=none, N+1=actual) │
|
|
84
|
+
* └───────────────────────────────────────────────────────────────────┘
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* ## Embedding in Generated Client
|
|
88
|
+
*
|
|
89
|
+
* ```js
|
|
90
|
+
* config.parameterizationSchema = {
|
|
91
|
+
* strings: JSON.parse('["where","id","email",...]'),
|
|
92
|
+
* graph: "base64url_encoded_binary_blob..."
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
import type { ParamGraphData } from './types';
|
|
97
|
+
/**
|
|
98
|
+
* Serialized format stored in the generated client.
|
|
99
|
+
*/
|
|
100
|
+
export interface SerializedParamGraph {
|
|
101
|
+
/** String table (field names, enum names, root keys) */
|
|
102
|
+
strings: string[];
|
|
103
|
+
/** Base64url-encoded binary blob for structural data */
|
|
104
|
+
graph: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Serializes a ParamGraphData to the compact binary format.
|
|
108
|
+
*/
|
|
109
|
+
export declare function serializeParamGraph(data: ParamGraphData): SerializedParamGraph;
|
|
110
|
+
/**
|
|
111
|
+
* Deserializes a binary-encoded ParamGraph.
|
|
112
|
+
*/
|
|
113
|
+
export declare function deserializeParamGraph(serialized: SerializedParamGraph): ParamGraphData;
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var serialization_exports = {};
|
|
20
|
+
__export(serialization_exports, {
|
|
21
|
+
deserializeParamGraph: () => deserializeParamGraph,
|
|
22
|
+
serializeParamGraph: () => serializeParamGraph
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(serialization_exports);
|
|
25
|
+
function serializeParamGraph(data) {
|
|
26
|
+
return new Serializer(data).serialize();
|
|
27
|
+
}
|
|
28
|
+
function deserializeParamGraph(serialized) {
|
|
29
|
+
return new Deserializer(serialized).deserialize();
|
|
30
|
+
}
|
|
31
|
+
function encodeBase64url(bytes) {
|
|
32
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64url");
|
|
33
|
+
}
|
|
34
|
+
function decodeBase64url(str) {
|
|
35
|
+
return Buffer.from(str, "base64url");
|
|
36
|
+
}
|
|
37
|
+
function varuintSize(value) {
|
|
38
|
+
let size = 1;
|
|
39
|
+
while (value >= 128) {
|
|
40
|
+
size++;
|
|
41
|
+
value >>>= 7;
|
|
42
|
+
}
|
|
43
|
+
return size;
|
|
44
|
+
}
|
|
45
|
+
class Serializer {
|
|
46
|
+
#data;
|
|
47
|
+
#buffer;
|
|
48
|
+
#view;
|
|
49
|
+
#offset = 0;
|
|
50
|
+
#rootKeys;
|
|
51
|
+
constructor(data) {
|
|
52
|
+
this.#data = data;
|
|
53
|
+
this.#rootKeys = Object.keys(data.roots);
|
|
54
|
+
const size = this.#calculateBufferSize();
|
|
55
|
+
this.#buffer = new ArrayBuffer(size);
|
|
56
|
+
this.#view = new DataView(this.#buffer);
|
|
57
|
+
}
|
|
58
|
+
serialize() {
|
|
59
|
+
this.#writeHeader();
|
|
60
|
+
this.#writeInputNodes();
|
|
61
|
+
this.#writeOutputNodes();
|
|
62
|
+
this.#writeRoots();
|
|
63
|
+
return {
|
|
64
|
+
strings: this.#data.strings,
|
|
65
|
+
graph: encodeBase64url(new Uint8Array(this.#buffer, 0, this.#offset))
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
#writeVaruint(value) {
|
|
69
|
+
while (value >= 128) {
|
|
70
|
+
this.#view.setUint8(this.#offset++, value & 127 | 128);
|
|
71
|
+
value >>>= 7;
|
|
72
|
+
}
|
|
73
|
+
this.#view.setUint8(this.#offset++, value);
|
|
74
|
+
}
|
|
75
|
+
#writeOptionalVaruint(value) {
|
|
76
|
+
this.#writeVaruint(value === void 0 ? 0 : value + 1);
|
|
77
|
+
}
|
|
78
|
+
#writeByte(value) {
|
|
79
|
+
this.#view.setUint8(this.#offset, value);
|
|
80
|
+
this.#offset += 1;
|
|
81
|
+
}
|
|
82
|
+
#writeU16(value) {
|
|
83
|
+
this.#view.setUint16(this.#offset, value, true);
|
|
84
|
+
this.#offset += 2;
|
|
85
|
+
}
|
|
86
|
+
#calculateBufferSize() {
|
|
87
|
+
let size = 0;
|
|
88
|
+
size += varuintSize(this.#data.inputNodes.length);
|
|
89
|
+
size += varuintSize(this.#data.outputNodes.length);
|
|
90
|
+
size += varuintSize(this.#rootKeys.length);
|
|
91
|
+
for (const node of this.#data.inputNodes) {
|
|
92
|
+
const fieldIndices = Object.keys(node.edges).map(Number);
|
|
93
|
+
size += varuintSize(fieldIndices.length);
|
|
94
|
+
for (const fieldIndex of fieldIndices) {
|
|
95
|
+
const edge = node.edges[fieldIndex];
|
|
96
|
+
size += varuintSize(fieldIndex);
|
|
97
|
+
size += 2;
|
|
98
|
+
size += varuintSize(edge.childNodeId === void 0 ? 0 : edge.childNodeId + 1);
|
|
99
|
+
size += varuintSize(edge.enumNameIndex === void 0 ? 0 : edge.enumNameIndex + 1);
|
|
100
|
+
size += 1;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const node of this.#data.outputNodes) {
|
|
104
|
+
const fieldIndices = Object.keys(node.edges).map(Number);
|
|
105
|
+
size += varuintSize(fieldIndices.length);
|
|
106
|
+
for (const fieldIndex of fieldIndices) {
|
|
107
|
+
const edge = node.edges[fieldIndex];
|
|
108
|
+
size += varuintSize(fieldIndex);
|
|
109
|
+
size += varuintSize(edge.argsNodeId === void 0 ? 0 : edge.argsNodeId + 1);
|
|
110
|
+
size += varuintSize(edge.outputNodeId === void 0 ? 0 : edge.outputNodeId + 1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const key of this.#rootKeys) {
|
|
114
|
+
const root = this.#data.roots[key];
|
|
115
|
+
const keyIndex = this.#data.strings.indexOf(key);
|
|
116
|
+
size += varuintSize(keyIndex);
|
|
117
|
+
size += varuintSize(root.argsNodeId === void 0 ? 0 : root.argsNodeId + 1);
|
|
118
|
+
size += varuintSize(root.outputNodeId === void 0 ? 0 : root.outputNodeId + 1);
|
|
119
|
+
}
|
|
120
|
+
return size;
|
|
121
|
+
}
|
|
122
|
+
#writeHeader() {
|
|
123
|
+
this.#writeVaruint(this.#data.inputNodes.length);
|
|
124
|
+
this.#writeVaruint(this.#data.outputNodes.length);
|
|
125
|
+
this.#writeVaruint(this.#rootKeys.length);
|
|
126
|
+
}
|
|
127
|
+
#writeInputNodes() {
|
|
128
|
+
for (const node of this.#data.inputNodes) {
|
|
129
|
+
const fieldIndices = Object.keys(node.edges).map(Number);
|
|
130
|
+
this.#writeVaruint(fieldIndices.length);
|
|
131
|
+
for (const fieldIndex of fieldIndices) {
|
|
132
|
+
const edge = node.edges[fieldIndex];
|
|
133
|
+
this.#writeVaruint(fieldIndex);
|
|
134
|
+
this.#writeU16(edge.scalarMask ?? 0);
|
|
135
|
+
this.#writeOptionalVaruint(edge.childNodeId);
|
|
136
|
+
this.#writeOptionalVaruint(edge.enumNameIndex);
|
|
137
|
+
this.#writeByte(edge.flags);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
#writeOutputNodes() {
|
|
142
|
+
for (const node of this.#data.outputNodes) {
|
|
143
|
+
const fieldIndices = Object.keys(node.edges).map(Number);
|
|
144
|
+
this.#writeVaruint(fieldIndices.length);
|
|
145
|
+
for (const fieldIndex of fieldIndices) {
|
|
146
|
+
const edge = node.edges[fieldIndex];
|
|
147
|
+
this.#writeVaruint(fieldIndex);
|
|
148
|
+
this.#writeOptionalVaruint(edge.argsNodeId);
|
|
149
|
+
this.#writeOptionalVaruint(edge.outputNodeId);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
#writeRoots() {
|
|
154
|
+
for (const key of this.#rootKeys) {
|
|
155
|
+
const root = this.#data.roots[key];
|
|
156
|
+
const keyIndex = this.#data.strings.indexOf(key);
|
|
157
|
+
if (keyIndex === -1) {
|
|
158
|
+
throw new Error(`Root key "${key}" not found in strings table`);
|
|
159
|
+
}
|
|
160
|
+
this.#writeVaruint(keyIndex);
|
|
161
|
+
this.#writeOptionalVaruint(root.argsNodeId);
|
|
162
|
+
this.#writeOptionalVaruint(root.outputNodeId);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
class Deserializer {
|
|
167
|
+
#serialized;
|
|
168
|
+
#view;
|
|
169
|
+
#offset = 0;
|
|
170
|
+
constructor(serialized) {
|
|
171
|
+
this.#serialized = serialized;
|
|
172
|
+
const bytes = decodeBase64url(serialized.graph);
|
|
173
|
+
this.#view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
174
|
+
}
|
|
175
|
+
deserialize() {
|
|
176
|
+
const { inputNodeCount, outputNodeCount, rootCount } = this.#readHeader();
|
|
177
|
+
const inputNodes = this.#readInputNodes(inputNodeCount);
|
|
178
|
+
const outputNodes = this.#readOutputNodes(outputNodeCount);
|
|
179
|
+
const roots = this.#readRoots(rootCount);
|
|
180
|
+
return {
|
|
181
|
+
strings: this.#serialized.strings,
|
|
182
|
+
inputNodes,
|
|
183
|
+
outputNodes,
|
|
184
|
+
roots
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
#readVaruint() {
|
|
188
|
+
let value = 0;
|
|
189
|
+
let shift = 0;
|
|
190
|
+
let byte;
|
|
191
|
+
do {
|
|
192
|
+
byte = this.#view.getUint8(this.#offset++);
|
|
193
|
+
value |= (byte & 127) << shift;
|
|
194
|
+
shift += 7;
|
|
195
|
+
} while (byte >= 128);
|
|
196
|
+
return value;
|
|
197
|
+
}
|
|
198
|
+
#readOptionalVaruint() {
|
|
199
|
+
const value = this.#readVaruint();
|
|
200
|
+
return value === 0 ? void 0 : value - 1;
|
|
201
|
+
}
|
|
202
|
+
#readByte() {
|
|
203
|
+
const value = this.#view.getUint8(this.#offset);
|
|
204
|
+
this.#offset += 1;
|
|
205
|
+
return value;
|
|
206
|
+
}
|
|
207
|
+
#readU16() {
|
|
208
|
+
const value = this.#view.getUint16(this.#offset, true);
|
|
209
|
+
this.#offset += 2;
|
|
210
|
+
return value;
|
|
211
|
+
}
|
|
212
|
+
#readHeader() {
|
|
213
|
+
const inputNodeCount = this.#readVaruint();
|
|
214
|
+
const outputNodeCount = this.#readVaruint();
|
|
215
|
+
const rootCount = this.#readVaruint();
|
|
216
|
+
return { inputNodeCount, outputNodeCount, rootCount };
|
|
217
|
+
}
|
|
218
|
+
#readInputNodes(count) {
|
|
219
|
+
const inputNodes = [];
|
|
220
|
+
for (let i = 0; i < count; i++) {
|
|
221
|
+
const edgeCount = this.#readVaruint();
|
|
222
|
+
const edges = {};
|
|
223
|
+
for (let j = 0; j < edgeCount; j++) {
|
|
224
|
+
const fieldIndex = this.#readVaruint();
|
|
225
|
+
const scalarMask = this.#readU16();
|
|
226
|
+
const childNodeId = this.#readOptionalVaruint();
|
|
227
|
+
const enumNameIndex = this.#readOptionalVaruint();
|
|
228
|
+
const flags = this.#readByte();
|
|
229
|
+
const edge = { flags };
|
|
230
|
+
if (scalarMask !== 0) edge.scalarMask = scalarMask;
|
|
231
|
+
if (childNodeId !== void 0) edge.childNodeId = childNodeId;
|
|
232
|
+
if (enumNameIndex !== void 0) edge.enumNameIndex = enumNameIndex;
|
|
233
|
+
edges[fieldIndex] = edge;
|
|
234
|
+
}
|
|
235
|
+
inputNodes.push({ edges });
|
|
236
|
+
}
|
|
237
|
+
return inputNodes;
|
|
238
|
+
}
|
|
239
|
+
#readOutputNodes(count) {
|
|
240
|
+
const outputNodes = [];
|
|
241
|
+
for (let i = 0; i < count; i++) {
|
|
242
|
+
const edgeCount = this.#readVaruint();
|
|
243
|
+
const edges = {};
|
|
244
|
+
for (let j = 0; j < edgeCount; j++) {
|
|
245
|
+
const fieldIndex = this.#readVaruint();
|
|
246
|
+
const argsNodeId = this.#readOptionalVaruint();
|
|
247
|
+
const outputNodeId = this.#readOptionalVaruint();
|
|
248
|
+
const edge = {};
|
|
249
|
+
if (argsNodeId !== void 0) edge.argsNodeId = argsNodeId;
|
|
250
|
+
if (outputNodeId !== void 0) edge.outputNodeId = outputNodeId;
|
|
251
|
+
edges[fieldIndex] = edge;
|
|
252
|
+
}
|
|
253
|
+
outputNodes.push({ edges });
|
|
254
|
+
}
|
|
255
|
+
return outputNodes;
|
|
256
|
+
}
|
|
257
|
+
#readRoots(count) {
|
|
258
|
+
const roots = {};
|
|
259
|
+
for (let i = 0; i < count; i++) {
|
|
260
|
+
const keyIndex = this.#readVaruint();
|
|
261
|
+
const argsNodeId = this.#readOptionalVaruint();
|
|
262
|
+
const outputNodeId = this.#readOptionalVaruint();
|
|
263
|
+
const key = this.#serialized.strings[keyIndex];
|
|
264
|
+
const root = {};
|
|
265
|
+
if (argsNodeId !== void 0) root.argsNodeId = argsNodeId;
|
|
266
|
+
if (outputNodeId !== void 0) root.outputNodeId = outputNodeId;
|
|
267
|
+
roots[key] = root;
|
|
268
|
+
}
|
|
269
|
+
return roots;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
273
|
+
0 && (module.exports = {
|
|
274
|
+
deserializeParamGraph,
|
|
275
|
+
serializeParamGraph
|
|
276
|
+
});
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
function serializeParamGraph(data) {
|
|
2
|
+
return new Serializer(data).serialize();
|
|
3
|
+
}
|
|
4
|
+
function deserializeParamGraph(serialized) {
|
|
5
|
+
return new Deserializer(serialized).deserialize();
|
|
6
|
+
}
|
|
7
|
+
function encodeBase64url(bytes) {
|
|
8
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64url");
|
|
9
|
+
}
|
|
10
|
+
function decodeBase64url(str) {
|
|
11
|
+
return Buffer.from(str, "base64url");
|
|
12
|
+
}
|
|
13
|
+
function varuintSize(value) {
|
|
14
|
+
let size = 1;
|
|
15
|
+
while (value >= 128) {
|
|
16
|
+
size++;
|
|
17
|
+
value >>>= 7;
|
|
18
|
+
}
|
|
19
|
+
return size;
|
|
20
|
+
}
|
|
21
|
+
class Serializer {
|
|
22
|
+
#data;
|
|
23
|
+
#buffer;
|
|
24
|
+
#view;
|
|
25
|
+
#offset = 0;
|
|
26
|
+
#rootKeys;
|
|
27
|
+
constructor(data) {
|
|
28
|
+
this.#data = data;
|
|
29
|
+
this.#rootKeys = Object.keys(data.roots);
|
|
30
|
+
const size = this.#calculateBufferSize();
|
|
31
|
+
this.#buffer = new ArrayBuffer(size);
|
|
32
|
+
this.#view = new DataView(this.#buffer);
|
|
33
|
+
}
|
|
34
|
+
serialize() {
|
|
35
|
+
this.#writeHeader();
|
|
36
|
+
this.#writeInputNodes();
|
|
37
|
+
this.#writeOutputNodes();
|
|
38
|
+
this.#writeRoots();
|
|
39
|
+
return {
|
|
40
|
+
strings: this.#data.strings,
|
|
41
|
+
graph: encodeBase64url(new Uint8Array(this.#buffer, 0, this.#offset))
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
#writeVaruint(value) {
|
|
45
|
+
while (value >= 128) {
|
|
46
|
+
this.#view.setUint8(this.#offset++, value & 127 | 128);
|
|
47
|
+
value >>>= 7;
|
|
48
|
+
}
|
|
49
|
+
this.#view.setUint8(this.#offset++, value);
|
|
50
|
+
}
|
|
51
|
+
#writeOptionalVaruint(value) {
|
|
52
|
+
this.#writeVaruint(value === void 0 ? 0 : value + 1);
|
|
53
|
+
}
|
|
54
|
+
#writeByte(value) {
|
|
55
|
+
this.#view.setUint8(this.#offset, value);
|
|
56
|
+
this.#offset += 1;
|
|
57
|
+
}
|
|
58
|
+
#writeU16(value) {
|
|
59
|
+
this.#view.setUint16(this.#offset, value, true);
|
|
60
|
+
this.#offset += 2;
|
|
61
|
+
}
|
|
62
|
+
#calculateBufferSize() {
|
|
63
|
+
let size = 0;
|
|
64
|
+
size += varuintSize(this.#data.inputNodes.length);
|
|
65
|
+
size += varuintSize(this.#data.outputNodes.length);
|
|
66
|
+
size += varuintSize(this.#rootKeys.length);
|
|
67
|
+
for (const node of this.#data.inputNodes) {
|
|
68
|
+
const fieldIndices = Object.keys(node.edges).map(Number);
|
|
69
|
+
size += varuintSize(fieldIndices.length);
|
|
70
|
+
for (const fieldIndex of fieldIndices) {
|
|
71
|
+
const edge = node.edges[fieldIndex];
|
|
72
|
+
size += varuintSize(fieldIndex);
|
|
73
|
+
size += 2;
|
|
74
|
+
size += varuintSize(edge.childNodeId === void 0 ? 0 : edge.childNodeId + 1);
|
|
75
|
+
size += varuintSize(edge.enumNameIndex === void 0 ? 0 : edge.enumNameIndex + 1);
|
|
76
|
+
size += 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
for (const node of this.#data.outputNodes) {
|
|
80
|
+
const fieldIndices = Object.keys(node.edges).map(Number);
|
|
81
|
+
size += varuintSize(fieldIndices.length);
|
|
82
|
+
for (const fieldIndex of fieldIndices) {
|
|
83
|
+
const edge = node.edges[fieldIndex];
|
|
84
|
+
size += varuintSize(fieldIndex);
|
|
85
|
+
size += varuintSize(edge.argsNodeId === void 0 ? 0 : edge.argsNodeId + 1);
|
|
86
|
+
size += varuintSize(edge.outputNodeId === void 0 ? 0 : edge.outputNodeId + 1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const key of this.#rootKeys) {
|
|
90
|
+
const root = this.#data.roots[key];
|
|
91
|
+
const keyIndex = this.#data.strings.indexOf(key);
|
|
92
|
+
size += varuintSize(keyIndex);
|
|
93
|
+
size += varuintSize(root.argsNodeId === void 0 ? 0 : root.argsNodeId + 1);
|
|
94
|
+
size += varuintSize(root.outputNodeId === void 0 ? 0 : root.outputNodeId + 1);
|
|
95
|
+
}
|
|
96
|
+
return size;
|
|
97
|
+
}
|
|
98
|
+
#writeHeader() {
|
|
99
|
+
this.#writeVaruint(this.#data.inputNodes.length);
|
|
100
|
+
this.#writeVaruint(this.#data.outputNodes.length);
|
|
101
|
+
this.#writeVaruint(this.#rootKeys.length);
|
|
102
|
+
}
|
|
103
|
+
#writeInputNodes() {
|
|
104
|
+
for (const node of this.#data.inputNodes) {
|
|
105
|
+
const fieldIndices = Object.keys(node.edges).map(Number);
|
|
106
|
+
this.#writeVaruint(fieldIndices.length);
|
|
107
|
+
for (const fieldIndex of fieldIndices) {
|
|
108
|
+
const edge = node.edges[fieldIndex];
|
|
109
|
+
this.#writeVaruint(fieldIndex);
|
|
110
|
+
this.#writeU16(edge.scalarMask ?? 0);
|
|
111
|
+
this.#writeOptionalVaruint(edge.childNodeId);
|
|
112
|
+
this.#writeOptionalVaruint(edge.enumNameIndex);
|
|
113
|
+
this.#writeByte(edge.flags);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
#writeOutputNodes() {
|
|
118
|
+
for (const node of this.#data.outputNodes) {
|
|
119
|
+
const fieldIndices = Object.keys(node.edges).map(Number);
|
|
120
|
+
this.#writeVaruint(fieldIndices.length);
|
|
121
|
+
for (const fieldIndex of fieldIndices) {
|
|
122
|
+
const edge = node.edges[fieldIndex];
|
|
123
|
+
this.#writeVaruint(fieldIndex);
|
|
124
|
+
this.#writeOptionalVaruint(edge.argsNodeId);
|
|
125
|
+
this.#writeOptionalVaruint(edge.outputNodeId);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
#writeRoots() {
|
|
130
|
+
for (const key of this.#rootKeys) {
|
|
131
|
+
const root = this.#data.roots[key];
|
|
132
|
+
const keyIndex = this.#data.strings.indexOf(key);
|
|
133
|
+
if (keyIndex === -1) {
|
|
134
|
+
throw new Error(`Root key "${key}" not found in strings table`);
|
|
135
|
+
}
|
|
136
|
+
this.#writeVaruint(keyIndex);
|
|
137
|
+
this.#writeOptionalVaruint(root.argsNodeId);
|
|
138
|
+
this.#writeOptionalVaruint(root.outputNodeId);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
class Deserializer {
|
|
143
|
+
#serialized;
|
|
144
|
+
#view;
|
|
145
|
+
#offset = 0;
|
|
146
|
+
constructor(serialized) {
|
|
147
|
+
this.#serialized = serialized;
|
|
148
|
+
const bytes = decodeBase64url(serialized.graph);
|
|
149
|
+
this.#view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
150
|
+
}
|
|
151
|
+
deserialize() {
|
|
152
|
+
const { inputNodeCount, outputNodeCount, rootCount } = this.#readHeader();
|
|
153
|
+
const inputNodes = this.#readInputNodes(inputNodeCount);
|
|
154
|
+
const outputNodes = this.#readOutputNodes(outputNodeCount);
|
|
155
|
+
const roots = this.#readRoots(rootCount);
|
|
156
|
+
return {
|
|
157
|
+
strings: this.#serialized.strings,
|
|
158
|
+
inputNodes,
|
|
159
|
+
outputNodes,
|
|
160
|
+
roots
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
#readVaruint() {
|
|
164
|
+
let value = 0;
|
|
165
|
+
let shift = 0;
|
|
166
|
+
let byte;
|
|
167
|
+
do {
|
|
168
|
+
byte = this.#view.getUint8(this.#offset++);
|
|
169
|
+
value |= (byte & 127) << shift;
|
|
170
|
+
shift += 7;
|
|
171
|
+
} while (byte >= 128);
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
#readOptionalVaruint() {
|
|
175
|
+
const value = this.#readVaruint();
|
|
176
|
+
return value === 0 ? void 0 : value - 1;
|
|
177
|
+
}
|
|
178
|
+
#readByte() {
|
|
179
|
+
const value = this.#view.getUint8(this.#offset);
|
|
180
|
+
this.#offset += 1;
|
|
181
|
+
return value;
|
|
182
|
+
}
|
|
183
|
+
#readU16() {
|
|
184
|
+
const value = this.#view.getUint16(this.#offset, true);
|
|
185
|
+
this.#offset += 2;
|
|
186
|
+
return value;
|
|
187
|
+
}
|
|
188
|
+
#readHeader() {
|
|
189
|
+
const inputNodeCount = this.#readVaruint();
|
|
190
|
+
const outputNodeCount = this.#readVaruint();
|
|
191
|
+
const rootCount = this.#readVaruint();
|
|
192
|
+
return { inputNodeCount, outputNodeCount, rootCount };
|
|
193
|
+
}
|
|
194
|
+
#readInputNodes(count) {
|
|
195
|
+
const inputNodes = [];
|
|
196
|
+
for (let i = 0; i < count; i++) {
|
|
197
|
+
const edgeCount = this.#readVaruint();
|
|
198
|
+
const edges = {};
|
|
199
|
+
for (let j = 0; j < edgeCount; j++) {
|
|
200
|
+
const fieldIndex = this.#readVaruint();
|
|
201
|
+
const scalarMask = this.#readU16();
|
|
202
|
+
const childNodeId = this.#readOptionalVaruint();
|
|
203
|
+
const enumNameIndex = this.#readOptionalVaruint();
|
|
204
|
+
const flags = this.#readByte();
|
|
205
|
+
const edge = { flags };
|
|
206
|
+
if (scalarMask !== 0) edge.scalarMask = scalarMask;
|
|
207
|
+
if (childNodeId !== void 0) edge.childNodeId = childNodeId;
|
|
208
|
+
if (enumNameIndex !== void 0) edge.enumNameIndex = enumNameIndex;
|
|
209
|
+
edges[fieldIndex] = edge;
|
|
210
|
+
}
|
|
211
|
+
inputNodes.push({ edges });
|
|
212
|
+
}
|
|
213
|
+
return inputNodes;
|
|
214
|
+
}
|
|
215
|
+
#readOutputNodes(count) {
|
|
216
|
+
const outputNodes = [];
|
|
217
|
+
for (let i = 0; i < count; i++) {
|
|
218
|
+
const edgeCount = this.#readVaruint();
|
|
219
|
+
const edges = {};
|
|
220
|
+
for (let j = 0; j < edgeCount; j++) {
|
|
221
|
+
const fieldIndex = this.#readVaruint();
|
|
222
|
+
const argsNodeId = this.#readOptionalVaruint();
|
|
223
|
+
const outputNodeId = this.#readOptionalVaruint();
|
|
224
|
+
const edge = {};
|
|
225
|
+
if (argsNodeId !== void 0) edge.argsNodeId = argsNodeId;
|
|
226
|
+
if (outputNodeId !== void 0) edge.outputNodeId = outputNodeId;
|
|
227
|
+
edges[fieldIndex] = edge;
|
|
228
|
+
}
|
|
229
|
+
outputNodes.push({ edges });
|
|
230
|
+
}
|
|
231
|
+
return outputNodes;
|
|
232
|
+
}
|
|
233
|
+
#readRoots(count) {
|
|
234
|
+
const roots = {};
|
|
235
|
+
for (let i = 0; i < count; i++) {
|
|
236
|
+
const keyIndex = this.#readVaruint();
|
|
237
|
+
const argsNodeId = this.#readOptionalVaruint();
|
|
238
|
+
const outputNodeId = this.#readOptionalVaruint();
|
|
239
|
+
const key = this.#serialized.strings[keyIndex];
|
|
240
|
+
const root = {};
|
|
241
|
+
if (argsNodeId !== void 0) root.argsNodeId = argsNodeId;
|
|
242
|
+
if (outputNodeId !== void 0) root.outputNodeId = outputNodeId;
|
|
243
|
+
roots[key] = root;
|
|
244
|
+
}
|
|
245
|
+
return roots;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
export {
|
|
249
|
+
deserializeParamGraph,
|
|
250
|
+
serializeParamGraph
|
|
251
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|