Gathering detailed insights and metrics for @pcd/podspec
Gathering detailed insights and metrics for @pcd/podspec
Gathering detailed insights and metrics for @pcd/podspec
Gathering detailed insights and metrics for @pcd/podspec
npm install @pcd/podspec
Typescript
Module System
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
A library for validating the structure of PODs in TypeScript, providing static types and runtime validation.
Install the package:
1npm install @pcd/podspec
Create a POD spec:
1import { p } from "@pcd/podspec"; 2 3const spec = p.entries({ 4 name: p.string(), 5 email: p.string(), 6 high_score: p.int() 7});
Then use the spec to validate POD entries:
1const entries = { 2 name: { type: "string", value: "Bob Dugnutt" }, 3 email: { type: "string", value: "bob@dugnutt.com" }, 4 high_score: { type: "int", value: 999999 } 5}; 6 7const result = spec.parse(entries); 8if (result.isValid) { 9 // Ready to use the POD 10 result.value; // Contains the POD entries 11} else { 12 // Handle the error 13 result.errors; // Contains information about the errors 14}
If the entries are valid, result.value
will be a PODEntries
object, with static types for the entries which are part of the spec. Otherwise, result.errors
will contain information about the errors encountered during parsing.
When signing a POD, we want to make sure that the POD's entries meet our expectations. This means not just that the POD is well-formed, but that it also has the right structure and types.
For example, if we have a POD that represents a weapon in a game, we might have a spec that looks like this:
1const weaponSpec = p.entries({ 2 name: p.string(), 3 damage: p.int(), 4 durability: p.int(), 5 price: p.int() 6});
Now we can use the spec to validate POD entries before signing a POD:
1const entries = { 2 name: { type: "string", value: "Narsil" }, 3 damage: { type: "int", value: 10n }, 4 durability: { type: "int", value: 100n }, 5 price: { type: "int", value: 100n } 6}; 7 8const result = weaponSpec.parse(entries); 9if (result.isValid) { 10 // Ready to sign the POD 11} else { 12 // Handle the error 13 result.errors; // Contains information about the errors 14}
In the above example, we assumed that already had POD entries to validate. However, we might have a JavaScript object that we want to turn into POD entries. podspec
can do some simple transformations to turn JavaScript objects into POD entries.
First we specify that we want to coerce JavaScript objects into POD entries:
1const coercingWeaponSpec = p.entries({ 2 name: p.coerce.string(), 3 damage: p.coerce.int(), 4 durability: p.coerce.int(), 5 price: p.coerce.int() 6});
Then we can use the spec to parse a JavaScript object:
1const javascriptObject = { 2 name: "Narsil", 3 damage: 10, 4 durability: 100, 5 price: 100 6}; 7 8const result = coercingWeaponSpec.parse(javascriptObject); 9if (result.isValid) { 10 // Ready to sign the POD 11} else { 12 // Handle the error 13 result.errors; // Contains information about the errors 14}
Here, regular JavaScript objects are turned into POD entries. In particular, numbers are turned into int
s, and strings are turned into string
s.
If you have a POD that is already signed, you can use podspec
to validate the POD, including both the entries and the signer public key.
1const pod = getPodFromSomewhere(); 2const pubKey = "expected_public_key"; 3const podSpec = p 4 .POD({ 5 eventId: p.string(), 6 productId: p.string() 7 }) 8 .signer(pubKey); 9 10const result = podSpec.parse(pod); 11if (result.isValid) { 12 // Ready to use the POD 13} else { 14 // Handle the error 15 result.errors; // Contains information about the errors 16}
This will check that the POD has the right structure and types, and that the signer is the expected signer.
You can also provide a list of valid signers:
1const podSpec = p
2 .POD({
3 eventId: p.string(),
4 productId: p.string()
5 })
6 .signerList([pubKey1, pubKey2]);
If you have an array of PODs, you can use the spec to query the array for PODs that match the spec:
1const pods = [pod1, pod2, pod3]; 2const podSpec = p.entries({ 3 eventId: p.string(), 4 productId: p.string() 5}); 6const result = podSpec.query(pods); 7result.matches; // Contains the PODs that match the spec 8result.matchingIndexes; // Contains the array indexes of the PODs that match the spec
To serialize a podspec to a JavaScript object, you can use the serialize
method:
1const serialized = podSpec.serialize();
Bear in mind that this will not serialize the podspec to a string, but rather to a JavaScript object. Since the object may contain bigint
values, you may need to serialize it using a specialized library like json-bigint
.
As well as ensuring the existence and type of POD entries, podspec
also provides some additional constraints, such as range and list checks.
1const rangeSpec = p.entries({ 2 value: p.int().range(0n, 100n) 3}); 4 5const entries = { 6 value: { type: "int", value: 50n } 7}; 8 9const result = rangeSpec.parse(entries);
This will parse successfully. This will not:
1const entries = { 2 value: { type: "int", value: 200n } 3}; 4 5const result = rangeSpec.parse(entries);
Entries can be checked against a list of values:
1const listSpec = p.entries({ 2 value: p.int().list([1n, 2n, 3n]) 3}); 4 5const entries = { 6 value: { type: "int", value: 2n } 7}; 8 9const result = listSpec.parse(entries);
This will parse successfully because the value 2n
in the list.
Lists can also be used to specify invalid values which should not be allowed:
1const listSpec = p.entries({ 2 value: p.int().list([1n, 2n, 3n], { exclude: true }) 3}); 4 5const entries = { 6 value: { type: "int", value: 2n } 7}; 8 9const result = listSpec.parse(entries);
This will not parse successfully because the value 2n
is in the list of excluded values.
Multiple entries can be checked against a list of valid tuples.
1const tupleSpec = p 2 .entries({ 3 foo: p.string(), 4 bar: p.int() 5 }) 6 .tuple({ 7 name: "test", 8 exclude: false, 9 entries: ["foo", "bar"], 10 members: [ 11 [ 12 { type: "string", value: "test" }, 13 { type: "int", value: 1n } 14 ], 15 [ 16 { type: "string", value: "test2" }, 17 { type: "int", value: 2n } 18 ] 19 ] 20 });
In this example, we will accept any set of POD entries which has either a foo entry with value "test" and a bar entry with value 1n
or a foo entry with value "test2" and a bar entry with value 2n
.
1const entries = { 2 foo: { type: "string", value: "test" }, 3 bar: { type: "int", value: 1n } 4}; 5 6const result = tupleSpec.parse(entries);
This matches the first tuple in the list, so the result will be valid.
1const entries = { 2 foo: { type: "string", value: "test2" }, 3 bar: { type: "int", value: 2n } 4}; 5 6const result = tupleSpec.parse(entries);
This matches the second tuple in the list, so the result will be valid.
1const entries = { 2 foo: { type: "string", value: "test" }, 3 bar: { type: "int", value: 2n } 4}; 5 6const result = tupleSpec.parse(entries);
This has a foo
entry which matches the first tuple, and a bar
entry which matches the second tuple, but does not match either tuple as a whole. Therefore, the result will be invalid.
No vulnerabilities found.
No security vulnerabilities found.