protobufjs 8.2.0 → 8.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.
package/README.md CHANGED
@@ -278,14 +278,6 @@ Protocol Buffers [Text Format](https://protobuf.dev/reference/protobuf/textforma
278
278
 
279
279
  In [CSP](https://w3c.github.io/webappsec-csp/)-restricted environments that disallow unsafe-eval, use generated static code instead of runtime code generation.
280
280
 
281
- ## Compatibility
282
-
283
- Supported runtimes are browsers, Node.js v12+, Deno (`deno add npm:protobufjs`) and Bun (`bun add protobufjs`). When using the CLI with Bun, Node.js must also be installed.
284
-
285
- ## Security
286
-
287
- protobuf.js favors transparent disclosure. Security-impacting reports are handled through coordinated GitHub Security Advisories where appropriate. See [SECURITY.md](./SECURITY.md) for supported release lines, reporting instructions, and notes on untrusted schema input.
288
-
289
281
  ## Conformance
290
282
 
291
283
  protobuf.js targets full binary wire-format conformance for **Proto2**, **Proto3** and **Editions**. CI runs the official Protocol Buffers conformance suite, with logs uploaded as artifacts.
@@ -298,62 +290,71 @@ protobuf.js targets full binary wire-format conformance for **Proto2**, **Proto3
298
290
 
299
291
  ## Performance
300
292
 
301
- In both reflection and static modes, protobuf.js builds specialized encoders and decoders for each message type instead of interpreting descriptors at runtime.
293
+ In both reflection and static modes, protobuf.js builds specialized encoders and decoders instead of interpreting descriptors at runtime.
302
294
 
303
- The repository includes a small benchmark for the bundled fixture in [`bench/`](./bench/). It compares protobuf.js reflection and static code against native `JSON.stringify`/`JSON.parse` and [google-protobuf](https://www.npmjs.com/package/google-protobuf) (`protoc-gen-js`). Results depend on hardware, Node.js version, and the message shape, so they should be treated as indicative rather than absolute.
295
+ The repository includes a [small benchmark](./bench). It compares protobuf.js reflection and static code against JSON encode/decode, protoc-gen-js, and protoc-gen-es. Results depend on hardware, Node.js version, and message shape, so they should be treated as indicative rather than absolute.
304
296
 
305
- One run on an AMD Ryzen 9 9950X3D with Node.js 24.13.0 and google-protobuf 4.0.2 produced:
297
+ One run on an AMD Ryzen 9 9950X3D with Node.js 24.15.0 produced:
306
298
 
307
299
  ```
308
- benchmarking encoding performance ...
309
-
310
- protobuf.js (reflect) x 2,492,315 ops/sec ±0.56% (94 runs sampled)
311
- protobuf.js (static) x 2,316,421 ops/sec ±0.49% (96 runs sampled)
312
- JSON (string) x 2,581,565 ops/sec ±0.22% (99 runs sampled)
313
- JSON (buffer) x 2,086,216 ops/sec ±0.68% (92 runs sampled)
314
- google-protobuf x 1,052,145 ops/sec ±0.24% (101 runs sampled)
315
-
316
- JSON (string) was fastest
317
- protobuf.js (reflect) was 3.8% ops/sec slower (factor 1.0)
318
- protobuf.js (static) was 10.5% ops/sec slower (factor 1.1)
319
- JSON (buffer) was 19.6% ops/sec slower (factor 1.2)
320
- google-protobuf was 59.3% ops/sec slower (factor 2.5)
321
-
322
- benchmarking decoding performance ...
323
-
324
- protobuf.js (reflect) x 6,053,370 ops/sec ±0.25% (98 runs sampled)
325
- protobuf.js (static) x 6,081,190 ops/sec ±0.35% (97 runs sampled)
326
- JSON (string) x 1,579,677 ops/sec ±0.11% (100 runs sampled)
327
- JSON (buffer) x 1,383,484 ops/sec ±0.15% (98 runs sampled)
328
- google-protobuf x 931,575 ops/sec ±0.25% (97 runs sampled)
329
-
330
- protobuf.js (static) was fastest
331
- protobuf.js (reflect) was 0.4% ops/sec slower (factor 1.0)
332
- JSON (string) was 74.0% ops/sec slower (factor 3.8)
333
- JSON (buffer) was 77.2% ops/sec slower (factor 4.4)
334
- google-protobuf was 84.7% ops/sec slower (factor 6.5)
335
-
336
- benchmarking combined performance ...
337
-
338
- protobuf.js (reflect) x 1,259,417 ops/sec ±0.33% (101 runs sampled)
339
- protobuf.js (static) x 1,296,628 ops/sec ±0.20% (98 runs sampled)
340
- JSON (string) x 848,422 ops/sec ±0.10% (100 runs sampled)
341
- JSON (buffer) x 727,866 ops/sec ±0.30% (100 runs sampled)
342
- google-protobuf x 477,041 ops/sec ±0.22% (101 runs sampled)
343
-
344
- protobuf.js (static) was fastest
345
- protobuf.js (reflect) was 3.0% ops/sec slower (factor 1.0)
346
- JSON (string) was 34.5% ops/sec slower (factor 1.5)
347
- JSON (buffer) was 43.9% ops/sec slower (factor 1.8)
348
- google-protobuf was 63.2% ops/sec slower (factor 2.7)
300
+ benchmarking encode performance ...
301
+
302
+ protobuf.js reflect x 2,430,103 ops/sec ±0.62% (95 runs sampled)
303
+ protobuf.js static x 2,390,407 ops/sec ±0.42% (96 runs sampled)
304
+ JSON encode x 2,155,918 ops/sec ±0.63% (92 runs sampled)
305
+ protoc-gen-js x 995,429 ops/sec ±0.18% (98 runs sampled)
306
+ protoc-gen-es x 403,334 ops/sec ±0.14% (96 runs sampled)
307
+
308
+ protobuf.js reflect was fastest
309
+ protobuf.js static was 1.4% ops/sec slower (factor 1.0)
310
+ JSON encode was 11.3% ops/sec slower (factor 1.1)
311
+ protoc-gen-js was 58.9% ops/sec slower (factor 2.4)
312
+ protoc-gen-es was 83.3% ops/sec slower (factor 6.0)
313
+
314
+ benchmarking decode performance ...
315
+
316
+ protobuf.js reflect x 6,440,387 ops/sec ±0.25% (97 runs sampled)
317
+ protobuf.js static x 6,463,283 ops/sec ±0.27% (101 runs sampled)
318
+ JSON decode x 1,409,923 ops/sec ±0.11% (97 runs sampled)
319
+ protoc-gen-js x 947,647 ops/sec ±0.15% (99 runs sampled)
320
+ protoc-gen-es x 731,819 ops/sec ±0.28% (98 runs sampled)
321
+
322
+ protobuf.js static was fastest
323
+ protobuf.js reflect was 0.3% ops/sec slower (factor 1.0)
324
+ JSON decode was 78.2% ops/sec slower (factor 4.6)
325
+ protoc-gen-js was 85.3% ops/sec slower (factor 6.8)
326
+ protoc-gen-es was 88.7% ops/sec slower (factor 8.8)
327
+
328
+ benchmarking round-trip performance ...
329
+
330
+ protobuf.js reflect x 1,310,677 ops/sec ±0.21% (97 runs sampled)
331
+ protobuf.js static x 1,310,926 ops/sec ±0.26% (101 runs sampled)
332
+ JSON encode/decode x 741,714 ops/sec ±0.24% (99 runs sampled)
333
+ protoc-gen-js x 472,844 ops/sec ±0.09% (96 runs sampled)
334
+ protoc-gen-es x 254,044 ops/sec ±0.05% (101 runs sampled)
335
+
336
+ protobuf.js reflect was fastest
337
+ protobuf.js static was 0.0% ops/sec slower (factor 1.0)
338
+ JSON encode/decode was 43.4% ops/sec slower (factor 1.8)
339
+ protoc-gen-js was 63.9% ops/sec slower (factor 2.8)
340
+ protoc-gen-es was 80.6% ops/sec slower (factor 5.2)
349
341
  ```
350
342
 
351
343
  Run it locally with:
352
344
 
353
345
  ```sh
346
+ npm --prefix bench install
354
347
  npm run bench
355
348
  ```
356
349
 
350
+ ## Compatibility
351
+
352
+ Supported runtimes are browsers, Node.js v12+, Deno and Bun. When using the CLI with Bun, Node.js must also be installed.
353
+
354
+ ## Security
355
+
356
+ protobuf.js favors transparent disclosure. Security-impacting reports are handled through coordinated GitHub Security Advisories where appropriate. See [SECURITY.md](./SECURITY.md) for supported release lines, reporting instructions, and notes on untrusted schema input.
357
+
357
358
  ## Development
358
359
 
359
360
  ```sh
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * protobuf.js v8.2.0 (c) 2016, daniel wirtz
3
- * compiled sat, 09 may 2026 19:37:43 utc
2
+ * protobuf.js v8.2.1 (c) 2016, daniel wirtz
3
+ * compiled wed, 13 may 2026 10:17:57 utc
4
4
  * licensed under the bsd-3-clause license
5
5
  * see: https://github.com/dcodeio/protobuf.js for details
6
6
  */
@@ -149,15 +149,15 @@ converter.fromObject = function fromObject(mtype) {
149
149
  /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
150
150
  var fields = mtype.fieldsArray;
151
151
  var gen = util.codegen(["d", "q"], mtype.name + "$fromObject")
152
- ("if(d instanceof this.ctor)")
152
+ ("if(d instanceof C)")
153
153
  ("return d")
154
154
  ("if(q===undefined)q=0")
155
155
  ("if(q>util.recursionLimit)")
156
156
  ("throw Error(\"max depth exceeded\")");
157
157
  if (!fields.length) return gen
158
- ("return new this.ctor");
158
+ ("return new C");
159
159
  gen
160
- ("var m=new this.ctor");
160
+ ("var m=new C");
161
161
  for (var i = 0; i < fields.length; ++i) {
162
162
  var field = fields[i].resolve(),
163
163
  prop = util.safeProp(field.name),
@@ -413,7 +413,7 @@ function decoder(mtype) {
413
413
  ("if(q===undefined)q=0")
414
414
  ("if(q>Reader.recursionLimit)")
415
415
  ("throw Error(\"max depth exceeded\")")
416
- ("var c=l===undefined?r.len:r.pos+l,m=g||new this.ctor" + (hasMapField ? ",k,v" : hasImplicitPresenceField ? ",v" : ""))
416
+ ("var c=l===undefined?r.len:r.pos+l,m=g||new C" + (hasMapField ? ",k,v" : hasImplicitPresenceField ? ",v" : ""))
417
417
  ("while(r.pos<c){")
418
418
  ("var s=r.pos")
419
419
  ("var t=r.tag()")
@@ -537,7 +537,11 @@ function decoder(mtype) {
537
537
  ("case %i:{", field.id)
538
538
  ("if(u!==%i)", types.basic[type])
539
539
  ("break");
540
- if (type === "string" || type === "bytes") gen
540
+ if (field.resolvedType instanceof Enum && field.typeDefault !== 0) gen
541
+ // TODO: Protoc rejects open enums whose first value is not zero.
542
+ // We should do the same, but for v8 this would be a regression.
543
+ ("if((v=r.%s())!==%j)", type, field.typeDefault);
544
+ else if (type === "string" || type === "bytes") gen
541
545
  ("if((v=r.%s()).length)", type);
542
546
  else if (types.long[type] !== undefined) gen
543
547
  ("if(typeof(v=r.%s())===\"object\"?v.low||v.high:v!==0)", type);
@@ -1991,7 +1995,10 @@ var Type, // cyclic
1991
1995
  * @throws {TypeError} If arguments are invalid
1992
1996
  */
1993
1997
  Namespace.fromJSON = function fromJSON(name, json, depth) {
1994
- depth = util.checkDepth(depth);
1998
+ if (depth === undefined)
1999
+ depth = 0;
2000
+ if (depth > util.recursionLimit)
2001
+ throw Error("max depth exceeded");
1995
2002
  return new Namespace(name, json.options).addJSON(json.nested, depth);
1996
2003
  };
1997
2004
 
@@ -2154,7 +2161,10 @@ Namespace.prototype.toJSON = function toJSON(toJSONOptions) {
2154
2161
  * @returns {Namespace} `this`
2155
2162
  */
2156
2163
  Namespace.prototype.addJSON = function addJSON(nestedJson, depth) {
2157
- depth = util.checkDepth(depth);
2164
+ if (depth === undefined)
2165
+ depth = 0;
2166
+ if (depth > util.recursionLimit)
2167
+ throw Error("max depth exceeded");
2158
2168
  var ns = this;
2159
2169
  /* istanbul ignore else */
2160
2170
  if (nestedJson) {
@@ -2294,6 +2304,8 @@ Namespace.prototype.define = function define(path, json) {
2294
2304
  throw TypeError("illegal path");
2295
2305
  if (path && path.length && path[0] === "")
2296
2306
  throw Error("path must be relative");
2307
+ if (path.length > util.recursionLimit)
2308
+ throw Error("max depth exceeded");
2297
2309
 
2298
2310
  var ptr = this;
2299
2311
  while (path.length > 0) {
@@ -3793,7 +3805,10 @@ function Root(options) {
3793
3805
  * @returns {Root} Root namespace
3794
3806
  */
3795
3807
  Root.fromJSON = function fromJSON(json, root, depth) {
3796
- depth = util.checkDepth(depth);
3808
+ if (depth === undefined)
3809
+ depth = 0;
3810
+ if (depth > util.recursionLimit)
3811
+ throw Error("max depth exceeded");
3797
3812
  if (!root)
3798
3813
  root = new Root();
3799
3814
  if (json.options)
@@ -4398,7 +4413,10 @@ function Service(name, options) {
4398
4413
  * @throws {TypeError} If arguments are invalid
4399
4414
  */
4400
4415
  Service.fromJSON = function fromJSON(name, json, depth) {
4401
- depth = util.checkDepth(depth);
4416
+ if (depth === undefined)
4417
+ depth = 0;
4418
+ if (depth > util.recursionLimit)
4419
+ throw Error("max depth exceeded");
4402
4420
  var service = new Service(name, json.options);
4403
4421
  /* istanbul ignore else */
4404
4422
  if (json.methods)
@@ -4713,6 +4731,8 @@ Object.defineProperties(Type.prototype, {
4713
4731
  util.merge(ctor, Message, true);
4714
4732
 
4715
4733
  this._ctor = ctor;
4734
+ delete this.decode;
4735
+ delete this.fromObject;
4716
4736
 
4717
4737
  // Messages have non-enumerable default values on their prototype
4718
4738
  var i = 0;
@@ -4781,7 +4801,10 @@ function clearCache(type) {
4781
4801
  * @returns {Type} Created message type
4782
4802
  */
4783
4803
  Type.fromJSON = function fromJSON(name, json, depth) {
4784
- depth = util.checkDepth(depth);
4804
+ if (depth === undefined)
4805
+ depth = 0;
4806
+ if (depth > util.nestingLimit)
4807
+ throw Error("max depth exceeded");
4785
4808
  var type = new Type(name, json.options);
4786
4809
  type.extensions = json.extensions;
4787
4810
  type.reserved = json.reserved;
@@ -5021,7 +5044,8 @@ Type.prototype.setup = function setup() {
5021
5044
  this.decode = decoder(this)({
5022
5045
  Reader : Reader,
5023
5046
  types : types,
5024
- util : util
5047
+ util : util,
5048
+ C : this.ctor
5025
5049
  });
5026
5050
  this.verify = verifier(this)({
5027
5051
  types : types,
@@ -5029,7 +5053,8 @@ Type.prototype.setup = function setup() {
5029
5053
  });
5030
5054
  this.fromObject = converter.fromObject(this)({
5031
5055
  types : types,
5032
- util : util
5056
+ util : util,
5057
+ C : this.ctor
5033
5058
  });
5034
5059
  this.toObject = converter.toObject(this)({
5035
5060
  types : types,
@@ -5404,20 +5429,6 @@ var reservedRe = util.patterns.reservedRe,
5404
5429
  */
5405
5430
  util.fs = require(31);
5406
5431
 
5407
- /**
5408
- * Checks a recursion depth.
5409
- * @param {number|undefined} depth Depth of recursion
5410
- * @returns {number} Depth of recursion
5411
- * @throws {Error} If depth exceeds util.recursionLimit
5412
- */
5413
- util.checkDepth = function checkDepth(depth) {
5414
- if (depth === undefined)
5415
- depth = 0;
5416
- if (depth > util.recursionLimit)
5417
- throw Error("max depth exceeded");
5418
- return depth;
5419
- };
5420
-
5421
5432
  /**
5422
5433
  * Converts an object's values to an array.
5423
5434
  * @param {Object.<string,*>} object Object to convert
@@ -5594,6 +5605,8 @@ util.setProperty = function setProperty(dst, path, value, ifNotSet) {
5594
5605
  throw TypeError("path must be specified");
5595
5606
 
5596
5607
  path = path.split(".");
5608
+ if (path.length > util.recursionLimit)
5609
+ throw Error("max depth exceeded");
5597
5610
  return setProp(dst, path, value);
5598
5611
  };
5599
5612
 
@@ -6995,12 +7008,19 @@ function merge(dst, src, ifNotSet) { // used by converters
6995
7008
 
6996
7009
  util.merge = merge;
6997
7010
 
7011
+ /**
7012
+ * Schema declaration nesting limit.
7013
+ * @memberof util
7014
+ * @type {number}
7015
+ */
7016
+ util.nestingLimit = 32; // protoc: MaxMessageDeclarationNestingDepth
7017
+
6998
7018
  /**
6999
7019
  * Recursion limit.
7000
7020
  * @memberof util
7001
7021
  * @type {number}
7002
7022
  */
7003
- util.recursionLimit = 100;
7023
+ util.recursionLimit = 100; // protoc: CodedInputStream::default_recursion_limit_
7004
7024
 
7005
7025
  /**
7006
7026
  * Makes a property safe for assignment as an own property.
@@ -7382,19 +7402,7 @@ utf8.length = function utf8_length(string) {
7382
7402
  return len;
7383
7403
  };
7384
7404
 
7385
- /**
7386
- * Reads UTF8 bytes as a string.
7387
- * @param {Uint8Array} buffer Source buffer
7388
- * @param {number} start Source start
7389
- * @param {number} end Source end
7390
- * @returns {string} String read
7391
- */
7392
- utf8.read = function utf8_read(buffer, start, end) {
7393
- if (end - start < 1) {
7394
- return "";
7395
- }
7396
-
7397
- var str = "";
7405
+ function utf8_read_js(buffer, start, end, str) {
7398
7406
  for (var i = start; i < end;) {
7399
7407
  var t = buffer[i++];
7400
7408
  if (t <= 0x7F) {
@@ -7416,6 +7424,44 @@ utf8.read = function utf8_read(buffer, start, end) {
7416
7424
  }
7417
7425
  }
7418
7426
  }
7427
+ return str;
7428
+ }
7429
+
7430
+ /**
7431
+ * Reads UTF8 bytes as a string.
7432
+ * @param {Uint8Array} buffer Source buffer
7433
+ * @param {number} start Source start
7434
+ * @param {number} end Source end
7435
+ * @returns {string} String read
7436
+ */
7437
+ utf8.read = function utf8_read_ascii(buffer, start, end) {
7438
+ if (end - start < 1)
7439
+ return "";
7440
+
7441
+ var str = "",
7442
+ i = start,
7443
+ c1, c2, c3, c4, c5, c6, c7, c8;
7444
+
7445
+ for (; i + 7 < end; i += 8) {
7446
+ c1 = buffer[i];
7447
+ c2 = buffer[i + 1];
7448
+ c3 = buffer[i + 2];
7449
+ c4 = buffer[i + 3];
7450
+ c5 = buffer[i + 4];
7451
+ c6 = buffer[i + 5];
7452
+ c7 = buffer[i + 6];
7453
+ c8 = buffer[i + 7];
7454
+ if ((c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8) & 0x80)
7455
+ return utf8_read_js(buffer, i, end, str);
7456
+ str += String.fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8);
7457
+ }
7458
+
7459
+ for (; i < end; ++i) {
7460
+ c1 = buffer[i];
7461
+ if (c1 & 0x80)
7462
+ return utf8_read_js(buffer, i, end, str);
7463
+ str += String.fromCharCode(c1);
7464
+ }
7419
7465
 
7420
7466
  return str;
7421
7467
  };
@@ -7917,6 +7963,11 @@ function writeByte(val, buf, pos) {
7917
7963
  buf[pos] = val & 255;
7918
7964
  }
7919
7965
 
7966
+ function writeStringAscii(val, buf, pos) {
7967
+ for (var i = 0; i < val.length;)
7968
+ buf[pos++] = val.charCodeAt(i++);
7969
+ }
7970
+
7920
7971
  function writeVarint32(val, buf, pos) {
7921
7972
  while (val > 127) {
7922
7973
  buf[pos++] = val & 127 | 128;
@@ -8145,7 +8196,7 @@ Writer.prototype.raw = function write_raw(value) {
8145
8196
  Writer.prototype.string = function write_string(value) {
8146
8197
  var len = utf8.length(value);
8147
8198
  return len
8148
- ? this.uint32(len)._push(utf8.write, len, value)
8199
+ ? this.uint32(len)._push(len === value.length ? writeStringAscii : utf8.write, len, value)
8149
8200
  : this._push(writeByte, 1, 0);
8150
8201
  };
8151
8202
 
@@ -8300,6 +8351,11 @@ BufferWriter.prototype.raw = function write_raw_buffer(value) {
8300
8351
  return len ? this._push(BufferWriter.writeBytesBuffer, len, value) : this;
8301
8352
  };
8302
8353
 
8354
+ function writeStringBufferAscii(val, buf, pos) {
8355
+ for (var i = 0; i < val.length;)
8356
+ buf[pos++] = val.charCodeAt(i++);
8357
+ }
8358
+
8303
8359
  function writeStringBuffer(val, buf, pos) {
8304
8360
  if (val.length < 40) // plain js is faster for short strings (probably due to redundant assertions)
8305
8361
  util.utf8.write(val, buf, pos);
@@ -8316,7 +8372,7 @@ BufferWriter.prototype.string = function write_string_buffer(value) {
8316
8372
  var len = util.Buffer.byteLength(value);
8317
8373
  this.uint32(len);
8318
8374
  if (len)
8319
- this._push(writeStringBuffer, len, value);
8375
+ this._push(len === value.length && len < 40 ? writeStringBufferAscii : writeStringBuffer, len, value);
8320
8376
  return this;
8321
8377
  };
8322
8378