@hocuspocus/common 2.0.1 → 2.0.3

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.
@@ -27,20 +27,47 @@ const fromCamelCaseRegex = /([A-Z])/g;
27
27
  */
28
28
  const fromCamelCase = (s, separator) => trimLeft(s.replace(fromCamelCaseRegex, match => `${separator}${toLowerCase(match)}`));
29
29
 
30
- /* istanbul ignore next */
31
- /** @type {TextEncoder} */ (typeof TextEncoder !== 'undefined' ? new TextEncoder() : null);
30
+ /**
31
+ * @param {string} str
32
+ * @return {Uint8Array}
33
+ */
34
+ const _encodeUtf8Polyfill = str => {
35
+ const encodedString = unescape(encodeURIComponent(str));
36
+ const len = encodedString.length;
37
+ const buf = new Uint8Array(len);
38
+ for (let i = 0; i < len; i++) {
39
+ buf[i] = /** @type {number} */ (encodedString.codePointAt(i));
40
+ }
41
+ return buf
42
+ };
32
43
 
33
- /* istanbul ignore next */
44
+ /* c8 ignore next */
45
+ const utf8TextEncoder = /** @type {TextEncoder} */ (typeof TextEncoder !== 'undefined' ? new TextEncoder() : null);
46
+
47
+ /**
48
+ * @param {string} str
49
+ * @return {Uint8Array}
50
+ */
51
+ const _encodeUtf8Native = str => utf8TextEncoder.encode(str);
52
+
53
+ /**
54
+ * @param {string} str
55
+ * @return {Uint8Array}
56
+ */
57
+ /* c8 ignore next */
58
+ const encodeUtf8 = utf8TextEncoder ? _encodeUtf8Native : _encodeUtf8Polyfill;
59
+
60
+ /* c8 ignore next */
34
61
  let utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
35
62
 
36
- /* istanbul ignore next */
63
+ /* c8 ignore start */
37
64
  if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) {
38
65
  // Safari doesn't handle BOM correctly.
39
66
  // This fixes a bug in Safari 13.0.5 where it produces a BOM the first time it is called.
40
67
  // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the first call and
41
68
  // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the second call
42
69
  // Another issue is that from then on no BOM chars are recognized anymore
43
- /* istanbul ignore next */
70
+ /* c8 ignore next */
44
71
  utf8TextDecoder = null;
45
72
  }
46
73
 
@@ -58,7 +85,7 @@ if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) {
58
85
  *
59
86
  * @function
60
87
  */
61
- const create = () => new Map();
88
+ const create$1 = () => new Map();
62
89
 
63
90
  /**
64
91
  * Often used conditions.
@@ -71,10 +98,10 @@ const create = () => new Map();
71
98
  * @param {T|null|undefined} v
72
99
  * @return {T|null}
73
100
  */
74
- /* istanbul ignore next */
101
+ /* c8 ignore next */
75
102
  const undefinedToNull = v => v === undefined ? null : v;
76
103
 
77
- /* global localStorage, addEventListener */
104
+ /* eslint-env browser */
78
105
 
79
106
  /**
80
107
  * Isomorphic variable storage.
@@ -84,7 +111,7 @@ const undefinedToNull = v => v === undefined ? null : v;
84
111
  * @module storage
85
112
  */
86
113
 
87
- /* istanbul ignore next */
114
+ /* c8 ignore start */
88
115
  class VarStoragePolyfill {
89
116
  constructor () {
90
117
  this.map = new Map();
@@ -105,54 +132,74 @@ class VarStoragePolyfill {
105
132
  return this.map.get(key)
106
133
  }
107
134
  }
135
+ /* c8 ignore stop */
108
136
 
109
- /* istanbul ignore next */
110
137
  /**
111
138
  * @type {any}
112
139
  */
113
140
  let _localStorage = new VarStoragePolyfill();
114
141
  let usePolyfill = true;
115
142
 
143
+ /* c8 ignore start */
116
144
  try {
117
145
  // if the same-origin rule is violated, accessing localStorage might thrown an error
118
- /* istanbul ignore next */
119
146
  if (typeof localStorage !== 'undefined') {
120
147
  _localStorage = localStorage;
121
148
  usePolyfill = false;
122
149
  }
123
150
  } catch (e) { }
151
+ /* c8 ignore stop */
124
152
 
125
- /* istanbul ignore next */
126
153
  /**
127
154
  * This is basically localStorage in browser, or a polyfill in nodejs
128
155
  */
156
+ /* c8 ignore next */
129
157
  const varStorage = _localStorage;
130
158
 
159
+ /**
160
+ * Common functions and function call helpers.
161
+ *
162
+ * @module function
163
+ */
164
+
165
+ /**
166
+ * @template V
167
+ * @template {V} OPTS
168
+ *
169
+ * @param {V} value
170
+ * @param {Array<OPTS>} options
171
+ */
172
+ // @ts-ignore
173
+ const isOneOf = (value, options) => options.includes(value);
174
+ /* c8 ignore stop */
175
+
131
176
  /**
132
177
  * Isomorphic module to work access the environment (query params, env variables).
133
178
  *
134
179
  * @module map
135
180
  */
136
181
 
137
- /* istanbul ignore next */
182
+ /* c8 ignore next */
138
183
  // @ts-ignore
139
- const isNode = typeof process !== 'undefined' && process.release && /node|io\.js/.test(process.release.name);
140
- /* istanbul ignore next */
141
- typeof navigator !== 'undefined' ? /Mac/.test(navigator.platform) : false;
184
+ const isNode = typeof process !== 'undefined' && process.release &&
185
+ /node|io\.js/.test(process.release.name);
186
+ /* c8 ignore next 3 */
187
+ typeof navigator !== 'undefined'
188
+ ? /Mac/.test(navigator.platform)
189
+ : false;
142
190
 
143
191
  /**
144
192
  * @type {Map<string,string>}
145
193
  */
146
194
  let params;
147
195
 
148
- /* istanbul ignore next */
196
+ /* c8 ignore start */
149
197
  const computeParams = () => {
150
198
  if (params === undefined) {
151
199
  if (isNode) {
152
- params = create();
200
+ params = create$1();
153
201
  const pargs = process.argv;
154
202
  let currParamName = null;
155
- /* istanbul ignore next */
156
203
  for (let i = 0; i < pargs.length; i++) {
157
204
  const parg = pargs[i];
158
205
  if (parg[0] === '-') {
@@ -170,11 +217,10 @@ const computeParams = () => {
170
217
  if (currParamName !== null) {
171
218
  params.set(currParamName, '');
172
219
  }
173
- // in ReactNative for example this would not be true (unless connected to the Remote Debugger)
220
+ // in ReactNative for example this would not be true (unless connected to the Remote Debugger)
174
221
  } else if (typeof location === 'object') {
175
- params = create()
176
- // eslint-disable-next-line no-undef
177
- ;(location.search || '?').slice(1).split('&').forEach(kv => {
222
+ params = create$1(); // eslint-disable-next-line no-undef
223
+ (location.search || '?').slice(1).split('&').forEach((kv) => {
178
224
  if (kv.length !== 0) {
179
225
  const [key, value] = kv.split('=');
180
226
  params.set(`--${fromCamelCase(key, '-')}`, value);
@@ -182,41 +228,103 @@ const computeParams = () => {
182
228
  }
183
229
  });
184
230
  } else {
185
- params = create();
231
+ params = create$1();
186
232
  }
187
233
  }
188
234
  return params
189
235
  };
236
+ /* c8 ignore stop */
190
237
 
191
238
  /**
192
239
  * @param {string} name
193
240
  * @return {boolean}
194
241
  */
195
- /* istanbul ignore next */
196
- const hasParam = name => computeParams().has(name);
197
- // export const getArgs = name => computeParams() && args
242
+ /* c8 ignore next */
243
+ const hasParam = (name) => computeParams().has(name);
198
244
 
199
245
  /**
200
246
  * @param {string} name
201
247
  * @return {string|null}
202
248
  */
203
- /* istanbul ignore next */
204
- const getVariable = name => isNode ? undefinedToNull(process.env[name.toUpperCase()]) : undefinedToNull(varStorage.getItem(name));
249
+ /* c8 ignore next 4 */
250
+ const getVariable = (name) =>
251
+ isNode
252
+ ? undefinedToNull(process.env[name.toUpperCase()])
253
+ : undefinedToNull(varStorage.getItem(name));
205
254
 
206
255
  /**
207
256
  * @param {string} name
208
257
  * @return {boolean}
209
258
  */
210
- /* istanbul ignore next */
211
- const hasConf = name => hasParam('--' + name) || getVariable(name) !== null;
259
+ /* c8 ignore next 2 */
260
+ const hasConf = (name) =>
261
+ hasParam('--' + name) || getVariable(name) !== null;
212
262
 
213
- /* istanbul ignore next */
263
+ /* c8 ignore next */
214
264
  hasConf('production');
215
265
 
266
+ /* c8 ignore next 2 */
267
+ const forceColor = isNode &&
268
+ isOneOf(process.env.FORCE_COLOR, ['true', '1', '2']);
269
+
270
+ /* c8 ignore start */
271
+ !hasParam('no-colors') &&
272
+ (!isNode || process.stdout.isTTY || forceColor) && (
273
+ !isNode || hasParam('color') || forceColor ||
274
+ getVariable('COLORTERM') !== null ||
275
+ (getVariable('TERM') || '').includes('color')
276
+ );
277
+ /* c8 ignore stop */
278
+
216
279
  /* eslint-env browser */
217
280
  const BIT8 = 128;
218
281
  const BITS7 = 127;
219
282
 
283
+ /**
284
+ * Common Math expressions.
285
+ *
286
+ * @module math
287
+ */
288
+
289
+ const floor = Math.floor;
290
+
291
+ /**
292
+ * @function
293
+ * @param {number} a
294
+ * @param {number} b
295
+ * @return {number} The smaller element of a and b
296
+ */
297
+ const min = (a, b) => a < b ? a : b;
298
+
299
+ /**
300
+ * @function
301
+ * @param {number} a
302
+ * @param {number} b
303
+ * @return {number} The bigger element of a and b
304
+ */
305
+ const max = (a, b) => a > b ? a : b;
306
+
307
+ /**
308
+ * Utility helpers for working with numbers.
309
+ *
310
+ * @module number
311
+ */
312
+
313
+ const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
314
+
315
+ /**
316
+ * Error helpers.
317
+ *
318
+ * @module error
319
+ */
320
+
321
+ /**
322
+ * @param {string} s
323
+ * @return {Error}
324
+ */
325
+ /* c8 ignore next */
326
+ const create = s => new Error(s);
327
+
220
328
  /**
221
329
  * Efficient schema-less binary decoding with support for variable length encoding.
222
330
  *
@@ -228,7 +336,7 @@ const BITS7 = 127;
228
336
  *
229
337
  * ```js
230
338
  * // encoding step
231
- * const encoder = new encoding.createEncoder()
339
+ * const encoder = encoding.createEncoder()
232
340
  * encoding.writeVarUint(encoder, 256)
233
341
  * encoding.writeVarString(encoder, 'Hello world!')
234
342
  * const buf = encoding.toUint8Array(encoder)
@@ -236,7 +344,7 @@ const BITS7 = 127;
236
344
  *
237
345
  * ```js
238
346
  * // decoding step
239
- * const decoder = new decoding.createDecoder(buf)
347
+ * const decoder = decoding.createDecoder(buf)
240
348
  * decoding.readVarUint(decoder) // => 256
241
349
  * decoding.readVarString(decoder) // => 'Hello world!'
242
350
  * decoding.hasContent(decoder) // => false - all data is read
@@ -245,6 +353,38 @@ const BITS7 = 127;
245
353
  * @module decoding
246
354
  */
247
355
 
356
+ const errorUnexpectedEndOfArray = create('Unexpected end of array');
357
+ const errorIntegerOutOfRange = create('Integer out of Range');
358
+
359
+ /**
360
+ * Create an Uint8Array view of the next `len` bytes and advance the position by `len`.
361
+ *
362
+ * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
363
+ * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
364
+ *
365
+ * @function
366
+ * @param {Decoder} decoder The decoder instance
367
+ * @param {number} len The length of bytes to read
368
+ * @return {Uint8Array}
369
+ */
370
+ const readUint8Array = (decoder, len) => {
371
+ const view = createUint8ArrayViewFromArrayBuffer(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len);
372
+ decoder.pos += len;
373
+ return view
374
+ };
375
+
376
+ /**
377
+ * Read variable length Uint8Array.
378
+ *
379
+ * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
380
+ * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
381
+ *
382
+ * @function
383
+ * @param {Decoder} decoder
384
+ * @return {Uint8Array}
385
+ */
386
+ const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder));
387
+
248
388
  /**
249
389
  * Read one byte as unsigned integer.
250
390
  * @function
@@ -265,24 +405,28 @@ const readUint8 = decoder => decoder.arr[decoder.pos++];
265
405
  */
266
406
  const readVarUint = decoder => {
267
407
  let num = 0;
268
- let len = 0;
269
- while (true) {
408
+ let mult = 1;
409
+ const len = decoder.arr.length;
410
+ while (decoder.pos < len) {
270
411
  const r = decoder.arr[decoder.pos++];
271
- num = num | ((r & BITS7) << len);
272
- len += 7;
412
+ // num = num | ((r & binary.BITS7) << len)
413
+ num = num + (r & BITS7) * mult; // shift $r << (7*#iterations) and add it to num
414
+ mult *= 128; // next iteration, shift 7 "more" to the left
273
415
  if (r < BIT8) {
274
- return num >>> 0 // return unsigned number!
416
+ return num
275
417
  }
276
- /* istanbul ignore if */
277
- if (len > 35) {
278
- throw new Error('Integer out of range!')
418
+ /* c8 ignore start */
419
+ if (num > MAX_SAFE_INTEGER) {
420
+ throw errorIntegerOutOfRange
279
421
  }
422
+ /* c8 ignore stop */
280
423
  }
424
+ throw errorUnexpectedEndOfArray
281
425
  };
282
426
 
283
427
  /**
284
- * Read string of variable length
285
- * * varUint is used to store the length of the string
428
+ * We don't test this function anymore as we use native decoding/encoding by default now.
429
+ * Better not modify this anymore..
286
430
  *
287
431
  * Transforming utf8 to a string is pretty expensive. The code performs 10x better
288
432
  * when String.fromCodePoint is fed with all characters as arguments.
@@ -293,7 +437,8 @@ const readVarUint = decoder => {
293
437
  * @param {Decoder} decoder
294
438
  * @return {String} The read String.
295
439
  */
296
- const readVarString = decoder => {
440
+ /* c8 ignore start */
441
+ const _readVarStringPolyfill = decoder => {
297
442
  let remainingLen = readVarUint(decoder);
298
443
  if (remainingLen === 0) {
299
444
  return ''
@@ -317,6 +462,42 @@ const readVarString = decoder => {
317
462
  return decodeURIComponent(escape(encodedString))
318
463
  }
319
464
  };
465
+ /* c8 ignore stop */
466
+
467
+ /**
468
+ * @function
469
+ * @param {Decoder} decoder
470
+ * @return {String} The read String
471
+ */
472
+ const _readVarStringNative = decoder =>
473
+ /** @type any */ (utf8TextDecoder).decode(readVarUint8Array(decoder));
474
+
475
+ /**
476
+ * Read string of variable length
477
+ * * varUint is used to store the length of the string
478
+ *
479
+ * @function
480
+ * @param {Decoder} decoder
481
+ * @return {String} The read String
482
+ *
483
+ */
484
+ /* c8 ignore next */
485
+ const readVarString = utf8TextDecoder ? _readVarStringNative : _readVarStringPolyfill;
486
+
487
+ /**
488
+ * Utility functions to work with buffers (Uint8Array).
489
+ *
490
+ * @module buffer
491
+ */
492
+
493
+ /**
494
+ * Create Uint8Array with initial content from buffer
495
+ *
496
+ * @param {ArrayBuffer} buffer
497
+ * @param {number} byteOffset
498
+ * @param {number} length
499
+ */
500
+ const createUint8ArrayViewFromArrayBuffer = (buffer, byteOffset, length) => new Uint8Array(buffer, byteOffset, length);
320
501
 
321
502
  /**
322
503
  * Efficient schema-less binary encoding with support for variable length encoding.
@@ -329,7 +510,7 @@ const readVarString = decoder => {
329
510
  *
330
511
  * ```js
331
512
  * // encoding step
332
- * const encoder = new encoding.createEncoder()
513
+ * const encoder = encoding.createEncoder()
333
514
  * encoding.writeVarUint(encoder, 256)
334
515
  * encoding.writeVarString(encoder, 'Hello world!')
335
516
  * const buf = encoding.toUint8Array(encoder)
@@ -337,7 +518,7 @@ const readVarString = decoder => {
337
518
  *
338
519
  * ```js
339
520
  * // decoding step
340
- * const decoder = new decoding.createDecoder(buf)
521
+ * const decoder = decoding.createDecoder(buf)
341
522
  * decoding.readVarUint(decoder) // => 256
342
523
  * decoding.readVarString(decoder) // => 'Hello world!'
343
524
  * decoding.hasContent(decoder) // => false - all data is read
@@ -364,9 +545,7 @@ const write = (encoder, num) => {
364
545
  };
365
546
 
366
547
  /**
367
- * Write a variable length unsigned integer.
368
- *
369
- * Encodes integers in the range from [0, 4294967295] / [0, 0xffffffff]. (max 32 bit unsigned integer)
548
+ * Write a variable length unsigned integer. Max encodable integer is 2^53.
370
549
  *
371
550
  * @function
372
551
  * @param {Encoder} encoder
@@ -375,11 +554,38 @@ const write = (encoder, num) => {
375
554
  const writeVarUint = (encoder, num) => {
376
555
  while (num > BITS7) {
377
556
  write(encoder, BIT8 | (BITS7 & num));
378
- num >>>= 7;
557
+ num = floor(num / 128); // shift >>> 7
379
558
  }
380
559
  write(encoder, BITS7 & num);
381
560
  };
382
561
 
562
+ /**
563
+ * A cache to store strings temporarily
564
+ */
565
+ const _strBuffer = new Uint8Array(30000);
566
+ const _maxStrBSize = _strBuffer.length / 3;
567
+
568
+ /**
569
+ * Write a variable length string.
570
+ *
571
+ * @function
572
+ * @param {Encoder} encoder
573
+ * @param {String} str The string that is to be encoded.
574
+ */
575
+ const _writeVarStringNative = (encoder, str) => {
576
+ if (str.length < _maxStrBSize) {
577
+ // We can encode the string into the existing buffer
578
+ /* c8 ignore next */
579
+ const written = utf8TextEncoder.encodeInto(str, _strBuffer).written || 0;
580
+ writeVarUint(encoder, written);
581
+ for (let i = 0; i < written; i++) {
582
+ write(encoder, _strBuffer[i]);
583
+ }
584
+ } else {
585
+ writeVarUint8Array(encoder, encodeUtf8(str));
586
+ }
587
+ };
588
+
383
589
  /**
384
590
  * Write a variable length string.
385
591
  *
@@ -387,7 +593,7 @@ const writeVarUint = (encoder, num) => {
387
593
  * @param {Encoder} encoder
388
594
  * @param {String} str The string that is to be encoded.
389
595
  */
390
- const writeVarString = (encoder, str) => {
596
+ const _writeVarStringPolyfill = (encoder, str) => {
391
597
  const encodedString = unescape(encodeURIComponent(str));
392
598
  const len = encodedString.length;
393
599
  writeVarUint(encoder, len);
@@ -396,6 +602,54 @@ const writeVarString = (encoder, str) => {
396
602
  }
397
603
  };
398
604
 
605
+ /**
606
+ * Write a variable length string.
607
+ *
608
+ * @function
609
+ * @param {Encoder} encoder
610
+ * @param {String} str The string that is to be encoded.
611
+ */
612
+ /* c8 ignore next */
613
+ const writeVarString = (utf8TextEncoder && /** @type {any} */ (utf8TextEncoder).encodeInto) ? _writeVarStringNative : _writeVarStringPolyfill;
614
+
615
+ /**
616
+ * Append fixed-length Uint8Array to the encoder.
617
+ *
618
+ * @function
619
+ * @param {Encoder} encoder
620
+ * @param {Uint8Array} uint8Array
621
+ */
622
+ const writeUint8Array = (encoder, uint8Array) => {
623
+ const bufferLen = encoder.cbuf.length;
624
+ const cpos = encoder.cpos;
625
+ const leftCopyLen = min(bufferLen - cpos, uint8Array.length);
626
+ const rightCopyLen = uint8Array.length - leftCopyLen;
627
+ encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos);
628
+ encoder.cpos += leftCopyLen;
629
+ if (rightCopyLen > 0) {
630
+ // Still something to write, write right half..
631
+ // Append new buffer
632
+ encoder.bufs.push(encoder.cbuf);
633
+ // must have at least size of remaining buffer
634
+ encoder.cbuf = new Uint8Array(max(bufferLen * 2, rightCopyLen));
635
+ // copy array
636
+ encoder.cbuf.set(uint8Array.subarray(leftCopyLen));
637
+ encoder.cpos = rightCopyLen;
638
+ }
639
+ };
640
+
641
+ /**
642
+ * Append an Uint8Array to Encoder.
643
+ *
644
+ * @function
645
+ * @param {Encoder} encoder
646
+ * @param {Uint8Array} uint8Array
647
+ */
648
+ const writeVarUint8Array = (encoder, uint8Array) => {
649
+ writeVarUint(encoder, uint8Array.byteLength);
650
+ writeUint8Array(encoder, uint8Array);
651
+ };
652
+
399
653
  var AuthMessageType;
400
654
  (function (AuthMessageType) {
401
655
  AuthMessageType[AuthMessageType["Token"] = 0] = "Token";