@nomosprotocol/sdk 1.3.4 → 2.0.0
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 +103 -1
- package/dist/index.cjs +5350 -77
- package/dist/index.d.cts +559 -26
- package/dist/index.d.ts +559 -26
- package/dist/index.js +5320 -74
- package/package.json +30 -11
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { CurrencyPolicy, ActVerdict } from '@nomosprotocol/verify';
|
|
2
|
+
export { bindingDigest, verifyAct, verifyArtifact, verifySeal } from '@nomosprotocol/verify';
|
|
3
|
+
|
|
1
4
|
interface VerifyDecisionParams {
|
|
2
5
|
/** Artifact ID from NOMOS Studio or the Exchange */
|
|
3
6
|
artifact_id: string;
|
|
@@ -68,7 +71,7 @@ interface CanParams {
|
|
|
68
71
|
* both `nomos.can()` and `client.can()`. */
|
|
69
72
|
artifact?: unknown;
|
|
70
73
|
/** The key certificates presented alongside `artifact` — order never affects the result. */
|
|
71
|
-
key_certs?: KeyCertificate[];
|
|
74
|
+
key_certs?: KeyCertificate$1[];
|
|
72
75
|
/** The root public key (PEM) YOU have independently decided to trust. There is deliberately no
|
|
73
76
|
* default — see the chain-of-trust design note for why. Required alongside `artifact`. */
|
|
74
77
|
root_public_key_pem?: string;
|
|
@@ -128,7 +131,10 @@ interface CanResult {
|
|
|
128
131
|
}>;
|
|
129
132
|
/** RECOMMENDED maximum seconds to hold this verdict before re-querying or re-checking the
|
|
130
133
|
* issuer's revocation list (NOMOS-SPEC-006 §6.2). Advisory; absent when the artifact isn't
|
|
131
|
-
* structurally revocable on this deployment — treat absence as "unknown," not "safe forever."
|
|
134
|
+
* structurally revocable on this deployment — treat absence as "unknown," not "safe forever."
|
|
135
|
+
* Disclosed gap: only ever set on the public authority rail today — client.can() and the
|
|
136
|
+
* presented-artifact rail don't emit it yet, so apply the same "don't hold a stale verdict
|
|
137
|
+
* across a meaningful delay" discipline manually on those two until that's closed. */
|
|
132
138
|
max_age?: number;
|
|
133
139
|
/** Present only when your own authenticated artifact answered — that rail's own provenance
|
|
134
140
|
* (a hash you can store for compliance), not a permanent public transcript like `query_id`. */
|
|
@@ -151,8 +157,67 @@ interface CanResult {
|
|
|
151
157
|
* (not a guess) on the Exchange/private-artifact rails, where this concept doesn't apply. */
|
|
152
158
|
revocation_checked?: 'live' | 'staple' | 'unchecked';
|
|
153
159
|
}
|
|
160
|
+
interface ConservedStateInfo {
|
|
161
|
+
artifact_id: string;
|
|
162
|
+
scope: string;
|
|
163
|
+
limit_amount: number;
|
|
164
|
+
consumed: number;
|
|
165
|
+
reserved: number;
|
|
166
|
+
available: number;
|
|
167
|
+
/** The raw ledger fact to pass into `can()` as `consumed_before` — already consumed+reserved
|
|
168
|
+
* (outstanding reservations count as spoken-for), not consumed alone. */
|
|
169
|
+
consumed_before: number;
|
|
170
|
+
version: number;
|
|
171
|
+
state_digest: string;
|
|
172
|
+
}
|
|
173
|
+
/** Reserve against a ledger using a real `can()` decision. */
|
|
174
|
+
interface ReserveByQueryParams {
|
|
175
|
+
artifact_id: string;
|
|
176
|
+
scope: string;
|
|
177
|
+
amount: number;
|
|
178
|
+
/** The `query_id` from a real `can()`/`nomos.can()` call that returned AUTHORIZED.
|
|
179
|
+
* `reserve()` looks that decision up itself and derives its own binding from it — this is a
|
|
180
|
+
* lookup key, not a claim you're asserting, and a made-up or already-used one is rejected. */
|
|
181
|
+
query_id: string;
|
|
182
|
+
action: string;
|
|
183
|
+
/** Optimistic-concurrency check: reject unless the ledger's state still matches what you last
|
|
184
|
+
* read via `conservedState.get()`. Omit only when you have no prior read to compare against. */
|
|
185
|
+
expected_state_digest?: string;
|
|
186
|
+
ttl_seconds?: number;
|
|
187
|
+
}
|
|
188
|
+
/** Reserve against a ledger using a NOMOS-SPEC-008 Act: the ledger verifies the Act itself (its
|
|
189
|
+
* own pinned root and audience id, its own `consumed_before`, single-use nonce) and holds exactly
|
|
190
|
+
* `act.action.params.amount` for `act.action.type === 'conserved_state.reserve'`, or nothing. */
|
|
191
|
+
interface ReserveByActParams {
|
|
192
|
+
artifact_id: string;
|
|
193
|
+
scope: string;
|
|
194
|
+
act: Record<string, unknown>;
|
|
195
|
+
ttl_seconds?: number;
|
|
196
|
+
}
|
|
197
|
+
type ReserveParams = ReserveByQueryParams | ReserveByActParams;
|
|
198
|
+
/** The cryptographically-bound reservation object — R-12 §5. */
|
|
199
|
+
interface Reservation {
|
|
200
|
+
reservation_id: string;
|
|
201
|
+
authority_seal: string;
|
|
202
|
+
decision_digest: string;
|
|
203
|
+
agent: string;
|
|
204
|
+
action: string;
|
|
205
|
+
scope: string;
|
|
206
|
+
amount: number;
|
|
207
|
+
state_digest: string;
|
|
208
|
+
expires_at: string;
|
|
209
|
+
status: 'held' | 'settled' | 'released' | 'expired';
|
|
210
|
+
}
|
|
211
|
+
interface ConservedStateReceipt {
|
|
212
|
+
reservation_id: string;
|
|
213
|
+
outcome: 'settled' | 'released';
|
|
214
|
+
amount: number;
|
|
215
|
+
ledger_key: string;
|
|
216
|
+
resolved_at: string;
|
|
217
|
+
reference?: string;
|
|
218
|
+
}
|
|
154
219
|
type ChainVerdictDecision = 'ALLOWED' | 'ISSUER_NOT_RECOGNIZED' | 'KEY_REVOKED' | 'CERTIFICATE_REVOKED' | 'OUT_OF_SCOPE' | 'SEAL_INVALID' | 'MALFORMED';
|
|
155
|
-
interface KeyCertificate {
|
|
220
|
+
interface KeyCertificate$1 {
|
|
156
221
|
parent_kid: string;
|
|
157
222
|
child_kid: string;
|
|
158
223
|
child_public_key_pem: string;
|
|
@@ -166,13 +231,15 @@ interface VerifyChainParams {
|
|
|
166
231
|
/** The sealed .nomos artifact being presented. */
|
|
167
232
|
artifact: unknown;
|
|
168
233
|
/** The set of key certificates presented alongside it — order never affects the result. */
|
|
169
|
-
key_certs: KeyCertificate[];
|
|
234
|
+
key_certs: KeyCertificate$1[];
|
|
170
235
|
/** The root public key (PEM) the CALLER has independently decided to trust. There is
|
|
171
236
|
* deliberately no default — see the chain-of-trust design note for why. */
|
|
172
237
|
root_public_key_pem: string;
|
|
173
238
|
}
|
|
174
239
|
interface VerifyChainOptions {
|
|
175
|
-
/**
|
|
240
|
+
/** Ask the hosted platform instead of verifying locally. Off by default. */
|
|
241
|
+
remote?: boolean;
|
|
242
|
+
/** With `remote`: override the API host (defaults to the public NOMOS platform). */
|
|
176
243
|
baseUrl?: string;
|
|
177
244
|
signal?: AbortSignal;
|
|
178
245
|
}
|
|
@@ -525,32 +592,107 @@ declare class Webhooks {
|
|
|
525
592
|
verifySignature(payload: string | Uint8Array, signature: string, secret: string, toleranceSeconds?: number): Promise<boolean>;
|
|
526
593
|
}
|
|
527
594
|
|
|
595
|
+
/**
|
|
596
|
+
* The state layer for a conserved (depleting) budget — R-12, a design in progress
|
|
597
|
+
* (docs/design-notes/conserved-state-authority.md in the platform repo; public mirror:
|
|
598
|
+
* computableauthority.com/research/conserved-state-authority). PROTOTYPE, not a numbered spec.
|
|
599
|
+
*
|
|
600
|
+
* `can()` stays exactly what it always was: pure, stateless, given facts and returning a
|
|
601
|
+
* verdict. Nothing here changes that. This resource is what a caller consults BEFORE calling
|
|
602
|
+
* `can()` (to build the `consumed_before` fact) and commits to AFTER `can()` returns AUTHORIZED
|
|
603
|
+
* and the caller has actually decided to act — never at `can()` time itself (repeatedly calling
|
|
604
|
+
* `can()` while deciding must never itself burn the budget).
|
|
605
|
+
*
|
|
606
|
+
* @example
|
|
607
|
+
* const state = await client.conservedState.get('supplier-budget-2026', 'supplier:acme');
|
|
608
|
+
* const verdict = await client.can({ artifact_id: 'supplier-budget-2026', consumed_before: state.consumed_before });
|
|
609
|
+
* if (verdict.allowed) {
|
|
610
|
+
* const reservation = await client.conservedState.reserve({
|
|
611
|
+
* artifact_id: 'supplier-budget-2026', scope: 'supplier:acme',
|
|
612
|
+
* amount: 5000, query_id: verdict.query_id!, action: 'payments.transfer',
|
|
613
|
+
* });
|
|
614
|
+
* try {
|
|
615
|
+
* // ... perform the real action ...
|
|
616
|
+
* await client.conservedState.settle(reservation.reservation_id);
|
|
617
|
+
* } catch {
|
|
618
|
+
* await client.conservedState.release(reservation.reservation_id);
|
|
619
|
+
* }
|
|
620
|
+
* }
|
|
621
|
+
*/
|
|
622
|
+
declare class ConservedState {
|
|
623
|
+
private readonly http;
|
|
624
|
+
constructor(http: HttpClient);
|
|
625
|
+
/**
|
|
626
|
+
* Read a ledger's current balance — no auth required, same posture as `can()`'s own keyless
|
|
627
|
+
* rail (reading how much budget remains is no more sensitive than reading a verdict).
|
|
628
|
+
*/
|
|
629
|
+
get(artifactId: string, scope: string, opts?: RequestOptions): Promise<WithLastResponse<ConservedStateInfo>>;
|
|
630
|
+
/**
|
|
631
|
+
* Commit capacity against a REAL, AUTHORIZED `can()` decision. Authenticated — unlike `can()`,
|
|
632
|
+
* spending against a shared budget requires an API key or session; `agent` on the returned
|
|
633
|
+
* reservation traces to that authenticated identity, never a value you pass in.
|
|
634
|
+
*
|
|
635
|
+
* Throws (via the SDK's standard NomosError hierarchy; `err.details?.code` carries the
|
|
636
|
+
* server's own code): `DECISION_NOT_FOUND` (the query_id names no real query), `DECISION_NOT
|
|
637
|
+
* _AUTHORIZED` (that decision didn't verdict AUTHORIZED for this artifact), `DECISION_ALREADY
|
|
638
|
+
* _USED` (already bound to a reservation — one decision authorizes one, ever), `STATE_CONFLICT`
|
|
639
|
+
* (a stale `expected_state_digest`), `INSUFFICIENT_CAPACITY` (`err.details.requested`/
|
|
640
|
+
* `.available` carry the numbers), or `NO_LEDGER` (nobody has declared this budget yet).
|
|
641
|
+
*
|
|
642
|
+
* Passing `{ artifact_id, scope, act }` instead authorizes the hold with a NOMOS-SPEC-008 Act.
|
|
643
|
+
* Extra codes: `ACT_NOT_ACCEPTED` (the ledger has no Act binding) and `ACT_REJECTED`, with the
|
|
644
|
+
* verifier's full answer in `err.details.result` — for `INCOMPLETE` it names the open rules and
|
|
645
|
+
* the facts whose testimony would decide them.
|
|
646
|
+
*/
|
|
647
|
+
reserve(params: ReserveParams, opts?: RequestOptions): Promise<WithLastResponse<Reservation>>;
|
|
648
|
+
/**
|
|
649
|
+
* The reserved action succeeded — moves the hold into real, settled spend. Idempotent when
|
|
650
|
+
* you pass the same `reference` again for a retry (e.g. after a network timeout): you get the
|
|
651
|
+
* ORIGINAL receipt back, never a double-charge.
|
|
652
|
+
*/
|
|
653
|
+
settle(reservationId: string, reference?: string, opts?: RequestOptions): Promise<WithLastResponse<ConservedStateReceipt>>;
|
|
654
|
+
/**
|
|
655
|
+
* The reserved action failed, or you decided not to act — gives the hold's capacity back
|
|
656
|
+
* without ever touching what's actually been spent.
|
|
657
|
+
*/
|
|
658
|
+
release(reservationId: string, reference?: string, opts?: RequestOptions): Promise<WithLastResponse<ConservedStateReceipt>>;
|
|
659
|
+
}
|
|
660
|
+
|
|
528
661
|
type NomosErrorCode = 'authentication_error' | 'authorization_error' | 'rate_limit_error' | 'validation_error' | 'not_found' | 'api_error' | 'network_error' | 'webhook_signature_error' | 'payment_required' | 'issuer_not_trusted';
|
|
529
662
|
declare class NomosError extends Error {
|
|
530
663
|
readonly code: NomosErrorCode;
|
|
531
664
|
readonly status?: number;
|
|
532
665
|
readonly requestId?: string;
|
|
533
|
-
|
|
666
|
+
/** The full parsed JSON response body, when the server sent one — every field it put there
|
|
667
|
+
* (its own `code`, and anything endpoint-specific like `requested`/`available` on a
|
|
668
|
+
* conserved-state capacity rejection, or `price_usd`/`purchase_url` before those got a
|
|
669
|
+
* dedicated error class). `NomosError`'s own `code` above is the SDK's fixed HTTP-status
|
|
670
|
+
* taxonomy; `details?.code` is the SERVER's own, finer-grained application code — the two
|
|
671
|
+
* are deliberately not conflated into one field. */
|
|
672
|
+
readonly details?: unknown;
|
|
673
|
+
constructor(message: string, code: NomosErrorCode, status?: number, requestId?: string, details?: unknown);
|
|
534
674
|
}
|
|
535
675
|
declare class NomosAuthenticationError extends NomosError {
|
|
536
|
-
constructor(message?: string, requestId?: string);
|
|
676
|
+
constructor(message?: string, requestId?: string, details?: unknown);
|
|
537
677
|
}
|
|
538
678
|
declare class NomosAuthorizationError extends NomosError {
|
|
539
|
-
constructor(message?: string, requestId?: string);
|
|
679
|
+
constructor(message?: string, requestId?: string, details?: unknown);
|
|
540
680
|
}
|
|
541
681
|
declare class NomosRateLimitError extends NomosError {
|
|
542
682
|
readonly retryAfter?: number;
|
|
543
|
-
constructor(message?: string, retryAfter?: number, requestId?: string);
|
|
683
|
+
constructor(message?: string, retryAfter?: number, requestId?: string, details?: unknown);
|
|
544
684
|
}
|
|
685
|
+
/** `details` is the parsed response body — kept as its own constructor param (rather than just
|
|
686
|
+
* relying on the base class field) since it long predates NomosError.details and every caller
|
|
687
|
+
* already passes it positionally in this slot; unchanged for backward compatibility. */
|
|
545
688
|
declare class NomosValidationError extends NomosError {
|
|
546
|
-
readonly details?: unknown;
|
|
547
689
|
constructor(message: string, details?: unknown, requestId?: string);
|
|
548
690
|
}
|
|
549
691
|
declare class NomosNotFoundError extends NomosError {
|
|
550
|
-
constructor(message: string, requestId?: string);
|
|
692
|
+
constructor(message: string, requestId?: string, details?: unknown);
|
|
551
693
|
}
|
|
552
694
|
declare class NomosAPIError extends NomosError {
|
|
553
|
-
constructor(message: string, status: number, requestId?: string);
|
|
695
|
+
constructor(message: string, status: number, requestId?: string, details?: unknown);
|
|
554
696
|
}
|
|
555
697
|
declare class NomosNetworkError extends NomosError {
|
|
556
698
|
constructor(message: string);
|
|
@@ -620,6 +762,9 @@ declare class Nomos {
|
|
|
620
762
|
readonly artifacts: Artifacts;
|
|
621
763
|
readonly governance: Governance;
|
|
622
764
|
readonly webhooks: Webhooks;
|
|
765
|
+
/** The R-12 conserved-state (depleting-budget) state layer — PROTOTYPE, not a numbered spec.
|
|
766
|
+
* See resources/conserved-state.ts for the full reserve/settle/release lifecycle. */
|
|
767
|
+
readonly conservedState: ConservedState;
|
|
623
768
|
/** Whether this instance is using a live or test API key. */
|
|
624
769
|
readonly mode: 'live' | 'test';
|
|
625
770
|
static readonly errors: typeof errors;
|
|
@@ -649,24 +794,412 @@ declare const nomos: {
|
|
|
649
794
|
};
|
|
650
795
|
|
|
651
796
|
/**
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
* have independently decided to trust — entirely server-side against nomos-chain.ts's pure
|
|
655
|
-
* verifier, with no account or API key required (keyless, matching `nomos.can()`'s precedent).
|
|
797
|
+
* NOMOS-SPEC-007 rev. 1.9 chain verification: does this artifact's signing key resolve, through the
|
|
798
|
+
* presented key certificates, to a root you have decided to trust, and was it delegated this artifact?
|
|
656
799
|
*
|
|
657
|
-
*
|
|
658
|
-
*
|
|
800
|
+
* Computed locally by @nomosprotocol/verify: no network call, no account, and no dependence on any
|
|
801
|
+
* NOMOS service being up or honest. There is no default root: `root_public_key_pem` is required, so
|
|
802
|
+
* the trust decision stays with you. Pass `{ remote: true }` only to ask the hosted platform instead.
|
|
659
803
|
*
|
|
660
804
|
* @example
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
* const result = await verifyChain({
|
|
664
|
-
* artifact: sealedArtifact,
|
|
665
|
-
* key_certs: [rootToIntermediate, intermediateToLeaf],
|
|
666
|
-
* root_public_key_pem: myPinnedRootPem,
|
|
667
|
-
* });
|
|
805
|
+
* const result = await verifyChain({ artifact, key_certs, root_public_key_pem: myPinnedRootPem });
|
|
668
806
|
* if (result.decision === 'ALLOWED') { ... }
|
|
669
807
|
*/
|
|
670
808
|
declare function verifyChain(params: VerifyChainParams, opts?: VerifyChainOptions): Promise<VerifyChainResult>;
|
|
671
809
|
|
|
672
|
-
|
|
810
|
+
type SignatureSuite = 'Ed25519' | 'ES256';
|
|
811
|
+
interface Signer {
|
|
812
|
+
/** NOMOS-SPEC-001 §8.4 key id of the public key. */
|
|
813
|
+
kid: string;
|
|
814
|
+
/** The public key, canonical SPKI PEM (NOMOS-SPEC-010 §3.1). */
|
|
815
|
+
publicKeyPem: string;
|
|
816
|
+
/** The suite this key signs under. */
|
|
817
|
+
algorithm: SignatureSuite;
|
|
818
|
+
/** Signs the exact payload bytes. Returns the signature in the suite's encoding, base64. */
|
|
819
|
+
sign(payload: Uint8Array): Promise<string>;
|
|
820
|
+
}
|
|
821
|
+
declare function kidOf(publicKeyPem: string): string;
|
|
822
|
+
/** A signer over a private key held in this process: PKCS#8 PEM. For development and tests;
|
|
823
|
+
* in production pass a Signer backed by your KMS or HSM. */
|
|
824
|
+
declare function localSigner(privateKeyPem: string): Signer;
|
|
825
|
+
/** A fresh in-memory key. For development and tests only. */
|
|
826
|
+
declare function generateSigner(algorithm?: SignatureSuite): Signer & {
|
|
827
|
+
privateKeyPem: string;
|
|
828
|
+
};
|
|
829
|
+
/** A deterministic Ed25519 key from a seed string: the same test key on every machine. Never for
|
|
830
|
+
* anything real — the seed is the key. */
|
|
831
|
+
declare function seededSigner(seed: string): Signer;
|
|
832
|
+
|
|
833
|
+
interface Action {
|
|
834
|
+
type: string;
|
|
835
|
+
subject?: string;
|
|
836
|
+
params?: Record<string, unknown>;
|
|
837
|
+
}
|
|
838
|
+
interface KeyCertificate {
|
|
839
|
+
parent_kid: string;
|
|
840
|
+
child_kid: string;
|
|
841
|
+
child_public_key_pem: string;
|
|
842
|
+
scope?: string | null;
|
|
843
|
+
issued_at: string;
|
|
844
|
+
expires_at: string;
|
|
845
|
+
algorithm: 'Ed25519' | 'ES256';
|
|
846
|
+
signature: string;
|
|
847
|
+
}
|
|
848
|
+
/** NOMOS-SPEC-007 §3: `parent` certifies `child` within `scope` until `expiresAt`. */
|
|
849
|
+
declare function certify(parent: Signer, child: {
|
|
850
|
+
kid: string;
|
|
851
|
+
publicKeyPem: string;
|
|
852
|
+
}, opts: {
|
|
853
|
+
scope?: string;
|
|
854
|
+
issuedAt?: Date;
|
|
855
|
+
expiresAt: Date;
|
|
856
|
+
}): Promise<KeyCertificate>;
|
|
857
|
+
/** NOMOS-SPEC-001 §8: seal an artifact body with the issuer's key. */
|
|
858
|
+
declare function seal(body: Record<string, unknown>, issuer: Signer, signedBy: Record<string, unknown> | string): Promise<any>;
|
|
859
|
+
/** NOMOS-SPEC-008 §3: a witness's signed statement of one fact about one subject. */
|
|
860
|
+
declare function signTestimony(witness: Signer, t: {
|
|
861
|
+
claim: string;
|
|
862
|
+
value: unknown;
|
|
863
|
+
about?: string | null;
|
|
864
|
+
asOf?: Date;
|
|
865
|
+
validUntil: Date;
|
|
866
|
+
}): Promise<any>;
|
|
867
|
+
/** NOMOS-SPEC-008 §4: an approver's consent to exactly this Act, in this role. */
|
|
868
|
+
declare function signConsent(approver: Signer, act: any, role: string, decision?: 'approve' | 'refuse'): Promise<any>;
|
|
869
|
+
/** NOMOS-SPEC-008 §5.4: the issuer's statement that this exact version is in force, for a day at most. */
|
|
870
|
+
declare function signInForce(issuer: Signer, artifact: any, opts: {
|
|
871
|
+
asOf?: Date;
|
|
872
|
+
validUntil: Date;
|
|
873
|
+
}): Promise<any>;
|
|
874
|
+
interface BuildActOptions {
|
|
875
|
+
relyingParty: string;
|
|
876
|
+
action: Action;
|
|
877
|
+
artifact: any;
|
|
878
|
+
keyCerts: KeyCertificate[];
|
|
879
|
+
testimony?: any[];
|
|
880
|
+
presenterFacts?: Record<string, unknown>;
|
|
881
|
+
inForce?: any;
|
|
882
|
+
/** Validity window in seconds (SPEC-008 §5.1). Longer windows leave a person time to approve. */
|
|
883
|
+
windowSeconds?: number;
|
|
884
|
+
now?: Date;
|
|
885
|
+
}
|
|
886
|
+
/** NOMOS-SPEC-008 §2: assemble an Act. It needs no key: what makes it valid is what it carries. */
|
|
887
|
+
declare function buildAct(o: BuildActOptions): any;
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* NOMOS-SPEC-009 §3 discovery documents. A document tells a carrier where to go and what to bring;
|
|
891
|
+
* it never decides anything (§2), so nothing here is trusted beyond what the verifier rechecks.
|
|
892
|
+
*/
|
|
893
|
+
|
|
894
|
+
interface RelyingPartyDocument {
|
|
895
|
+
nomos_document: 'relying-party';
|
|
896
|
+
version: '1';
|
|
897
|
+
relying_party_id: string;
|
|
898
|
+
act_endpoint: string;
|
|
899
|
+
roots: Array<{
|
|
900
|
+
kid: string;
|
|
901
|
+
public_key_pem: string;
|
|
902
|
+
}>;
|
|
903
|
+
authorities: Array<{
|
|
904
|
+
artifact_id: string;
|
|
905
|
+
issuer?: string;
|
|
906
|
+
actions: string[];
|
|
907
|
+
currency_policy: 'record' | 'record_or_statement';
|
|
908
|
+
in_force_seal_hash?: string;
|
|
909
|
+
}>;
|
|
910
|
+
local_facts?: string[];
|
|
911
|
+
max_window_seconds: number;
|
|
912
|
+
max_act_bytes?: number;
|
|
913
|
+
consent_suites?: string[];
|
|
914
|
+
valid_until?: string;
|
|
915
|
+
}
|
|
916
|
+
interface IssuerDocument {
|
|
917
|
+
nomos_document: 'issuer';
|
|
918
|
+
version: '1';
|
|
919
|
+
issuer_id: string;
|
|
920
|
+
authorities: Array<{
|
|
921
|
+
artifact_id: string;
|
|
922
|
+
version: string;
|
|
923
|
+
seal_hash: string;
|
|
924
|
+
artifact_url: string;
|
|
925
|
+
in_force_url?: string;
|
|
926
|
+
}>;
|
|
927
|
+
key_certs: KeyCertificate[];
|
|
928
|
+
witnesses?: string[];
|
|
929
|
+
approvals?: Array<{
|
|
930
|
+
role: string;
|
|
931
|
+
endpoint: string;
|
|
932
|
+
}>;
|
|
933
|
+
revocations_url?: string;
|
|
934
|
+
valid_until?: string;
|
|
935
|
+
}
|
|
936
|
+
interface WitnessDocument {
|
|
937
|
+
nomos_document: 'witness';
|
|
938
|
+
version: '1';
|
|
939
|
+
witness_id: string;
|
|
940
|
+
kid: string;
|
|
941
|
+
claims: string[];
|
|
942
|
+
statement_endpoint: string;
|
|
943
|
+
access?: string;
|
|
944
|
+
valid_until?: string;
|
|
945
|
+
}
|
|
946
|
+
declare const PATH: {
|
|
947
|
+
readonly 'relying-party': "/.well-known/nomos-relying-party";
|
|
948
|
+
readonly issuer: "/.well-known/nomos-issuer";
|
|
949
|
+
readonly witness: "/.well-known/nomos-witness";
|
|
950
|
+
};
|
|
951
|
+
type Kind = keyof typeof PATH;
|
|
952
|
+
type DocOf<K extends Kind> = K extends 'relying-party' ? RelyingPartyDocument : K extends 'issuer' ? IssuerDocument : WitnessDocument;
|
|
953
|
+
declare class NomosDiscoveryError extends Error {
|
|
954
|
+
readonly url: string;
|
|
955
|
+
constructor(message: string, url: string);
|
|
956
|
+
}
|
|
957
|
+
/** The origin of a URL or bare origin: `https://shop.example/anything` → `https://shop.example`. */
|
|
958
|
+
declare function originOf(to: string): string;
|
|
959
|
+
/** Fetches and checks one discovery document (§2 rule 4, §3). */
|
|
960
|
+
declare function fetchDocument<K extends Kind>(kind: K, origin: string, fetchImpl?: typeof fetch): Promise<DocOf<K>>;
|
|
961
|
+
declare const WELL_KNOWN: {
|
|
962
|
+
readonly 'relying-party': "/.well-known/nomos-relying-party";
|
|
963
|
+
readonly issuer: "/.well-known/nomos-issuer";
|
|
964
|
+
readonly witness: "/.well-known/nomos-witness";
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* accept() — the relying party: the system that makes the change.
|
|
969
|
+
*
|
|
970
|
+
* const rp = accept({ relyingPartyId, root, authorities, commit });
|
|
971
|
+
* app.use(rp.express()); // Express, Connect, node:http
|
|
972
|
+
* export default { fetch: rp.fetch }; // Hono, Next.js, Cloudflare, Deno, Bun
|
|
973
|
+
*
|
|
974
|
+
* For every Act it receives it runs NOMOS-SPEC-008 §6 with @nomosprotocol/verify, locally, and on
|
|
975
|
+
* AUTHORIZED applies §8 exactly, in one transaction: record the nonce, re-read its own facts
|
|
976
|
+
* (re-verifying if they moved), hand `commit` a copy of exactly the verified action, and store the
|
|
977
|
+
* receipt. It answers with the NOMOS-SPEC-009 §6.2 status codes and serves its own discovery
|
|
978
|
+
* document (§3.1), generated from this same configuration so the two can never disagree (§2).
|
|
979
|
+
*/
|
|
980
|
+
|
|
981
|
+
interface AcceptedAuthority {
|
|
982
|
+
/** The sealed artifact's meta.artifact_id. */
|
|
983
|
+
artifactId: string;
|
|
984
|
+
/** Origin of the issuer document (NOMOS-SPEC-009 §3.2), advertised so carriers can find it. */
|
|
985
|
+
issuer?: string;
|
|
986
|
+
/** The action types this system commits under this authority. Anything else is refused. */
|
|
987
|
+
actions: string[];
|
|
988
|
+
/** SPEC-008 §5.5. `record` (RECOMMENDED) needs `inForceSealHash`. */
|
|
989
|
+
currencyPolicy: CurrencyPolicy;
|
|
990
|
+
/** Your record of the version in force: the seal hash of the version you accept. */
|
|
991
|
+
inForceSealHash?: string;
|
|
992
|
+
}
|
|
993
|
+
interface Receipt {
|
|
994
|
+
act_id: string;
|
|
995
|
+
act_digest: string;
|
|
996
|
+
decision: string;
|
|
997
|
+
rule: string | null;
|
|
998
|
+
by_consent?: boolean;
|
|
999
|
+
verified_at: string;
|
|
1000
|
+
committed_at?: string;
|
|
1001
|
+
relying_party_facts: Record<string, unknown>;
|
|
1002
|
+
in_force_source?: string;
|
|
1003
|
+
currency_policy: CurrencyPolicy;
|
|
1004
|
+
consent_origins?: string[];
|
|
1005
|
+
}
|
|
1006
|
+
/** One atomic operation (SPEC-008 §8). `tx` is passed to `commit` and `localFacts` so your own
|
|
1007
|
+
* writes and reads share it. */
|
|
1008
|
+
interface AcceptTransaction<Tx = unknown> {
|
|
1009
|
+
/** Records the nonce. false if it was already recorded (a concurrent duplicate). */
|
|
1010
|
+
claimNonce(nonce: string): Promise<boolean>;
|
|
1011
|
+
putReceipt(nonce: string, receipt: Receipt): Promise<void>;
|
|
1012
|
+
tx: Tx;
|
|
1013
|
+
}
|
|
1014
|
+
interface AcceptStore<Tx = unknown> {
|
|
1015
|
+
hasNonce(nonce: string): Promise<boolean>;
|
|
1016
|
+
receiptFor(nonce: string): Promise<Receipt | null>;
|
|
1017
|
+
transaction<T>(fn: (t: AcceptTransaction<Tx>) => Promise<T>): Promise<T>;
|
|
1018
|
+
}
|
|
1019
|
+
interface AcceptOptions<Tx = unknown> {
|
|
1020
|
+
/** Your identifier. Acts addressed to anything else are refused (SPEC-008 §5.3). */
|
|
1021
|
+
relyingPartyId: string;
|
|
1022
|
+
/** The root you pin (PEM). There is no default root. */
|
|
1023
|
+
root: string;
|
|
1024
|
+
authorities: AcceptedAuthority[];
|
|
1025
|
+
/** Applies the change. Receives a deep copy of exactly the verified action, and nothing else
|
|
1026
|
+
* from the request (SPEC-009 §6.4). Its return value is sent back as `result`. */
|
|
1027
|
+
commit: (action: {
|
|
1028
|
+
type: string;
|
|
1029
|
+
subject?: string;
|
|
1030
|
+
params: Record<string, unknown>;
|
|
1031
|
+
}, ctx: {
|
|
1032
|
+
tx: Tx;
|
|
1033
|
+
actId: string;
|
|
1034
|
+
}) => Promise<unknown> | unknown;
|
|
1035
|
+
/** Facts you supply from your own state (inputs with source `relying_party`). Called once to
|
|
1036
|
+
* verify, and again inside the transaction to check nothing moved (SPEC-008 §8 step 3). */
|
|
1037
|
+
localFacts?: (act: any, tx?: Tx) => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
1038
|
+
/** Where nonces and receipts live. Defaults to memory, for development only. */
|
|
1039
|
+
store?: AcceptStore<Tx>;
|
|
1040
|
+
/** The absolute URL carriers POST Acts to, as advertised in your discovery document. */
|
|
1041
|
+
actEndpoint: string;
|
|
1042
|
+
/** SPEC-008 §5.1 / SPEC-009 §6.3. Long enough for a person to approve. Default 900. */
|
|
1043
|
+
maxWindowSeconds?: number;
|
|
1044
|
+
maxActBytes?: number;
|
|
1045
|
+
/** Current revocation state (SPEC-006, SPEC-007 §5). Read on every verification. */
|
|
1046
|
+
revocations?: () => Promise<{
|
|
1047
|
+
kids?: Set<string>;
|
|
1048
|
+
certs?: Set<string>;
|
|
1049
|
+
artifacts?: Set<string>;
|
|
1050
|
+
}> | {
|
|
1051
|
+
kids?: Set<string>;
|
|
1052
|
+
certs?: Set<string>;
|
|
1053
|
+
artifacts?: Set<string>;
|
|
1054
|
+
};
|
|
1055
|
+
/** `shadow`: verify and record every verdict, never commit. For pilots. */
|
|
1056
|
+
mode?: 'enforce' | 'shadow';
|
|
1057
|
+
/** Every verdict, committed or not (SPEC-008 §9: a receipt for every verification). */
|
|
1058
|
+
onVerdict?: (verdict: ActVerdict, receipt: Receipt) => void | Promise<void>;
|
|
1059
|
+
/** How long this document is valid for, in seconds. Default one day. */
|
|
1060
|
+
documentTtlSeconds?: number;
|
|
1061
|
+
now?: () => Date;
|
|
1062
|
+
}
|
|
1063
|
+
interface Answer {
|
|
1064
|
+
status: number;
|
|
1065
|
+
headers: Record<string, string>;
|
|
1066
|
+
body: Record<string, unknown>;
|
|
1067
|
+
}
|
|
1068
|
+
declare const statusFor: (decision: string) => number;
|
|
1069
|
+
declare const ACT_MEDIA_TYPE = "application/nomos-act+json";
|
|
1070
|
+
/** Nonces and receipts in memory, one transaction at a time. Lost on restart, single process:
|
|
1071
|
+
* for development and tests only. Use a database-backed store in production. */
|
|
1072
|
+
declare function memoryStore(): AcceptStore<null>;
|
|
1073
|
+
declare function accept<Tx = unknown>(o: AcceptOptions<Tx>): {
|
|
1074
|
+
handle: (req: {
|
|
1075
|
+
method?: string;
|
|
1076
|
+
headers: Record<string, string | string[] | undefined>;
|
|
1077
|
+
body: string | Uint8Array;
|
|
1078
|
+
}) => Promise<Answer>;
|
|
1079
|
+
document: () => RelyingPartyDocument;
|
|
1080
|
+
fetch: (request: Request) => Promise<Response>;
|
|
1081
|
+
express: () => (req: any, res: any, next?: () => void) => Promise<void>;
|
|
1082
|
+
node: () => (req: any, res: any, next?: () => void) => Promise<void>;
|
|
1083
|
+
};
|
|
1084
|
+
|
|
1085
|
+
type ActStatus = 'committed' | 'escalated' | 'incomplete' | 'denied' | 'refused' | 'replayed';
|
|
1086
|
+
interface ActResult {
|
|
1087
|
+
status: ActStatus;
|
|
1088
|
+
/** The relying party's verdict, exactly as it returned it (SPEC-009 §6.2). */
|
|
1089
|
+
verdict: Record<string, any>;
|
|
1090
|
+
/** When committed: the receipt, and what the relying party's commit returned. */
|
|
1091
|
+
receipt?: Record<string, any>;
|
|
1092
|
+
result?: unknown;
|
|
1093
|
+
/** When incomplete: the facts that could still change the outcome, and why each is missing. */
|
|
1094
|
+
missing?: Array<{
|
|
1095
|
+
fact: string;
|
|
1096
|
+
source: string | null;
|
|
1097
|
+
why: string;
|
|
1098
|
+
}>;
|
|
1099
|
+
/** When escalated and not approved in time: where a person can approve. */
|
|
1100
|
+
approvalUrl?: string;
|
|
1101
|
+
/** The Act as submitted, for your records. */
|
|
1102
|
+
act: any;
|
|
1103
|
+
/** What happened, in one sentence. */
|
|
1104
|
+
summary: string;
|
|
1105
|
+
}
|
|
1106
|
+
interface ActOptions {
|
|
1107
|
+
/** The relying party: its origin or any URL on it. */
|
|
1108
|
+
to: string;
|
|
1109
|
+
action: Action;
|
|
1110
|
+
/** Which authority to act under, when the relying party accepts several for this action type. */
|
|
1111
|
+
authority?: string;
|
|
1112
|
+
/** Facts the carrier supplies itself (inputs whose declared source is `presenter`). */
|
|
1113
|
+
presenterFacts?: Record<string, unknown>;
|
|
1114
|
+
/** Credentials for witnesses that need them: origin → headers (SPEC-009 §3.3 `access`). */
|
|
1115
|
+
witnessHeaders?: Record<string, Record<string, string>>;
|
|
1116
|
+
/** Wait up to this long for a person to approve, in ms. Default: until the Act expires. */
|
|
1117
|
+
approvalTimeoutMs?: number;
|
|
1118
|
+
/** Called once per pending approval with the page a person can approve on. */
|
|
1119
|
+
onApproval?: (approval: {
|
|
1120
|
+
role: string;
|
|
1121
|
+
url?: string;
|
|
1122
|
+
actDigest: string;
|
|
1123
|
+
}) => void;
|
|
1124
|
+
/** Use a specific fetch (tests, proxies). */
|
|
1125
|
+
fetch?: typeof fetch;
|
|
1126
|
+
/** Poll interval for pending approvals, ms. Default 1000. */
|
|
1127
|
+
pollMs?: number;
|
|
1128
|
+
}
|
|
1129
|
+
declare class NomosActError extends Error {
|
|
1130
|
+
constructor(message: string);
|
|
1131
|
+
}
|
|
1132
|
+
declare function act(o: ActOptions): Promise<ActResult>;
|
|
1133
|
+
|
|
1134
|
+
interface IssuerOptions {
|
|
1135
|
+
/** Your public origin, e.g. https://policy.acme.example */
|
|
1136
|
+
origin: string;
|
|
1137
|
+
issuerId: string;
|
|
1138
|
+
/** The key that sealed the authorities; it also signs in-force statements (SPEC-008 §5.4). */
|
|
1139
|
+
signer: Signer;
|
|
1140
|
+
/** Sealed artifacts, each the version currently in force. */
|
|
1141
|
+
authorities: any[];
|
|
1142
|
+
/** The certificate pool carriers present: your sealing key, witnesses, approvers (SPEC-007). */
|
|
1143
|
+
keyCerts: KeyCertificate[];
|
|
1144
|
+
witnesses?: string[];
|
|
1145
|
+
approvals?: Array<{
|
|
1146
|
+
role: string;
|
|
1147
|
+
endpoint: string;
|
|
1148
|
+
}>;
|
|
1149
|
+
revocationsUrl?: string;
|
|
1150
|
+
}
|
|
1151
|
+
declare function issuer(o: IssuerOptions): {
|
|
1152
|
+
fetch: (request: Request) => Promise<Response>;
|
|
1153
|
+
express: () => (req: any, res: any, next?: () => void) => Promise<any>;
|
|
1154
|
+
node: () => (req: any, res: any, next?: () => void) => Promise<any>;
|
|
1155
|
+
document: () => IssuerDocument;
|
|
1156
|
+
};
|
|
1157
|
+
interface WitnessOptions {
|
|
1158
|
+
origin: string;
|
|
1159
|
+
witnessId: string;
|
|
1160
|
+
/** A key certified for exactly these claims (SPEC-007 rev. 1.8 §3.4.1). */
|
|
1161
|
+
signer: Signer;
|
|
1162
|
+
/** Each claim this witness states, and how to read its current value for a subject. Return
|
|
1163
|
+
* undefined when the subject is unknown. */
|
|
1164
|
+
claims: Record<string, (about: string | null) => unknown | Promise<unknown>>;
|
|
1165
|
+
/** How long a statement stays true, at most, in seconds. Default 900. */
|
|
1166
|
+
maxValiditySeconds?: number;
|
|
1167
|
+
/** Your access control (SPEC-009 §3.3): return false to refuse a requester. */
|
|
1168
|
+
authorize?: (request: {
|
|
1169
|
+
claim: string;
|
|
1170
|
+
about: string | null;
|
|
1171
|
+
}) => boolean | Promise<boolean>;
|
|
1172
|
+
access?: string;
|
|
1173
|
+
}
|
|
1174
|
+
declare function witness(o: WitnessOptions): {
|
|
1175
|
+
fetch: (request: Request) => Promise<Response>;
|
|
1176
|
+
express: () => (req: any, res: any, next?: () => void) => Promise<any>;
|
|
1177
|
+
node: () => (req: any, res: any, next?: () => void) => Promise<any>;
|
|
1178
|
+
document: () => WitnessDocument;
|
|
1179
|
+
};
|
|
1180
|
+
interface ApproverOptions {
|
|
1181
|
+
origin: string;
|
|
1182
|
+
/** The person's key, certified with `consent:<role> approver:<their id>` (SPEC-007 rev. 1.9 §3.7). */
|
|
1183
|
+
signer: Signer;
|
|
1184
|
+
roles: string[];
|
|
1185
|
+
/** 'page' (default): a person approves on a page this handler serves. 'auto': approve every
|
|
1186
|
+
* request at once — development only. Or a function that decides. */
|
|
1187
|
+
decide?: 'page' | 'auto' | ((request: {
|
|
1188
|
+
role: string;
|
|
1189
|
+
act: any;
|
|
1190
|
+
}) => boolean | Promise<boolean>);
|
|
1191
|
+
}
|
|
1192
|
+
interface Pending {
|
|
1193
|
+
role: string;
|
|
1194
|
+
act: any;
|
|
1195
|
+
status: 'pending' | 'approved' | 'refused' | 'expired';
|
|
1196
|
+
consent?: any;
|
|
1197
|
+
}
|
|
1198
|
+
declare function approver(o: ApproverOptions): {
|
|
1199
|
+
fetch: (request: Request) => Promise<Response>;
|
|
1200
|
+
express: () => (req: any, res: any, next?: () => void) => Promise<any>;
|
|
1201
|
+
node: () => (req: any, res: any, next?: () => void) => Promise<any>;
|
|
1202
|
+
pending: Map<string, Pending>;
|
|
1203
|
+
};
|
|
1204
|
+
|
|
1205
|
+
export { ACT_MEDIA_TYPE, type AcceptOptions, type AcceptStore, type AcceptTransaction, type AcceptedAuthority, type KeyCertificate as ActKeyCertificate, type ActOptions, type ActResult, type ActStatus, type Action, type Answer, type ApproverOptions, type Artifact, type ArtifactList, type ArtifactSchema, type ArtifactSchemaField, type AttestationInfo, type BuildActOptions, type CanOptions, type CanParams, type CanResult, type CanVerdict, type ChainVerdictDecision, type ConservedStateInfo, type ConservedStateReceipt, type Contradiction, type DetectContradictionsParams, type DetectContradictionsResult, type GenerateGovernanceParams, type GenerateGovernanceResult, type IssuerDocument, type IssuerOptions, type KeyCertificate$1 as KeyCertificate, type ListArtifactsParams, Nomos, NomosAPIError, NomosActError, NomosAuthenticationError, NomosAuthorizationError, type NomosConfig, NomosDiscoveryError, NomosError, type NomosErrorCode, NomosIssuerNotTrustedError, NomosNetworkError, NomosNotFoundError, NomosPaymentRequiredError, NomosRateLimitError, type NomosRawResponse, NomosValidationError, type NomosWebhookEvent, type NomosWebhookEventType, NomosWebhookSignatureError, type Receipt, type RelyingPartyDocument, type RequestOptions, type Reservation, type ReserveByActParams, type ReserveByQueryParams, type ReserveParams, type SignatureSuite, type Signer, type Verdict, type VerifyChainOptions, type VerifyChainParams, type VerifyChainResult, type VerifyDecisionParams, type VerifyDecisionResult, WELL_KNOWN, type WithLastResponse, type WitnessDocument, type WitnessOptions, accept, act, approver, buildAct, can, certify, fetchDocument, generateSigner, issuer, kidOf, localSigner, memoryStore, nomos, originOf, seal, seededSigner, signConsent, signInForce, signTestimony, statusFor, verifyChain, witness };
|