@reallyme/codec 0.1.22 → 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.
@@ -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
+ };