npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ndn/packet

v0.0.20240113

Published

NDNts: Network Layer Packets

Downloads

38

Readme

@ndn/packet

This package is part of NDNts, Named Data Networking libraries for the modern web.

This package implements Name, Interest, and Data types as specified in NDN Packet Format v0.3.

import { TT, Name, Component, ImplicitDigest, AltUri, Interest, Data, digestSigning } from "@ndn/packet";

// other imports for examples
import { Decoder, Encoder } from "@ndn/tlv";
import { fromUtf8, toUtf8 } from "@ndn/util";
import assert from "node:assert/strict";

Name Component

// Name components are immutable. Once it's created, you can never change it.
// Construct a Component from its TLV-TYPE and TLV-VALUE.
const compA = new Component(TT.GenericNameComponent, Uint8Array.of(0x41));
// Create a Component from URI representation.
const compB = Component.from("B");
// Typed components are supported, too.
const compMetadata = Component.from("32=metadata");

// We can retrieve TLV-TYPE, TLV-LENGTH, and TLV-VALUE.
assert.equal(compA.type, TT.GenericNameComponent);
assert.equal(compB.type, TT.GenericNameComponent);
assert.equal(compMetadata.type, 0x20);

assert.equal(compA.length, 1);
assert.equal(compB.length, 1);
assert.equal(compMetadata.length, 8);

assert.deepEqual(compA.value, Uint8Array.of(0x41));
assert.deepEqual(compB.value, Uint8Array.of(0x42));
assert.deepEqual(compMetadata.value, Uint8Array.of(0x6D, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61));

// For convenience, we can retrieve TLV-VALUE as text string, too.
assert.equal(compA.text, "A");
assert.equal(compB.text, "B");
assert.equal(compMetadata.text, "metadata");

// Components are comparable.
assert.equal(compA.compare(compA), Component.CompareResult.EQUAL);
assert.equal(compA.compare(compB), Component.CompareResult.LT);
assert.equal(compB.compare(compA), Component.CompareResult.GT);
assert.equal(compA.equals(compA), true);
assert.equal(compA.equals(compB), false);

Name

// Names, like components, are immutable.
// Construct from URI.
const name1 = new Name("/localhost/2020=NDNts/rocks");
// Construct from a list of components, or strings to create components.
const name2 = new Name([compA, compB, "C", compMetadata]);
// Name parsing functions expect URI in canonical format. They DO NOT recognize alternate/pretty
// URI syntax other than allow omitting "8=" prefix of GenericNameComponent.

// You can always convert a name back to its URI in canonical format.
assert.equal(name1.toString(), "/8=localhost/2020=NDNts/8=rocks");
assert.equal(name2.toString(), "/8=A/8=B/8=C/32=metadata");

// AltUri.ofName() function allows printing a name as alternate/pretty URI syntax.
assert.equal(AltUri.ofName(name1), "/localhost/2020=NDNts/rocks");
assert.equal(AltUri.ofName(name2), "/A/B/C/32=metadata");
// AltUri.ofName() from this package only recognizes 0x01, 0x02, and 0x08 types. If you are using
// naming conventions from @ndn/naming-convention2 package, use the AltUri from that package.
// This feature isn't in the regular name.toString(), so that it does not unnecessarily increase
// browser bundle size in applications that do not need it.

// It's crucial to know how many name components you have.
assert.equal(name1.length, 3);
assert.equal(name2.length, 4);

// You can get an individual name component.
const name1comp1 = name1.get(1);
// It would return 'undefined' if the component does not exist, so we have to check.
if (name1comp1 === undefined) {
  assert.fail(); // This isn't supposed to happen for this name, though.
} else {
  assert.equal(name1comp1.text, "NDNts");
}

// To save the 'undefined' check, use at(i). It throws if the component does not exist.
assert.throws(() => name1.at(5));
assert.equal(name1.at(1).text, "NDNts");

// Slice the name to obtain part of it.
const name1sliced = name1.slice(1, 3);
assert.equal(name1sliced.toString(), "/2020=NDNts/8=rocks");

// Or, get the prefix.
const name2prefix = name2.getPrefix(3);
assert.equal(name2prefix.toString(), "/8=A/8=B/8=C");

// Indexing from the back is supported, too.
assert.equal(name1.at(-1).text, "rocks");
assert.equal(name1.slice(-2).toString(), "/2020=NDNts/8=rocks");
assert.equal(name2.getPrefix(-1).toString(), "/8=A/8=B/8=C");

// Names are comparable.
const nameAB = new Name("/A/B");
const nameABB = new Name("/A/B/B");
const nameABC = new Name("/A/B/C");
const nameABD = new Name("/A/B/D");
const nameABCD = new Name("/A/B/C/D");
assert.equal(nameABC.equals(nameABC), true);
assert.equal(nameABC.equals(nameABD), false);
assert.equal(nameABC.compare(nameABC), Name.CompareResult.EQUAL);
assert.equal(nameABC.compare(nameABB), Name.CompareResult.GT);
assert.equal(nameABC.compare(nameABD), Name.CompareResult.LT);
assert.equal(nameABC.compare(nameABCD), Name.CompareResult.LPREFIX);
assert.equal(nameABC.compare(nameAB), Name.CompareResult.RPREFIX);

// LPREFIX means the first name is a strict prefix of the second name.
// It implies the first name is less than the second name.
// If you only care about the order, check if the result is less than zero.
assert(nameABC.compare(nameABCD) < 0);

// RPREFIX means the second name is a strict prefix of the first name.
// It implies the first name is greater than the second name.
// If you only care about the order, check if the result is greater than zero.
assert(nameABC.compare(nameAB) > 0);

// If you want to know whether a name is a prefix of another, it's EQUAL or LPREFIX.
// But we got a faster way:
assert.equal(nameABC.isPrefixOf(nameABC), true);
assert.equal(nameABC.isPrefixOf(nameABCD), true);
assert.equal(nameABC.isPrefixOf(nameAB), false);

// I said names are immutable, but you can surely modify them to get a new Name.
const name1modified = name1.getPrefix(-1).append("is", "awesome");
assert(name1modified.toString(), "/8=localhost/2020=NDNts/8=rocks/8=is/8=awesome");
assert(name1.toString(), "/8=localhost/2020=NDNts/8=rocks"); // unchanged

Layer-3 Packet Types: Interest and Data

// We have an Interest type, of course.
// You can set fields via constructor or setters.
const interest = new Interest(new Name("/A"), Interest.CanBePrefix, Interest.MustBeFresh);
interest.canBePrefix = false;
interest.lifetime = 2000;

// Encode and decode the Interest.
const interestWire = Encoder.encode(interest);
const interest2 = Decoder.decode(interestWire, Interest);
assert.equal(interest2.name.toString(), "/8=A");

// We got a Data type, too.
// You can set fields via constructor or setters.
const data = new Data(interest.name, Data.FreshnessPeriod(5000));
data.content = toUtf8("hello NDNts");

Signing and Verification

// Every NDN Data must be signed.
// This package provides the low-level API, and an implementation of SHA256 digest signing.
// Other signature types are in @ndn/keychain package.

// Sign the Data. The API is asynchronous as required by WebCrypto.
await digestSigning.sign(data);

// After signing, we can encode the Data.
const dataWire = Encoder.encode(data);

// And then decode it.
const data2 = Decoder.decode(dataWire, Data);

// Data signature should be verified.
// If the verify() function does not throw, it means the signature is good.
await digestSigning.verify(data);

// It's very important that you do not modify the Data if you need to verify its signature.
// Otherwise, you'll get errors or incorrect results.

// After verifying, we can access the Content.
assert.equal(fromUtf8(data2.content), "hello NDNts");

Implicit Digest

// To obtain implicit digest, we'll have to await, because it internally uses WebCrypto, which is async.
const digest = await data.computeImplicitDigest();
assert.equal(digest.length, 32);

// Full names are available, too.
const fullName = await data2.computeFullName();
assert.equal(fullName.length - 1, data2.name.length);
assert(fullName.at(-1).is(ImplicitDigest));

// After computation, implicit digest is cached on the Data instance,
// so we can get them without await:
const digest2 = data.getImplicitDigest();
const fullName2 = data.getFullName();
assert.equal(digest2, digest);
assert(fullName2 !== undefined);
assert.equal(fullName2.toString(), fullName.toString());

// Note that you cannot modify the Data after encoding or decoding,
// or you'll get incorrect implicit digest results.

Interest-Data Matching

// data.canSatisfy(interest) determines whether a Data satisfy an Interest.
// This is an async function because it potentially involves computing the implicit digest.

assert.equal(await data.canSatisfy(interest), true);
const interest3 = new Interest("/B");
assert.equal(await data.canSatisfy(interest3), false);
const data3 = Decoder.decode(dataWire, Data);
const interestWithFullName = new Interest(fullName);
assert.equal(await data.canSatisfy(interestWithFullName), true);