Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ndn/tlv

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ndn/tlv - npm Package Compare versions

Comparing version 0.0.20230121 to 0.0.20240113

lib/struct-builder_browser.js

41

lib/decoder_browser.js

@@ -53,2 +53,8 @@ import { asDataView, fromUtf8 } from "@ndn/util";

input;
constructor(input) {
this.input = input;
this.dv = asDataView(input);
}
dv;
offset = 0;
/** Determine whether end of input has been reached. */

@@ -58,7 +64,7 @@ get eof() {

}
dv;
offset = 0;
constructor(input) {
this.input = input;
this.dv = asDataView(input);
/** Throw an error if EOF has not been reached. */
throwUnlessEof() {
if (!this.eof) {
throw new Error("junk after end of TLV");
}
}

@@ -86,3 +92,3 @@ /** Read TLV structure. */

switch (this.input[this.offset]) {
case 0xFD:
case 0xFD: {
this.offset += 3;

@@ -93,3 +99,4 @@ if (this.offset > this.input.length) {

return this.dv.getUint16(this.offset - 2);
case 0xFE:
}
case 0xFE: {
this.offset += 5;

@@ -100,10 +107,26 @@ if (this.offset > this.input.length) {

return this.dv.getUint32(this.offset - 4);
case 0xFF:
}
case 0xFF: {
// JavaScript cannot reliably represent 64-bit integers
return undefined;
default:
}
default: {
this.offset += 1;
return this.input[this.offset - 1];
}
}
}
}
(function (Decoder) {
/**
* Decode a single object from Uint8Array.
* The input is expected to contain no junk after the object.
*/
function decode(input, d) {
const decoder = new Decoder(input);
const res = d.decodeFrom(decoder);
decoder.throwUnlessEof();
return res;
}
Decoder.decode = decode;
})(Decoder || (Decoder = {}));

@@ -53,2 +53,8 @@ import { asDataView, fromUtf8 } from "@ndn/util";

input;
constructor(input) {
this.input = input;
this.dv = asDataView(input);
}
dv;
offset = 0;
/** Determine whether end of input has been reached. */

@@ -58,7 +64,7 @@ get eof() {

}
dv;
offset = 0;
constructor(input) {
this.input = input;
this.dv = asDataView(input);
/** Throw an error if EOF has not been reached. */
throwUnlessEof() {
if (!this.eof) {
throw new Error("junk after end of TLV");
}
}

@@ -86,3 +92,3 @@ /** Read TLV structure. */

switch (this.input[this.offset]) {
case 0xFD:
case 0xFD: {
this.offset += 3;

@@ -93,3 +99,4 @@ if (this.offset > this.input.length) {

return this.dv.getUint16(this.offset - 2);
case 0xFE:
}
case 0xFE: {
this.offset += 5;

@@ -100,10 +107,26 @@ if (this.offset > this.input.length) {

return this.dv.getUint32(this.offset - 4);
case 0xFF:
}
case 0xFF: {
// JavaScript cannot reliably represent 64-bit integers
return undefined;
default:
}
default: {
this.offset += 1;
return this.input[this.offset - 1];
}
}
}
}
(function (Decoder) {
/**
* Decode a single object from Uint8Array.
* The input is expected to contain no junk after the object.
*/
function decode(input, d) {
const decoder = new Decoder(input);
const res = d.decodeFrom(decoder);
decoder.throwUnlessEof();
return res;
}
Decoder.decode = decode;
})(Decoder || (Decoder = {}));

@@ -7,7 +7,9 @@ export interface Decodable<R> {

private readonly input;
constructor(input: Uint8Array);
private readonly dv;
private offset;
/** Determine whether end of input has been reached. */
get eof(): boolean;
private readonly dv;
private offset;
constructor(input: Uint8Array);
/** Throw an error if EOF has not been reached. */
throwUnlessEof(): void;
/** Read TLV structure. */

@@ -47,2 +49,7 @@ read(): Decoder.Tlv;

}
/**
* Decode a single object from Uint8Array.
* The input is expected to contain no junk after the object.
*/
function decode<R>(input: Uint8Array, d: Decodable<R>): R;
}

@@ -32,2 +32,5 @@ import { assert } from "@ndn/util";

}
applyDefaultsToRuleOptions({ order = (this.nextOrder += AUTO_ORDER_SKIP), required = false, repeat = false, } = {}) {
return { order, required, repeat };
}
/**

@@ -37,13 +40,12 @@ * Add a decoding rule.

* @param cb callback or nested EvDecoder to handle element TLV.
* @param options additional rule options.
* @param opts additional rule options.
*/
add(tt, cb, { order = (this.nextOrder += AUTO_ORDER_SKIP), required = false, repeat = false, } = {}) {
add(tt, cb, opts = {}) {
const ro = this.applyDefaultsToRuleOptions(opts);
assert(!this.rules.has(tt), "duplicate rule for same TLV-TYPE");
this.rules.set(tt, {
...ro,
cb: cb instanceof EvDecoder ? nest(cb) : cb,
order,
required,
repeat,
});
if (required) {
if (ro.required) {
this.requiredTT.add(tt);

@@ -119,1 +121,8 @@ }

}
(function (EvDecoder) {
/**
* IsCritical callback that always returns false.
* This means unrecognized or out-of-order TLV elements are ignored.
*/
EvDecoder.neverCritical = () => false;
})(EvDecoder || (EvDecoder = {}));

@@ -32,2 +32,5 @@ import { assert } from "@ndn/util";

}
applyDefaultsToRuleOptions({ order = (this.nextOrder += AUTO_ORDER_SKIP), required = false, repeat = false, } = {}) {
return { order, required, repeat };
}
/**

@@ -37,13 +40,12 @@ * Add a decoding rule.

* @param cb callback or nested EvDecoder to handle element TLV.
* @param options additional rule options.
* @param opts additional rule options.
*/
add(tt, cb, { order = (this.nextOrder += AUTO_ORDER_SKIP), required = false, repeat = false, } = {}) {
add(tt, cb, opts = {}) {
const ro = this.applyDefaultsToRuleOptions(opts);
assert(!this.rules.has(tt), "duplicate rule for same TLV-TYPE");
this.rules.set(tt, {
...ro,
cb: cb instanceof EvDecoder ? nest(cb) : cb,
order,
required,
repeat,
});
if (required) {
if (ro.required) {
this.requiredTT.add(tt);

@@ -119,1 +121,8 @@ }

}
(function (EvDecoder) {
/**
* IsCritical callback that always returns false.
* This means unrecognized or out-of-order TLV elements are ignored.
*/
EvDecoder.neverCritical = () => false;
})(EvDecoder || (EvDecoder = {}));

@@ -21,2 +21,3 @@ import type { Decoder } from "./decoder.js";

constructor(typeName: string, topTT?: number | readonly number[]);
applyDefaultsToRuleOptions({ order, required, repeat, }?: Partial<EvDecoder.RuleOptions>): EvDecoder.RuleOptions;
/**

@@ -26,5 +27,5 @@ * Add a decoding rule.

* @param cb callback or nested EvDecoder to handle element TLV.
* @param options additional rule options.
* @param opts additional rule options.
*/
add(tt: number, cb: EvDecoder.ElementDecoder<T> | EvDecoder<T>, { order, required, repeat, }?: Partial<EvDecoder.RuleOptions>): this;
add(tt: number, cb: EvDecoder.ElementDecoder<T> | EvDecoder<T>, opts?: Partial<EvDecoder.RuleOptions>): this;
/** Set callback to determine whether TLV-TYPE is critical. */

@@ -74,2 +75,7 @@ setIsCritical(cb: EvDecoder.IsCritical): this;

/**
* IsCritical callback that always returns false.
* This means unrecognized or out-of-order TLV elements are ignored.
*/
const neverCritical: IsCritical;
/**
* Callback before or after decoding TLV-VALUE.

@@ -76,0 +82,0 @@ * @param target target object.

@@ -12,2 +12,26 @@ import { __importDefault, __importStar } from "tslib";

Extensible.cloneRecord = cloneRecord;
/**
* Define simple getters and setters.
* @param typ Extensible subclass constructor.
* @param exts extensions, each key is a property name and each value is the TLV-TYPE number.
*/
function defineGettersSetters(typ, exts) {
for (const [prop, tt] of Object.entries(exts)) {
Object.defineProperty(typ.prototype, prop, {
enumerable: true,
get() {
return Extension.get(this, tt);
},
set(value) {
if (value === undefined) {
Extension.clear(this, tt);
}
else {
Extension.set(this, tt, value);
}
},
});
}
}
Extensible.defineGettersSetters = defineGettersSetters;
})(Extensible || (Extensible = {}));

@@ -45,2 +69,3 @@ export var Extension;

decodeUnknown = (target, tlv, order) => {
void order;
const { type: tt } = tlv;

@@ -47,0 +72,0 @@ const ext = this.table.get(tt);

@@ -12,2 +12,26 @@ import { __importDefault, __importStar } from "tslib";

Extensible.cloneRecord = cloneRecord;
/**
* Define simple getters and setters.
* @param typ Extensible subclass constructor.
* @param exts extensions, each key is a property name and each value is the TLV-TYPE number.
*/
function defineGettersSetters(typ, exts) {
for (const [prop, tt] of Object.entries(exts)) {
Object.defineProperty(typ.prototype, prop, {
enumerable: true,
get() {
return Extension.get(this, tt);
},
set(value) {
if (value === undefined) {
Extension.clear(this, tt);
}
else {
Extension.set(this, tt, value);
}
},
});
}
}
Extensible.defineGettersSetters = defineGettersSetters;
})(Extensible || (Extensible = {}));

@@ -45,2 +69,3 @@ export var Extension;

decodeUnknown = (target, tlv, order) => {
void order;
const { type: tt } = tlv;

@@ -47,0 +72,0 @@ const ext = this.table.get(tt);

@@ -11,2 +11,8 @@ import type { Decoder } from "./decoder.js";

function cloneRecord(dst: Extensible, src: Extensible): void;
/**
* Define simple getters and setters.
* @param typ Extensible subclass constructor.
* @param exts extensions, each key is a property name and each value is the TLV-TYPE number.
*/
function defineGettersSetters<T extends Extensible>(typ: new () => T, exts: Record<string, number>): void;
}

@@ -13,0 +19,0 @@ /**

@@ -7,1 +7,2 @@ export * from "./decoder_browser.js";

export * from "./string_browser.js";
export * from "./struct-builder_browser.js";

@@ -7,1 +7,2 @@ export * from "./decoder_node.js";

export * from "./string_node.js";
export * from "./struct-builder_node.js";

@@ -7,1 +7,2 @@ export * from "./decoder.js";

export * from "./string.js";
export * from "./struct-builder.js";

@@ -51,8 +51,11 @@ import { asDataView, toHex } from "@ndn/util";

switch (dv.byteLength) {
case 1:
case 1: {
return dv.getUint8(0);
case 2:
}
case 2: {
return dv.getUint16(0);
case 4:
}
case 4: {
return dv.getUint32(0);
}
}

@@ -77,24 +80,33 @@ throw new Error("incorrect TLV-LENGTH of NNI");

switch (true) {
case n < 0x100000000n:
case n < 0x100000000n: {
n = Number(n);
break;
case n <= 0xffffffffffffffffn:
}
case n <= 0xffffffffffffffffn: {
return new Nni8Big(n);
default:
}
default: {
throw new RangeError("NNI is too large");
}
}
}
switch (true) {
case n < 0:
case n < 0: {
throw new RangeError("NNI cannot be negative");
case n < 0x100:
}
case n < 0x100: {
return new Nni1(n);
case n < 0x10000:
}
case n < 0x10000: {
return new Nni2(n);
case n < 0x100000000:
}
case n < 0x100000000: {
return new Nni4(n);
case n <= (unsafe ? 0xFFFFFFFFFFFFFFFF : Number.MAX_SAFE_INTEGER): // eslint-disable-line @typescript-eslint/no-loss-of-precision
}
case n <= (unsafe ? 0xFFFFFFFFFFFFFFFF : Number.MAX_SAFE_INTEGER): { // eslint-disable-line @typescript-eslint/no-loss-of-precision
return new Nni8Number(n);
default:
}
default: {
throw new RangeError("NNI is too large");
}
}

@@ -126,10 +138,2 @@ }

NNI.decode = decode;
function constrain(n, typeName, limit0, limit1) {
const [min = 0, max = Number.MAX_SAFE_INTEGER] = typeof limit1 === "number" ? [limit0, limit1] : [0, limit0];
if (!(n >= min && n <= max)) {
throw new RangeError(`${n} is out of ${typeName} valid range`);
}
return Math.trunc(n);
}
NNI.constrain = constrain;
})(NNI || (NNI = {}));

@@ -51,8 +51,11 @@ import { asDataView, toHex } from "@ndn/util";

switch (dv.byteLength) {
case 1:
case 1: {
return dv.getUint8(0);
case 2:
}
case 2: {
return dv.getUint16(0);
case 4:
}
case 4: {
return dv.getUint32(0);
}
}

@@ -77,24 +80,33 @@ throw new Error("incorrect TLV-LENGTH of NNI");

switch (true) {
case n < 0x100000000n:
case n < 0x100000000n: {
n = Number(n);
break;
case n <= 0xffffffffffffffffn:
}
case n <= 0xffffffffffffffffn: {
return new Nni8Big(n);
default:
}
default: {
throw new RangeError("NNI is too large");
}
}
}
switch (true) {
case n < 0:
case n < 0: {
throw new RangeError("NNI cannot be negative");
case n < 0x100:
}
case n < 0x100: {
return new Nni1(n);
case n < 0x10000:
}
case n < 0x10000: {
return new Nni2(n);
case n < 0x100000000:
}
case n < 0x100000000: {
return new Nni4(n);
case n <= (unsafe ? 0xFFFFFFFFFFFFFFFF : Number.MAX_SAFE_INTEGER): // eslint-disable-line @typescript-eslint/no-loss-of-precision
}
case n <= (unsafe ? 0xFFFFFFFFFFFFFFFF : Number.MAX_SAFE_INTEGER): { // eslint-disable-line @typescript-eslint/no-loss-of-precision
return new Nni8Number(n);
default:
}
default: {
throw new RangeError("NNI is too large");
}
}

@@ -126,10 +138,2 @@ }

NNI.decode = decode;
function constrain(n, typeName, limit0, limit1) {
const [min = 0, max = Number.MAX_SAFE_INTEGER] = typeof limit1 === "number" ? [limit0, limit1] : [0, limit0];
if (!(n >= min && n <= max)) {
throw new RangeError(`${n} is out of ${typeName} valid range`);
}
return Math.trunc(n);
}
NNI.constrain = constrain;
})(NNI || (NNI = {}));

@@ -22,9 +22,3 @@ import type { Encodable } from "./encoder.js";

}): bigint;
/** Error if n exceeds [0,MAX_SAFE_INTEGER] range. */
function constrain(n: number, typeName: string): number;
/** Error if n exceeds [0,max] range. */
function constrain(n: number, typeName: string, max: number): number;
/** Error if n exceeds [min,max] range. */
function constrain(n: number, typeName: string, min: number, max: number): number;
}
export {};
{
"name": "@ndn/tlv",
"version": "0.0.20230121",
"version": "0.0.20240113",
"description": "NDNts: TLV",

@@ -25,7 +25,8 @@ "keywords": [

"dependencies": {
"@ndn/util": "0.0.20230121",
"mnemonist": "^0.39.5",
"tslib": "^2.4.1"
"@ndn/util": "0.0.20240113",
"mnemonist": "^0.39.7",
"tslib": "^2.6.2",
"type-fest": "^4.9.0"
},
"types": "lib/mod.d.ts"
}

@@ -5,11 +5,11 @@ # @ndn/tlv

This package implements Type-Length-Value structure encoder and decoder as specified in [NDN Packet Format v0.3](https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html).
This package implements Type-Length-Value structure encoder and decoder as specified in [NDN Packet Format v0.3](https://docs.named-data.net/NDN-packet-spec/0.3/tlv.html).
It has full support for TLV evolvability guidelines.
```ts
import { Encoder, Decoder, EvDecoder, NNI } from "@ndn/tlv";
import { Encoder, Decoder, EvDecoder, NNI, StructBuilder, StructFieldNNI, StructFieldText } from "@ndn/tlv";
// other imports for examples
import { Name, TT as nameTT } from "@ndn/packet";
import { strict as assert } from "node:assert";
import { Name, TT as l3TT, StructFieldName } from "@ndn/packet";
import assert from "node:assert/strict";
```

@@ -73,3 +73,3 @@

Suppose we want to decode [NLSR's LSDB Dataset](https://redmine.named-data.net/projects/nlsr/wiki/LSDB_DataSet/11):
Suppose we want to decode `Adjacency` type in [NLSR's LSDB Dataset](https://redmine.named-data.net/projects/nlsr/wiki/LSDB_DataSet/13):

@@ -99,7 +99,7 @@ ```abnf

const TT = {
...nameTT,
...l3TT,
Adjacency: 0x84,
Cost: 0x8C,
Uri: 0x8D,
};
} as const;

@@ -126,6 +126,5 @@ // Create the decoder.

);
const adjacencyDecoder = new Decoder(adjacencyWire);
// We can decode it with the EVD.
const adjacency = EVD.decode(new Adjacency(), adjacencyDecoder);
const adjacency = EVD.decode(new Adjacency(), new Decoder(adjacencyWire));
assert.equal(adjacency.name.toString(), "/8=A");

@@ -135,1 +134,53 @@ assert.equal(adjacency.uri, "B");

```
## StructBuilder
The **StructBuilder** is a helper for defining a class that represents a TLV structure.
It allows you to define the typing, constructor, encoder, and decoder, while writing each field only once.
```ts
// Create a StructBuilder and add the fields.
const buildAdj = new StructBuilder("Adjacency", TT.Adjacency)
.add(TT.Name, "name", StructFieldName, { required: true })
.add(TT.Uri, "uri", StructFieldText, { required: true })
.add(TT.Cost, "cost", StructFieldNNI, { required: true });
// You should call .add() on each successive return value, and save the last return value into the
// builder variable. This gradually builds up the typing of the TLV class.
// WRONG EXAMPLE:
// const builder = new StructBuilder();
// builder.add(...);
// builder.add(...);
// In the wrong example, typing information is not saved into the builder variable.
// Declare a class to represent the Adjacency type, inheriting from a base class supplied by the builder.
class Adj extends buildAdj.baseClass<Adj>() {}
// Assign the subclass to the builder (otherwise the decoding function will not work).
buildAdj.subclass = Adj;
// We can construct an instance and encode it.
const adj0 = new Adj();
adj0.name = new Name("/A");
adj0.uri = "B";
adj0.cost = 128;
const adj0Wire = Encoder.encode(adj0);
assert.deepEqual(adj0Wire, Uint8Array.of(
0x84, 0x0B,
0x07, 0x03, 0x08, 0x01, 0x41, // Name
0x8D, 0x01, 0x42, // Uri
0x8C, 0x01, 0x80, // Cost
));
// We can decode the wire encoding.
const adj1 = Decoder.decode(adjacencyWire, Adj);
assert.equal(adj1.name.toString(), "/8=A");
assert.equal(adj1.uri, "B");
assert.equal(adj1.cost, 128);
```
**StructBuilder** enables rapid development of TLV based structures, but is less flexible than writing code with Encoder, Decoder, and EvDecoder.
Some limitations are:
* You cannot write JSDoc for individual fields.
* You cannot decode multiple TLV-TYPE numbers into the same field (counterexample: `Name` with typed name components).
* You cannot encode the structure with different TLV-TYPE numbers (counterexample: `SigInfo` encoded as either ISigInfo or DSigInfo).

@@ -1,6 +0,6 @@

import { Encoder, Decoder, EvDecoder, NNI } from "@ndn/tlv";
import { Encoder, Decoder, EvDecoder, NNI, StructBuilder, StructFieldNNI, StructFieldText } from "@ndn/tlv";
// other imports for examples
import { Name, TT as nameTT } from "@ndn/packet";
import { strict as assert } from "node:assert";
import { Name, TT as l3TT, StructFieldName } from "@ndn/packet";
import assert from "node:assert/strict";

@@ -54,7 +54,7 @@ // Encode TLV object that implements EncodableObj interface:

const TT = {
...nameTT,
...l3TT,
Adjacency: 0x84,
Cost: 0x8C,
Uri: 0x8D,
};
} as const;

@@ -81,8 +81,45 @@ // Create the decoder.

);
const adjacencyDecoder = new Decoder(adjacencyWire);
// We can decode it with the EVD.
const adjacency = EVD.decode(new Adjacency(), adjacencyDecoder);
const adjacency = EVD.decode(new Adjacency(), new Decoder(adjacencyWire));
assert.equal(adjacency.name.toString(), "/8=A");
assert.equal(adjacency.uri, "B");
assert.equal(adjacency.cost, 128);
// Create a StructBuilder and add the fields.
const buildAdj = new StructBuilder("Adjacency", TT.Adjacency)
.add(TT.Name, "name", StructFieldName, { required: true })
.add(TT.Uri, "uri", StructFieldText, { required: true })
.add(TT.Cost, "cost", StructFieldNNI, { required: true });
// You should call .add() on each successive return value, and save the last return value into the
// builder variable. This gradually builds up the typing of the TLV class.
// WRONG EXAMPLE:
// const builder = new StructBuilder();
// builder.add(...);
// builder.add(...);
// In the wrong example, typing information is not saved into the builder variable.
// Declare a class to represent the Adjacency type, inheriting from a base class supplied by the builder.
class Adj extends buildAdj.baseClass<Adj>() {}
// Assign the subclass to the builder (otherwise the decoding function will not work).
buildAdj.subclass = Adj;
// We can construct an instance and encode it.
const adj0 = new Adj();
adj0.name = new Name("/A");
adj0.uri = "B";
adj0.cost = 128;
const adj0Wire = Encoder.encode(adj0);
assert.deepEqual(adj0Wire, Uint8Array.of(
0x84, 0x0B,
0x07, 0x03, 0x08, 0x01, 0x41, // Name
0x8D, 0x01, 0x42, // Uri
0x8C, 0x01, 0x80, // Cost
));
// We can decode the wire encoding.
const adj1 = Decoder.decode(adjacencyWire, Adj);
assert.equal(adj1.name.toString(), "/8=A");
assert.equal(adj1.uri, "B");
assert.equal(adj1.cost, 128);
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc