@reallyme/codec 0.1.21 → 0.2.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/NOTICE +16 -0
- package/README.md +55 -4
- package/dist/boundary.d.ts +17 -0
- package/dist/boundary.js +277 -0
- package/dist/cbor.d.ts +67 -4
- package/dist/cbor.js +1252 -66
- package/dist/deterministicCborBoundary.d.ts +11 -0
- package/dist/deterministicCborBoundary.js +17 -0
- package/dist/index.d.ts +39 -22
- package/dist/index.js +14 -18
- package/dist/jcs.js +3 -60
- package/dist/multiformat.d.ts +10 -12
- package/dist/multiformat.js +155 -91
- package/dist/operationContract.d.ts +31 -0
- package/dist/operationContract.js +754 -0
- package/dist/pem.d.ts +2 -5
- package/dist/pem.js +265 -41
- package/dist/proto/generated/reallyme/codec/v1/codec_pb.d.ts +906 -13
- package/dist/proto/generated/reallyme/codec/v1/codec_pb.js +278 -23
- package/dist/proto.d.ts +2 -2
- package/dist/proto.js +1 -1
- package/dist/readOutput.d.ts +8 -7
- package/dist/readOutput.js +136 -22
- package/dist/wasm/reallyme_codec_wasm.d.ts +25 -140
- package/dist/wasm/reallyme_codec_wasm.js +134 -428
- package/dist/wasm/reallyme_codec_wasm_bg.wasm +0 -0
- package/dist/wasmProvider.d.ts +5 -31
- package/dist/wasmProvider.js +18 -51
- package/package.json +4 -1
|
@@ -0,0 +1,754 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import { fromBinary, toBinary } from "@bufbuild/protobuf";
|
|
5
|
+
import { MAX_CODEC_FFI_INPUT_BYTES, MAX_CODEC_PROTO_JSON_BYTES, MAX_CODEC_PROTO_MESSAGE_BYTES, requireBoundaryAggregate, strictUtf8ByteLength, utf8ByteLength, } from "./boundary.js";
|
|
6
|
+
import { DETERMINISTIC_CBOR_I64_MIN, DETERMINISTIC_CBOR_U64_MAX, MAX_DETERMINISTIC_CBOR_AGGREGATE_BYTE_STRING_BYTES, MAX_DETERMINISTIC_CBOR_AGGREGATE_TEXT_BYTES, MAX_DETERMINISTIC_CBOR_CONTAINER_ENTRIES, MAX_DETERMINISTIC_CBOR_INPUT_LEN, MAX_DETERMINISTIC_CBOR_NESTING_DEPTH, MAX_DETERMINISTIC_CBOR_NODES, MAX_DETERMINISTIC_CBOR_PROTO_RECURSION_DEPTH, } from "./deterministicCborBoundary.js";
|
|
7
|
+
import { ReallyMeCodecError } from "./errors.js";
|
|
8
|
+
import { CodecErrorOrigin, CodecErrorReason, CodecOperationResponseSchema, CodecOperationRequestSchema, } from "./proto/generated/reallyme/codec/v1/codec_pb.js";
|
|
9
|
+
import { readIndependentBoundedBytesOutput, snapshotBoundedBytesInput, } from "./readOutput.js";
|
|
10
|
+
import { requireReallyMeCodecWasmProvider } from "./wasmProvider.js";
|
|
11
|
+
const PROTO_REQUEST_OVERHEAD_BUDGET = 64;
|
|
12
|
+
const DETERMINISTIC_CBOR_PROTO_NODE_OVERHEAD_BUDGET = 16;
|
|
13
|
+
const DAG_CBOR_I64_MAX = (1n << 63n) - 1n;
|
|
14
|
+
const requireNoGeneratedUnknownFields = (message) => {
|
|
15
|
+
if (message.$unknown !== undefined && message.$unknown.length !== 0) {
|
|
16
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const hasUnknownFields = (message) => message.$unknown !== undefined && message.$unknown.length !== 0;
|
|
20
|
+
const requireProtoBytes = (value) => {
|
|
21
|
+
if (!(value instanceof Uint8Array)) {
|
|
22
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
23
|
+
}
|
|
24
|
+
return value.length;
|
|
25
|
+
};
|
|
26
|
+
const requireProtoString = (value) => {
|
|
27
|
+
if (typeof value !== "string") {
|
|
28
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
const protoUtf8Length = (value, maximum = MAX_CODEC_FFI_INPUT_BYTES) => {
|
|
33
|
+
const text = requireProtoString(value);
|
|
34
|
+
if (text.length > maximum) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
return utf8ByteLength(text);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (error instanceof ReallyMeCodecError) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const deterministicCborProtoUtf8Length = (value, maximum = MAX_DETERMINISTIC_CBOR_AGGREGATE_TEXT_BYTES) => {
|
|
48
|
+
const text = requireProtoString(value);
|
|
49
|
+
if (text.length > maximum) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
return strictUtf8ByteLength(text);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof ReallyMeCodecError) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const consumeGeneratedDeterministicCborBudget = (current, amount, maximum) => {
|
|
63
|
+
if (!Number.isSafeInteger(amount) ||
|
|
64
|
+
amount < 0 ||
|
|
65
|
+
current > maximum - amount) {
|
|
66
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
67
|
+
}
|
|
68
|
+
return current + amount;
|
|
69
|
+
};
|
|
70
|
+
const consumeGeneratedDeterministicCborText = (value, budget, lengths) => {
|
|
71
|
+
const text = requireProtoString(value);
|
|
72
|
+
if (budget.textBytes >
|
|
73
|
+
MAX_DETERMINISTIC_CBOR_AGGREGATE_TEXT_BYTES - text.length) {
|
|
74
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
75
|
+
}
|
|
76
|
+
const length = deterministicCborProtoUtf8Length(text);
|
|
77
|
+
if (length === undefined) {
|
|
78
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
79
|
+
}
|
|
80
|
+
budget.textBytes = consumeGeneratedDeterministicCborBudget(budget.textBytes, length, MAX_DETERMINISTIC_CBOR_AGGREGATE_TEXT_BYTES);
|
|
81
|
+
lengths.push(length);
|
|
82
|
+
};
|
|
83
|
+
const validateGeneratedDeterministicCborInteger = (integer) => {
|
|
84
|
+
requireNoGeneratedUnknownFields(integer);
|
|
85
|
+
switch (integer.value.case) {
|
|
86
|
+
case "unsignedValue":
|
|
87
|
+
requireNoGeneratedUnknownFields(integer.value.value);
|
|
88
|
+
if (integer.value.value.value < 0n ||
|
|
89
|
+
integer.value.value.value > DETERMINISTIC_CBOR_U64_MAX) {
|
|
90
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
91
|
+
}
|
|
92
|
+
return integer.value.value.value;
|
|
93
|
+
case "negativeValue":
|
|
94
|
+
requireNoGeneratedUnknownFields(integer.value.value);
|
|
95
|
+
if (integer.value.value.value < DETERMINISTIC_CBOR_I64_MIN ||
|
|
96
|
+
integer.value.value.value >= 0n) {
|
|
97
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
98
|
+
}
|
|
99
|
+
return integer.value.value.value;
|
|
100
|
+
case undefined:
|
|
101
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const validateGeneratedDeterministicCborMapKey = (key, budget, lengths) => {
|
|
105
|
+
if (key === undefined) {
|
|
106
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
107
|
+
}
|
|
108
|
+
requireNoGeneratedUnknownFields(key);
|
|
109
|
+
budget.nodes = consumeGeneratedDeterministicCborBudget(budget.nodes, 1, MAX_DETERMINISTIC_CBOR_NODES);
|
|
110
|
+
lengths.push(DETERMINISTIC_CBOR_PROTO_NODE_OVERHEAD_BUDGET);
|
|
111
|
+
switch (key.key.case) {
|
|
112
|
+
case "integerKey":
|
|
113
|
+
return {
|
|
114
|
+
type: "integer",
|
|
115
|
+
value: validateGeneratedDeterministicCborInteger(key.key.value),
|
|
116
|
+
};
|
|
117
|
+
case "textKey": {
|
|
118
|
+
requireNoGeneratedUnknownFields(key.key.value);
|
|
119
|
+
consumeGeneratedDeterministicCborText(key.key.value.value, budget, lengths);
|
|
120
|
+
return { type: "text", value: key.key.value.value };
|
|
121
|
+
}
|
|
122
|
+
case undefined:
|
|
123
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const validateGeneratedDeterministicCborValue = (value, depth, budget, lengths) => {
|
|
127
|
+
if (value === undefined) {
|
|
128
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
129
|
+
}
|
|
130
|
+
requireNoGeneratedUnknownFields(value);
|
|
131
|
+
budget.nodes = consumeGeneratedDeterministicCborBudget(budget.nodes, 1, MAX_DETERMINISTIC_CBOR_NODES);
|
|
132
|
+
lengths.push(DETERMINISTIC_CBOR_PROTO_NODE_OVERHEAD_BUDGET);
|
|
133
|
+
switch (value.value.case) {
|
|
134
|
+
case "nullValue":
|
|
135
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
136
|
+
break;
|
|
137
|
+
case "boolValue":
|
|
138
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
139
|
+
break;
|
|
140
|
+
case "integerValue":
|
|
141
|
+
validateGeneratedDeterministicCborInteger(value.value.value);
|
|
142
|
+
break;
|
|
143
|
+
case "textValue": {
|
|
144
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
145
|
+
consumeGeneratedDeterministicCborText(value.value.value.value, budget, lengths);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case "bytesValue": {
|
|
149
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
150
|
+
const length = requireProtoBytes(value.value.value.value);
|
|
151
|
+
budget.byteStringBytes = consumeGeneratedDeterministicCborBudget(budget.byteStringBytes, length, MAX_DETERMINISTIC_CBOR_AGGREGATE_BYTE_STRING_BYTES);
|
|
152
|
+
lengths.push(length);
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
case "arrayValue": {
|
|
156
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
157
|
+
const values = value.value.value.values;
|
|
158
|
+
if (!Array.isArray(values) ||
|
|
159
|
+
values.length > MAX_DETERMINISTIC_CBOR_CONTAINER_ENTRIES ||
|
|
160
|
+
depth >= MAX_DETERMINISTIC_CBOR_NESTING_DEPTH) {
|
|
161
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
162
|
+
}
|
|
163
|
+
for (const entry of values) {
|
|
164
|
+
validateGeneratedDeterministicCborValue(entry, depth + 1, budget, lengths);
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case "mapValue": {
|
|
169
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
170
|
+
const entries = value.value.value.entries;
|
|
171
|
+
if (!Array.isArray(entries) ||
|
|
172
|
+
entries.length > MAX_DETERMINISTIC_CBOR_CONTAINER_ENTRIES ||
|
|
173
|
+
depth >= MAX_DETERMINISTIC_CBOR_NESTING_DEPTH) {
|
|
174
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
175
|
+
}
|
|
176
|
+
const integerKeys = new Set();
|
|
177
|
+
const textKeys = new Set();
|
|
178
|
+
for (const entry of entries) {
|
|
179
|
+
requireNoGeneratedUnknownFields(entry);
|
|
180
|
+
const key = validateGeneratedDeterministicCborMapKey(entry.key, budget, lengths);
|
|
181
|
+
if (key.type === "integer") {
|
|
182
|
+
if (integerKeys.has(key.value)) {
|
|
183
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
184
|
+
}
|
|
185
|
+
integerKeys.add(key.value);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
if (textKeys.has(key.value)) {
|
|
189
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
190
|
+
}
|
|
191
|
+
textKeys.add(key.value);
|
|
192
|
+
}
|
|
193
|
+
validateGeneratedDeterministicCborValue(entry.value, depth + 1, budget, lengths);
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
case undefined:
|
|
198
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const validateGeneratedDagCborInteger = (integer) => {
|
|
202
|
+
const value = validateGeneratedDeterministicCborInteger(integer);
|
|
203
|
+
if (value > DAG_CBOR_I64_MAX) {
|
|
204
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
205
|
+
}
|
|
206
|
+
return value;
|
|
207
|
+
};
|
|
208
|
+
const validateGeneratedDagCborMapKey = (key, budget, lengths) => {
|
|
209
|
+
if (key === undefined) {
|
|
210
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
211
|
+
}
|
|
212
|
+
requireNoGeneratedUnknownFields(key);
|
|
213
|
+
budget.nodes = consumeGeneratedDeterministicCborBudget(budget.nodes, 1, MAX_DETERMINISTIC_CBOR_NODES);
|
|
214
|
+
lengths.push(DETERMINISTIC_CBOR_PROTO_NODE_OVERHEAD_BUDGET);
|
|
215
|
+
switch (key.key.case) {
|
|
216
|
+
case "textKey":
|
|
217
|
+
requireNoGeneratedUnknownFields(key.key.value);
|
|
218
|
+
consumeGeneratedDeterministicCborText(key.key.value.value, budget, lengths);
|
|
219
|
+
return key.key.value.value;
|
|
220
|
+
case "integerKey":
|
|
221
|
+
case undefined:
|
|
222
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const validateGeneratedDagCborValue = (value, depth, budget, lengths) => {
|
|
226
|
+
if (value === undefined) {
|
|
227
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
228
|
+
}
|
|
229
|
+
requireNoGeneratedUnknownFields(value);
|
|
230
|
+
budget.nodes = consumeGeneratedDeterministicCborBudget(budget.nodes, 1, MAX_DETERMINISTIC_CBOR_NODES);
|
|
231
|
+
lengths.push(DETERMINISTIC_CBOR_PROTO_NODE_OVERHEAD_BUDGET);
|
|
232
|
+
switch (value.value.case) {
|
|
233
|
+
case "nullValue":
|
|
234
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
235
|
+
break;
|
|
236
|
+
case "boolValue":
|
|
237
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
238
|
+
break;
|
|
239
|
+
case "integerValue":
|
|
240
|
+
validateGeneratedDagCborInteger(value.value.value);
|
|
241
|
+
break;
|
|
242
|
+
case "textValue":
|
|
243
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
244
|
+
consumeGeneratedDeterministicCborText(value.value.value.value, budget, lengths);
|
|
245
|
+
break;
|
|
246
|
+
case "bytesValue": {
|
|
247
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
248
|
+
const length = requireProtoBytes(value.value.value.value);
|
|
249
|
+
budget.byteStringBytes = consumeGeneratedDeterministicCborBudget(budget.byteStringBytes, length, MAX_DETERMINISTIC_CBOR_AGGREGATE_BYTE_STRING_BYTES);
|
|
250
|
+
lengths.push(length);
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
case "arrayValue": {
|
|
254
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
255
|
+
const values = value.value.value.values;
|
|
256
|
+
if (!Array.isArray(values) ||
|
|
257
|
+
values.length > MAX_DETERMINISTIC_CBOR_CONTAINER_ENTRIES ||
|
|
258
|
+
depth >= MAX_DETERMINISTIC_CBOR_NESTING_DEPTH) {
|
|
259
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
260
|
+
}
|
|
261
|
+
for (const entry of values) {
|
|
262
|
+
validateGeneratedDagCborValue(entry, depth + 1, budget, lengths);
|
|
263
|
+
}
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
case "mapValue": {
|
|
267
|
+
requireNoGeneratedUnknownFields(value.value.value);
|
|
268
|
+
const entries = value.value.value.entries;
|
|
269
|
+
if (!Array.isArray(entries) ||
|
|
270
|
+
entries.length > MAX_DETERMINISTIC_CBOR_CONTAINER_ENTRIES ||
|
|
271
|
+
depth >= MAX_DETERMINISTIC_CBOR_NESTING_DEPTH) {
|
|
272
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
273
|
+
}
|
|
274
|
+
const textKeys = new Set();
|
|
275
|
+
for (const entry of entries) {
|
|
276
|
+
requireNoGeneratedUnknownFields(entry);
|
|
277
|
+
const key = validateGeneratedDagCborMapKey(entry.key, budget, lengths);
|
|
278
|
+
if (textKeys.has(key)) {
|
|
279
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
280
|
+
}
|
|
281
|
+
textKeys.add(key);
|
|
282
|
+
validateGeneratedDagCborValue(entry.value, depth + 1, budget, lengths);
|
|
283
|
+
}
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
case undefined:
|
|
287
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
const validateGeneratedOperationRequest = (request) => {
|
|
291
|
+
requireNoGeneratedUnknownFields(request);
|
|
292
|
+
const lengths = [PROTO_REQUEST_OVERHEAD_BUDGET];
|
|
293
|
+
switch (request.operation.case) {
|
|
294
|
+
case undefined:
|
|
295
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
296
|
+
case "multicodecTable":
|
|
297
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
298
|
+
break;
|
|
299
|
+
case "multicodecPrefixForName":
|
|
300
|
+
{
|
|
301
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
302
|
+
const length = protoUtf8Length(request.operation.value.name);
|
|
303
|
+
if (length === undefined) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
if (length > MAX_CODEC_FFI_INPUT_BYTES) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
lengths.push(length);
|
|
310
|
+
}
|
|
311
|
+
break;
|
|
312
|
+
case "multicodecLookupPrefix": {
|
|
313
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
314
|
+
const length = requireProtoBytes(request.operation.value.value);
|
|
315
|
+
if (length > MAX_CODEC_FFI_INPUT_BYTES) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
lengths.push(length);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
case "multikeyParse":
|
|
322
|
+
{
|
|
323
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
324
|
+
const length = protoUtf8Length(request.operation.value.multikey);
|
|
325
|
+
if (length === undefined) {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
if (length > MAX_CODEC_FFI_INPUT_BYTES) {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
lengths.push(length);
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
case "dagCborVerifyCid":
|
|
335
|
+
{
|
|
336
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
337
|
+
const length = protoUtf8Length(request.operation.value.cid);
|
|
338
|
+
if (length === undefined) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
const payloadLength = requireProtoBytes(request.operation.value.payload);
|
|
342
|
+
try {
|
|
343
|
+
requireBoundaryAggregate([length, payloadLength], MAX_CODEC_FFI_INPUT_BYTES);
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
if (error instanceof ReallyMeCodecError) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
lengths.push(length, payloadLength);
|
|
352
|
+
}
|
|
353
|
+
break;
|
|
354
|
+
case "dagCborEncode":
|
|
355
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
356
|
+
validateGeneratedDagCborValue(request.operation.value.value, 0, { nodes: 0, textBytes: 0, byteStringBytes: 0 }, lengths);
|
|
357
|
+
break;
|
|
358
|
+
case "dagCborDecode": {
|
|
359
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
360
|
+
const length = requireProtoBytes(request.operation.value.encoded);
|
|
361
|
+
if (length > MAX_DETERMINISTIC_CBOR_INPUT_LEN) {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
lengths.push(length);
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
case "deterministicCborEncode":
|
|
368
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
369
|
+
validateGeneratedDeterministicCborValue(request.operation.value.value, 0, { nodes: 0, textBytes: 0, byteStringBytes: 0 }, lengths);
|
|
370
|
+
break;
|
|
371
|
+
case "deterministicCborDecode": {
|
|
372
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
373
|
+
const length = requireProtoBytes(request.operation.value.encoded);
|
|
374
|
+
if (length > MAX_DETERMINISTIC_CBOR_INPUT_LEN) {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
lengths.push(length);
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
case "pemDecode": {
|
|
381
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
382
|
+
const pemLength = requireProtoBytes(request.operation.value.pem);
|
|
383
|
+
const options = request.operation.value.options;
|
|
384
|
+
let optionsLength = 0;
|
|
385
|
+
if (options !== undefined) {
|
|
386
|
+
requireNoGeneratedUnknownFields(options);
|
|
387
|
+
if (!Array.isArray(options.allowedLabels)) {
|
|
388
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
389
|
+
}
|
|
390
|
+
if (options.allowedLabels.length > MAX_CODEC_PROTO_MESSAGE_BYTES / 5) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
optionsLength = options.allowedLabels.length * 5;
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
requireBoundaryAggregate([pemLength, optionsLength], MAX_CODEC_FFI_INPUT_BYTES);
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
if (error instanceof ReallyMeCodecError) {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
throw error;
|
|
403
|
+
}
|
|
404
|
+
lengths.push(pemLength, optionsLength);
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
case "pemEncode": {
|
|
408
|
+
requireNoGeneratedUnknownFields(request.operation.value);
|
|
409
|
+
const derLength = requireProtoBytes(request.operation.value.der);
|
|
410
|
+
const options = request.operation.value.options;
|
|
411
|
+
if (options !== undefined) {
|
|
412
|
+
requireNoGeneratedUnknownFields(options);
|
|
413
|
+
}
|
|
414
|
+
try {
|
|
415
|
+
requireBoundaryAggregate([derLength], MAX_CODEC_FFI_INPUT_BYTES);
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
if (error instanceof ReallyMeCodecError) {
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
throw error;
|
|
422
|
+
}
|
|
423
|
+
lengths.push(derLength);
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
default:
|
|
427
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
428
|
+
}
|
|
429
|
+
try {
|
|
430
|
+
requireBoundaryAggregate(lengths, MAX_CODEC_PROTO_MESSAGE_BYTES);
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
if (error instanceof ReallyMeCodecError) {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
throw error;
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
/**
|
|
441
|
+
* Execute one binary generated-protobuf request and return the fully
|
|
442
|
+
* discriminated binary `CodecOperationResponse`.
|
|
443
|
+
*
|
|
444
|
+
* Oversized requests are rejected before the provider call. Malformed and
|
|
445
|
+
* unsupported in-limit requests are represented by the response error oneof
|
|
446
|
+
* rather than a boundary-local exception.
|
|
447
|
+
*/
|
|
448
|
+
export const processOperation = (requestBytes) => {
|
|
449
|
+
const requestSnapshot = snapshotBoundedBytesInput(requestBytes, MAX_CODEC_PROTO_MESSAGE_BYTES);
|
|
450
|
+
try {
|
|
451
|
+
return readIndependentBoundedBytesOutput(requireReallyMeCodecWasmProvider().processOperation(requestSnapshot), requestSnapshot, MAX_CODEC_PROTO_MESSAGE_BYTES);
|
|
452
|
+
}
|
|
453
|
+
finally {
|
|
454
|
+
requestSnapshot.fill(0);
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
/**
|
|
458
|
+
* Execute one generated ProtoJSON request and return the same discriminated
|
|
459
|
+
* binary response used by `processOperation`.
|
|
460
|
+
*/
|
|
461
|
+
export const processOperationJson = (requestJson) => {
|
|
462
|
+
const requestSnapshot = snapshotBoundedBytesInput(requestJson, MAX_CODEC_PROTO_JSON_BYTES);
|
|
463
|
+
try {
|
|
464
|
+
return readIndependentBoundedBytesOutput(requireReallyMeCodecWasmProvider().processOperationJson(requestSnapshot), requestSnapshot, MAX_CODEC_PROTO_MESSAGE_BYTES);
|
|
465
|
+
}
|
|
466
|
+
finally {
|
|
467
|
+
requestSnapshot.fill(0);
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
/**
|
|
471
|
+
* Execute a generated request through the fully discriminated response lane.
|
|
472
|
+
*
|
|
473
|
+
* Structured convenience methods use this boundary so a provider cannot
|
|
474
|
+
* return a valid payload of the wrong operation-specific result type.
|
|
475
|
+
*/
|
|
476
|
+
export const processGeneratedOperationRequest = (request) => {
|
|
477
|
+
let withinBoundary;
|
|
478
|
+
try {
|
|
479
|
+
withinBoundary = validateGeneratedOperationRequest(request);
|
|
480
|
+
}
|
|
481
|
+
catch (error) {
|
|
482
|
+
if (error instanceof ReallyMeCodecError) {
|
|
483
|
+
throw error;
|
|
484
|
+
}
|
|
485
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
486
|
+
}
|
|
487
|
+
if (!withinBoundary) {
|
|
488
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
489
|
+
}
|
|
490
|
+
let requestBytes;
|
|
491
|
+
try {
|
|
492
|
+
requestBytes = toBinary(CodecOperationRequestSchema, request);
|
|
493
|
+
}
|
|
494
|
+
catch (_error) {
|
|
495
|
+
throw new ReallyMeCodecError("provider-failure");
|
|
496
|
+
}
|
|
497
|
+
try {
|
|
498
|
+
if (requestBytes.length > MAX_CODEC_PROTO_MESSAGE_BYTES) {
|
|
499
|
+
throw new ReallyMeCodecError("invalid-input");
|
|
500
|
+
}
|
|
501
|
+
const responseBytes = processOperation(requestBytes);
|
|
502
|
+
try {
|
|
503
|
+
const response = fromBinary(CodecOperationResponseSchema, responseBytes, {
|
|
504
|
+
readUnknownFields: true,
|
|
505
|
+
recursionLimit: MAX_DETERMINISTIC_CBOR_PROTO_RECURSION_DEPTH,
|
|
506
|
+
});
|
|
507
|
+
if (hasUnknownFields(response)) {
|
|
508
|
+
throw new ReallyMeCodecError("provider-failure");
|
|
509
|
+
}
|
|
510
|
+
switch (response.outcome.case) {
|
|
511
|
+
case "result":
|
|
512
|
+
if (hasUnknownFields(response.outcome.value)) {
|
|
513
|
+
clearGeneratedOperationResult(response.outcome.value);
|
|
514
|
+
throw new ReallyMeCodecError("provider-failure");
|
|
515
|
+
}
|
|
516
|
+
try {
|
|
517
|
+
detachGeneratedOperationResultBytes(response.outcome.value);
|
|
518
|
+
}
|
|
519
|
+
catch (_error) {
|
|
520
|
+
// Detachment can allocate recursively. If an allocation or a
|
|
521
|
+
// future generated-shape invariant fails after only some fields
|
|
522
|
+
// were detached, clear both the detached owners and any remaining
|
|
523
|
+
// views before the serialized response owner is wiped below.
|
|
524
|
+
clearGeneratedOperationResult(response.outcome.value);
|
|
525
|
+
throw new ReallyMeCodecError("provider-failure");
|
|
526
|
+
}
|
|
527
|
+
return response.outcome.value;
|
|
528
|
+
case "error":
|
|
529
|
+
throw new ReallyMeCodecError(errorCodeForCodecErrorMessage(response.outcome.value));
|
|
530
|
+
case undefined:
|
|
531
|
+
throw new ReallyMeCodecError("provider-failure");
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
if (error instanceof ReallyMeCodecError) {
|
|
536
|
+
throw error;
|
|
537
|
+
}
|
|
538
|
+
throw new ReallyMeCodecError("provider-failure");
|
|
539
|
+
}
|
|
540
|
+
finally {
|
|
541
|
+
responseBytes.fill(0);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
finally {
|
|
545
|
+
requestBytes.fill(0);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
// Buf's binary decoder may expose byte fields as views into the serialized
|
|
549
|
+
// response owner. Detach every byte field before that owner is wiped so the
|
|
550
|
+
// returned generated result remains valid and has independent cleanup.
|
|
551
|
+
const detachGeneratedOperationResultBytes = (result) => {
|
|
552
|
+
switch (result.result.case) {
|
|
553
|
+
case "multicodecPrefixForName":
|
|
554
|
+
result.result.value.prefix = result.result.value.prefix.slice();
|
|
555
|
+
break;
|
|
556
|
+
case "multicodecLookupPrefix":
|
|
557
|
+
if (result.result.value.metadata !== undefined) {
|
|
558
|
+
result.result.value.metadata.prefix =
|
|
559
|
+
result.result.value.metadata.prefix.slice();
|
|
560
|
+
}
|
|
561
|
+
break;
|
|
562
|
+
case "multicodecTable":
|
|
563
|
+
for (const entry of result.result.value.entries) {
|
|
564
|
+
entry.prefix = entry.prefix.slice();
|
|
565
|
+
}
|
|
566
|
+
break;
|
|
567
|
+
case "multikeyParse":
|
|
568
|
+
result.result.value.publicKey = result.result.value.publicKey.slice();
|
|
569
|
+
break;
|
|
570
|
+
case "dagCborVerifyCid":
|
|
571
|
+
break;
|
|
572
|
+
case "dagCborEncode":
|
|
573
|
+
result.result.value.encoded = result.result.value.encoded.slice();
|
|
574
|
+
break;
|
|
575
|
+
case "dagCborDecode":
|
|
576
|
+
detachGeneratedCborValueBytes(result.result.value.value);
|
|
577
|
+
break;
|
|
578
|
+
case "pemDecode":
|
|
579
|
+
result.result.value.der = result.result.value.der.slice();
|
|
580
|
+
break;
|
|
581
|
+
case "pemEncode":
|
|
582
|
+
result.result.value.pem = result.result.value.pem.slice();
|
|
583
|
+
break;
|
|
584
|
+
case "deterministicCborEncode":
|
|
585
|
+
result.result.value.encoded = result.result.value.encoded.slice();
|
|
586
|
+
break;
|
|
587
|
+
case "deterministicCborDecode":
|
|
588
|
+
detachGeneratedCborValueBytes(result.result.value.value);
|
|
589
|
+
break;
|
|
590
|
+
case undefined:
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
const detachGeneratedCborValueBytes = (value) => {
|
|
595
|
+
if (value === undefined) {
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
switch (value.value.case) {
|
|
599
|
+
case "bytesValue":
|
|
600
|
+
value.value.value.value = value.value.value.value.slice();
|
|
601
|
+
break;
|
|
602
|
+
case "arrayValue":
|
|
603
|
+
for (const child of value.value.value.values) {
|
|
604
|
+
detachGeneratedCborValueBytes(child);
|
|
605
|
+
}
|
|
606
|
+
break;
|
|
607
|
+
case "mapValue":
|
|
608
|
+
for (const entry of value.value.value.entries) {
|
|
609
|
+
detachGeneratedCborValueBytes(entry.value);
|
|
610
|
+
}
|
|
611
|
+
break;
|
|
612
|
+
case "nullValue":
|
|
613
|
+
case "boolValue":
|
|
614
|
+
case "integerValue":
|
|
615
|
+
case "textValue":
|
|
616
|
+
case undefined:
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
/**
|
|
621
|
+
* Clears mutable byte owners held by a generated operation result.
|
|
622
|
+
*
|
|
623
|
+
* Callers invoke this before rejecting an unexpected valid oneof variant and
|
|
624
|
+
* after copying a sensitive result into its public SDK owner. JavaScript
|
|
625
|
+
* strings remain subject to the managed-runtime memory model, but every
|
|
626
|
+
* mutable `Uint8Array` created by this adapter is released promptly.
|
|
627
|
+
*/
|
|
628
|
+
export const clearGeneratedOperationResult = (result) => {
|
|
629
|
+
switch (result.result.case) {
|
|
630
|
+
case "multicodecPrefixForName":
|
|
631
|
+
result.result.value.prefix.fill(0);
|
|
632
|
+
break;
|
|
633
|
+
case "multicodecLookupPrefix":
|
|
634
|
+
result.result.value.metadata?.prefix.fill(0);
|
|
635
|
+
break;
|
|
636
|
+
case "multicodecTable":
|
|
637
|
+
for (const entry of result.result.value.entries) {
|
|
638
|
+
entry.prefix.fill(0);
|
|
639
|
+
}
|
|
640
|
+
break;
|
|
641
|
+
case "multikeyParse":
|
|
642
|
+
result.result.value.publicKey.fill(0);
|
|
643
|
+
break;
|
|
644
|
+
case "dagCborVerifyCid":
|
|
645
|
+
break;
|
|
646
|
+
case "dagCborEncode":
|
|
647
|
+
result.result.value.encoded.fill(0);
|
|
648
|
+
break;
|
|
649
|
+
case "dagCborDecode":
|
|
650
|
+
wipeGeneratedCborValue(result.result.value.value);
|
|
651
|
+
break;
|
|
652
|
+
case "pemDecode":
|
|
653
|
+
result.result.value.der.fill(0);
|
|
654
|
+
break;
|
|
655
|
+
case "pemEncode":
|
|
656
|
+
result.result.value.pem.fill(0);
|
|
657
|
+
break;
|
|
658
|
+
case "deterministicCborEncode":
|
|
659
|
+
result.result.value.encoded.fill(0);
|
|
660
|
+
break;
|
|
661
|
+
case "deterministicCborDecode":
|
|
662
|
+
wipeGeneratedCborValue(result.result.value.value);
|
|
663
|
+
break;
|
|
664
|
+
case undefined:
|
|
665
|
+
break;
|
|
666
|
+
}
|
|
667
|
+
result.result = { case: undefined };
|
|
668
|
+
};
|
|
669
|
+
const wipeGeneratedCborValue = (value) => {
|
|
670
|
+
if (value === undefined) {
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
switch (value.value.case) {
|
|
674
|
+
case "bytesValue":
|
|
675
|
+
value.value.value.value.fill(0);
|
|
676
|
+
break;
|
|
677
|
+
case "arrayValue":
|
|
678
|
+
for (const child of value.value.value.values) {
|
|
679
|
+
wipeGeneratedCborValue(child);
|
|
680
|
+
}
|
|
681
|
+
break;
|
|
682
|
+
case "mapValue":
|
|
683
|
+
for (const entry of value.value.value.entries) {
|
|
684
|
+
wipeGeneratedCborValue(entry.value);
|
|
685
|
+
}
|
|
686
|
+
break;
|
|
687
|
+
case "nullValue":
|
|
688
|
+
case "boolValue":
|
|
689
|
+
case "integerValue":
|
|
690
|
+
case "textValue":
|
|
691
|
+
case undefined:
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
value.value = { case: undefined };
|
|
695
|
+
};
|
|
696
|
+
const errorCodeForCodecErrorMessage = (error) => {
|
|
697
|
+
if (hasUnknownFields(error) ||
|
|
698
|
+
(error.error.value !== undefined && hasUnknownFields(error.error.value))) {
|
|
699
|
+
return "provider-failure";
|
|
700
|
+
}
|
|
701
|
+
const reason = error.error.value?.reason;
|
|
702
|
+
// Protobuf enums are open on the wire; generated decoders can preserve
|
|
703
|
+
// numeric values that this SDK version does not understand. Treat those as
|
|
704
|
+
// provider failures so unknown future reasons never downgrade to caller
|
|
705
|
+
// input errors.
|
|
706
|
+
const reasonIsKnown = reason !== undefined &&
|
|
707
|
+
Object.values(CodecErrorReason).some((candidate) => candidate === reason);
|
|
708
|
+
if (!reasonIsKnown) {
|
|
709
|
+
return "provider-failure";
|
|
710
|
+
}
|
|
711
|
+
let expectedOrigin;
|
|
712
|
+
switch (error.error.case) {
|
|
713
|
+
case "baseEncoding":
|
|
714
|
+
if (reason < 100 || reason > 199)
|
|
715
|
+
return "provider-failure";
|
|
716
|
+
expectedOrigin = CodecErrorOrigin.CALLER;
|
|
717
|
+
break;
|
|
718
|
+
case "pem":
|
|
719
|
+
if (reason < 200 || reason > 299)
|
|
720
|
+
return "provider-failure";
|
|
721
|
+
expectedOrigin = CodecErrorOrigin.CALLER;
|
|
722
|
+
break;
|
|
723
|
+
case "multiformat":
|
|
724
|
+
if (reason < 300 || reason > 399)
|
|
725
|
+
return "provider-failure";
|
|
726
|
+
expectedOrigin = CodecErrorOrigin.CALLER;
|
|
727
|
+
break;
|
|
728
|
+
case "canonicalization":
|
|
729
|
+
if (reason < 400 || reason > 499)
|
|
730
|
+
return "provider-failure";
|
|
731
|
+
expectedOrigin = reason === CodecErrorReason.CANONICAL_INTERNAL
|
|
732
|
+
? CodecErrorOrigin.PROVIDER
|
|
733
|
+
: CodecErrorOrigin.CALLER;
|
|
734
|
+
break;
|
|
735
|
+
case "backend":
|
|
736
|
+
if (reason < 500 || reason > 599)
|
|
737
|
+
return "provider-failure";
|
|
738
|
+
expectedOrigin = CodecErrorOrigin.PROVIDER;
|
|
739
|
+
break;
|
|
740
|
+
case "boundary":
|
|
741
|
+
if (reason < 600 || reason > 699)
|
|
742
|
+
return "provider-failure";
|
|
743
|
+
expectedOrigin = CodecErrorOrigin.CALLER;
|
|
744
|
+
break;
|
|
745
|
+
case undefined:
|
|
746
|
+
return "provider-failure";
|
|
747
|
+
}
|
|
748
|
+
if (error.origin !== expectedOrigin) {
|
|
749
|
+
return "provider-failure";
|
|
750
|
+
}
|
|
751
|
+
return error.origin === CodecErrorOrigin.CALLER
|
|
752
|
+
? "invalid-input"
|
|
753
|
+
: "provider-failure";
|
|
754
|
+
};
|