@blamejs/core 0.12.5 → 0.12.7
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/CHANGELOG.md +4 -0
- package/README.md +1 -1
- package/index.js +15 -1
- package/lib/archive-adapters.js +629 -0
- package/lib/archive-read.js +781 -0
- package/lib/archive.js +12 -0
- package/lib/backup/index.js +245 -0
- package/lib/guard-archive.js +140 -0
- package/lib/guard-filename.js +205 -0
- package/lib/observability-otlp-exporter.js +245 -3
- package/lib/protobuf-encoder.js +87 -9
- package/lib/safe-archive.js +275 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
|
@@ -36,6 +36,7 @@ var safeAsync = require("./safe-async");
|
|
|
36
36
|
var safeBuffer = require("./safe-buffer");
|
|
37
37
|
var validateOpts = require("./validate-opts");
|
|
38
38
|
var safeUrl = require("./safe-url");
|
|
39
|
+
var pb = require("./protobuf-encoder");
|
|
39
40
|
var { defineClass } = require("./framework-error");
|
|
40
41
|
|
|
41
42
|
var OtlpExporterError = defineClass("OtlpExporterError", { alwaysPermanent: true });
|
|
@@ -189,6 +190,221 @@ function _bundleSpans(spans) {
|
|
|
189
190
|
return { resourceSpans: resourceSpans };
|
|
190
191
|
}
|
|
191
192
|
|
|
193
|
+
// ---- OTLP/protobuf encoder ------------------------------------------------
|
|
194
|
+
//
|
|
195
|
+
// OTLP §3 — `application/x-protobuf` body shape per the
|
|
196
|
+
// opentelemetry-proto repo's ExportTraceServiceRequest message.
|
|
197
|
+
//
|
|
198
|
+
// Wire-format encoding composes b.protobufEncoder. Fields are:
|
|
199
|
+
//
|
|
200
|
+
// ExportTraceServiceRequest {
|
|
201
|
+
// repeated ResourceSpans resource_spans = 1;
|
|
202
|
+
// }
|
|
203
|
+
// ResourceSpans {
|
|
204
|
+
// Resource resource = 1;
|
|
205
|
+
// repeated ScopeSpans scope_spans = 2;
|
|
206
|
+
// string schema_url = 3;
|
|
207
|
+
// }
|
|
208
|
+
// Resource {
|
|
209
|
+
// repeated KeyValue attributes = 1;
|
|
210
|
+
// uint32 dropped_attributes_count = 2;
|
|
211
|
+
// }
|
|
212
|
+
// ScopeSpans {
|
|
213
|
+
// InstrumentationScope scope = 1;
|
|
214
|
+
// repeated Span spans = 2;
|
|
215
|
+
// string schema_url = 3;
|
|
216
|
+
// }
|
|
217
|
+
// InstrumentationScope { string name = 1; string version = 2; ... }
|
|
218
|
+
// Span {
|
|
219
|
+
// bytes trace_id = 1; // 16 bytes
|
|
220
|
+
// bytes span_id = 2; // 8 bytes
|
|
221
|
+
// string trace_state = 3;
|
|
222
|
+
// bytes parent_span_id = 4; // 8 bytes or empty
|
|
223
|
+
// string name = 5;
|
|
224
|
+
// SpanKind kind = 6; // enum 0..5
|
|
225
|
+
// fixed64 start_time_unix_nano = 7;
|
|
226
|
+
// fixed64 end_time_unix_nano = 8;
|
|
227
|
+
// repeated KeyValue attributes = 9;
|
|
228
|
+
// uint32 dropped_attributes_count = 10;
|
|
229
|
+
// repeated Event events = 11;
|
|
230
|
+
// uint32 dropped_events_count = 12;
|
|
231
|
+
// repeated Link links = 13;
|
|
232
|
+
// uint32 dropped_links_count = 14;
|
|
233
|
+
// Status status = 15;
|
|
234
|
+
// }
|
|
235
|
+
// Event { fixed64 time_unix_nano = 1; string name = 2; repeated KeyValue attributes = 3; uint32 dropped_attributes_count = 4; }
|
|
236
|
+
// Status { string message = 2; enum code = 3; } // field 1 reserved
|
|
237
|
+
// KeyValue { string key = 1; AnyValue value = 2; }
|
|
238
|
+
// AnyValue {
|
|
239
|
+
// oneof value {
|
|
240
|
+
// string string_value = 1;
|
|
241
|
+
// bool bool_value = 2;
|
|
242
|
+
// int64 int_value = 3;
|
|
243
|
+
// double double_value = 4;
|
|
244
|
+
// ArrayValue array_value = 5;
|
|
245
|
+
// }
|
|
246
|
+
// }
|
|
247
|
+
// ArrayValue { repeated AnyValue values = 1; }
|
|
248
|
+
//
|
|
249
|
+
// AnyValue recursion is capped at MAX_ANYVALUE_DEPTH to defend the
|
|
250
|
+
// CVE-2024-7254 + CVE-2025-4565 protobuf nested-group DoS class.
|
|
251
|
+
|
|
252
|
+
var MAX_ANYVALUE_DEPTH = 100; // allow:raw-byte-literal — protobuf nested-message DoS cap
|
|
253
|
+
|
|
254
|
+
function _hexToBytes(hex) {
|
|
255
|
+
if (typeof hex !== "string" || hex.length === 0) return Buffer.alloc(0);
|
|
256
|
+
// Tolerate odd-length hex by left-padding with zero; OTLP spec
|
|
257
|
+
// requires fixed lengths but the exporter should not crash a request
|
|
258
|
+
// with a malformed inbound trace_id — drop-silent and emit empty.
|
|
259
|
+
if (hex.length % 2 !== 0) return Buffer.alloc(0);
|
|
260
|
+
var out = Buffer.alloc(hex.length / 2);
|
|
261
|
+
for (var i = 0; i < hex.length; i += 2) {
|
|
262
|
+
var byte = parseInt(hex.substr(i, 2), 16); // allow:raw-byte-literal — radix=16 for hex parse, not byte count
|
|
263
|
+
if (!isFinite(byte)) return Buffer.alloc(0);
|
|
264
|
+
out[i / 2] = byte;
|
|
265
|
+
}
|
|
266
|
+
return out;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
var KIND_TEXT_TO_ENUM = {
|
|
270
|
+
unspecified: 0, internal: 1, server: 2, client: 3, producer: 4, consumer: 5,
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
function _anyValueToProto(v, depth) {
|
|
274
|
+
if (depth >= MAX_ANYVALUE_DEPTH) {
|
|
275
|
+
// Refuse to descend further; emit empty AnyValue. Matches the spec's
|
|
276
|
+
// "unknown wire type" tolerant-parser behaviour on the receive side.
|
|
277
|
+
return Buffer.alloc(0);
|
|
278
|
+
}
|
|
279
|
+
var t = typeof v;
|
|
280
|
+
if (t === "string") return pb.string(1, v);
|
|
281
|
+
if (t === "boolean") return pb.bool(2, v);
|
|
282
|
+
if (t === "number") {
|
|
283
|
+
if (Number.isInteger(v)) {
|
|
284
|
+
// OTLP AnyValue field 3 is proto int64 — wire-type 0 varint, NOT
|
|
285
|
+
// length-delimited. Negatives encode as the 64-bit two's-complement
|
|
286
|
+
// reinterpret-cast (10-byte varint per the spec). Composes
|
|
287
|
+
// `pb.int64` which carries the BigInt conversion + range check so
|
|
288
|
+
// a negative attribute value (e.g. retry-after offset, signed
|
|
289
|
+
// metric delta) doesn't poison the whole batch.
|
|
290
|
+
return pb.int64(3, v);
|
|
291
|
+
}
|
|
292
|
+
return pb.double(4, v);
|
|
293
|
+
}
|
|
294
|
+
if (Array.isArray(v)) {
|
|
295
|
+
var items = new Array(v.length);
|
|
296
|
+
for (var i = 0; i < v.length; i += 1) {
|
|
297
|
+
items[i] = _anyValueToProto(v[i], depth + 1);
|
|
298
|
+
}
|
|
299
|
+
var arrayInner = pb.repeatedMessage(1, items, function (b) { return b; });
|
|
300
|
+
return pb.embeddedMessage(5, arrayInner);
|
|
301
|
+
}
|
|
302
|
+
// Unknown → coerce to string per the JSON path's behaviour.
|
|
303
|
+
return pb.string(1, String(v));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function _keyValueToProto(kvObj) {
|
|
307
|
+
// kvObj is { key, value: <plain-js> } from _attrToOtlp — but we
|
|
308
|
+
// re-derive directly here so the protobuf path doesn't depend on
|
|
309
|
+
// the JSON-shaped intermediate.
|
|
310
|
+
return Buffer.concat([
|
|
311
|
+
pb.string(1, kvObj.key),
|
|
312
|
+
pb.embeddedMessage(2, _anyValueToProto(kvObj.rawValue, 0)),
|
|
313
|
+
]);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function _attrsToProto(attrs) {
|
|
317
|
+
// attrs is the raw `{ key: value }` operator attribute object; OTLP
|
|
318
|
+
// KeyValue gets emitted per entry with field 9 (attributes) on Span,
|
|
319
|
+
// field 1 (attributes) on Resource, etc.
|
|
320
|
+
if (!attrs || typeof attrs !== "object") return [];
|
|
321
|
+
var keys = Object.keys(attrs);
|
|
322
|
+
var out = new Array(keys.length);
|
|
323
|
+
for (var i = 0; i < keys.length; i += 1) {
|
|
324
|
+
out[i] = { key: keys[i], rawValue: attrs[keys[i]] };
|
|
325
|
+
}
|
|
326
|
+
return out;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function _spanToProto(span) {
|
|
330
|
+
// Status code: 0=Unset, 1=Ok, 2=Error. Status field 1 is reserved.
|
|
331
|
+
var statusBody = Buffer.concat([
|
|
332
|
+
pb.string(2, (span.status && span.status.message) || ""),
|
|
333
|
+
pb.uint32(3, STATUS_CODE_TO_OTLP[span.status && span.status.code] || 0),
|
|
334
|
+
]);
|
|
335
|
+
var eventsRepeated = pb.repeatedMessage(11, span.events || [], function (e) {
|
|
336
|
+
return Buffer.concat([
|
|
337
|
+
pb.fixed64(1, e.timeUnixNano || 0),
|
|
338
|
+
pb.string(2, e.name || ""),
|
|
339
|
+
pb.repeatedMessage(3, _attrsToProto(e.attributes), _keyValueToProto),
|
|
340
|
+
pb.uint32(4, 0),
|
|
341
|
+
]);
|
|
342
|
+
});
|
|
343
|
+
return Buffer.concat([
|
|
344
|
+
pb.bytes(1, _hexToBytes(span.traceId)),
|
|
345
|
+
pb.bytes(2, _hexToBytes(span.spanId)),
|
|
346
|
+
pb.string(3, ""), // trace_state (not yet propagated by the framework)
|
|
347
|
+
pb.bytes(4, _hexToBytes(span.parentSpanId || "")),
|
|
348
|
+
pb.string(5, span.name || ""),
|
|
349
|
+
pb.uint32(6, KIND_TEXT_TO_ENUM[span.kind] != null ? KIND_TEXT_TO_ENUM[span.kind] : KIND_TEXT_TO_ENUM.internal),
|
|
350
|
+
pb.fixed64(7, span.startTimeUnixNano || 0),
|
|
351
|
+
pb.fixed64(8, span.endTimeUnixNano || span.startTimeUnixNano || 0), // allow:raw-byte-literal — proto field number 8, not bytes
|
|
352
|
+
pb.repeatedMessage(9, _attrsToProto(span.attributes), _keyValueToProto),
|
|
353
|
+
pb.uint32(10, span.droppedAttributesCount || 0),
|
|
354
|
+
eventsRepeated,
|
|
355
|
+
pb.uint32(12, span.droppedEventsCount || 0),
|
|
356
|
+
pb.uint32(15, 0), // links repeated count placeholder; encoder emits 0 length-delim when no links
|
|
357
|
+
Buffer.concat([
|
|
358
|
+
pb._tag(15, 2), // WIRE_LDELIM tag for status
|
|
359
|
+
pb._writeVarint(statusBody.length),
|
|
360
|
+
statusBody,
|
|
361
|
+
]),
|
|
362
|
+
]);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// `bundle` is the value returned by _bundleSpans — { resourceSpans: [...] }
|
|
366
|
+
// where each entry has { resource, scopeSpans: [{ scope, spans: [...] }] }
|
|
367
|
+
// in the JSON-shape. We re-derive the proto bytes from the SAME pre-OTLP
|
|
368
|
+
// span list so the protobuf path doesn't double-transform the data.
|
|
369
|
+
function _bundleSpansToProto(spansArray) {
|
|
370
|
+
if (spansArray.length === 0) return Buffer.alloc(0);
|
|
371
|
+
var byResource = new Map();
|
|
372
|
+
for (var i = 0; i < spansArray.length; i += 1) {
|
|
373
|
+
var s = spansArray[i];
|
|
374
|
+
var resKey = JSON.stringify(s.resource || {});
|
|
375
|
+
var bucket = byResource.get(resKey);
|
|
376
|
+
if (!bucket) {
|
|
377
|
+
bucket = {
|
|
378
|
+
resource: s.resource || {},
|
|
379
|
+
scope: s.scope || { name: "blamejs", version: null },
|
|
380
|
+
spans: [],
|
|
381
|
+
};
|
|
382
|
+
byResource.set(resKey, bucket);
|
|
383
|
+
}
|
|
384
|
+
bucket.spans.push(s);
|
|
385
|
+
}
|
|
386
|
+
var resourceSpansPieces = [];
|
|
387
|
+
for (var entry of byResource) {
|
|
388
|
+
var b = entry[1];
|
|
389
|
+
var resourceBody = pb.repeatedMessage(1, _attrsToProto(b.resource), _keyValueToProto);
|
|
390
|
+
var scopeBody = Buffer.concat([
|
|
391
|
+
pb.string(1, b.scope.name || "blamejs"),
|
|
392
|
+
pb.string(2, b.scope.version || ""),
|
|
393
|
+
]);
|
|
394
|
+
var spansRepeated = pb.repeatedMessage(2, b.spans, _spanToProto);
|
|
395
|
+
var scopeSpansBody = Buffer.concat([
|
|
396
|
+
pb.embeddedMessage(1, scopeBody),
|
|
397
|
+
spansRepeated,
|
|
398
|
+
]);
|
|
399
|
+
var resourceSpansBody = Buffer.concat([
|
|
400
|
+
pb.embeddedMessage(1, resourceBody),
|
|
401
|
+
pb.embeddedMessage(2, scopeSpansBody),
|
|
402
|
+
]);
|
|
403
|
+
resourceSpansPieces.push(pb.embeddedMessage(1, resourceSpansBody));
|
|
404
|
+
}
|
|
405
|
+
return Buffer.concat(resourceSpansPieces);
|
|
406
|
+
}
|
|
407
|
+
|
|
192
408
|
function create(opts) {
|
|
193
409
|
validateOpts.requireObject(opts, "otlpExporter", OtlpExporterError);
|
|
194
410
|
validateOpts(opts, [
|
|
@@ -196,6 +412,7 @@ function create(opts) {
|
|
|
196
412
|
"flushIntervalMs", "timeoutMs", "maxAttempts",
|
|
197
413
|
"backoffInitialMs", "backoffMaxMs",
|
|
198
414
|
"fetchImpl", "audit", "allowedProtocols",
|
|
415
|
+
"encoding",
|
|
199
416
|
], "otlpExporter.create");
|
|
200
417
|
validateOpts.requireNonEmptyString(opts.endpoint,
|
|
201
418
|
"otlpExporter.create: endpoint", OtlpExporterError, "otlp/bad-endpoint");
|
|
@@ -224,8 +441,24 @@ function create(opts) {
|
|
|
224
441
|
"otlpExporter.create: maxAttempts", OtlpExporterError, "otlp/bad-opts");
|
|
225
442
|
|
|
226
443
|
var endpoint = opts.endpoint;
|
|
444
|
+
// OTLP §3 — operators with high-volume traces opt into the binary
|
|
445
|
+
// `application/x-protobuf` encoding via `opts.encoding: "protobuf"`
|
|
446
|
+
// (composes lib/protobuf-encoder.js for the wire-level emission).
|
|
447
|
+
// Default stays `"json"` for backward compatibility with existing
|
|
448
|
+
// collectors. The third encoding option (`"http/protobuf"` per the
|
|
449
|
+
// OTLP spec wording) is an alias for "protobuf".
|
|
450
|
+
var encoding = opts.encoding || "json";
|
|
451
|
+
if (encoding === "http/protobuf") encoding = "protobuf";
|
|
452
|
+
if (encoding !== "json" && encoding !== "protobuf") {
|
|
453
|
+
throw new OtlpExporterError("otlp/bad-encoding",
|
|
454
|
+
"otlpExporter.create: opts.encoding must be \"json\" or \"protobuf\" (got " +
|
|
455
|
+
JSON.stringify(opts.encoding) + ")");
|
|
456
|
+
}
|
|
457
|
+
var contentType = encoding === "protobuf"
|
|
458
|
+
? "application/x-protobuf"
|
|
459
|
+
: "application/json";
|
|
227
460
|
var headers = Object.assign({
|
|
228
|
-
"Content-Type":
|
|
461
|
+
"Content-Type": contentType,
|
|
229
462
|
}, opts.headers || {});
|
|
230
463
|
var batchSize = opts.batchSize || DEFAULT_BATCH_SIZE;
|
|
231
464
|
var maxQueue = opts.maxQueueSize || DEFAULT_MAX_QUEUE_SIZE;
|
|
@@ -298,10 +531,14 @@ function create(opts) {
|
|
|
298
531
|
var ac = (typeof AbortController === "function") ? new AbortController() : null;
|
|
299
532
|
var t = ac ? setTimeout(function () { ac.abort(); }, timeoutMs) : null;
|
|
300
533
|
try {
|
|
534
|
+
// The flush() path now passes EITHER a JSON-shape object (encoding
|
|
535
|
+
// "json") OR an already-encoded Buffer (encoding "protobuf").
|
|
536
|
+
// Stringify only the JSON path; pass the Buffer through.
|
|
537
|
+
var body = Buffer.isBuffer(payload) ? payload : JSON.stringify(payload);
|
|
301
538
|
var res = await fetchImpl(endpoint, {
|
|
302
539
|
method: "POST",
|
|
303
540
|
headers: headers,
|
|
304
|
-
body:
|
|
541
|
+
body: body,
|
|
305
542
|
signal: ac ? ac.signal : undefined,
|
|
306
543
|
});
|
|
307
544
|
if (res && res.ok) return { ok: true, status: res.status };
|
|
@@ -343,7 +580,12 @@ function create(opts) {
|
|
|
343
580
|
inFlight = true;
|
|
344
581
|
try {
|
|
345
582
|
var batch = queue.splice(0, batchSize);
|
|
346
|
-
|
|
583
|
+
// OTLP §3 — JSON encoding emits the resourceSpans envelope as
|
|
584
|
+
// JSON; protobuf encoding emits the same shape as binary
|
|
585
|
+
// ExportTraceServiceRequest bytes.
|
|
586
|
+
var payload = encoding === "protobuf"
|
|
587
|
+
? _bundleSpansToProto(batch)
|
|
588
|
+
: _bundleSpans(batch);
|
|
347
589
|
var result = await _post(payload, 1);
|
|
348
590
|
if (result.ok) {
|
|
349
591
|
_emitMetric("export_ok", batch.length, { http_status: String(result.status) });
|
package/lib/protobuf-encoder.js
CHANGED
|
@@ -95,27 +95,103 @@ function uint64(fieldNumber, value) {
|
|
|
95
95
|
return Buffer.concat([_tag(fieldNumber, WIRE_VARINT), _writeVarint(value)]);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
function int64(fieldNumber, value) {
|
|
99
|
+
// proto3 int64: wire-type 0 varint. Negatives encode as the 64-bit
|
|
100
|
+
// two's-complement reinterpret-cast to uint64, which always sets the
|
|
101
|
+
// top bit — every negative int64 occupies the full 10 varint bytes
|
|
102
|
+
// per the spec. https://protobuf.dev/programming-guides/encoding/#signed-ints
|
|
103
|
+
if (value === 0 || value === 0n) return Buffer.alloc(0); // proto3 default
|
|
104
|
+
var bi;
|
|
105
|
+
if (typeof value === "bigint") {
|
|
106
|
+
bi = value;
|
|
107
|
+
} else if (typeof value === "number") {
|
|
108
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) {
|
|
109
|
+
throw new Error("protobuf-encoder: int64 must be finite integer (got " + value + ")");
|
|
110
|
+
}
|
|
111
|
+
bi = BigInt(value);
|
|
112
|
+
} else {
|
|
113
|
+
throw new Error("protobuf-encoder: int64 must be number or bigint, got " + typeof value);
|
|
114
|
+
}
|
|
115
|
+
// Refuse out-of-range — proto int64 is [-2^63, 2^63 - 1].
|
|
116
|
+
if (bi < -(1n << 63n) || bi > (1n << 63n) - 1n) {
|
|
117
|
+
throw new Error("protobuf-encoder: int64 out of range (got " + bi.toString() + ")");
|
|
118
|
+
}
|
|
119
|
+
if (bi < 0n) bi = bi + (1n << 64n); // two's-complement reinterpret
|
|
120
|
+
return Buffer.concat([_tag(fieldNumber, WIRE_VARINT), _writeVarint(bi)]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function sint64(fieldNumber, value) {
|
|
124
|
+
// proto3 sint64: wire-type 0 varint with ZigZag encoding —
|
|
125
|
+
// small negatives encode compactly. https://protobuf.dev/programming-guides/encoding/#signed-ints
|
|
126
|
+
if (value === 0 || value === 0n) return Buffer.alloc(0);
|
|
127
|
+
var bi;
|
|
128
|
+
if (typeof value === "bigint") bi = value;
|
|
129
|
+
else if (typeof value === "number") {
|
|
130
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) {
|
|
131
|
+
throw new Error("protobuf-encoder: sint64 must be finite integer (got " + value + ")");
|
|
132
|
+
}
|
|
133
|
+
bi = BigInt(value);
|
|
134
|
+
} else {
|
|
135
|
+
throw new Error("protobuf-encoder: sint64 must be number or bigint, got " + typeof value);
|
|
136
|
+
}
|
|
137
|
+
if (bi < -(1n << 63n) || bi > (1n << 63n) - 1n) {
|
|
138
|
+
throw new Error("protobuf-encoder: sint64 out of range (got " + bi.toString() + ")");
|
|
139
|
+
}
|
|
140
|
+
// ZigZag: (n << 1) ^ (n >> 63) for 64-bit signed.
|
|
141
|
+
var zz = (bi << 1n) ^ (bi >> 63n);
|
|
142
|
+
if (zz < 0n) zz = zz + (1n << 64n);
|
|
143
|
+
return Buffer.concat([_tag(fieldNumber, WIRE_VARINT), _writeVarint(zz)]);
|
|
144
|
+
}
|
|
145
|
+
|
|
98
146
|
function bool(fieldNumber, value) {
|
|
99
147
|
if (!value) return Buffer.alloc(0); // proto3 default
|
|
100
148
|
return Buffer.concat([_tag(fieldNumber, WIRE_VARINT), Buffer.from([1])]);
|
|
101
149
|
}
|
|
102
150
|
|
|
103
151
|
function fixed64(fieldNumber, value) {
|
|
104
|
-
// For OTel: time_unix_nano fields are fixed64. Accept BigInt
|
|
105
|
-
//
|
|
152
|
+
// For OTel: time_unix_nano fields are fixed64. Accept BigInt, Number,
|
|
153
|
+
// or string-form digits (OTLP/JSON encodes uint64 as a JSON string per
|
|
154
|
+
// https://protobuf.dev/programming-guides/proto3/#json; the framework
|
|
155
|
+
// tracer emits strings for that reason and the same value flows into
|
|
156
|
+
// both encoding paths). Encode as little-endian 8 bytes.
|
|
106
157
|
var buf = Buffer.alloc(FIXED64_BYTES);
|
|
158
|
+
var bi;
|
|
107
159
|
if (typeof value === "bigint") {
|
|
108
|
-
|
|
109
|
-
} else {
|
|
160
|
+
bi = value;
|
|
161
|
+
} else if (typeof value === "string") {
|
|
162
|
+
// Char-code walk rather than /^[0-9]+$/ — that exact regex already
|
|
163
|
+
// appears in guard-cidr + guard-domain; the codebase-patterns
|
|
164
|
+
// duplicate-regex detector fires at the 3rd file (same shape as the
|
|
165
|
+
// SemVer-pre-release walk in lib/self-update.js).
|
|
166
|
+
if (value.length === 0) {
|
|
167
|
+
throw new Error("protobuf-encoder: fixed64 string must be non-empty unsigned digit-only");
|
|
168
|
+
}
|
|
169
|
+
for (var ci = 0; ci < value.length; ci += 1) {
|
|
170
|
+
var cc = value.charCodeAt(ci);
|
|
171
|
+
if (cc < 0x30 || cc > 0x39) { // allow:raw-byte-literal — ASCII '0' (0x30) .. '9' (0x39)
|
|
172
|
+
throw new Error("protobuf-encoder: fixed64 string must be unsigned digit-only (got " + JSON.stringify(value) + ")");
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
bi = BigInt(value);
|
|
176
|
+
} else if (typeof value === "number") {
|
|
110
177
|
if (value < 0 || !Number.isFinite(value)) {
|
|
111
178
|
throw new Error("protobuf-encoder: fixed64 must be non-negative finite (got " + value + ")");
|
|
112
179
|
}
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
180
|
+
// Refuse silently-rounded values beyond Number.MAX_SAFE_INTEGER —
|
|
181
|
+
// the caller MUST pass a BigInt or string in that range. JS doubles
|
|
182
|
+
// lose precision past 2^53 so a Number 1779518164402000000 isn't
|
|
183
|
+
// actually that exact value once it touches Number arithmetic.
|
|
184
|
+
if (value > Number.MAX_SAFE_INTEGER) {
|
|
185
|
+
throw new Error("protobuf-encoder: fixed64 Number above MAX_SAFE_INTEGER loses precision; pass a BigInt or digit-string (got " + value + ")");
|
|
186
|
+
}
|
|
187
|
+
bi = BigInt(value);
|
|
188
|
+
} else {
|
|
189
|
+
throw new Error("protobuf-encoder: fixed64 must be bigint, number, or digit-string (got " + typeof value + ")");
|
|
190
|
+
}
|
|
191
|
+
if (bi < 0n || bi > (1n << 64n) - 1n) {
|
|
192
|
+
throw new Error("protobuf-encoder: fixed64 out of uint64 range (got " + bi.toString() + ")");
|
|
118
193
|
}
|
|
194
|
+
buf.writeBigUInt64LE(bi, 0);
|
|
119
195
|
return Buffer.concat([_tag(fieldNumber, WIRE_64BIT), buf]);
|
|
120
196
|
}
|
|
121
197
|
|
|
@@ -177,6 +253,8 @@ function repeatedMessage(fieldNumber, items, perItemBodyEncoder) {
|
|
|
177
253
|
module.exports = {
|
|
178
254
|
uint32: uint32,
|
|
179
255
|
uint64: uint64,
|
|
256
|
+
int64: int64,
|
|
257
|
+
sint64: sint64,
|
|
180
258
|
bool: bool,
|
|
181
259
|
fixed64: fixed64,
|
|
182
260
|
double: double,
|