lib0 1.0.0-rc.23 → 1.0.0-rc.26

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/dist/schema.d.ts CHANGED
@@ -191,21 +191,15 @@ export const $$constructedBy: Schema<$ConstructedBy<(new (...args: any[]) => any
191
191
  */
192
192
  export class $Custom extends Schema<any> {
193
193
  /**
194
- * @param {(o:any) => boolean} check
194
+ * @param {(o:any,err?:ValidationError) => boolean} check
195
195
  */
196
- constructor(check: (o: any) => boolean);
196
+ constructor(check: (o: any, err?: ValidationError) => boolean);
197
197
  /**
198
- * @type {(o:any) => boolean}
198
+ * @type {(o:any,err?:ValidationError) => boolean}
199
199
  */
200
- shape: (o: any) => boolean;
201
- /**
202
- * @param {any} o
203
- * @param {ValidationError} err
204
- * @return {o is any}
205
- */
206
- check(o: any, err: ValidationError): o is any;
200
+ shape: (o: any, err?: ValidationError) => boolean;
207
201
  }
208
- export function $custom(check: (o: any) => boolean): Schema<any>;
202
+ export function $custom(check: (o: any, err?: ValidationError) => boolean): Schema<any>;
209
203
  export const $$custom: Schema<$Custom>;
210
204
  /**
211
205
  * @template {Primitive} T
@@ -220,6 +214,7 @@ export class $Literal<T extends Primitive> extends Schema<T> {
220
214
  }
221
215
  export function $literal<T extends Primitive[]>(...literals: T): CastToSchema<$Literal<T[number]>>;
222
216
  export const $$literal: Schema<$Literal<Primitive>>;
217
+ export function $$literalWith<T extends Primitive[]>(...literals: T): Schema<CastToSchema<$Literal<T[number]>>>;
223
218
  /**
224
219
  * @template {Array<string|Schema<string|number>>} T
225
220
  * @extends {Schema<CastStringTemplateArgsToTemplate<T>>}
@@ -295,6 +290,10 @@ export function $partial<S extends {
295
290
  [key: string | symbol | number]: any;
296
291
  }>(def: S): Schema<Partial<_ObjectDefToSchema<S>>>;
297
292
  /**
293
+ * Matches plain objects only - `{}`-literals and `Object.create(null)` objects, not class
294
+ * instances. The check is prototype-based, not `o.constructor === Object`, because a plain
295
+ * object may declare an own property named "constructor".
296
+ *
298
297
  * @type {Schema<{[key:string]: any}>}
299
298
  */
300
299
  export const $objectAny: Schema<{
@@ -480,6 +479,22 @@ export const $$symbol: Schema<Schema<Symbol>>;
480
479
  */
481
480
  export const $number: Schema<number>;
482
481
  export const $$number: Schema<Schema<number>>;
482
+ /**
483
+ * A number without fractional component (`Number.isInteger`). The unwrapped type is still
484
+ * `number` - JS has no separate integer type.
485
+ *
486
+ * @type {Schema<number>}
487
+ */
488
+ export const $int: Schema<number>;
489
+ export const $$int: Schema<Schema<number>>;
490
+ /**
491
+ * An unsigned integer: a number without fractional component that is `>= 0`. The unwrapped type is
492
+ * still `number` - JS has no separate integer type.
493
+ *
494
+ * @type {Schema<number>}
495
+ */
496
+ export const $uint: Schema<number>;
497
+ export const $$uint: Schema<Schema<number>>;
483
498
  /**
484
499
  * @type {Schema<string>}
485
500
  */
@@ -490,18 +505,26 @@ export const $$string: Schema<Schema<string>>;
490
505
  */
491
506
  export const $boolean: Schema<boolean>;
492
507
  export const $$boolean: Schema<Schema<boolean>>;
508
+ /**
509
+ * `$true`, `$false`, `$undefined` & `$null` are plain `$Literal`s (no own `$type`), so the generic
510
+ * `$$literal` handling covers them in `random`, `coerce` & error messages.
511
+ *
512
+ * @type {Schema<true>}
513
+ */
514
+ export const $true: Schema<true>;
515
+ /**
516
+ * @type {Schema<false>}
517
+ */
518
+ export const $false: Schema<false>;
493
519
  /**
494
520
  * @type {Schema<undefined>}
495
521
  */
496
522
  export const $undefined: Schema<undefined>;
497
- export const $$undefined: Schema<Schema<undefined>>;
498
523
  /**
499
524
  * @type {Schema<void>}
500
525
  */
501
526
  export const $void: Schema<void>;
502
- export const $$void: Schema<Schema<void>>;
503
527
  export const $null: Schema<null>;
504
- export const $$null: Schema<Schema<null>>;
505
528
  export const $uint8Array: Schema<Uint8Array<ArrayBuffer>>;
506
529
  export const $$uint8Array: Schema<Schema<Uint8Array>>;
507
530
  export const $promise: Schema<Promise<unknown>>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lib0",
3
- "version": "1.0.0-rc.23",
4
- "description": "",
3
+ "version": "1.0.0-rc.26",
4
+ "description": "isomorphic utility functions",
5
5
  "sideEffects": false,
6
6
  "type": "module",
7
7
  "funding": {
@@ -9,9 +9,9 @@
9
9
  "url": "https://github.com/sponsors/dmonad"
10
10
  },
11
11
  "bin": {
12
- "0gentesthtml": "./src/bin/gentesthtml.js",
13
- "0serve": "./src/bin/0serve.js",
14
- "0ecdsa-generate-keypair": "./src/bin/0ecdsa-generate-keypair.js"
12
+ "0gentesthtml": "src/bin/gentesthtml.js",
13
+ "0serve": "src/bin/0serve.js",
14
+ "0ecdsa-generate-keypair": "src/bin/0ecdsa-generate-keypair.js"
15
15
  },
16
16
  "files": [
17
17
  "dist/**/*.d.ts",
@@ -822,6 +822,10 @@ export class ModifyOp extends list.ListNode {
822
822
  * @return {ModifyOp<DTypes>}
823
823
  */
824
824
  clone (_start = 0, _end = 1, markAsDone = true) {
825
+ // `markAsDone=false` is currently unreachable: only `_splitOp` passes `false`, and a length-1
826
+ // modify is never split (apply's `move ? op : op.clone(0, 1, keep)` evaluates the clone only when
827
+ // `keep` is true). Kept for the uniform children-op `clone` signature.
828
+ /* c8 ignore next */
825
829
  return new ModifyOp(/** @type {DTypes} */ (markAsDone ? this.value.done() : this.value), _cloneAttrs(this.format), _cloneAttrs(this.attribution))
826
830
  }
827
831
  }
@@ -2847,6 +2851,11 @@ const applyDim = (op, field, update) => {
2847
2851
  // additionally merges its nested `format` key one level (see {@link mergeAttr}); format stays shallow.
2848
2852
  const cur = /** @type {any} */ (op)[field]
2849
2853
  const merged = field === 'attribution' ? mergeAttr(cur, update, false) : object.assign({}, cur, update)
2854
+ // the empty-merge guard is currently unreachable: a stored `update` is canonical (the builder's
2855
+ // combine strips `{k:undefined}` keys and drops empty objects to `undefined`, which `applyDim`
2856
+ // already returned on), and a verbatim (non-resolving) merge never removes keys — so `merged`
2857
+ // keeps at least one key of `update`. Kept to document that an empty result means skip.
2858
+ /* c8 ignore next */
2850
2859
  ;/** @type {any} */ (op)[field] = object.isEmpty(merged) ? undefined : merged
2851
2860
  } else if (field === 'attribution') {
2852
2861
  // data op, attribution: resolve per key; the nested `format` key merges one level (see {@link mergeAttr})
@@ -2857,6 +2866,9 @@ const applyDim = (op, field, update) => {
2857
2866
  let f = /** @type {any} */ (op)[field]
2858
2867
  for (const k in update) {
2859
2868
  const v = update[k]
2869
+ // the skip is currently unreachable: a stored `update` never carries a `{k:undefined}` key
2870
+ // (the builder's combine strips them). Kept for the unified tri-state contract.
2871
+ /* c8 ignore next */
2860
2872
  if (v === undefined) continue // skip this key
2861
2873
  if (v === null) { // remove this key (no-op when the stored value is already `null`)
2862
2874
  if (f !== null) {
@@ -2915,6 +2927,9 @@ const diffDim = (aVal, bVal, deep) => {
2915
2927
  * @param {{[k:string]:any}|null|undefined} attributionUpdate
2916
2928
  */
2917
2929
  const updateOpFormat = (op, formatUpdate, attributionUpdate) => {
2930
+ // defensive: apply's walk never passes a delete op (the initial `opsI` skips leading deletes and
2931
+ // every advance goes through `opNextUndeleted`)
2932
+ /* c8 ignore next */
2918
2933
  if ($deleteOp.check(op)) return
2919
2934
  const changedF = applyDim(op, 'format', formatUpdate)
2920
2935
  const changedA = applyDim(op, 'attribution', attributionUpdate)
@@ -2960,6 +2975,9 @@ const cmpKey = (a, b) =>
2960
2975
  * @param {Mark} a
2961
2976
  * @param {Mark} b
2962
2977
  */
2978
+ // the `: 0` id tie is unreachable: a Marks set is deduplicated by id (`add` replaces), so the sort
2979
+ // never compares two marks with the same id
2980
+ /* c8 ignore next */
2963
2981
  const cmpMarkKey = (a, b) => cmpKey(a.key, b.key) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
2964
2982
 
2965
2983
  /**
@@ -31,7 +31,7 @@ export const globalScope = /* @__PURE__ */(() =>/** @type {any} */ (typeof globa
31
31
  * which has `btoa`/`atob`/`fetch` but no DOM). Excludes Node and Deno.
32
32
  * @type {boolean}
33
33
  */
34
- /* c8 ignore next */
34
+ /* c8 ignore start */
35
35
  export const isBrowser = /* @__PURE__ */(() =>
36
36
  !isNode && !isDeno && (
37
37
  (typeof window !== 'undefined' && typeof document !== 'undefined') ||
@@ -39,3 +39,4 @@ export const isBrowser = /* @__PURE__ */(() =>
39
39
  (typeof globalScope.WorkerGlobalScope !== 'undefined' && globalScope.self instanceof globalScope.WorkerGlobalScope)
40
40
  )
41
41
  )()
42
+ /* c8 ignore stop */
package/src/schema.js CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import * as arr from './array.js'
8
+ import * as buffer from './buffer.js'
8
9
  import * as error from './error.js'
9
10
  import * as equalityTraits from './trait/equality.js'
10
11
  import * as fun from './function.js'
@@ -356,23 +357,23 @@ export const $$constructedBy = $type('s:$ConstructedBy', $ConstructedBy)
356
357
  */
357
358
  export class $Custom extends Schema {
358
359
  /**
359
- * @param {(o:any) => boolean} check
360
+ * @param {(o:any,err?:ValidationError) => boolean} check
360
361
  */
361
362
  constructor (check) {
362
363
  super()
363
364
  /**
364
- * @type {(o:any) => boolean}
365
+ * @type {(o:any,err?:ValidationError) => boolean}
365
366
  */
366
367
  this.shape = check
367
368
  }
368
369
 
369
370
  /**
370
371
  * @param {any} o
371
- * @param {ValidationError} err
372
+ * @param {ValidationError} [err]
372
373
  * @return {o is any}
373
374
  */
374
375
  check (o, err) {
375
- const c = this.shape(o)
376
+ const c = this.shape(o, err)
376
377
  /* c8 ignore next */
377
378
  !c && err?.extend(null, 'custom prop', o?.constructor.name, 'failed to check custom prop')
378
379
  return c
@@ -380,7 +381,7 @@ export class $Custom extends Schema {
380
381
  }
381
382
 
382
383
  /**
383
- * @param {(o:any) => boolean} check
384
+ * @param {(o:any,err?:ValidationError) => boolean} check
384
385
  * @return {Schema<any>}
385
386
  */
386
387
  /* @__NO_SIDE_EFFECTS__ */
@@ -423,6 +424,17 @@ export class $Literal extends Schema {
423
424
  export const $literal = (...literals) => new $Literal(literals)
424
425
  export const $$literal = $type('s:$Literal', $Literal)
425
426
 
427
+ /**
428
+ * Meta schema that matches a `$Literal` whose shape is exactly `literals` - e.g.
429
+ * `$$literalWith(null).check($null)` or `.if($$literalWith(true), ..)` in a pattern matcher.
430
+ *
431
+ * @template {Primitive[]} T
432
+ * @param {T} literals
433
+ * @return {Schema<CastToSchema<$Literal<T[number]>>>}
434
+ */
435
+ /* @__NO_SIDE_EFFECTS__ */
436
+ export const $$literalWith = (...literals) => $custom((o, err) => $$literal.check(o, err) && o.shape.length === literals.length && arr.every(o.shape, (l, i) => l === literals[i]))
437
+
426
438
  /**
427
439
  * @template {Array<string|Schema<string|number>>} Ts
428
440
  * @typedef {Ts extends [] ? `` : (Ts extends [infer T] ? (Unwrap<T> extends (string|number) ? Unwrap<T> : never) : (Ts extends [infer T1, ...infer Rest] ? `${Unwrap<T1> extends (string|number) ? Unwrap<T1> : never}${Rest extends Array<string|Schema<string|number>> ? CastStringTemplateArgsToTemplate<Rest> : never}` : never))} CastStringTemplateArgsToTemplate
@@ -623,9 +635,17 @@ export const $$object = /* @__PURE__ */$type('s:$Object', $Object)
623
635
  export const $partial = def => /** @type {any} */ (new $Object(def, true))
624
636
 
625
637
  /**
638
+ * Matches plain objects only - `{}`-literals and `Object.create(null)` objects, not class
639
+ * instances. The check is prototype-based, not `o.constructor === Object`, because a plain
640
+ * object may declare an own property named "constructor".
641
+ *
626
642
  * @type {Schema<{[key:string]: any}>}
627
643
  */
628
- export const $objectAny = $custom(o => o != null && (o.constructor === Object || o.constructor == null))
644
+ export const $objectAny = $custom(o => {
645
+ if (o == null) return false
646
+ const proto = Object.getPrototypeOf(o)
647
+ return proto === Object.prototype || proto === null
648
+ })
629
649
 
630
650
  /**
631
651
  * @template {Schema<string|number|symbol>} Keys
@@ -1007,6 +1027,24 @@ export const $$symbol = /** @type {Schema<Schema<Symbol>>} */ (/* @__PURE__ */$t
1007
1027
  export const $number = /* @__PURE__ */$custom(o => typeof o === 'number')
1008
1028
  export const $$number = /** @type {Schema<Schema<number>>} */ (/* @__PURE__ */$type('s:$number', $number))
1009
1029
 
1030
+ /**
1031
+ * A number without fractional component (`Number.isInteger`). The unwrapped type is still
1032
+ * `number` - JS has no separate integer type.
1033
+ *
1034
+ * @type {Schema<number>}
1035
+ */
1036
+ export const $int = /* @__PURE__ */$custom(o => number.isInteger(o))
1037
+ export const $$int = /** @type {Schema<Schema<number>>} */ (/* @__PURE__ */$type('s:$int', $int))
1038
+
1039
+ /**
1040
+ * An unsigned integer: a number without fractional component that is `>= 0`. The unwrapped type is
1041
+ * still `number` - JS has no separate integer type.
1042
+ *
1043
+ * @type {Schema<number>}
1044
+ */
1045
+ export const $uint = /* @__PURE__ */$custom(o => number.isInteger(o) && o >= 0)
1046
+ export const $$uint = /** @type {Schema<Schema<number>>} */ (/* @__PURE__ */$type('s:$uint', $uint))
1047
+
1010
1048
  /**
1011
1049
  * @type {Schema<string>}
1012
1050
  */
@@ -1019,20 +1057,30 @@ export const $$string = /** @type {Schema<Schema<string>>} */ (/* @__PURE__ */$t
1019
1057
  export const $boolean = /* @__PURE__ */$custom(o => typeof o === 'boolean')
1020
1058
  export const $$boolean = /** @type {Schema<Schema<Boolean>>} */ (/* @__PURE__ */$type('s:$boolean', $boolean))
1021
1059
 
1060
+ /**
1061
+ * `$true`, `$false`, `$undefined` & `$null` are plain `$Literal`s (no own `$type`), so the generic
1062
+ * `$$literal` handling covers them in `random`, `coerce` & error messages.
1063
+ *
1064
+ * @type {Schema<true>}
1065
+ */
1066
+ export const $true = /* @__PURE__ */$literal(true)
1067
+
1068
+ /**
1069
+ * @type {Schema<false>}
1070
+ */
1071
+ export const $false = /* @__PURE__ */$literal(false)
1072
+
1022
1073
  /**
1023
1074
  * @type {Schema<undefined>}
1024
1075
  */
1025
1076
  export const $undefined = /* @__PURE__ */$literal(undefined)
1026
- export const $$undefined = /** @type {Schema<Schema<undefined>>} */ (/* @__PURE__ */$type('s:$undefined', $undefined))
1027
1077
 
1028
1078
  /**
1029
1079
  * @type {Schema<void>}
1030
1080
  */
1031
1081
  export const $void = $undefined
1032
- export const $$void = /** @type {Schema<Schema<void>>} */ ($$undefined)
1033
1082
 
1034
1083
  export const $null = $literal(null)
1035
- export const $$null = /** @type {Schema<Schema<null>>} */ ($type('s:$null', $null))
1036
1084
 
1037
1085
  export const $uint8Array = $constructedBy(Uint8Array)
1038
1086
  export const $$uint8Array = /** @type {Schema<Schema<Uint8Array>>} */ ($type('s:$uint8Array', $uint8Array))
@@ -1165,9 +1213,10 @@ export const match = state => new PatternMatcher(/** @type {any} */ (state))
1165
1213
  */
1166
1214
  const _random = /* @__PURE__ */ (() => match({ gen: /** @type {Schema<prng.PRNG>} */ ($any), fallback: $lambda($any, $any, $any).optional })
1167
1215
  .if($$number, (_o, { gen }) => prng.oneOf(gen, [-1, 0, 1, prng.int53(gen, number.MIN_SAFE_INTEGER, number.MAX_SAFE_INTEGER)]))
1216
+ .if($$int, (_o, { gen }) => prng.oneOf(gen, [-1, 0, 1, prng.int53(gen, number.MIN_SAFE_INTEGER, number.MAX_SAFE_INTEGER)]))
1217
+ .if($$uint, (_o, { gen }) => prng.oneOf(gen, [0, 1, prng.int53(gen, 0, number.MAX_SAFE_INTEGER)]))
1168
1218
  .if($$string, (_o, { gen }) => prng.word(gen))
1169
1219
  .if($$boolean, (_o, { gen }) => prng.bool(gen))
1170
- .if($$undefined, (_o) => undefined)
1171
1220
  .if($$bigint, (_o, { gen }) => BigInt(prng.int53(gen, number.MIN_SAFE_INTEGER, number.MAX_SAFE_INTEGER)))
1172
1221
  .if($$union, (o, opts) => _random(prng.oneOf(opts.gen, o.shape), opts))
1173
1222
  .if($$object, (o, opts) => {
@@ -1199,9 +1248,6 @@ const _random = /* @__PURE__ */ (() => match({ gen: /** @type {Schema<prng.PRNG>
1199
1248
  .if($$literal, (o, { gen }) => {
1200
1249
  return prng.oneOf(gen, o.shape)
1201
1250
  })
1202
- .if($$null, (_o) => {
1203
- return null
1204
- })
1205
1251
  .if($$lambda, (o, opts) => {
1206
1252
  const res = _random(o.res, opts)
1207
1253
  return () => res
@@ -1259,6 +1305,8 @@ const _failed = Symbol('schema:coercion failed')
1259
1305
 
1260
1306
  const _bigintRegex = /^[+-]?\d+$/
1261
1307
 
1308
+ const _base64Regex = /^[A-Za-z0-9+/]+={0,2}$/
1309
+
1262
1310
  /**
1263
1311
  * Render a value for an error message. Objects are only rendered by kind - printing them adds
1264
1312
  * noise (and `String` throws on null-prototype objects).
@@ -1322,10 +1370,12 @@ const _nameOf = $s => {
1322
1370
  if (_isMeta($$any, $s)) return 'any'
1323
1371
  if (_isMeta($$string, $s)) return 'string'
1324
1372
  if (_isMeta($$number, $s)) return 'number'
1373
+ if (_isMeta($$int, $s)) return 'int'
1374
+ if (_isMeta($$uint, $s)) return 'uint'
1325
1375
  if (_isMeta($$bigint, $s)) return 'bigint'
1326
1376
  if (_isMeta($$boolean, $s)) return 'boolean'
1327
1377
  if (_isMeta($$symbol, $s)) return 'symbol'
1328
- if (_isMeta($$literal, $s) || _isMeta($$null, $s) || _isMeta($$undefined, $s)) {
1378
+ if (_isMeta($$literal, $s)) {
1329
1379
  return /** @type {Array<Primitive>} */ (shape).map(l => String(l)).join(' | ')
1330
1380
  }
1331
1381
  if (_isMeta($$optional, $s)) return `${_nameOf(shape)} | undefined`
@@ -1342,8 +1392,7 @@ const _nameOf = $s => {
1342
1392
 
1343
1393
  /**
1344
1394
  * Compile a coercer for `$s`. Dispatches on the meta schemas (`$$string`, `$$object`, ..) which are
1345
- * an exact identity check. The order matters: `$string` & friends are `$Custom` instances and
1346
- * `$null` & `$undefined` are `$Literal` instances that are only distinguishable by their `$type`.
1395
+ * an exact identity check.
1347
1396
  *
1348
1397
  * @param {Schema<any>} $s
1349
1398
  * @param {Map<Schema<any>,_Coercer>} cache
@@ -1373,6 +1422,18 @@ const _createCoercer = ($s, cache) => {
1373
1422
  return _fail(ctx, path, o, expected)
1374
1423
  }
1375
1424
  }
1425
+ if (_isMeta($$int, $s) || _isMeta($$uint, $s)) {
1426
+ const min = _isMeta($$uint, $s) ? 0 : -Infinity
1427
+ return (o, path, ctx) => {
1428
+ if (number.isInteger(o) && o >= min) return o
1429
+ const t = typeof o
1430
+ if (t === 'boolean' || t === 'bigint' || (t === 'string' && o.trim() !== '')) {
1431
+ const n = Number(o)
1432
+ if (number.isInteger(n) && n >= min) return n
1433
+ }
1434
+ return _fail(ctx, path, o, expected)
1435
+ }
1436
+ }
1376
1437
  if (_isMeta($$bigint, $s)) {
1377
1438
  return (o, path, ctx) => {
1378
1439
  const t = typeof o
@@ -1388,7 +1449,21 @@ const _createCoercer = ($s, cache) => {
1388
1449
  ? o
1389
1450
  : (o === 'true' ? true : (o === 'false' ? false : _fail(ctx, path, o, expected)))
1390
1451
  }
1391
- if (_isMeta($$literal, $s) || _isMeta($$null, $s) || _isMeta($$undefined, $s)) {
1452
+ if (_isMeta($$uint8Array, $s)) {
1453
+ // the format is checked here (rather than left to the decoder) because the `buffer.fromBase64`
1454
+ // backends disagree on invalid input: `Buffer` silently ignores unexpected characters, `atob` &
1455
+ // `Uint8Array.fromBase64` throw
1456
+ return (o, path, ctx) => {
1457
+ if ($uint8Array.check(o)) return o
1458
+ if (typeof o !== 'string' || !_base64Regex.test(o)) return _fail(ctx, path, o, expected)
1459
+ // base64 encodes 3 bytes as 4 characters. The '=' padding is optional, but when it is there
1460
+ // the length has to be a multiple of 4 - and without it the last chunk must not be a single
1461
+ // character, which carries no full byte.
1462
+ const rest = o.length % 4
1463
+ return (o.endsWith('=') ? rest === 0 : rest !== 1) ? buffer.fromBase64(o) : _fail(ctx, path, o, expected)
1464
+ }
1465
+ }
1466
+ if (_isMeta($$literal, $s)) {
1392
1467
  const literals = /** @type {Array<Primitive>} */ (shape)
1393
1468
  return (o, path, ctx) => {
1394
1469
  if (arr.some(literals, l => l === o)) return o
@@ -1530,8 +1605,9 @@ const _buildCoercer = ($s, cache) => {
1530
1605
  * Unlike `check` (which only validates) a coercion converts values that don't match yet - `'42'`
1531
1606
  * becomes `42` for `$number`, `'true'` becomes `true` for `$boolean`. Values that already match
1532
1607
  * are returned untouched (including object identity). Containers (`$object`, `$array`, `$record`,
1533
- * `$tuple`, `$union`, `$optional`) are coerced recursively. Schemas without a meaningful
1534
- * conversion (`$instanceOf`, `$custom`, ..) simply have to match.
1608
+ * `$tuple`, `$union`, `$optional`) are coerced recursively. `$uint8Array` accepts a base64 string
1609
+ * (padding optional) - the inverse of `buffer.toBase64`. Schemas without a meaningful conversion
1610
+ * (`$instanceOf`, `$custom`, ..) simply have to match.
1535
1611
  *
1536
1612
  * Failures are returned instead of thrown - this is the only api in lib0 that reports errors as a
1537
1613
  * value.