@reallyme/codec 0.1.22 → 0.2.1

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.
@@ -1,282 +0,0 @@
1
- // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
- //
3
- // SPDX-License-Identifier: Apache-2.0
4
- import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
5
- import { MAX_CODEC_PROTO_JSON_BYTES, MAX_CODEC_PROTO_MESSAGE_BYTES, requireBoundaryAggregate, utf8ByteLength, } from "./boundary.js";
6
- import { ReallyMeCodecError } from "./errors.js";
7
- import { CodecBoundaryErrorSchema, CodecErrorReason, CodecErrorSchema, CodecOperationRequestSchema, CodecProtoResultEnvelopeSchema, CodecProtoResultStatus, } from "./proto/generated/reallyme/codec/v1/codec_pb.js";
8
- import { ensureBytesInput, readIndependentBoundedBytesOutput, } from "./readOutput.js";
9
- import { requireReallyMeCodecWasmProvider } from "./wasmProvider.js";
10
- const MAX_CODEC_PROTO_RESULT_ENVELOPE_BYTES = 1_048_592;
11
- const PROTO_REQUEST_OVERHEAD_BUDGET = 64;
12
- const requireProtoBytes = (value) => {
13
- if (!(value instanceof Uint8Array)) {
14
- throw new ReallyMeCodecError("invalid-input");
15
- }
16
- return value.length;
17
- };
18
- const requireProtoString = (value) => {
19
- if (typeof value !== "string") {
20
- throw new ReallyMeCodecError("invalid-input");
21
- }
22
- return value;
23
- };
24
- const protoUtf8Length = (value) => {
25
- const text = requireProtoString(value);
26
- try {
27
- return utf8ByteLength(text);
28
- }
29
- catch (error) {
30
- if (error instanceof ReallyMeCodecError) {
31
- return undefined;
32
- }
33
- throw error;
34
- }
35
- };
36
- const validateGeneratedProtoRequest = (request) => {
37
- const lengths = [PROTO_REQUEST_OVERHEAD_BUDGET];
38
- switch (request.operation.case) {
39
- case undefined:
40
- case "multicodecTable":
41
- break;
42
- case "multicodecPrefixForName":
43
- {
44
- const length = protoUtf8Length(request.operation.value.name);
45
- if (length === undefined) {
46
- return false;
47
- }
48
- lengths.push(length);
49
- }
50
- break;
51
- case "multicodecLookupPrefix":
52
- lengths.push(requireProtoBytes(request.operation.value.value));
53
- break;
54
- case "multikeyParse":
55
- {
56
- const length = protoUtf8Length(request.operation.value.multikey);
57
- if (length === undefined) {
58
- return false;
59
- }
60
- lengths.push(length);
61
- }
62
- break;
63
- case "dagCborVerifyCid":
64
- {
65
- const length = protoUtf8Length(request.operation.value.cid);
66
- if (length === undefined) {
67
- return false;
68
- }
69
- lengths.push(length);
70
- }
71
- lengths.push(requireProtoBytes(request.operation.value.payload));
72
- break;
73
- case "pemDecode": {
74
- lengths.push(requireProtoBytes(request.operation.value.pem));
75
- const options = request.operation.value.options;
76
- if (options !== undefined) {
77
- if (!Array.isArray(options.allowedLabels)) {
78
- throw new ReallyMeCodecError("invalid-input");
79
- }
80
- if (options.allowedLabels.length > MAX_CODEC_PROTO_MESSAGE_BYTES / 5) {
81
- return false;
82
- }
83
- lengths.push(options.allowedLabels.length * 5);
84
- }
85
- break;
86
- }
87
- default:
88
- throw new ReallyMeCodecError("invalid-input");
89
- }
90
- try {
91
- requireBoundaryAggregate(lengths, MAX_CODEC_PROTO_MESSAGE_BYTES);
92
- return true;
93
- }
94
- catch (error) {
95
- if (error instanceof ReallyMeCodecError) {
96
- return false;
97
- }
98
- throw error;
99
- }
100
- };
101
- const boundaryResourceLimitResult = () => {
102
- try {
103
- return {
104
- status: "codec-error",
105
- bytes: toBinary(CodecErrorSchema, create(CodecErrorSchema, {
106
- error: {
107
- case: "boundary",
108
- value: create(CodecBoundaryErrorSchema, {
109
- reason: CodecErrorReason.BOUNDARY_RESOURCE_LIMIT_EXCEEDED,
110
- }),
111
- },
112
- })),
113
- isCodecError: true,
114
- };
115
- }
116
- catch (_error) {
117
- throw new ReallyMeCodecError("provider-failure");
118
- }
119
- };
120
- const boundaryResourceLimitEnvelope = () => {
121
- const result = boundaryResourceLimitResult();
122
- try {
123
- return toBinary(CodecProtoResultEnvelopeSchema, create(CodecProtoResultEnvelopeSchema, {
124
- status: CodecProtoResultStatus.CODEC_ERROR,
125
- payload: result.bytes,
126
- }));
127
- }
128
- catch (_error) {
129
- throw new ReallyMeCodecError("provider-failure");
130
- }
131
- finally {
132
- result.bytes.fill(0);
133
- }
134
- };
135
- const decodeResultEnvelope = (envelopeBytes) => {
136
- try {
137
- const envelope = fromBinary(CodecProtoResultEnvelopeSchema, envelopeBytes);
138
- try {
139
- switch (envelope.status) {
140
- case CodecProtoResultStatus.RESULT:
141
- return {
142
- status: "result",
143
- bytes: envelope.payload.slice(),
144
- isCodecError: false,
145
- };
146
- case CodecProtoResultStatus.CODEC_ERROR:
147
- return {
148
- status: "codec-error",
149
- bytes: envelope.payload.slice(),
150
- isCodecError: true,
151
- };
152
- case CodecProtoResultStatus.UNSPECIFIED:
153
- throw new ReallyMeCodecError("provider-failure");
154
- }
155
- }
156
- finally {
157
- envelope.payload.fill(0);
158
- }
159
- }
160
- catch (error) {
161
- if (error instanceof ReallyMeCodecError) {
162
- throw error;
163
- }
164
- throw new ReallyMeCodecError("provider-failure");
165
- }
166
- };
167
- /**
168
- * Execute one binary generated-protobuf request.
169
- *
170
- * The returned bytes are always a `CodecProtoResultEnvelope`; malformed or
171
- * unsupported requests are represented inside that envelope.
172
- */
173
- export const processProto = (requestBytes) => {
174
- ensureBytesInput(requestBytes);
175
- if (requestBytes.length > MAX_CODEC_PROTO_MESSAGE_BYTES) {
176
- return boundaryResourceLimitEnvelope();
177
- }
178
- return readIndependentBoundedBytesOutput(requireReallyMeCodecWasmProvider().processProto(requestBytes), requestBytes, MAX_CODEC_PROTO_RESULT_ENVELOPE_BYTES);
179
- };
180
- /**
181
- * Execute one generated ProtoJSON request and return the same binary envelope
182
- * used by `processProto`.
183
- */
184
- export const processProtoJson = (requestJson) => {
185
- ensureBytesInput(requestJson);
186
- if (requestJson.length > MAX_CODEC_PROTO_JSON_BYTES) {
187
- return boundaryResourceLimitEnvelope();
188
- }
189
- return readIndependentBoundedBytesOutput(requireReallyMeCodecWasmProvider().processProtoJson(requestJson), requestJson, MAX_CODEC_PROTO_RESULT_ENVELOPE_BYTES);
190
- };
191
- export const processGeneratedProtoRequest = (request) => {
192
- let withinBoundary;
193
- try {
194
- withinBoundary = validateGeneratedProtoRequest(request);
195
- }
196
- catch (error) {
197
- if (error instanceof ReallyMeCodecError) {
198
- throw error;
199
- }
200
- throw new ReallyMeCodecError("invalid-input");
201
- }
202
- if (!withinBoundary) {
203
- return boundaryResourceLimitResult();
204
- }
205
- let requestBytes;
206
- try {
207
- requestBytes = toBinary(CodecOperationRequestSchema, request);
208
- }
209
- catch (_error) {
210
- throw new ReallyMeCodecError("provider-failure");
211
- }
212
- try {
213
- if (requestBytes.length > MAX_CODEC_PROTO_MESSAGE_BYTES) {
214
- throw new ReallyMeCodecError("invalid-input");
215
- }
216
- const envelopeBytes = processProto(requestBytes);
217
- try {
218
- return decodeResultEnvelope(envelopeBytes);
219
- }
220
- finally {
221
- envelopeBytes.fill(0);
222
- }
223
- }
224
- finally {
225
- requestBytes.fill(0);
226
- }
227
- };
228
- const errorCodeForCodecError = (bytes) => {
229
- let error;
230
- try {
231
- error = fromBinary(CodecErrorSchema, bytes);
232
- }
233
- catch (_error) {
234
- return "provider-failure";
235
- }
236
- const reason = error.error.value?.reason;
237
- const reasonIsKnown = reason !== undefined &&
238
- Object.values(CodecErrorReason).some((candidate) => candidate === reason);
239
- if (!reasonIsKnown) {
240
- return "provider-failure";
241
- }
242
- switch (error.error.case) {
243
- case "baseEncoding":
244
- return reason >= 100 && reason <= 199
245
- ? "invalid-input"
246
- : "provider-failure";
247
- case "pem":
248
- return reason >= 200 && reason <= 299
249
- ? "invalid-input"
250
- : "provider-failure";
251
- case "multiformat":
252
- return reason >= 300 && reason <= 399
253
- ? "invalid-input"
254
- : "provider-failure";
255
- case "canonicalization":
256
- if (reason === CodecErrorReason.CANONICAL_INTERNAL) {
257
- return "provider-failure";
258
- }
259
- return reason >= 400 && reason <= 499
260
- ? "invalid-input"
261
- : "provider-failure";
262
- case "backend":
263
- return "provider-failure";
264
- case "boundary":
265
- // This is the only boundary error the generated facade creates from
266
- // caller input. Malformed/missing generated requests indicate provider
267
- // corruption or skew, not bad input supplied to the high-level API.
268
- return reason === CodecErrorReason.BOUNDARY_RESOURCE_LIMIT_EXCEEDED
269
- ? "invalid-input"
270
- : "provider-failure";
271
- case undefined:
272
- return "provider-failure";
273
- }
274
- };
275
- export const protoPayloadOrThrow = (result) => {
276
- if (result.isCodecError) {
277
- const code = errorCodeForCodecError(result.bytes);
278
- result.bytes.fill(0);
279
- throw new ReallyMeCodecError(code);
280
- }
281
- return result.bytes;
282
- };