@bcts/uniform-resources 1.0.0-alpha.8 → 1.0.0-beta.0

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/index.d.mts CHANGED
@@ -1,7 +1,11 @@
1
- import { Cbor } from "@bcts/dcbor";
1
+ import { Cbor, CborTaggedDecodable, CborTaggedEncodable } from "@bcts/dcbor";
2
2
 
3
3
  //#region src/error.d.ts
4
4
  /**
5
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6
+ * Copyright © 2025-2026 Parity Technologies
7
+ *
8
+ *
5
9
  * Error type for UR encoding/decoding operations.
6
10
  */
7
11
  declare class URError extends Error {
@@ -9,18 +13,24 @@ declare class URError extends Error {
9
13
  }
10
14
  /**
11
15
  * Error type for invalid UR schemes.
16
+ *
17
+ * Message matches Rust bc-ur-rust/src/error.rs: `invalid UR scheme`.
12
18
  */
13
19
  declare class InvalidSchemeError extends URError {
14
20
  constructor();
15
21
  }
16
22
  /**
17
23
  * Error type for unspecified UR types.
24
+ *
25
+ * Message matches Rust bc-ur-rust/src/error.rs: `no UR type specified`.
18
26
  */
19
27
  declare class TypeUnspecifiedError extends URError {
20
28
  constructor();
21
29
  }
22
30
  /**
23
31
  * Error type for invalid UR types.
32
+ *
33
+ * Message matches Rust bc-ur-rust/src/error.rs: `invalid UR type`.
24
34
  */
25
35
  declare class InvalidTypeError extends URError {
26
36
  constructor();
@@ -33,22 +43,36 @@ declare class NotSinglePartError extends URError {
33
43
  }
34
44
  /**
35
45
  * Error type for unexpected UR types.
46
+ *
47
+ * Message matches Rust bc-ur-rust/src/error.rs:
48
+ * `expected UR type {expected}, but found {found}`.
36
49
  */
37
50
  declare class UnexpectedTypeError extends URError {
38
51
  constructor(expected: string, found: string);
39
52
  }
40
53
  /**
41
54
  * Error type for Bytewords encoding/decoding errors.
55
+ *
56
+ * Message matches Rust bc-ur-rust/src/error.rs: `Bytewords error ({0})`.
42
57
  */
43
58
  declare class BytewordsError extends URError {
44
59
  constructor(message: string);
45
60
  }
46
61
  /**
47
62
  * Error type for CBOR encoding/decoding errors.
63
+ *
64
+ * Message matches Rust bc-ur-rust/src/error.rs: `CBOR error ({0})`.
48
65
  */
49
66
  declare class CBORError extends URError {
50
67
  constructor(message: string);
51
68
  }
69
+ /**
70
+ * Error type for UR decoder errors.
71
+ * Matches Rust's Error::UR(String) variant.
72
+ */
73
+ declare class URDecodeError extends URError {
74
+ constructor(message: string);
75
+ }
52
76
  type Result<T> = T | Error;
53
77
  /**
54
78
  * Helper function to check if a result is an error.
@@ -108,12 +132,36 @@ declare class URType {
108
132
  */
109
133
  static from(value: string): URType;
110
134
  /**
111
- * Safely creates a URType, returning an error if invalid.
135
+ * Safely creates a URType, returning a typed `Result`-shaped
136
+ * discriminated union instead of throwing.
137
+ *
138
+ * Mirrors Rust `impl TryFrom<&str> for URType` /
139
+ * `impl TryFrom<String> for URType` (`bc-ur-rust/src/ur_type.rs`),
140
+ * which return `Result<URType, Error>`. The TS shape is the
141
+ * idiomatic discriminated form so callers can branch on `ok`
142
+ * without `instanceof`:
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * const r = URType.tryFrom("test");
147
+ * if (r.ok) {
148
+ * console.log(r.value.string()); // "test"
149
+ * } else {
150
+ * console.error(r.error.message);
151
+ * }
152
+ * ```
112
153
  *
113
154
  * @param value - The UR type string
114
- * @returns Either a URType or an error
115
- */
116
- static tryFrom(value: string): URType | InvalidTypeError;
155
+ * @returns A typed Result: `{ ok: true; value: URType }` on success,
156
+ * `{ ok: false; error: InvalidTypeError }` on failure.
157
+ */
158
+ static tryFrom(value: string): {
159
+ ok: true;
160
+ value: URType;
161
+ } | {
162
+ ok: false;
163
+ error: InvalidTypeError;
164
+ };
117
165
  }
118
166
  //#endregion
119
167
  //#region src/ur.d.ts
@@ -159,11 +207,26 @@ declare class UR {
159
207
  /**
160
208
  * Creates a new UR from a UR string.
161
209
  *
210
+ * Mirrors Rust's `UR::from_ur_string` (`bc-ur-rust/src/ur.rs:25-38`):
211
+ * 1. lowercase the entire string.
212
+ * 2. strip the `"ur:"` prefix → {@link InvalidSchemeError} if absent.
213
+ * 3. split on the first `/` → {@link TypeUnspecifiedError} if absent.
214
+ * 4. validate the type via {@link URType} → {@link InvalidTypeError}.
215
+ * 5. delegate the data section to the upstream-style decoder, which
216
+ * classifies the UR as single- or multi-part. Multi-part input is
217
+ * rejected with {@link NotSinglePartError}.
218
+ * 6. decode the bytewords payload (CRC32 + minimal mapping) →
219
+ * {@link BytewordsError} on failure.
220
+ * 7. parse the resulting bytes as CBOR → {@link CBORError} on failure.
221
+ *
162
222
  * @param urString - A UR string like "ur:test/..."
163
223
  * @throws {InvalidSchemeError} If the string doesn't start with "ur:"
164
- * @throws {TypeUnspecifiedError} If no type is specified
224
+ * @throws {TypeUnspecifiedError} If no `/` separator is present
225
+ * @throws {InvalidTypeError} If the type contains invalid characters
165
226
  * @throws {NotSinglePartError} If the UR is multi-part
166
- * @throws {URError} If decoding fails
227
+ * @throws {URDecodeError} For upstream-decoder errors (invalid indices, etc.)
228
+ * @throws {BytewordsError} If bytewords decoding fails
229
+ * @throws {CBORError} If CBOR parsing fails
167
230
  *
168
231
  * @example
169
232
  * ```typescript
@@ -200,6 +263,12 @@ declare class UR {
200
263
  qrString(): string;
201
264
  /**
202
265
  * Returns the QR data as bytes (uppercase UR string as UTF-8).
266
+ *
267
+ * Mirrors Rust's `UR::qr_data` (`ur.rs:52`) which does
268
+ * `self.qr_string().as_bytes().to_vec()` — the string's UTF-8 byte
269
+ * representation. We use `TextEncoder` rather than per-codepoint
270
+ * truncation so the behaviour stays correct if the QR string ever
271
+ * contains non-ASCII characters.
203
272
  */
204
273
  qrData(): Uint8Array;
205
274
  /**
@@ -215,6 +284,12 @@ declare class UR {
215
284
  toString(): string;
216
285
  /**
217
286
  * Checks equality with another UR.
287
+ *
288
+ * Mirrors Rust's derived `PartialEq for UR` which compares the inner
289
+ * `ur_type` and the inner `cbor` field directly. We compare CBOR
290
+ * bytewise — `Uint8Array` equality, not `Array#toString` (which would
291
+ * coerce to a comma-joined string and could collide on pathological
292
+ * inputs).
218
293
  */
219
294
  equals(other: UR): boolean;
220
295
  }
@@ -226,17 +301,27 @@ declare class UR {
226
301
  * Types implementing this interface should be able to convert themselves
227
302
  * to CBOR data and associate that with a UR type identifier.
228
303
  *
304
+ * Mirrors Rust's `UREncodable` trait (`bc-ur-rust/src/ur_encodable.rs`),
305
+ * which has a blanket impl `impl<T> UREncodable for T where T:
306
+ * CBORTaggedEncodable`. TypeScript has no equivalent of blanket impls, so
307
+ * implementers either write `ur()` / `urString()` directly *or* — for a
308
+ * type that already implements `CborTaggedEncodable` — call the helper
309
+ * functions {@link urFromEncodable} / {@link urStringFromEncodable} below
310
+ * to get the same auto-derivation that Rust provides for free.
311
+ *
229
312
  * @example
230
313
  * ```typescript
231
- * class MyType implements UREncodable {
232
- * toCBOR(): CBOR {
233
- * // Convert to CBOR
314
+ * class MyType implements UREncodable, CborTaggedEncodable {
315
+ * cborTags(): Tag[] {
316
+ * return [createTag(40000, "mytype")];
234
317
  * }
235
318
  *
236
- * ur(): UR {
237
- * const cbor = this.toCBOR();
238
- * return UR.new('mytype', cbor);
239
- * }
319
+ * untaggedCbor(): Cbor { ... }
320
+ * taggedCbor(): Cbor { return createTaggedCbor(this); }
321
+ *
322
+ * // Auto-derived from the first cbor tag's name, just like Rust.
323
+ * ur(): UR { return urFromEncodable(this); }
324
+ * urString(): string { return urStringFromEncodable(this); }
240
325
  * }
241
326
  * ```
242
327
  */
@@ -250,6 +335,26 @@ interface UREncodable {
250
335
  */
251
336
  urString(): string;
252
337
  }
338
+ /**
339
+ * Concrete equivalent of Rust's default `UREncodable::ur` impl
340
+ * (`bc-ur-rust/src/ur_encodable.rs:8-18`):
341
+ *
342
+ * - Reads the first tag returned by `encodable.cborTags()`.
343
+ * - Uses that tag's `name` as the UR type, throwing if no name is set —
344
+ * matching Rust's `panic!("CBOR tag {} must have a name. Did you call
345
+ * `register_tags()`?", tag.value())`.
346
+ * - Wraps the encodable's `untaggedCbor()` in a fresh {@link UR} bound to
347
+ * that type.
348
+ *
349
+ * Use from a class implementing both `UREncodable` and
350
+ * `CborTaggedEncodable` to skip writing the boilerplate yourself.
351
+ */
352
+ declare function urFromEncodable(encodable: CborTaggedEncodable): UR;
353
+ /**
354
+ * Concrete equivalent of Rust's default `UREncodable::ur_string` impl
355
+ * (`bc-ur-rust/src/ur_encodable.rs:21`): `self.ur().string()`.
356
+ */
357
+ declare function urStringFromEncodable(encodable: CborTaggedEncodable): string;
253
358
  /**
254
359
  * Helper function to check if an object implements UREncodable.
255
360
  */
@@ -262,17 +367,26 @@ declare function isUREncodable(obj: unknown): obj is UREncodable;
262
367
  * Types implementing this interface should be able to create themselves
263
368
  * from a UR containing their data.
264
369
  *
370
+ * Mirrors Rust's `URDecodable` trait (`bc-ur-rust/src/ur_decodable.rs`),
371
+ * which has a blanket impl `impl<T> URDecodable for T where T:
372
+ * CBORTaggedDecodable`. TypeScript has no equivalent of blanket impls, so
373
+ * implementers either write `fromUR()` directly *or* — for a type that
374
+ * already implements `CborTaggedDecodable` — call the helper functions
375
+ * {@link decodableFromUR} / {@link decodableFromURString} below to get the
376
+ * same auto-derivation that Rust provides for free.
377
+ *
265
378
  * @example
266
379
  * ```typescript
267
- * class MyType implements URDecodable {
268
- * fromUR(ur: UR): MyType {
269
- * const cbor = ur.cbor();
270
- * // Decode from CBOR and return MyType instance
380
+ * class MyType implements URDecodable, CborTaggedDecodable<MyType> {
381
+ * cborTags(): Tag[] {
382
+ * return [createTag(40000, "mytype")];
271
383
  * }
384
+ * fromUntaggedCbor(cbor: Cbor): MyType { ... }
385
+ * fromTaggedCbor(cbor: Cbor): MyType { ... }
272
386
  *
273
- * fromURString(urString: string): MyType {
274
- * return this.fromUR(UR.fromURString(urString));
275
- * }
387
+ * // Auto-derived from the first cbor tag's name, matching Rust.
388
+ * fromUR(ur: UR): MyType { return decodableFromUR(this, ur); }
389
+ * fromURString(s: string): MyType { return decodableFromURString(this, s); }
276
390
  * }
277
391
  * ```
278
392
  */
@@ -297,6 +411,26 @@ interface URDecodable {
297
411
  */
298
412
  fromURString?(urString: string): unknown;
299
413
  }
414
+ /**
415
+ * Concrete equivalent of Rust's default `URDecodable::from_ur` impl
416
+ * (`bc-ur-rust/src/ur_decodable.rs:7-15`):
417
+ *
418
+ * 1. Read the first tag returned by `decodable.cborTags()`.
419
+ * 2. Verify the UR's type matches that tag's name via `UR#checkType`
420
+ * (this is what Rust's `ur.check_type(...)` does — surface
421
+ * `UnexpectedTypeError` on mismatch).
422
+ * 3. Delegate to `decodable.fromUntaggedCbor(ur.cbor())`.
423
+ *
424
+ * Use from a class implementing both `URDecodable` and
425
+ * `CborTaggedDecodable<T>` to skip the type-check / delegate boilerplate.
426
+ */
427
+ declare function decodableFromUR<T>(decodable: CborTaggedDecodable<T>, ur: UR): T;
428
+ /**
429
+ * Concrete equivalent of Rust's default `URDecodable::from_ur_string` impl
430
+ * (`bc-ur-rust/src/ur_decodable.rs:17-22`):
431
+ * `Self::from_ur(UR::from_ur_string(s)?)`.
432
+ */
433
+ declare function decodableFromURString<T>(decodable: CborTaggedDecodable<T>, urString: string): T;
300
434
  /**
301
435
  * Helper function to check if an object implements URDecodable.
302
436
  */
@@ -382,12 +516,6 @@ declare class MultipartEncoder {
382
516
  * ```
383
517
  */
384
518
  constructor(ur: UR, maxFragmentLen: number);
385
- /**
386
- * Returns whether the message fits in a single part.
387
- *
388
- * For single-part messages, consider using UR.string() directly.
389
- */
390
- isSinglePart(): boolean;
391
519
  /**
392
520
  * Gets the next part of the encoding.
393
521
  *
@@ -405,10 +533,17 @@ declare class MultipartEncoder {
405
533
  nextPart(): string;
406
534
  /**
407
535
  * Encodes a fountain part as a UR string.
536
+ *
537
+ * Always emits the multipart `ur:<type>/<seqNum>-<seqLen>/<bytewords>`
538
+ * format — including for single-part messages (`1-1/...`). This mirrors
539
+ * Rust's `bc_ur::MultipartEncoder::next_part`, which never short-circuits
540
+ * to plain UR. Callers that want plain UR for tiny payloads should use
541
+ * `UR.string()` directly instead of constructing a `MultipartEncoder`.
408
542
  */
409
543
  private _encodePart;
410
544
  /**
411
- * Encodes part metadata and data into bytes for bytewords encoding.
545
+ * Encodes part metadata and data as CBOR for bytewords encoding.
546
+ * Format: CBOR array [seqNum, seqLen, messageLen, checksum, data]
412
547
  */
413
548
  private _encodePartData;
414
549
  /**
@@ -422,17 +557,6 @@ declare class MultipartEncoder {
422
557
  * for additional redundancy.
423
558
  */
424
559
  partsCount(): number;
425
- /**
426
- * Checks if all pure parts have been emitted.
427
- *
428
- * Even after this returns true, you can continue calling nextPart()
429
- * to generate additional rateless parts for redundancy.
430
- */
431
- isComplete(): boolean;
432
- /**
433
- * Resets the encoder to start from the beginning.
434
- */
435
- reset(): void;
436
560
  }
437
561
  //#endregion
438
562
  //#region src/multipart-decoder.d.ts
@@ -473,6 +597,8 @@ declare class MultipartDecoder {
473
597
  private _parsePart;
474
598
  /**
475
599
  * Decodes a multipart UR's fountain part data.
600
+ *
601
+ * The multipart body is a CBOR array: [seqNum, seqLen, messageLen, checksum, data]
476
602
  */
477
603
  private _decodeFountainPart;
478
604
  /**
@@ -485,226 +611,29 @@ declare class MultipartDecoder {
485
611
  * @returns The decoded UR, or null if not yet complete
486
612
  */
487
613
  message(): UR | null;
488
- /**
489
- * Returns the decoding progress as a fraction (0 to 1).
490
- */
491
- progress(): number;
492
- /**
493
- * Resets the decoder to receive a new message.
494
- */
495
- reset(): void;
496
- }
497
- //#endregion
498
- //#region src/fountain.d.ts
499
- /**
500
- * Fountain code implementation for multipart URs.
501
- *
502
- * This implements a hybrid fixed-rate and rateless fountain code system
503
- * as specified in BCR-2020-005 and BCR-2024-001.
504
- *
505
- * Key concepts:
506
- * - Parts 1-seqLen are "pure" fragments (fixed-rate)
507
- * - Parts > seqLen are "mixed" fragments using XOR (rateless)
508
- * - Xoshiro256** PRNG ensures encoder/decoder agree on mixing
509
- */
510
- /**
511
- * Represents a fountain code part with metadata.
512
- */
513
- interface FountainPart {
514
- /** Sequence number (1-based) */
515
- seqNum: number;
516
- /** Total number of pure fragments */
517
- seqLen: number;
518
- /** Length of original message */
519
- messageLen: number;
520
- /** CRC32 checksum of original message */
521
- checksum: number;
522
- /** Fragment data */
523
- data: Uint8Array;
524
- }
525
- /**
526
- * Splits data into fragments of the specified size.
527
- */
528
- declare function splitMessage(message: Uint8Array, fragmentLen: number): Uint8Array[];
529
- /**
530
- * XOR two Uint8Arrays together.
531
- */
532
- declare function xorBytes(a: Uint8Array, b: Uint8Array): Uint8Array;
533
- /**
534
- * Chooses which fragments to mix for a given sequence number.
535
- *
536
- * This uses a seeded Xoshiro256** PRNG to deterministically select fragments,
537
- * ensuring encoder and decoder agree without explicit coordination.
538
- *
539
- * @param seqNum - The sequence number (1-based)
540
- * @param seqLen - Total number of pure fragments
541
- * @param checksum - CRC32 checksum of the message
542
- * @returns Array of fragment indices (0-based)
543
- */
544
- declare function chooseFragments(seqNum: number, seqLen: number, checksum: number): number[];
545
- /**
546
- * Mixes the selected fragments using XOR.
547
- */
548
- declare function mixFragments(fragments: Uint8Array[], indices: number[]): Uint8Array;
549
- /**
550
- * Fountain encoder for creating multipart URs.
551
- */
552
- declare class FountainEncoder {
553
- private readonly fragments;
554
- private readonly messageLen;
555
- private readonly checksum;
556
- private seqNum;
557
- /**
558
- * Creates a fountain encoder for the given message.
559
- *
560
- * @param message - The message to encode
561
- * @param maxFragmentLen - Maximum length of each fragment
562
- */
563
- constructor(message: Uint8Array, maxFragmentLen: number);
564
- /**
565
- * Returns the number of pure fragments.
566
- */
567
- get seqLen(): number;
568
- /**
569
- * Returns whether the message fits in a single part.
570
- */
571
- isSinglePart(): boolean;
572
- /**
573
- * Returns whether all pure parts have been emitted.
574
- */
575
- isComplete(): boolean;
576
- /**
577
- * Generates the next fountain part.
578
- */
579
- nextPart(): FountainPart;
580
- /**
581
- * Returns the current sequence number.
582
- */
583
- currentSeqNum(): number;
584
- /**
585
- * Resets the encoder to start from the beginning.
586
- */
587
- reset(): void;
588
- }
589
- /**
590
- * Fountain decoder for reassembling multipart URs.
591
- */
592
- declare class FountainDecoder {
593
- private seqLen;
594
- private messageLen;
595
- private checksum;
596
- private readonly pureFragments;
597
- private readonly mixedParts;
598
- /**
599
- * Receives a fountain part and attempts to decode.
600
- *
601
- * @param part - The fountain part to receive
602
- * @returns true if the message is now complete
603
- */
604
- receive(part: FountainPart): boolean;
605
- /**
606
- * Attempts to extract pure fragments from mixed parts.
607
- */
608
- private reduceMixedParts;
609
- /**
610
- * Returns whether all fragments have been received.
611
- */
612
- isComplete(): boolean;
613
- /**
614
- * Reconstructs the original message.
615
- *
616
- * @returns The original message, or null if not yet complete
617
- */
618
- message(): Uint8Array | null;
619
- /**
620
- * Returns the progress as a fraction (0 to 1).
621
- */
622
- progress(): number;
623
- /**
624
- * Resets the decoder.
625
- */
626
- reset(): void;
627
614
  }
628
615
  //#endregion
629
- //#region src/xoshiro.d.ts
630
- /**
631
- * Xoshiro256** PRNG implementation.
632
- *
633
- * This is a high-quality, fast pseudo-random number generator used
634
- * for deterministic fragment selection in fountain codes.
635
- *
636
- * Reference: https://prng.di.unimi.it/
637
- */
638
- /**
639
- * Xoshiro256** pseudo-random number generator.
640
- *
641
- * This PRNG is used for deterministic mixing in fountain codes,
642
- * allowing both encoder and decoder to agree on which fragments
643
- * are combined without transmitting that information.
644
- */
645
- declare class Xoshiro256 {
646
- private s;
647
- /**
648
- * Creates a new Xoshiro256** instance from a seed.
649
- *
650
- * The seed is hashed using SHA-256 to initialize the state.
651
- * For consistent results across encoder/decoder, use the same seed.
652
- *
653
- * @param seed - The seed bytes (any length)
654
- */
655
- constructor(seed: Uint8Array);
656
- /**
657
- * Creates a Xoshiro256** instance from raw state values.
658
- * Useful for seeding with specific values.
659
- */
660
- static fromState(s0: bigint, s1: bigint, s2: bigint, s3: bigint): Xoshiro256;
661
- /**
662
- * Simple hash function for seeding.
663
- * This is a basic implementation - in production use SHA-256.
664
- */
665
- private hashSeed;
666
- /**
667
- * Converts 8 bytes to a 64-bit BigInt (little-endian).
668
- */
669
- private bytesToBigInt;
670
- /**
671
- * Generates the next 64-bit random value.
672
- */
673
- next(): bigint;
674
- /**
675
- * Generates a random double in [0, 1).
676
- */
677
- nextDouble(): number;
678
- /**
679
- * Generates a random integer in [low, high).
680
- */
681
- nextInt(low: number, high: number): number;
682
- /**
683
- * Generates a random byte [0, 255].
684
- */
685
- nextByte(): number;
686
- /**
687
- * Generates an array of random bytes.
688
- */
689
- nextData(count: number): Uint8Array;
690
- }
616
+ //#region src/utils.d.ts
691
617
  /**
692
- * Creates a seed for the Xoshiro PRNG from message checksum and sequence number.
618
+ * Copyright © 2023-2026 Blockchain Commons, LLC
619
+ * Copyright © 2025-2026 Parity Technologies
693
620
  *
694
- * This ensures that both encoder and decoder produce the same random sequence
695
- * for a given message and part number.
696
621
  */
697
- declare function createSeed(checksum: number, seqNum: number): Uint8Array;
698
- //#endregion
699
- //#region src/utils.d.ts
700
622
  /**
701
623
  * Checks if a character is a valid UR type character.
702
- * Valid characters are lowercase letters, digits, and hyphens.
624
+ *
625
+ * Mirrors Rust's `URTypeChar::is_ur_type` (`bc-ur-rust/src/utils.rs:6-19`):
626
+ * lowercase a-z, digits 0-9, and the hyphen `-`.
703
627
  */
704
628
  declare function isURTypeChar(char: string): boolean;
705
629
  /**
706
630
  * Checks if a string is a valid UR type.
707
- * Valid UR types contain only lowercase letters, digits, and hyphens.
631
+ *
632
+ * Mirrors Rust's `URTypeString::is_ur_type` (`bc-ur-rust/src/utils.rs:26-32`)
633
+ * which is `self.chars().all(...)` — meaning **the empty string is accepted**
634
+ * (a vacuously-true `all` over no chars). We mirror that here so that
635
+ * `URType::new("")` succeeds in both ports; the round-trip then fails at
636
+ * decode-time with `TypeUnspecified`.
708
637
  */
709
638
  declare function isValidURType(urType: string): boolean;
710
639
  /**
@@ -716,36 +645,78 @@ declare function validateURType(urType: string): string;
716
645
  * See: https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-004-bytewords.md
717
646
  */
718
647
  declare const BYTEWORDS: string[];
719
- declare const BYTEWORDS_MAP: Map<string, number>;
720
648
  /**
721
649
  * Bytemojis for encoding/decoding bytes as emojis.
722
650
  * See: https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2024-008-bytemoji.md
723
651
  */
724
652
  declare const BYTEMOJIS: string[];
653
+ /**
654
+ * Encodes an arbitrary byte slice as a string of space-separated bytewords.
655
+ *
656
+ * Mirrors `bytewords::encode_to_words` in `bc-ur-rust` (≥ v0.19.1). Does not
657
+ * add a CRC32 checksum — use {@link encodeBytewords} for UR-style encoding.
658
+ */
659
+ declare function encodeToWords(data: Uint8Array): string;
660
+ /**
661
+ * Encodes an arbitrary byte slice as a string of space-separated bytemojis.
662
+ *
663
+ * Mirrors `bytewords::encode_to_bytemojis` in `bc-ur-rust` (≥ v0.19.1).
664
+ */
665
+ declare function encodeToBytemojis(data: Uint8Array): string;
666
+ /**
667
+ * Encodes an arbitrary byte slice as minimal bytewords (first + last letter of
668
+ * each word, concatenated with no separator).
669
+ *
670
+ * Mirrors `bytewords::encode_to_minimal_bytewords` in `bc-ur-rust`
671
+ * (≥ v0.19.1). Does not add a CRC32 checksum.
672
+ */
673
+ declare function encodeToMinimalBytewords(data: Uint8Array): string;
725
674
  /**
726
675
  * Encodes a 4-byte slice as a string of bytewords for identification.
676
+ *
677
+ * Thin wrapper over {@link encodeToWords} that enforces the 4-byte length
678
+ * contract historically used by `bc-ur-rust`'s `bytewords::identifier`.
727
679
  */
728
680
  declare function encodeBytewordsIdentifier(data: Uint8Array): string;
729
681
  /**
730
682
  * Encodes a 4-byte slice as a string of bytemojis for identification.
683
+ *
684
+ * Thin wrapper over {@link encodeToBytemojis} that enforces the 4-byte length
685
+ * contract historically used by `bc-ur-rust`'s `bytewords::bytemoji_identifier`.
731
686
  */
732
687
  declare function encodeBytemojisIdentifier(data: Uint8Array): string;
688
+ /**
689
+ * Returns `true` if `emoji` is one of the 256 bytemojis.
690
+ *
691
+ * Mirrors `bytewords::is_valid_bytemoji` in `bc-ur-rust` (≥ v0.19.1).
692
+ */
693
+ declare function isValidBytemoji(emoji: string): boolean;
694
+ /**
695
+ * Canonicalises a byteword token (2–4 ASCII letters, case-insensitive) to its
696
+ * full 4-letter lowercase form. Returns `undefined` if the token is not a
697
+ * valid byteword or any of its short forms.
698
+ *
699
+ * Mirrors `bytewords::canonicalize_byteword` in `bc-ur-rust` (≥ v0.19.1).
700
+ *
701
+ * - 2-letter tokens are matched against the first + last letter of each
702
+ * byteword (identical to the minimal bytewords encoding).
703
+ * - 3-letter tokens are matched against the first 3 and the last 3 letters of
704
+ * each byteword; if both match different entries, the first-3 match wins
705
+ * (matching rust's `or_else` priority).
706
+ * - 4-letter tokens must exactly match a full byteword (after lower-casing).
707
+ */
708
+ declare function canonicalizeByteword(token: string): string | undefined;
733
709
  /**
734
710
  * Bytewords encoding style.
735
711
  */
736
712
  declare enum BytewordsStyle {
737
713
  /** Full 4-letter words separated by spaces */
738
714
  Standard = "standard",
739
- /** Full 4-letter words without separators */
715
+ /** Full 4-letter words separated by hyphens (URI-safe) */
740
716
  Uri = "uri",
741
717
  /** First and last character only (minimal) - used by UR encoding */
742
- Minimal = "minimal",
718
+ Minimal = "minimal"
743
719
  }
744
- declare const MINIMAL_BYTEWORDS_MAP: Map<string, number>;
745
- /**
746
- * Calculate CRC32 checksum of data.
747
- */
748
- declare function crc32(data: Uint8Array): number;
749
720
  /**
750
721
  * Encode data as bytewords with the specified style.
751
722
  * Includes CRC32 checksum.
@@ -754,8 +725,23 @@ declare function encodeBytewords(data: Uint8Array, style?: BytewordsStyle): stri
754
725
  /**
755
726
  * Decode bytewords string back to data.
756
727
  * Validates and removes CRC32 checksum.
728
+ *
729
+ * Errors mirror the upstream Rust `ur::bytewords::Error` enum
730
+ * (`ur-0.4.1/src/bytewords.rs`):
731
+ * - `NonAscii` — input contains non-ASCII characters (checked first).
732
+ * - `InvalidLength` — minimal-style input has odd length.
733
+ * - `InvalidWord` — a token does not map to a byteword index.
734
+ * - `InvalidChecksum` — the trailing 4-byte CRC32 does not match.
735
+ *
736
+ * All variants are surfaced as {@link BytewordsError} with the same default
737
+ * `Display` strings as Rust (e.g. "invalid checksum", "non-ASCII"), so
738
+ * callers can branch on the error class rather than the bare `Error`
739
+ * thrown by earlier revisions of this port.
757
740
  */
758
741
  declare function decodeBytewords(encoded: string, style?: BytewordsStyle): Uint8Array;
742
+ declare namespace bytewords_namespace_d_exports {
743
+ export { BYTEMOJIS, BYTEWORDS, BytewordsStyle as Style, encodeBytemojisIdentifier as bytemojiIdentifier, canonicalizeByteword, decodeBytewords as decode, encodeBytewords as encode, encodeToBytemojis, encodeToMinimalBytewords, encodeToWords, encodeBytewordsIdentifier as identifier, isValidBytemoji };
744
+ }
759
745
  //#endregion
760
- export { BYTEMOJIS, BYTEWORDS, BYTEWORDS_MAP, BytewordsError, BytewordsStyle, CBORError, FountainDecoder, FountainEncoder, type FountainPart, InvalidSchemeError, InvalidTypeError, MINIMAL_BYTEWORDS_MAP, MultipartDecoder, MultipartEncoder, NotSinglePartError, type Result, TypeUnspecifiedError, UR, type URCodable, type URDecodable, type UREncodable, URError, URType, UnexpectedTypeError, Xoshiro256, chooseFragments, crc32, createSeed, decodeBytewords, encodeBytemojisIdentifier, encodeBytewords, encodeBytewordsIdentifier, isError, isURCodable, isURDecodable, isUREncodable, isURTypeChar, isValidURType, mixFragments, splitMessage, validateURType, xorBytes };
746
+ export { BYTEMOJIS, BYTEWORDS, BytewordsError, BytewordsStyle, CBORError, InvalidSchemeError, InvalidTypeError, MultipartDecoder, MultipartEncoder, NotSinglePartError, type Result, TypeUnspecifiedError, UR, type URCodable, type URDecodable, URDecodeError, type UREncodable, URError, URType, UnexpectedTypeError, bytewords_namespace_d_exports as bytewords, canonicalizeByteword, decodableFromUR, decodableFromURString, decodeBytewords, encodeBytemojisIdentifier, encodeBytewords, encodeBytewordsIdentifier, encodeToBytemojis, encodeToMinimalBytewords, encodeToWords, isError, isURCodable, isURDecodable, isUREncodable, isURTypeChar, isValidBytemoji, isValidURType, urFromEncodable, urStringFromEncodable, validateURType };
761
747
  //# sourceMappingURL=index.d.mts.map