signet-protocol 1.11.0 → 1.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -10
- package/docs/bot-ownership-v1.md +43 -0
- package/docs/implementation-levels.md +235 -0
- package/docs/private-vault-v1.md +104 -0
- package/docs/signet-in-5-minutes.md +181 -0
- package/examples/full-flow.ts +260 -0
- package/examples/jurisdictions/brazil-lawyer.ts +186 -0
- package/examples/jurisdictions/eu-doctor.ts +160 -0
- package/examples/jurisdictions/india-doctor.ts +207 -0
- package/examples/jurisdictions/japan-notary.ts +157 -0
- package/examples/jurisdictions/multi-jurisdiction.ts +174 -0
- package/examples/jurisdictions/uae-professional.ts +190 -0
- package/examples/jurisdictions/uk-solicitor.ts +170 -0
- package/examples/jurisdictions/us-attorney.ts +161 -0
- package/examples/signet-me.ts +253 -0
- package/llms-full.txt +3775 -0
- package/llms.txt +152 -0
- package/package.json +14 -3
- package/spec/protocol.md +2628 -0
- package/spec/voting.md +563 -0
package/llms.txt
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Signet Protocol
|
|
2
|
+
|
|
3
|
+
> Nostr has no identity layer: anyone can impersonate anyone, and there's no way to verify age for child safety. Signet is a decentralised identity verification protocol for Nostr that lets users prove claims about their identity (age, profession, parenthood) using zero-knowledge proofs, without revealing personal data or relying on a central authority.
|
|
4
|
+
|
|
5
|
+
Signet is for Nostr client developers, relay operators, and anyone building identity-aware applications on Nostr. It provides a TypeScript library (`signet-protocol`) that handles credentials, vouches, trust scoring, and ZKP age proofs. Unlike centralised identity services, Signet anchors trust to professional bodies (law societies, medical boards, notary commissions) and uses cryptographic proofs instead of data collection.
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install signet-protocol
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires Node ≥22. ESM only (no CommonJS `require` export).
|
|
14
|
+
|
|
15
|
+
Display a verification badge for any Nostr pubkey (Level 1 integration: a weekend):
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { computeBadge, buildBadgeFilters, fetchFromRelay, meetsMinimumTier } from 'signet-protocol';
|
|
19
|
+
|
|
20
|
+
// Build relay filters and fetch events (fetchFromRelay is the package's own minimal relay client)
|
|
21
|
+
const filters = buildBadgeFilters(['<hex-pubkey>']);
|
|
22
|
+
const events = await fetchFromRelay('wss://relay.example.com', filters);
|
|
23
|
+
|
|
24
|
+
// Compute badge (async: returns Promise<BadgeInfo>)
|
|
25
|
+
const badge = await computeBadge('<hex-pubkey>', events, { verifySignatures: true });
|
|
26
|
+
// badge.tier => 3, badge.score => 106, badge.displayLabel => "Verified (Tier 3)"
|
|
27
|
+
// (illustrative values; badge.score is a Level 1 approximation, see "Trust & Badges")
|
|
28
|
+
|
|
29
|
+
// Gate features on verification level
|
|
30
|
+
if (meetsMinimumTier(badge, 2)) {
|
|
31
|
+
// allow posting in verified-only community
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`verifySignatures` defaults to `false` in `computeBadge`, so keep `{ verifySignatures: true }` in copied code unless the events were already verified. `computeBadge` also does not check who issued a Tier 3 or Tier 4 credential; see "Who may issue Tier 3 and Tier 4" before gating on a professional tier.
|
|
36
|
+
|
|
37
|
+
`fetchFromRelay(relayUrl: string, filters: NostrFilter[]): Promise<NostrEvent[]>` connects, collects events until EOSE and disconnects. Non-localhost relay URLs must be `wss://`. Any other Nostr client works equally well: pass the `buildBadgeFilters` output as REQ filters and give the returned events to `computeBadge`.
|
|
38
|
+
|
|
39
|
+
## Key Concepts
|
|
40
|
+
|
|
41
|
+
- **4 verification tiers**: Self-declared (Tier 1) → Web-of-trust via peer vouches (Tier 2) → Professional verification with ZKP age proof (Tier 3) → Professional + child safety (Tier 4)
|
|
42
|
+
- **Signet IQ** (0–200): A continuous identity quality score measuring statistical confidence that an identity is real, not fabricated. Weighted by professional verification, in-person vouches, online vouches, account age, and identity bridges. 100 represents the current government standard. IQ is not reputation: it measures identity quality, not trustworthiness. The source calls the same number the "Signet Score" (`TrustScoreBreakdown.score`).
|
|
43
|
+
- **Zero-knowledge age proofs**: Pedersen range proofs on secp256k1 (the `@forgesworn/range-proof` dependency; no trusted setup) prove age ranges (e.g. "adult" or "child aged 8–12") without revealing date of birth.
|
|
44
|
+
- **Document nullifiers**: SHA-256 of document fields prevents duplicate identity registration without storing any personal data.
|
|
45
|
+
- **Single attestation kind** (31000, NIP-VA) plus policies (30078): All identity attestations (credentials, vouches, verifier management, challenges, revocations, identity bridges, delegation) share kind 31000, differentiated by `type` tag. The voting extension (kinds 30482–30484) is a separate package, `nostr-anon-vote`.
|
|
46
|
+
|
|
47
|
+
## API Surface
|
|
48
|
+
|
|
49
|
+
Conventions used throughout:
|
|
50
|
+
- Private keys are 64-character hex strings (not `Uint8Array`). Public keys are 64-character x-only hex. The identity functions are the exception: `createSignetIdentity` takes a BIP-39 mnemonic and `createSignetIdentityFromNsec` takes a bech32 nsec string or 32 raw bytes.
|
|
51
|
+
- Of the `create*` functions documented in this file, the event-signing ones (credentials, vouches, policies, verifiers, challenges, revocations, identity bridges, guardian delegations) are async and return a signed `Promise<NostrEvent>` (with `id` and `sig`). The matching `build*Event` functions return an unsigned `UnsignedEvent`. The documented `create*` helpers that are not event signers return what is stated beside them: `createAgeRangeProof` (synchronous, `RangeProof`), `createSignetIdentity` / `createSignetIdentityFromNsec` (synchronous, `SignetIdentity`) and `createLinkageProof` (synchronous, `LinkageProof`). The package root exports other `create*` functions that this file does not cover (for example `createTwoCredentialCeremony`, `createBondProof`); check their return types in `src/` rather than assuming the event-signer shape.
|
|
52
|
+
- Tiers are `SignetTier` (`1 | 2 | 3 | 4`). Timestamps (`expiresAt`, `occurredAt`, `accountCreatedAt`) are unix seconds.
|
|
53
|
+
- Throws use the `SignetError` hierarchy (`SignetValidationError`, `SignetCryptoError`).
|
|
54
|
+
- Types are exported from the package root as type-only exports (use `import type { NostrEvent } from 'signet-protocol'`; they have no runtime value): `NostrEvent` (`{ id, pubkey, created_at, kind, tags: string[][], content, sig }`), `UnsignedEvent` (the same without `id` and `sig`), `NostrFilter` (`{ ids?, authors?, kinds?, '#d'?, '#p'?, '#L'?, '#l'?, since?, until?, limit? }`), `BadgeInfo` and `RangeProof`. The error classes `SignetError`, `SignetValidationError` and `SignetCryptoError` are exported from the root as ordinary values you can use with `instanceof`. `src/errors.ts` also defines `SignetVotingError`, but it is not exported from the root and nothing in this package throws it.
|
|
55
|
+
- Arguments named `events`, `credentials`, `vouches`, `bridges`, `revocations`, `verifierCredentials` and `confirmationEvents` are raw signed `NostrEvent[]` as returned by a relay, not parsed objects (`ParsedCredential`, `ParsedVouch` and so on). The functions read the tags themselves and skip events of the wrong kind or `type`. Unless a signature check is stated beside a function, it does not verify signatures: verify first, or fetch with `fetchFromRelay`, whose `RelayClient` drops events with an invalid signature or id by default.
|
|
56
|
+
- Issuer standing is not checked by the Level 1 and scoring functions. See "Who may issue Tier 3 and Tier 4" below.
|
|
57
|
+
|
|
58
|
+
### Credentials (kind 31000, type: credential)
|
|
59
|
+
- `createSelfDeclaredCredential(privateKey, scope = 'adult', expiresAt?)`: Tier 1. `scope` is `'adult' | 'adult+child'`.
|
|
60
|
+
- `createPeerVouchedCredential(issuerPrivateKey, subjectPubkey, opts)`: Tier 2. `opts: { assertionEventId: string; assertionRelay?: string; expiresAt?: number }`. `assertionEventId` is the subject's Tier 1 event.
|
|
61
|
+
- `createProfessionalCredential(verifierPrivateKey, subjectPubkey, opts)`: Tier 3. `opts: { assertionEventId: string; profession: string; jurisdiction: string; actualAge: number; assertionRelay?: string; expiresAt?: number; occurredAt?: number; proofBlob?: string }`. Generates an `'18+'` range proof from `actualAge` into the event content.
|
|
62
|
+
- `createChildSafetyCredential(verifierPrivateKey, subjectPubkey, opts)`: Tier 4. Same `opts` as Tier 3 plus `ageRange: string` (the range proved, e.g. `'8-12'`).
|
|
63
|
+
- `verifyCredential(event: NostrEvent)`: `Promise<{ signatureValid: boolean; structureValid: boolean; expired: boolean; errors: string[] }>`. Checks the event's own Schnorr signature, tag structure (for example a Tier 3 or Tier 4 credential must carry `verification-type: professional` and a `profession` tag) and expiry. It does not look at who signed it: a valid result does not mean the issuer is an activated, unrevoked verifier. See "Who may issue Tier 3 and Tier 4".
|
|
64
|
+
- `parseCredential(event)`: `ParsedCredential | null`
|
|
65
|
+
|
|
66
|
+
`ageRange` format everywhere: `'<min>-<max>'` inclusive (e.g. `'8-12'`, `'13-17'`) or `'<min>+'` (e.g. `'18+'`, upper bound 150). Anything else fails to parse.
|
|
67
|
+
|
|
68
|
+
Default credential expiry is two years (`DEFAULT_CREDENTIAL_EXPIRY_SECONDS`) when `expiresAt` is omitted.
|
|
69
|
+
|
|
70
|
+
### Vouches (kind 31000, type: vouch)
|
|
71
|
+
- `createVouch(voucherPrivateKey, params)`: vouch for another user. `params: { subjectPubkey: string; method: 'in-person' | 'online'; voucherTier: SignetTier; voucherScore: number; context?: string; occurredAt?: number }`. `voucherScore` is the voucher's own Signet IQ (0–200).
|
|
72
|
+
- `hasEnoughVouches(vouches: NostrEvent[], subjectPubkey: string, threshold = 3, minVoucherTier: SignetTier = 2)`: `boolean`. `vouches` is raw kind 31000 vouch events (`NostrEvent[]`), not `ParsedVouch` objects. `true` when the number of qualifying vouches (one per voucher, `voucher-tier` tag ≥ `minVoucherTier`) reaches `threshold`. It does not verify signatures, and the voucher tier is the self-reported tag, not looked up. `countQualifyingVouches(vouches: NostrEvent[], subjectPubkey: string, minVoucherTier?: SignetTier)` returns the count.
|
|
73
|
+
|
|
74
|
+
### Trust & Badges
|
|
75
|
+
- `computeBadge(pubkey: string, events: NostrEvent[], opts?)`: `Promise<BadgeInfo>`. `opts: { verifySignatures?: boolean (default false); now?: number }`. `BadgeInfo: { pubkey, tier, tierLabel, score, isVerified, displayLabel, credentialCount, vouchCount, entityType? }`. `verifySignatures` defaults to `false`: with the default, `computeBadge` does not check any signature, so a call that omits it trusts every event it is given. Pass `{ verifySignatures: true }` unless the events came from `fetchFromRelay` or another source that has already dropped events with an invalid signature or id. `computeBadge` reads the `tier`, `verification-type`, `expiration`, `method` and `voucher-score` tags. It does not run `validateCredential` and does not check who signed a credential, so it does not enforce issuer standing (see "Who may issue Tier 3 and Tier 4").
|
|
76
|
+
- `buildBadgeFilters(pubkeys: string[])`: `Array<{ kinds: number[]; '#d': string[] }>`. One filter for kind 31000 with d-tags `credential:<pubkey>` and `vouch:<pubkey>` for each pubkey. It fetches no verifier, challenge or revocation events, so the events it returns cannot be used to check issuer standing.
|
|
77
|
+
- `meetsMinimumTier(badge: BadgeInfo, minTier: SignetTier)`: `boolean`. `true` only when `badge.isVerified` and `badge.tier >= minTier`.
|
|
78
|
+
- `computeTrustScore(subjectPubkey: string, credentials: NostrEvent[], vouches: NostrEvent[], accountCreatedAt?: number, bridges?: NostrEvent[])`: `TrustScoreBreakdown` (`{ score, tier, professionalVerifications, inPersonVouches, onlineVouches, accountAgeDays, signals }`). This is the full Signet IQ. `credentials`, `vouches` and `bridges` are raw kind 31000 events (`NostrEvent[]`), not parsed objects. It does not verify signatures and, like `computeBadge`, does not check issuer standing. `bridges` are matched by `event.pubkey === subjectPubkey` and are not ring-signature verified here: run `verifyIdentityBridge` first.
|
|
79
|
+
|
|
80
|
+
`badge.score` is on the same 0–200 scale and uses the same weights as `computeTrustScore(...).score` (professional verification 80, in-person vouch up to 16, online vouch up to 4, each vouch scaled by the voucher's score ÷ 200), but it is a Level 1 approximation, not the full IQ: `computeBadge` ignores account age and identity bridges and does not apply the per-type caps (1 professional, 3 in-person vouches, 5 online vouches). Use `computeTrustScore` when you need the full IQ.
|
|
81
|
+
|
|
82
|
+
### Who may issue Tier 3 and Tier 4
|
|
83
|
+
|
|
84
|
+
The library does not enforce issuer standing in `computeBadge`, `computeTrustScore`, `verifyCredential` or `countChallengeConfirmations`. A kind 31000 `type: credential` event that carries `tier: 3` (or 4) and `verification-type: professional` counts toward the tier and the score whichever key signed it, including a key that has never published a verifier credential, and `verifySignatures: true` only proves the signer wrote the event. `buildBadgeFilters` fetches only `credential:` and `vouch:` events, so a badge built from its output cannot tell a licensed verifier from any other key. The protocol requires issuers of Tier 3 and Tier 4 to be activated, unrevoked verifiers (see `spec/protocol.md`); your client has to apply that rule before calling `computeBadge`:
|
|
85
|
+
|
|
86
|
+
1. Fetch the candidate issuer's `type: verifier` credential, the vouches for that issuer, the verifier credentials of those vouchers, and any `type: revocation` events (all kind 31000). `buildBadgeFilters` does not fetch these, so build your own filters.
|
|
87
|
+
2. Treat an issuer as acceptable only when `checkCrossVerification(issuerPubkey, vouches, verifierCredentials).activated` is `true` and `isVerifierRevoked(issuerPubkey, revocations)` is `false`.
|
|
88
|
+
3. Drop every Tier 3 and Tier 4 credential whose `event.pubkey` is not an acceptable issuer, then pass the remaining events to `computeBadge`.
|
|
89
|
+
|
|
90
|
+
`checkCrossVerification` does not check that each voucher is itself activated or unrevoked, so filter `verifierCredentials` the same way before step 2 if you need the spec's full rule.
|
|
91
|
+
|
|
92
|
+
### Policies (kind 30078, NIP-78)
|
|
93
|
+
- `createPolicy(operatorPrivateKey, params)`: community verification requirements. `params: { communityId: string; adultMinTier: SignetTier; childMinTier: SignetTier; enforcement: 'client' | 'relay' | 'both'; minScore?: number; modMinTier?: SignetTier; verifierBond?: number; revocationThreshold?: number; description?: string }`. The d-tag is `signet:policy:<communityId>`.
|
|
94
|
+
- `new PolicyChecker(policyEvent: NostrEvent)`: throws `SignetValidationError('Invalid policy event')` if the event is not a valid policy. Methods: `getPolicy(): ParsedPolicy`, `checkAdult(tier, score)`, `checkChild(tier, score)`, `checkModerator(tier, score)`. Each check returns `PolicyCheckResult`: `{ allowed: boolean; reason?: string; requiredTier: SignetTier; actualTier: SignetTier; requiredScore?: number; actualScore?: number }`.
|
|
95
|
+
- `parsePolicy(event)`: `ParsedPolicy | null`. `checkPolicyCompliance(policy, userTier, userScore, { isChild?, isModerator? })`: `PolicyCheckResult`.
|
|
96
|
+
|
|
97
|
+
### Verifiers (kind 31000, type: verifier)
|
|
98
|
+
- `createVerifierCredential(privateKey, params)`: register as professional verifier. `params: { profession: string; jurisdiction: string; licenceHash: string; professionalBody: string; statement?: string; bondProof?: BondProof }`.
|
|
99
|
+
- `checkCrossVerification(verifierPubkey: string, vouches: NostrEvent[], verifierCredentials: NostrEvent[])`: activation check. `vouches` is kind 31000 vouch events (`NostrEvent[]`) and `verifierCredentials` is kind 31000 `type: verifier` events (`NostrEvent[]`), not parsed objects. Returns `{ activated: boolean; vouchCount: number; professions: string[]; errors: string[] }`. `activated` is `true` when at least `VERIFIER_ACTIVATION.MIN_VOUCHES` vouches for `verifierPubkey` come from distinct vouchers that each appear in `verifierCredentials` with a `profession` tag, and those vouchers cover at least `VERIFIER_ACTIVATION.MIN_PROFESSIONS` different professions. It does not verify signatures, and it does not check that a voucher is itself activated or unrevoked (the spec asks for that, the function does not do it), so filter `verifierCredentials` to activated, unrevoked verifiers yourself.
|
|
100
|
+
- `isVerifierRevoked(verifierPubkey: string, revocations: NostrEvent[])`: `boolean`. `true` when any kind 31000 `type: revocation` event in `revocations` targets `verifierPubkey`. It does not verify signatures or check who signed the revocation.
|
|
101
|
+
|
|
102
|
+
### Challenges and Revocations (kind 31000, type: challenge / revocation)
|
|
103
|
+
- `createChallenge(reporterPrivateKey, params)`: `Promise<NostrEvent>`. `params: { verifierPubkey: string; reason: 'anomalous-volume' | 'registry-mismatch' | 'fraudulent-attestation' | 'licence-revoked' | 'other'; evidenceType: string; reporterTier: SignetTier; evidence: string; occurredAt?: number }`. `evidence` becomes the event content.
|
|
104
|
+
- `createRevocation(authorityPrivateKey, params)`: `Promise<NostrEvent>`. `params: { verifierPubkey: string; challengeEventId: string; confirmations: number; bondAction: 'slashed' | 'returned' | 'held'; scope: 'full' | 'partial'; effectiveAt: number; summary: string }`.
|
|
105
|
+
- `countChallengeConfirmations(challengeEventId: string, confirmationEvents: NostrEvent[], credentialEvents: NostrEvent[])`: `number`. All arrays are raw `NostrEvent[]`. Counts distinct confirmation signers whose `challenge` tag equals `challengeEventId` and who hold a credential event with a `tier` tag of 3 or higher in `credentialEvents`. It does not verify signatures or the issuers of those credentials.
|
|
106
|
+
- `hasReachedRevocationThreshold(confirmations, threshold = 5)`: `boolean`
|
|
107
|
+
- `parseChallenge(event)` / `parseRevocation(event)`: parsed object or `null`.
|
|
108
|
+
|
|
109
|
+
### Identity Bridge (kind 31000, type: identity-bridge)
|
|
110
|
+
- `createIdentityBridge(anonPrivateKey: string, realPrivateKey: string, ring: string[], signerIndex: number, ringMinTier: SignetTier, opts?)`: `Promise<NostrEvent>`. Links an anonymous account to a verified identity via ring signature. `ring: string[]` is the anonymity set of verified pubkeys (at least 5, `MIN_BRIDGE_RING_SIZE`) and must contain the public key of `realPrivateKey`. `signerIndex` is the zero-based position in `ring` of that real public key (`selectDecoyRing` returns it for you); a wrong index makes ring signing throw (`Private key does not match ring member at signerIndex`). `ringMinTier` is the lowest verification tier among the ring members, which you assert yourself: it is written to the event's `ring-min-tier` tag and scales the bridge's contribution to `computeTrustScore` (`TRUST_WEIGHTS.IDENTITY_BRIDGE` of 50 × `ringMinTier` ÷ 4). Neither `createIdentityBridge` nor `verifyIdentityBridge` checks that the ring members hold that tier. `opts: { occurredAt?: number }`. Signed by the anonymous key.
|
|
111
|
+
- `selectDecoyRing(verifiedPubkeys: string[], realPubkey: string, ringSize = 5)`: `{ ring: string[]; signerIndex: number }`. Picks decoys from `verifiedPubkeys` (`realPubkey` is filtered out of the pool if present) and places `realPubkey` at a random position. Throws if the pool has fewer than `ringSize - 1` other pubkeys.
|
|
112
|
+
- `verifyIdentityBridge(event: NostrEvent, opts?)`: `Promise<boolean>`. `opts: { maxAgeSeconds?: number }` (default 24 hours; `0` disables the freshness check).
|
|
113
|
+
|
|
114
|
+
### ZKP Age Proofs
|
|
115
|
+
- `createAgeRangeProof(age: number, ageRange: string, subjectPubkey?: string)`: `RangeProof` (synchronous). `subjectPubkey` binds the proof to one credential.
|
|
116
|
+
- `verifyAgeRangeProof(proof, expectedAgeRange, expectedSubjectPubkey?)`: `boolean`. Verify against the age policy you expect, not the range the proof claims.
|
|
117
|
+
- `serializeRangeProof(proof): string` / `deserializeRangeProof(json: string): RangeProof`
|
|
118
|
+
|
|
119
|
+
### Identity & Personas
|
|
120
|
+
- `createSignetIdentity(mnemonic, passphrase?)` / `createSignetIdentityFromNsec(nsec: string | Uint8Array)`: derive a master identity. Both return `SignetIdentity` (`{ root, naturalPerson, persona, mnemonic? }`) with natural-person and persona sub-identities.
|
|
121
|
+
- `deriveAdditionalPersona(root, name, index = 0)`: further `Persona`. `deriveDependantIdentity(root, dependantIndex)`: `DependantIdentity` (`{ derivationPath, naturalPerson, persona }`) for a child.
|
|
122
|
+
- `createLinkageProof(root, child, type: 'blind' | 'full')` / `verifyLinkageProof(proof)` (returns `boolean`): prove or verify that a child identity belongs to a root.
|
|
123
|
+
- `destroyIdentity(identity)`: zeroes the root and persona keys.
|
|
124
|
+
- nsec-tree's own `fromMnemonic` / `fromNsec` are not re-exported; this package wraps them as the two `createSignetIdentity*` functions. `derive` and `zeroise` are re-exported.
|
|
125
|
+
|
|
126
|
+
### Guardian Delegation
|
|
127
|
+
- `createGuardianDelegation(guardianPrivateKey, params)`: kind 31000 (type: delegation) event scoping a guardian's authority over a dependant. `params: { childPubkey: string; delegatePubkey: string; scope: 'full' | 'activity-approval' | 'content-management' | 'contact-approval'; expiresAt?: number; occurredAt?: number }`.
|
|
128
|
+
|
|
129
|
+
### signet-protocol/experimental (unstable)
|
|
130
|
+
|
|
131
|
+
Import from `signet-protocol/experimental`. Nothing here is exported from the package root. These are unreleased draft contracts under protocol review: any export may change or be removed in any release, including a minor or patch, with no deprecation period. Do not depend on them for production data.
|
|
132
|
+
|
|
133
|
+
- Private vault keys (see `docs/private-vault-v1.md`): `vaultPurpose`, `parseVaultPurpose`, `vaultKeyContext`, `deriveVaultIdentity`, `vaultIdentityFromMnemonic`; type `VaultDataset`.
|
|
134
|
+
- Private vault checkpoints: `VAULT_EVENT_KIND`, `MAX_VAULT_CHUNKS`, `MAX_VAULT_DEVICES`, `MAX_VAULT_CONTROL_BYTES`, `MAX_VAULT_CHUNK_BYTES`, `vaultCheckpointTag`, `vaultContentHash`, `parseVaultCheckpoint`, `matchesVaultChunk`, `vaultCheckpointShapedTag`; types `VaultCheckpoint`, `VaultChunkRef`.
|
|
135
|
+
- Private vault recovery: `readVaultSnapshot`, `readVaultRotations`, `readVaultHeads`, `readVaultHeadRotations`, `VAULT_CLOCK_TOLERANCE_SECONDS`; types `VaultReadResult`, `VaultReader`, `VaultHeadsResult`.
|
|
136
|
+
- Private vault relay reads: `createVaultRelayReader`, `fetchVaultEvents`, `MAX_VAULT_EVENTS_PER_RELAY`, `VaultRelayError`.
|
|
137
|
+
- Bot ownership profile (see `docs/bot-ownership-v1.md`): `BOT_OWNERSHIP_TYPE`, `BOT_OWNERSHIP_POLICY`, `buildBotOwnership`, `buildBotOwnershipRevocation`, `readBotOwnership`, `readBotOwnershipSync`, `botOwnershipRenewalDue`; types `BotOwnershipClaim`, `BotOwnershipResult`.
|
|
138
|
+
|
|
139
|
+
The voting extension (kinds 30482–30484) is specified in `spec/voting.md` and implemented in the separate `nostr-anon-vote` package on npm, not in `signet-protocol`.
|
|
140
|
+
|
|
141
|
+
## Optional
|
|
142
|
+
|
|
143
|
+
These paths ship in the npm package (`spec/`, `examples/`, and the `docs/` pages named below and in the experimental section above), so the relative links resolve inside `node_modules/signet-protocol/`. The examples import from the package's own `src/` directory; in your own code import from `signet-protocol`.
|
|
144
|
+
|
|
145
|
+
- [llms-full.txt](llms-full.txt): llms.txt plus the full protocol and voting specifications and the developer guides in one file
|
|
146
|
+
- [Full protocol specification](spec/protocol.md)
|
|
147
|
+
- [Voting extension specification](spec/voting.md)
|
|
148
|
+
- [Signet in 5 Minutes: developer overview](docs/signet-in-5-minutes.md)
|
|
149
|
+
- [Implementation levels guide](docs/implementation-levels.md)
|
|
150
|
+
- [Full flow example](examples/full-flow.ts)
|
|
151
|
+
- [Jurisdiction-specific examples](examples/jurisdictions/)
|
|
152
|
+
- [Regulatory compatibility](README.md#regulatory-compatibility)
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signet-protocol",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.2",
|
|
4
4
|
"description": "Decentralised identity verification protocol for Nostr",
|
|
5
|
+
"homepage": "https://github.com/forgesworn/signet#readme",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "./dist/index.js",
|
|
7
8
|
"types": "./dist/index.d.ts",
|
|
@@ -17,7 +18,15 @@
|
|
|
17
18
|
},
|
|
18
19
|
"files": [
|
|
19
20
|
"dist",
|
|
20
|
-
"src"
|
|
21
|
+
"src",
|
|
22
|
+
"spec",
|
|
23
|
+
"examples",
|
|
24
|
+
"docs/signet-in-5-minutes.md",
|
|
25
|
+
"docs/implementation-levels.md",
|
|
26
|
+
"docs/private-vault-v1.md",
|
|
27
|
+
"docs/bot-ownership-v1.md",
|
|
28
|
+
"llms.txt",
|
|
29
|
+
"llms-full.txt"
|
|
21
30
|
],
|
|
22
31
|
"publishConfig": {
|
|
23
32
|
"provenance": true
|
|
@@ -29,7 +38,9 @@
|
|
|
29
38
|
"typecheck": "tsc --noEmit",
|
|
30
39
|
"clean": "rm -rf dist",
|
|
31
40
|
"prepare": "npm run build",
|
|
32
|
-
"
|
|
41
|
+
"build:llms": "node scripts/build-llms-full.mjs",
|
|
42
|
+
"check:llms": "node scripts/build-llms-full.mjs --check",
|
|
43
|
+
"prepublishOnly": "npm run build:llms && npm run typecheck && npm test && npm run build"
|
|
33
44
|
},
|
|
34
45
|
"keywords": [
|
|
35
46
|
"nostr",
|