protons-runtime
Advanced tools
Comparing version 2.0.2 to 3.0.0
@@ -1,2 +0,2 @@ | ||
import type { Uint8ArrayList } from 'uint8arraylist'; | ||
import type { Writer, Reader } from './index.js'; | ||
export declare enum CODEC_TYPES { | ||
@@ -10,11 +10,11 @@ VARINT = 0, | ||
} | ||
export interface EncodeOptions { | ||
lengthDelimited?: boolean; | ||
} | ||
export interface EncodeFunction<T> { | ||
(value: T): Uint8Array | Uint8ArrayList; | ||
(value: T, writer: Writer, opts?: EncodeOptions): void; | ||
} | ||
export interface DecodeFunction<T> { | ||
(buf: Uint8ArrayList, offset: number): T; | ||
(reader: Reader, length?: number): T; | ||
} | ||
export interface EncodingLengthFunction<T> { | ||
(value: T): number; | ||
} | ||
export interface Codec<T> { | ||
@@ -25,5 +25,4 @@ name: string; | ||
decode: DecodeFunction<T>; | ||
encodingLength: EncodingLengthFunction<T>; | ||
} | ||
export declare function createCodec<T>(name: string, type: CODEC_TYPES, encode: EncodeFunction<T>, decode: DecodeFunction<T>, encodingLength: EncodingLengthFunction<T>): Codec<T>; | ||
export declare function createCodec<T>(name: string, type: CODEC_TYPES, encode: EncodeFunction<T>, decode: DecodeFunction<T>): Codec<T>; | ||
//# sourceMappingURL=codec.d.ts.map |
@@ -11,3 +11,3 @@ // https://developers.google.com/protocol-buffers/docs/encoding#structure | ||
})(CODEC_TYPES || (CODEC_TYPES = {})); | ||
export function createCodec(name, type, encode, decode, encodingLength) { | ||
export function createCodec(name, type, encode, decode) { | ||
return { | ||
@@ -17,6 +17,5 @@ name, | ||
encode, | ||
decode, | ||
encodingLength | ||
decode | ||
}; | ||
} | ||
//# sourceMappingURL=codec.js.map |
@@ -1,36 +0,22 @@ | ||
import { unsigned } from 'uint8-varint'; | ||
import { createCodec, CODEC_TYPES } from '../codec.js'; | ||
import { allocUnsafe } from '../utils/alloc.js'; | ||
export function enumeration(v) { | ||
function findValue(val) { | ||
// Use the reverse mapping to look up the enum key for the stored value | ||
// https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings | ||
if (v[val.toString()] == null) { | ||
throw new Error('Invalid enum value'); | ||
} | ||
if (typeof val === 'number') { | ||
return val; | ||
} | ||
return v[val]; | ||
} | ||
const encodingLength = function enumEncodingLength(val) { | ||
return unsigned.encodingLength(findValue(val)); | ||
}; | ||
const encode = function enumEncode(val) { | ||
const encode = function enumEncode(val, writer) { | ||
const enumValue = findValue(val); | ||
const buf = allocUnsafe(unsigned.encodingLength(enumValue)); | ||
unsigned.encode(enumValue, buf); | ||
return buf; | ||
writer.int32(enumValue); | ||
}; | ||
const decode = function enumDecode(buf, offset) { | ||
const value = unsigned.decode(buf, offset); | ||
const strValue = value.toString(); | ||
// Use the reverse mapping to look up the enum key for the stored value | ||
// https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings | ||
if (v[strValue] == null) { | ||
throw new Error('Invalid enum value'); | ||
} | ||
return v[strValue]; | ||
const decode = function enumDecode(reader) { | ||
const val = reader.uint32(); | ||
return findValue(val); | ||
}; | ||
// @ts-expect-error yeah yeah | ||
return createCodec('enum', CODEC_TYPES.VARINT, encode, decode, encodingLength); | ||
return createCodec('enum', CODEC_TYPES.VARINT, encode, decode); | ||
} | ||
//# sourceMappingURL=enum.js.map |
@@ -0,7 +1,8 @@ | ||
import { EncodeOptions } from '../codec.js'; | ||
import type { Codec } from '../codec.js'; | ||
import type { FieldDefs } from '../index.js'; | ||
import type { Reader, Writer } from '../index.js'; | ||
export interface Factory<A, T> { | ||
new (obj: A): T; | ||
} | ||
export declare function message<T>(fieldDefs: FieldDefs): Codec<T>; | ||
export declare function message<T>(encode: (obj: T, writer: Writer, opts?: EncodeOptions) => void, decode: (reader: Reader, length?: number) => T): Codec<T>; | ||
//# sourceMappingURL=message.d.ts.map |
@@ -1,109 +0,5 @@ | ||
import { unsigned } from 'uint8-varint'; | ||
import { createCodec, CODEC_TYPES } from '../codec.js'; | ||
import { Uint8ArrayList } from 'uint8arraylist'; | ||
import { allocUnsafe } from '../utils/alloc.js'; | ||
export function message(fieldDefs) { | ||
const encodingLength = function messageEncodingLength(val) { | ||
let length = 0; | ||
for (const fieldDef of Object.values(fieldDefs)) { | ||
length += fieldDef.codec.encodingLength(val[fieldDef.name]); | ||
} | ||
return unsigned.encodingLength(length) + length; | ||
}; | ||
const encode = function messageEncode(val) { | ||
const bytes = new Uint8ArrayList(); | ||
function encodeValue(value, fieldNumber, fieldDef) { | ||
if (value == null) { | ||
if (fieldDef.optional === true) { | ||
return; | ||
} | ||
throw new Error(`Non optional field "${fieldDef.name}" was ${value === null ? 'null' : 'undefined'}`); | ||
} | ||
const key = (fieldNumber << 3) | fieldDef.codec.type; | ||
const prefix = allocUnsafe(unsigned.encodingLength(key)); | ||
unsigned.encode(key, prefix); | ||
const encoded = fieldDef.codec.encode(value); | ||
bytes.append(prefix); | ||
bytes.append(encoded); | ||
} | ||
for (const [fieldNumberStr, fieldDef] of Object.entries(fieldDefs)) { | ||
const fieldNumber = parseInt(fieldNumberStr); | ||
if (fieldDef.repeats === true) { | ||
if (!Array.isArray(val[fieldDef.name])) { | ||
throw new Error(`Repeating field "${fieldDef.name}" was not an array`); | ||
} | ||
for (const value of val[fieldDef.name]) { | ||
encodeValue(value, fieldNumber, fieldDef); | ||
} | ||
} | ||
else { | ||
encodeValue(val[fieldDef.name], fieldNumber, fieldDef); | ||
} | ||
} | ||
const prefix = unsigned.encode(bytes.length); | ||
return new Uint8ArrayList(prefix, bytes); | ||
}; | ||
const decode = function messageDecode(buffer, offset) { | ||
const length = unsigned.decode(buffer, offset); | ||
offset += unsigned.encodingLength(length); | ||
const end = offset + length; | ||
const fields = {}; | ||
while (offset < end) { | ||
const key = unsigned.decode(buffer, offset); | ||
offset += unsigned.encodingLength(key); | ||
const wireType = key & 0x7; | ||
const fieldNumber = key >> 3; | ||
const fieldDef = fieldDefs[fieldNumber]; | ||
let fieldLength = 0; | ||
if (wireType === CODEC_TYPES.VARINT) { | ||
if (fieldDef != null) { | ||
// use the codec if it is available as this could be a bigint | ||
const value = fieldDef.codec.decode(buffer, offset); | ||
fieldLength = fieldDef.codec.encodingLength(value); | ||
} | ||
else { | ||
const value = unsigned.decode(buffer, offset); | ||
fieldLength = unsigned.encodingLength(value); | ||
} | ||
} | ||
else if (wireType === CODEC_TYPES.BIT64) { | ||
fieldLength = 8; | ||
} | ||
else if (wireType === CODEC_TYPES.LENGTH_DELIMITED) { | ||
const valueLength = unsigned.decode(buffer, offset); | ||
fieldLength = valueLength + unsigned.encodingLength(valueLength); | ||
} | ||
else if (wireType === CODEC_TYPES.BIT32) { | ||
fieldLength = 4; | ||
} | ||
else if (wireType === CODEC_TYPES.START_GROUP) { | ||
throw new Error('Unsupported wire type START_GROUP'); | ||
} | ||
else if (wireType === CODEC_TYPES.END_GROUP) { | ||
throw new Error('Unsupported wire type END_GROUP'); | ||
} | ||
if (fieldDef != null) { | ||
const value = fieldDef.codec.decode(buffer, offset); | ||
if (fieldDef.repeats === true) { | ||
if (fields[fieldDef.name] == null) { | ||
fields[fieldDef.name] = []; | ||
} | ||
fields[fieldDef.name].push(value); | ||
} | ||
else { | ||
fields[fieldDef.name] = value; | ||
} | ||
} | ||
offset += fieldLength; | ||
} | ||
// make sure repeated fields have an array if not set | ||
for (const fieldDef of Object.values(fieldDefs)) { | ||
if (fieldDef.repeats === true && fields[fieldDef.name] == null) { | ||
fields[fieldDef.name] = []; | ||
} | ||
} | ||
return fields; | ||
}; | ||
return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength); | ||
export function message(encode, decode) { | ||
return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode); | ||
} | ||
//# sourceMappingURL=message.js.map |
@@ -1,4 +0,4 @@ | ||
import { Uint8ArrayList } from 'uint8arraylist'; | ||
import type { Uint8ArrayList } from 'uint8arraylist'; | ||
import type { Codec } from './codec.js'; | ||
export declare function decodeMessage<T>(buf: Uint8Array | Uint8ArrayList, codec: Codec<T>): T; | ||
//# sourceMappingURL=decode.d.ts.map |
@@ -1,10 +0,20 @@ | ||
import { Uint8ArrayList } from 'uint8arraylist'; | ||
import { unsigned } from 'uint8-varint'; | ||
import { allocUnsafe } from './utils/alloc.js'; | ||
import pb from 'protobufjs'; | ||
const Reader = pb.Reader; | ||
// monkey patch the reader to add native bigint support | ||
const methods = [ | ||
'uint64', 'int64', 'sint64', 'fixed64', 'sfixed64' | ||
]; | ||
methods.forEach(method => { | ||
// @ts-expect-error | ||
const original = Reader.prototype[method]; | ||
// @ts-expect-error | ||
Reader.prototype[method] = function () { | ||
return BigInt(original.call(this).toString()); | ||
}; | ||
}); | ||
export function decodeMessage(buf, codec) { | ||
// wrap root message | ||
const prefix = allocUnsafe(unsigned.encodingLength(buf.byteLength)); | ||
unsigned.encode(buf.byteLength, prefix); | ||
return codec.decode(new Uint8ArrayList(prefix, buf), 0); | ||
const reader = Reader.create(buf instanceof Uint8Array ? buf : buf.subarray()); | ||
// @ts-expect-error | ||
return codec.decode(reader); | ||
} | ||
//# sourceMappingURL=decode.js.map |
@@ -1,4 +0,3 @@ | ||
import { Uint8ArrayList } from 'uint8arraylist'; | ||
import type { Codec } from './codec.js'; | ||
export declare function encodeMessage<T>(message: T, codec: Codec<T>): Uint8ArrayList; | ||
export declare function encodeMessage<T>(message: T, codec: Codec<T>): Uint8Array; | ||
//# sourceMappingURL=encode.d.ts.map |
@@ -1,12 +0,23 @@ | ||
import { Uint8ArrayList } from 'uint8arraylist'; | ||
import { unsigned } from 'uint8-varint'; | ||
import pb from 'protobufjs'; | ||
const Writer = pb.Writer; | ||
// monkey patch the writer to add native bigint support | ||
const methods = [ | ||
'uint64', 'int64', 'sint64', 'fixed64', 'sfixed64' | ||
]; | ||
methods.forEach(method => { | ||
// @ts-expect-error | ||
const original = Writer.prototype[method]; | ||
// @ts-expect-error | ||
Writer.prototype[method] = function (val) { | ||
return original.call(this, val.toString()); | ||
}; | ||
}); | ||
export function encodeMessage(message, codec) { | ||
// unwrap root message | ||
const encoded = codec.encode(message); | ||
const skip = unsigned.encodingLength(unsigned.decode(encoded)); | ||
if (encoded instanceof Uint8Array) { | ||
return new Uint8ArrayList(encoded.subarray(skip)); | ||
} | ||
return encoded.sublist(skip); | ||
const w = Writer.create(); | ||
// @ts-expect-error | ||
codec.encode(message, w, { | ||
lengthDelimited: false | ||
}); | ||
return w.finish(); | ||
} | ||
//# sourceMappingURL=encode.js.map |
@@ -9,23 +9,172 @@ import type { Codec } from './codec.js'; | ||
} | ||
export declare type FieldDefs = Record<number, FieldDef>; | ||
export { decodeMessage } from './decode.js'; | ||
export { encodeMessage } from './encode.js'; | ||
export { bool } from './codecs/bool.js'; | ||
export { bytes } from './codecs/bytes.js'; | ||
export { double } from './codecs/double.js'; | ||
export { enumeration } from './codecs/enum.js'; | ||
export { fixed32 } from './codecs/fixed32.js'; | ||
export { fixed64 } from './codecs/fixed64.js'; | ||
export { float } from './codecs/float.js'; | ||
export { int32 } from './codecs/int32.js'; | ||
export { int64 } from './codecs/int64.js'; | ||
export { message } from './codecs/message.js'; | ||
export { sfixed32 } from './codecs/sfixed32.js'; | ||
export { sfixed64 } from './codecs/sfixed64.js'; | ||
export { sint32 } from './codecs/sint32.js'; | ||
export { sint64 } from './codecs/sint64.js'; | ||
export { string } from './codecs/string.js'; | ||
export { uint32 } from './codecs/uint32.js'; | ||
export { uint64 } from './codecs/uint64.js'; | ||
export type { Codec } from './codec.js'; | ||
export type { Codec, EncodeOptions } from './codec.js'; | ||
export interface Writer { | ||
/** | ||
* Current length | ||
*/ | ||
len: number; | ||
/** | ||
* Writes an unsigned 32 bit value as a varint | ||
*/ | ||
uint32: (value: number) => Writer; | ||
/** | ||
* Writes a signed 32 bit value as a varint` | ||
*/ | ||
int32: (value: number) => Writer; | ||
/** | ||
* Writes a 32 bit value as a varint, zig-zag encoded | ||
*/ | ||
sint32: (value: number) => Writer; | ||
/** | ||
* Writes an unsigned 64 bit value as a varint | ||
*/ | ||
uint64: (value: bigint) => Writer; | ||
/** | ||
* Writes a signed 64 bit value as a varint | ||
*/ | ||
int64: (value: bigint) => Writer; | ||
/** | ||
* Writes a signed 64 bit value as a varint, zig-zag encoded | ||
*/ | ||
sint64: (value: bigint) => Writer; | ||
/** | ||
* Writes a boolish value as a varint | ||
*/ | ||
bool: (value: boolean) => Writer; | ||
/** | ||
* Writes an unsigned 32 bit value as fixed 32 bits | ||
*/ | ||
fixed32: (value: number) => Writer; | ||
/** | ||
* Writes a signed 32 bit value as fixed 32 bits | ||
*/ | ||
sfixed32: (value: number) => Writer; | ||
/** | ||
* Writes an unsigned 64 bit value as fixed 64 bits | ||
*/ | ||
fixed64: (value: bigint) => Writer; | ||
/** | ||
* Writes a signed 64 bit value as fixed 64 bits | ||
*/ | ||
sfixed64: (value: bigint) => Writer; | ||
/** | ||
* Writes a float (32 bit) | ||
*/ | ||
float: (value: number) => Writer; | ||
/** | ||
* Writes a double (64 bit float) | ||
*/ | ||
double: (value: number) => Writer; | ||
/** | ||
* Writes a sequence of bytes | ||
*/ | ||
bytes: (value: Uint8Array) => Writer; | ||
/** | ||
* Writes a string | ||
*/ | ||
string: (value: string) => Writer; | ||
/** | ||
* Forks this writer's state by pushing it to a stack. | ||
* Calling {@link Writer#reset|reset} or {@link Writer#ldelim|ldelim} resets the writer to the previous state. | ||
*/ | ||
fork: () => Writer; | ||
/** | ||
* Resets this instance to the last state. | ||
*/ | ||
reset: () => Writer; | ||
/** | ||
* Resets to the last state and appends the fork state's current write length as a varint followed by its operations. | ||
*/ | ||
ldelim: () => Writer; | ||
/** | ||
* Finishes the write operation | ||
*/ | ||
finish: () => Uint8Array; | ||
} | ||
export interface Reader { | ||
/** | ||
* Read buffer | ||
*/ | ||
buf: Uint8Array; | ||
/** | ||
* Read buffer position | ||
*/ | ||
pos: number; | ||
/** | ||
* Read buffer length | ||
*/ | ||
len: number; | ||
/** | ||
* Reads a varint as an unsigned 32 bit value | ||
*/ | ||
uint32: () => number; | ||
/** | ||
* Reads a varint as a signed 32 bit value | ||
*/ | ||
int32: () => number; | ||
/** | ||
* Reads a zig-zag encoded varint as a signed 32 bit value | ||
*/ | ||
sint32: () => number; | ||
/** | ||
* Reads a varint as a boolean | ||
*/ | ||
bool: () => boolean; | ||
/** | ||
* Reads fixed 32 bits as an unsigned 32 bit integer | ||
*/ | ||
fixed32: () => number; | ||
/** | ||
* Reads fixed 32 bits as a signed 32 bit integer | ||
*/ | ||
sfixed32: () => number; | ||
/** | ||
* Reads a float (32 bit) as a number | ||
*/ | ||
float: () => number; | ||
/** | ||
* Reads a double (64 bit float) as a number | ||
*/ | ||
double: () => number; | ||
/** | ||
* Reads a sequence of bytes preceeded by its length as a varint | ||
*/ | ||
bytes: () => number; | ||
/** | ||
* Reads a string preceeded by its byte length as a varint | ||
*/ | ||
string: () => string; | ||
/** | ||
* Skips the specified number of bytes if specified, otherwise skips a varints` | ||
*/ | ||
skip: (length?: number) => void; | ||
/** | ||
* Skips the next element of the specified wire type | ||
*/ | ||
skipType: (wireType: number) => void; | ||
/** | ||
* Reads a varint as a signed 64 bit value | ||
*/ | ||
int64: () => bigint; | ||
/** | ||
* Reads a varint as an unsigned 64 bit value | ||
*/ | ||
uint64: () => bigint; | ||
/** | ||
* Reads a zig-zag encoded varint as a signed 64 bit value | ||
*/ | ||
sint64: () => bigint; | ||
/** | ||
* Reads fixed 64 bits | ||
*/ | ||
fixed64: () => bigint; | ||
/** | ||
* Reads zig-zag encoded fixed 64 bits | ||
*/ | ||
sfixed64: () => bigint; | ||
} | ||
//# sourceMappingURL=index.d.ts.map |
export { decodeMessage } from './decode.js'; | ||
export { encodeMessage } from './encode.js'; | ||
export { bool } from './codecs/bool.js'; | ||
export { bytes } from './codecs/bytes.js'; | ||
export { double } from './codecs/double.js'; | ||
export { enumeration } from './codecs/enum.js'; | ||
export { fixed32 } from './codecs/fixed32.js'; | ||
export { fixed64 } from './codecs/fixed64.js'; | ||
export { float } from './codecs/float.js'; | ||
export { int32 } from './codecs/int32.js'; | ||
export { int64 } from './codecs/int64.js'; | ||
export { message } from './codecs/message.js'; | ||
export { sfixed32 } from './codecs/sfixed32.js'; | ||
export { sfixed64 } from './codecs/sfixed64.js'; | ||
export { sint32 } from './codecs/sint32.js'; | ||
export { sint64 } from './codecs/sint64.js'; | ||
export { string } from './codecs/string.js'; | ||
export { uint32 } from './codecs/uint32.js'; | ||
export { uint64 } from './codecs/uint64.js'; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "protons-runtime", | ||
"version": "2.0.2", | ||
"version": "3.0.0", | ||
"description": "Shared code to make your bundle smaller when running protons in your app", | ||
@@ -151,7 +151,4 @@ "license": "Apache-2.0 OR MIT", | ||
"dependencies": { | ||
"byte-access": "^1.0.1", | ||
"longbits": "^1.1.0", | ||
"uint8-varint": "^1.0.2", | ||
"uint8arraylist": "^2.0.0", | ||
"uint8arrays": "^3.0.0" | ||
"protobufjs": "^7.0.0", | ||
"uint8arraylist": "^2.3.2" | ||
}, | ||
@@ -158,0 +155,0 @@ "devDependencies": { |
@@ -1,2 +0,2 @@ | ||
import type { Uint8ArrayList } from 'uint8arraylist' | ||
import type { Writer, Reader } from './index.js' | ||
@@ -13,14 +13,14 @@ // https://developers.google.com/protocol-buffers/docs/encoding#structure | ||
export interface EncodeOptions { | ||
lengthDelimited?: boolean | ||
} | ||
export interface EncodeFunction<T> { | ||
(value: T): Uint8Array | Uint8ArrayList | ||
(value: T, writer: Writer, opts?: EncodeOptions): void | ||
} | ||
export interface DecodeFunction<T> { | ||
(buf: Uint8ArrayList, offset: number): T | ||
(reader: Reader, length?: number): T | ||
} | ||
export interface EncodingLengthFunction<T> { | ||
(value: T): number | ||
} | ||
export interface Codec<T> { | ||
@@ -31,6 +31,5 @@ name: string | ||
decode: DecodeFunction<T> | ||
encodingLength: EncodingLengthFunction<T> | ||
} | ||
export function createCodec <T> (name: string, type: CODEC_TYPES, encode: EncodeFunction<T>, decode: DecodeFunction<T>, encodingLength: EncodingLengthFunction<T>): Codec<T> { | ||
export function createCodec <T> (name: string, type: CODEC_TYPES, encode: EncodeFunction<T>, decode: DecodeFunction<T>): Codec<T> { | ||
return { | ||
@@ -40,5 +39,4 @@ name, | ||
encode, | ||
decode, | ||
encodingLength | ||
decode | ||
} | ||
} |
import { unsigned } from 'uint8-varint' | ||
import { createCodec, CODEC_TYPES } from '../codec.js' | ||
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction, Codec } from '../codec.js' | ||
import { allocUnsafe } from '../utils/alloc.js' | ||
import type { DecodeFunction, EncodeFunction, Codec } from '../codec.js' | ||
export function enumeration <T> (v: any): Codec<T> { | ||
function findValue (val: string | number): number { | ||
// Use the reverse mapping to look up the enum key for the stored value | ||
// https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings | ||
if (v[val.toString()] == null) { | ||
@@ -13,37 +13,19 @@ throw new Error('Invalid enum value') | ||
if (typeof val === 'number') { | ||
return val | ||
} | ||
return v[val] | ||
} | ||
const encodingLength: EncodingLengthFunction<number | string> = function enumEncodingLength (val) { | ||
return unsigned.encodingLength(findValue(val)) | ||
} | ||
const encode: EncodeFunction<number | string> = function enumEncode (val) { | ||
const encode: EncodeFunction<number | string> = function enumEncode (val, writer) { | ||
const enumValue = findValue(val) | ||
const buf = allocUnsafe(unsigned.encodingLength(enumValue)) | ||
unsigned.encode(enumValue, buf) | ||
return buf | ||
writer.int32(enumValue) | ||
} | ||
const decode: DecodeFunction<number | string> = function enumDecode (buf, offset) { | ||
const value = unsigned.decode(buf, offset) | ||
const strValue = value.toString() | ||
const decode: DecodeFunction<number | string> = function enumDecode (reader) { | ||
const val = reader.uint32() | ||
// Use the reverse mapping to look up the enum key for the stored value | ||
// https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings | ||
if (v[strValue] == null) { | ||
throw new Error('Invalid enum value') | ||
} | ||
return v[strValue] | ||
return findValue(val) | ||
} | ||
// @ts-expect-error yeah yeah | ||
return createCodec('enum', CODEC_TYPES.VARINT, encode, decode, encodingLength) | ||
return createCodec('enum', CODEC_TYPES.VARINT, encode, decode) | ||
} |
@@ -1,7 +0,4 @@ | ||
import { unsigned } from 'uint8-varint' | ||
import { createCodec, CODEC_TYPES } from '../codec.js' | ||
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction, Codec } from '../codec.js' | ||
import { Uint8ArrayList } from 'uint8arraylist' | ||
import type { FieldDefs, FieldDef } from '../index.js' | ||
import { allocUnsafe } from '../utils/alloc.js' | ||
import { createCodec, CODEC_TYPES, EncodeOptions } from '../codec.js' | ||
import type { Codec } from '../codec.js' | ||
import type { Reader, Writer } from '../index.js' | ||
@@ -12,120 +9,4 @@ export interface Factory<A, T> { | ||
export function message <T> (fieldDefs: FieldDefs): Codec<T> { | ||
const encodingLength: EncodingLengthFunction<T> = function messageEncodingLength (val: Record<string, any>) { | ||
let length = 0 | ||
for (const fieldDef of Object.values(fieldDefs)) { | ||
length += fieldDef.codec.encodingLength(val[fieldDef.name]) | ||
} | ||
return unsigned.encodingLength(length) + length | ||
} | ||
const encode: EncodeFunction<Record<string, any>> = function messageEncode (val) { | ||
const bytes = new Uint8ArrayList() | ||
function encodeValue (value: any, fieldNumber: number, fieldDef: FieldDef) { | ||
if (value == null) { | ||
if (fieldDef.optional === true) { | ||
return | ||
} | ||
throw new Error(`Non optional field "${fieldDef.name}" was ${value === null ? 'null' : 'undefined'}`) | ||
} | ||
const key = (fieldNumber << 3) | fieldDef.codec.type | ||
const prefix = allocUnsafe(unsigned.encodingLength(key)) | ||
unsigned.encode(key, prefix) | ||
const encoded = fieldDef.codec.encode(value) | ||
bytes.append(prefix) | ||
bytes.append(encoded) | ||
} | ||
for (const [fieldNumberStr, fieldDef] of Object.entries(fieldDefs)) { | ||
const fieldNumber = parseInt(fieldNumberStr) | ||
if (fieldDef.repeats === true) { | ||
if (!Array.isArray(val[fieldDef.name])) { | ||
throw new Error(`Repeating field "${fieldDef.name}" was not an array`) | ||
} | ||
for (const value of val[fieldDef.name]) { | ||
encodeValue(value, fieldNumber, fieldDef) | ||
} | ||
} else { | ||
encodeValue(val[fieldDef.name], fieldNumber, fieldDef) | ||
} | ||
} | ||
const prefix = unsigned.encode(bytes.length) | ||
return new Uint8ArrayList(prefix, bytes) | ||
} | ||
const decode: DecodeFunction<T> = function messageDecode (buffer, offset) { | ||
const length = unsigned.decode(buffer, offset) | ||
offset += unsigned.encodingLength(length) | ||
const end = offset + length | ||
const fields: any = {} | ||
while (offset < end) { | ||
const key = unsigned.decode(buffer, offset) | ||
offset += unsigned.encodingLength(key) | ||
const wireType = key & 0x7 | ||
const fieldNumber = key >> 3 | ||
const fieldDef = fieldDefs[fieldNumber] | ||
let fieldLength = 0 | ||
if (wireType === CODEC_TYPES.VARINT) { | ||
if (fieldDef != null) { | ||
// use the codec if it is available as this could be a bigint | ||
const value = fieldDef.codec.decode(buffer, offset) | ||
fieldLength = fieldDef.codec.encodingLength(value) | ||
} else { | ||
const value = unsigned.decode(buffer, offset) | ||
fieldLength = unsigned.encodingLength(value) | ||
} | ||
} else if (wireType === CODEC_TYPES.BIT64) { | ||
fieldLength = 8 | ||
} else if (wireType === CODEC_TYPES.LENGTH_DELIMITED) { | ||
const valueLength = unsigned.decode(buffer, offset) | ||
fieldLength = valueLength + unsigned.encodingLength(valueLength) | ||
} else if (wireType === CODEC_TYPES.BIT32) { | ||
fieldLength = 4 | ||
} else if (wireType === CODEC_TYPES.START_GROUP) { | ||
throw new Error('Unsupported wire type START_GROUP') | ||
} else if (wireType === CODEC_TYPES.END_GROUP) { | ||
throw new Error('Unsupported wire type END_GROUP') | ||
} | ||
if (fieldDef != null) { | ||
const value = fieldDef.codec.decode(buffer, offset) | ||
if (fieldDef.repeats === true) { | ||
if (fields[fieldDef.name] == null) { | ||
fields[fieldDef.name] = [] | ||
} | ||
fields[fieldDef.name].push(value) | ||
} else { | ||
fields[fieldDef.name] = value | ||
} | ||
} | ||
offset += fieldLength | ||
} | ||
// make sure repeated fields have an array if not set | ||
for (const fieldDef of Object.values(fieldDefs)) { | ||
if (fieldDef.repeats === true && fields[fieldDef.name] == null) { | ||
fields[fieldDef.name] = [] | ||
} | ||
} | ||
return fields | ||
} | ||
return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength) | ||
export function message <T> (encode: (obj: T, writer: Writer, opts?: EncodeOptions) => void, decode: (reader: Reader, length?: number) => T): Codec<T> { | ||
return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode) | ||
} |
@@ -1,12 +0,25 @@ | ||
import { Uint8ArrayList } from 'uint8arraylist' | ||
import { unsigned } from 'uint8-varint' | ||
import type { Uint8ArrayList } from 'uint8arraylist' | ||
import type { Codec } from './codec.js' | ||
import { allocUnsafe } from './utils/alloc.js' | ||
import pb from 'protobufjs' | ||
const Reader = pb.Reader | ||
// monkey patch the reader to add native bigint support | ||
const methods = [ | ||
'uint64', 'int64', 'sint64', 'fixed64', 'sfixed64' | ||
] | ||
methods.forEach(method => { | ||
// @ts-expect-error | ||
const original = Reader.prototype[method] | ||
// @ts-expect-error | ||
Reader.prototype[method] = function (): bigint { | ||
return BigInt(original.call(this).toString()) | ||
} | ||
}) | ||
export function decodeMessage <T> (buf: Uint8Array | Uint8ArrayList, codec: Codec<T>): T { | ||
// wrap root message | ||
const prefix = allocUnsafe(unsigned.encodingLength(buf.byteLength)) | ||
unsigned.encode(buf.byteLength, prefix) | ||
const reader = Reader.create(buf instanceof Uint8Array ? buf : buf.subarray()) | ||
return codec.decode(new Uint8ArrayList(prefix, buf), 0) | ||
// @ts-expect-error | ||
return codec.decode(reader) | ||
} |
@@ -1,15 +0,28 @@ | ||
import { Uint8ArrayList } from 'uint8arraylist' | ||
import type { Codec } from './codec.js' | ||
import { unsigned } from 'uint8-varint' | ||
import pb from 'protobufjs' | ||
export function encodeMessage <T> (message: T, codec: Codec<T>): Uint8ArrayList { | ||
// unwrap root message | ||
const encoded = codec.encode(message) | ||
const skip = unsigned.encodingLength(unsigned.decode(encoded)) | ||
const Writer = pb.Writer | ||
if (encoded instanceof Uint8Array) { | ||
return new Uint8ArrayList(encoded.subarray(skip)) | ||
// monkey patch the writer to add native bigint support | ||
const methods = [ | ||
'uint64', 'int64', 'sint64', 'fixed64', 'sfixed64' | ||
] | ||
methods.forEach(method => { | ||
// @ts-expect-error | ||
const original = Writer.prototype[method] | ||
// @ts-expect-error | ||
Writer.prototype[method] = function (val: bigint): pb.Writer { | ||
return original.call(this, val.toString()) | ||
} | ||
}) | ||
return encoded.sublist(skip) | ||
export function encodeMessage <T> (message: T, codec: Codec<T>): Uint8Array { | ||
const w = Writer.create() | ||
// @ts-expect-error | ||
codec.encode(message, w, { | ||
lengthDelimited: false | ||
}) | ||
return w.finish() | ||
} |
224
src/index.ts
@@ -11,4 +11,2 @@ import type { Codec } from './codec.js' | ||
export type FieldDefs = Record<number, FieldDef> | ||
export { | ||
@@ -22,19 +20,209 @@ decodeMessage | ||
export { bool } from './codecs/bool.js' | ||
export { bytes } from './codecs/bytes.js' | ||
export { double } from './codecs/double.js' | ||
export { enumeration } from './codecs/enum.js' | ||
export { fixed32 } from './codecs/fixed32.js' | ||
export { fixed64 } from './codecs/fixed64.js' | ||
export { float } from './codecs/float.js' | ||
export { int32 } from './codecs/int32.js' | ||
export { int64 } from './codecs/int64.js' | ||
export { message } from './codecs/message.js' | ||
export { sfixed32 } from './codecs/sfixed32.js' | ||
export { sfixed64 } from './codecs/sfixed64.js' | ||
export { sint32 } from './codecs/sint32.js' | ||
export { sint64 } from './codecs/sint64.js' | ||
export { string } from './codecs/string.js' | ||
export { uint32 } from './codecs/uint32.js' | ||
export { uint64 } from './codecs/uint64.js' | ||
export type { Codec } from './codec.js' | ||
export type { Codec, EncodeOptions } from './codec.js' | ||
export interface Writer { | ||
/** | ||
* Current length | ||
*/ | ||
len: number | ||
/** | ||
* Writes an unsigned 32 bit value as a varint | ||
*/ | ||
uint32: (value: number) => Writer | ||
/** | ||
* Writes a signed 32 bit value as a varint` | ||
*/ | ||
int32: (value: number) => Writer | ||
/** | ||
* Writes a 32 bit value as a varint, zig-zag encoded | ||
*/ | ||
sint32: (value: number) => Writer | ||
/** | ||
* Writes an unsigned 64 bit value as a varint | ||
*/ | ||
uint64: (value: bigint) => Writer | ||
/** | ||
* Writes a signed 64 bit value as a varint | ||
*/ | ||
int64: (value: bigint) => Writer | ||
/** | ||
* Writes a signed 64 bit value as a varint, zig-zag encoded | ||
*/ | ||
sint64: (value: bigint) => Writer | ||
/** | ||
* Writes a boolish value as a varint | ||
*/ | ||
bool: (value: boolean) => Writer | ||
/** | ||
* Writes an unsigned 32 bit value as fixed 32 bits | ||
*/ | ||
fixed32: (value: number) => Writer | ||
/** | ||
* Writes a signed 32 bit value as fixed 32 bits | ||
*/ | ||
sfixed32: (value: number) => Writer | ||
/** | ||
* Writes an unsigned 64 bit value as fixed 64 bits | ||
*/ | ||
fixed64: (value: bigint) => Writer | ||
/** | ||
* Writes a signed 64 bit value as fixed 64 bits | ||
*/ | ||
sfixed64: (value: bigint) => Writer | ||
/** | ||
* Writes a float (32 bit) | ||
*/ | ||
float: (value: number) => Writer | ||
/** | ||
* Writes a double (64 bit float) | ||
*/ | ||
double: (value: number) => Writer | ||
/** | ||
* Writes a sequence of bytes | ||
*/ | ||
bytes: (value: Uint8Array) => Writer | ||
/** | ||
* Writes a string | ||
*/ | ||
string: (value: string) => Writer | ||
/** | ||
* Forks this writer's state by pushing it to a stack. | ||
* Calling {@link Writer#reset|reset} or {@link Writer#ldelim|ldelim} resets the writer to the previous state. | ||
*/ | ||
fork: () => Writer | ||
/** | ||
* Resets this instance to the last state. | ||
*/ | ||
reset: () => Writer | ||
/** | ||
* Resets to the last state and appends the fork state's current write length as a varint followed by its operations. | ||
*/ | ||
ldelim: () => Writer | ||
/** | ||
* Finishes the write operation | ||
*/ | ||
finish: () => Uint8Array | ||
} | ||
export interface Reader { | ||
/** | ||
* Read buffer | ||
*/ | ||
buf: Uint8Array | ||
/** | ||
* Read buffer position | ||
*/ | ||
pos: number | ||
/** | ||
* Read buffer length | ||
*/ | ||
len: number | ||
/** | ||
* Reads a varint as an unsigned 32 bit value | ||
*/ | ||
uint32: () => number | ||
/** | ||
* Reads a varint as a signed 32 bit value | ||
*/ | ||
int32: () => number | ||
/** | ||
* Reads a zig-zag encoded varint as a signed 32 bit value | ||
*/ | ||
sint32: () => number | ||
/** | ||
* Reads a varint as a boolean | ||
*/ | ||
bool: () => boolean | ||
/** | ||
* Reads fixed 32 bits as an unsigned 32 bit integer | ||
*/ | ||
fixed32: () => number | ||
/** | ||
* Reads fixed 32 bits as a signed 32 bit integer | ||
*/ | ||
sfixed32: () => number | ||
/** | ||
* Reads a float (32 bit) as a number | ||
*/ | ||
float: () => number | ||
/** | ||
* Reads a double (64 bit float) as a number | ||
*/ | ||
double: () => number | ||
/** | ||
* Reads a sequence of bytes preceeded by its length as a varint | ||
*/ | ||
bytes: () => number | ||
/** | ||
* Reads a string preceeded by its byte length as a varint | ||
*/ | ||
string: () => string | ||
/** | ||
* Skips the specified number of bytes if specified, otherwise skips a varints` | ||
*/ | ||
skip: (length?: number) => void | ||
/** | ||
* Skips the next element of the specified wire type | ||
*/ | ||
skipType: (wireType: number) => void | ||
/** | ||
* Reads a varint as a signed 64 bit value | ||
*/ | ||
int64: () => bigint | ||
/** | ||
* Reads a varint as an unsigned 64 bit value | ||
*/ | ||
uint64: () => bigint | ||
/** | ||
* Reads a zig-zag encoded varint as a signed 64 bit value | ||
*/ | ||
sint64: () => bigint | ||
/** | ||
* Reads fixed 64 bits | ||
*/ | ||
fixed64: () => bigint | ||
/** | ||
* Reads zig-zag encoded fixed 64 bits | ||
*/ | ||
sfixed64: () => bigint | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2
30903
33
595
2
+ Addedprotobufjs@^7.0.0
+ Added@protobufjs/aspromise@1.1.2(transitive)
+ Added@protobufjs/base64@1.1.2(transitive)
+ Added@protobufjs/codegen@2.0.4(transitive)
+ Added@protobufjs/eventemitter@1.1.0(transitive)
+ Added@protobufjs/fetch@1.1.0(transitive)
+ Added@protobufjs/float@1.0.2(transitive)
+ Added@protobufjs/inquire@1.1.0(transitive)
+ Added@protobufjs/path@1.1.2(transitive)
+ Added@protobufjs/pool@1.1.0(transitive)
+ Added@protobufjs/utf8@1.1.0(transitive)
+ Added@types/node@22.10.2(transitive)
+ Addedlong@5.2.3(transitive)
+ Addedprotobufjs@7.4.0(transitive)
+ Addedundici-types@6.20.0(transitive)
- Removedbyte-access@^1.0.1
- Removedlongbits@^1.1.0
- Removeduint8-varint@^1.0.2
- Removeduint8arrays@^3.0.0
- Removedbyte-access@1.0.1(transitive)
- Removedlongbits@1.1.0(transitive)
- Removedmultiformats@12.1.39.9.0(transitive)
- Removeduint8-varint@1.0.8(transitive)
- Removeduint8arrays@3.1.14.0.10(transitive)
Updateduint8arraylist@^2.3.2