Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
Streamable sync/async CBOR parser/serializer
This is a streamble CBOR parser/serializer that can be used synchronously or asynchronously.
Simple non-streaming usage:
const bytes = encodeValueSync(inputValue); const outputValue = decodeValue(bytes);
The second parameter of these functions is an array of EncodingHandler and
DecodingHandler objects respectively, which can be used to customize the
behaviour.
// Encoding const stream: WritableStream<Uint8Array>; const writer = intoAsyncWriter(stream.getWriter()); await writeValue(writer, value); await writer.close(); // Decoding const stream: ReadableStream<Uint8Array>; const decoder = decoderFromStream(stream); const value = await parseDecoder(decoder); // If you need a more low-level API, you can iterate over the events of the decoder object. const events = decoder.events(); for await (const event of events) { // Handle events if (isStartEvent(event, MajorTypes.TextString)) { const it = consumeTextString(event); // Returns an AsyncIterableIterator<string> or IterableIterator<string> } }
Note: Multiple event iterators may exist simultaneously but events are only
consumed once. For consumeTextString and consumeByteString you should reach
the end of the string iterator before you continue to use an events iterator. If
you consume an event an then attempt to continue consuming a text/byte string,
the internal logic of the string consumption may break.
Iterables and Async iterables will be serialized as indefinite length arrays by default.
You may override the default encoding/decoding handlers.
Example of an EncodingHandler:
export const mapEncodingHandler: EncodingHandler<Map<unknown, unknown>> = { match: (value) => value instanceof Map, write: writeMap, // WriteFunction }; export function writeMap<Writer extends AnyWriter>( writer: Writer, value: Map<unknown, unknown>, encodingHandlers: EncodingHandler[] = defaultEncodingHandlers, ): WriterReturnType<Writer> { return sequentialWriteGenerator(writer, function* () { yield writeMapHeader(writer, value.size); for (const [key, item] of value) { yield writeValue(writer, key, encodingHandlers); yield writeValue(writer, item, encodingHandlers); } }); }
The above WriteFunction can be used both synchronously or asynchronously
depending on the type of Writer received. You may imagine await calls being
inserted at uses of the yield keyword.
If your WriteFunction needs to make use of async calls, you can use the
mustUseAsyncWriter helper function. When this function is called with a Writer
that does not support asynchronous writing an Error will be thrown.
export function writeAsyncIterable<Writer extends AnyWriter>( writer: Writer, value: AsyncIterable<unknown>, encodingHandlers: EncodingHandler[] = defaultEncodingHandlers, ): WriterReturnType<Writer> { return mustUseAsyncWriter(writer, async () => { await writeArrayHeader(writer); for await (const element of value as AsyncIterable<unknown>) { await writeValue(writer, element, encodingHandlers); } await writeBreak(writer); }); }
You may create your own WriteFunction, but there are plenty available in the
package.
Example of a DecodingHandler:
export const bigNumDecodingHandler: DecodingHandler<TagEvent> = createTaggedValueDecodingHandler((tag) => { return tag === 2 || tag === 3; }, (taggedValue: TaggedValue<unknown>) => { const bytes = (taggedValue as TaggedValue<Uint8Array>) .value as Uint8Array; const isNegative = taggedValue.tag === 3; let value = 0n; for (const byte of bytes) { value = (value << 8n) | BigInt(byte); } if (isNegative) { value = -1n - value; } return value; });
Add Package
deno add jsr:@kilo/cbor
Import symbol
import * as cbor from "@kilo/cbor";
Import directly with a jsr specifier
import * as cbor from "jsr:@kilo/cbor";
Add Package
pnpm i jsr:@kilo/cbor
pnpm dlx jsr add @kilo/cbor
Import symbol
import * as cbor from "@kilo/cbor";
Add Package
yarn add jsr:@kilo/cbor
yarn dlx jsr add @kilo/cbor
Import symbol
import * as cbor from "@kilo/cbor";
Add Package
vlt install jsr:@kilo/cbor
Import symbol
import * as cbor from "@kilo/cbor";
Add Package
npx jsr add @kilo/cbor
Import symbol
import * as cbor from "@kilo/cbor";
Add Package
bunx jsr add @kilo/cbor
Import symbol
import * as cbor from "@kilo/cbor";