Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions .github/workflows/cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ name: CD

on:
push:
branches: [ "main" ]
branches: ["main"]
workflow_dispatch:

concurrency:
group: "publish"
cancel-in-progress: true

permissions:
id-token: write # Required for NPM Trusted Publisher
id-token: write # Required for NPM Trusted Publisher
contents: read

jobs:
Expand All @@ -37,13 +37,12 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
submodules: 'recursive'
submodules: "recursive"
- uses: actions/setup-node@v4
with:
node-version: "23"
node-version: "24"
registry-url: "https://registry.npmjs.org"
- uses: pnpm/action-setup@v4
- run: pnpm install
- run: pnpm build
- run: pnpm exec biome ci
- run: tsc
- run: pnpm check
9 changes: 4 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
submodules: 'recursive'
submodules: "recursive"
- uses: actions/setup-node@v4
with:
node-version: "23"
node-version: "24"
- uses: pnpm/action-setup@v4
- run: pnpm install
- run: pnpm build
- run: pnpm exec biome ci
- run: tsc
- run: pnpm check

test:
needs: check
Expand All @@ -29,7 +28,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "23"
node-version: "24"
- uses: pnpm/action-setup@v4
- run: pnpm install
- run: pnpm vitest --coverage
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ dist
docs
dist/**
node_modules/**
tsconfig.tsbuildinfo
9 changes: 9 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"printWidth": 120,
"experimentalSortImports": {
"groups": ["builtin", "external", "internal", ["parent", "sibling", "index"]],
"internalPattern": ["@nillion/"],
"newlinesBetween": true
}
}
27 changes: 27 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript", "import", "unicorn", "vitest"],
"categories": {
"correctness": "warn"
},
"rules": {
"no-nested-ternary": "error",
"no-unneeded-ternary": "error",
"no-unused-vars": "error",
"typescript/no-explicit-any": "error",
"typescript/explicit-function-return-type": "error",
"unicorn/prefer-node-protocol": "error",
"unicorn/filename-case": ["error", { "case": "kebabCase" }],
"import/no-cycle": "error"
},
"overrides": [
{
"files": ["tests/**/*.ts"],
"rules": {
"typescript/no-explicit-any": "off",
"typescript/no-non-null-assertion": "off",
"typescript/no-floating-promises": "off"
}
}
]
}
18 changes: 10 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ This project is managed via [pnpm](https://pnpm.io/). To install dependencies ru
The library uses [pino](https://github.com/pinojs/pino) for structured logging. You can control the log level to help debug issues:

1. **Node.js**: Set the `NILLION_LOG_LEVEL` environment variable

```bash
NILLION_LOG_LEVEL=debug pnpm test
NILLION_LOG_LEVEL=trace node your-script.js
```

2. **Browser**: Use the developer console to configure logging

```javascript
// Set log level via localStorage
localStorage.setItem("NILLION_LOG_LEVEL", "debug");
Expand All @@ -32,12 +34,12 @@ The library uses [pino](https://github.com/pinojs/pino) for structured logging.
```

3. **Available log levels** (from most to least verbose):
- `trace` - Extremely detailed debugging information
- `debug` - Detailed debugging information
- `info` - General informational messages
- `warn` - Warning messages
- `error` - Error messages only
- `silent` - Disable all logging
- `trace` - Extremely detailed debugging information
- `debug` - Detailed debugging information
- `info` - General informational messages
- `warn` - Warning messages
- `error` - Error messages only
- `silent` - Disable all logging

## Documentation

Expand All @@ -49,12 +51,12 @@ The documentation can be generated automatically from the source files using [Ty
All unit tests are executed and their coverage is measured when using [vitest](https://vitest.dev/):
`pnpm test --coverage`

Style conventions are enforced using [Biome](https://biomejs.dev/): `biome check`
Style conventions are enforced using [oxlint](https://oxc.rs/docs/guide/usage/linter) and [oxfmt](https://oxc.rs/docs/guide/usage/formatter): `pnpm check`

## Versioning

The version number format for this library and the changes to the library associated with version number increments conform with [Semantic Versioning 2.0.0](https://semver.org/#semantic-versioning-200).

## Publishing

This library can be published as a [package on npmjs](https://www.npmjs.com/package/@nillion/nuc) via the GitHub Actions workflow.
This library can be published as a [package on npmjs](https://www.npmjs.com/package/@nillion/nuc) via the GitHub Actions workflow.
33 changes: 17 additions & 16 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ pnpm install @nillion/nuc
```

```typescript
import { Builder, Codec, Signer, Validator } from '@nillion/nuc';
import { Builder, Codec, Signer, Validator } from "@nillion/nuc";
```

## Core Concepts

A Nuc (Nillion User Controlled) token is a type of capability-based authorisation token inspired by the UCAN specification. It grants specific permissions from a sender to a receiver. Three core claims define the actors in this relationship:

| Claim | Role | Description |
|:----------|:------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| :-------- | :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`iss`** | **Issuer (Sender)** | The principal who created and signed the token. |
| **`aud`** | **Audience (Receiver)** | The principal the token is addressed to. This is the only entity that can use (i.e., invoke or delegate) the token. |
| **`sub`** | **Subject** | The principal the token is "about". It represents the identity whose authority is being granted. This value must stay the same throughout a delegation chain. |
Expand All @@ -29,7 +29,7 @@ In a simple, two-party delegation, the `aud` and `sub` are often the same. When
This example demonstrates the primary workflow of creating delegation and invocation tokens:

```typescript
import { Signer, Builder, Codec, Validator } from '@nillion/nuc';
import { Signer, Builder, Codec, Validator } from "@nillion/nuc";

// Step 1: Create Signers for different parties
// A root authority (e.g., for a server-side process with a private key)
Expand All @@ -49,22 +49,23 @@ const serviceDidString = serviceDid.didString; // e.g., "did:key:zDnae..."
// Step 3: Build a root delegation token
// This grants capabilities from the root to the user
const rootDelegation = await Builder.delegation()
.audience(userDid) // Who can use this delegation
.subject(userDid) // Who the delegation is about
.command("/nil/db/collections/read") // The authorized command namespace
.policy([ // Policy rules that must be satisfied
.audience(userDid) // Who can use this delegation
.subject(userDid) // Who the delegation is about
.command("/nil/db/collections/read") // The authorized command namespace
.policy([
// Policy rules that must be satisfied
["==", ".command", "/nil/db/collections"], // Command must be an attenuation
["!=", ".args.collection", "secrets"]
["!=", ".args.collection", "secrets"],
])
.expiresIn(3600 * 1000) // Expires in 1 hour
.expiresIn(3600 * 1000) // Expires in 1 hour
.sign(rootSigner);

// Step 4: Build an invocation token from the delegation
// The user invokes their granted capability for the service
const invocation = await Builder.invocationFrom(rootDelegation)
.audience(serviceDid) // The service that will process this
.command("/nil/db/collections/read") // The specific command being invoked
.arguments({ collection: "users" }) // Arguments for the command
.audience(serviceDid) // The service that will process this
.command("/nil/db/collections/read") // The specific command being invoked
.arguments({ collection: "users" }) // Arguments for the command
.sign(userSigner); // Signed by the user

// Step 5: Serialize for transmission
Expand All @@ -81,13 +82,13 @@ try {
params: {
tokenRequirements: {
type: "invocation",
audience: serviceDidString
}
audience: serviceDidString,
},
},
context: {
// Additional context for policy evaluation
environment: "production"
}
environment: "production",
},
});
console.log("Token is valid!", decoded);
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ If you're unsure where to start, head over to [docs.nillion.com](https://docs.ni

## License

This project is licensed under the [MIT License](./LICENSE).
This project is licensed under the [MIT License](./LICENSE).
7 changes: 3 additions & 4 deletions bin/check-version.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
#!/usr/bin/env tsx

import { appendFileSync } from "node:fs";

import semver from "semver";

import packageJson from "../package.json";

interface NpmRegistryResponse {
"dist-tags": Record<string, string>;
}

async function getNpmVersion(
packageName: string,
distTag: string,
): Promise<string> {
async function getNpmVersion(packageName: string, distTag: string): Promise<string> {
const response = await fetch(`https://registry.npmjs.org/${packageName}`);
if (response.ok) {
const data = (await response.json()) as NpmRegistryResponse;
Expand Down
66 changes: 0 additions & 66 deletions biome.jsonc

This file was deleted.

6 changes: 1 addition & 5 deletions commitlint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ import { RuleConfigSeverity, type UserConfig } from "@commitlint/types";
const config: UserConfig = {
extends: ["@commitlint/config-conventional"],
rules: {
"body-max-line-length": [
RuleConfigSeverity.Disabled,
"always",
Number.POSITIVE_INFINITY,
],
"body-max-line-length": [RuleConfigSeverity.Disabled, "always", Number.POSITIVE_INFINITY],
},
};

Expand Down
15 changes: 5 additions & 10 deletions lefthook.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pre-commit:
commands:
biome-format:
oxfmt:
glob: "*.{ts,json,jsonc}"
run: pnpm exec biome format --write --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files}
run: pnpm exec oxfmt {staged_files}
stage_fixed: true

commit-msg:
Expand All @@ -12,12 +12,7 @@ commit-msg:

pre-push:
commands:
biome-check:
glob: "*.{ts,json,jsonc}"
run: pnpm biome check --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {push_files}
tsc-check:
glob: "*.{ts}"
run: pnpm exec tsc
check:
run: pnpm check
test:
glob: "*.{ts}"
run: pnpm test
run: pnpm test
Loading