@nomosprotocol/sdk 1.3.0 → 1.3.1

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.
Files changed (2) hide show
  1. package/README.md +75 -11
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,14 +1,24 @@
1
1
  # @nomosprotocol/sdk
2
2
 
3
- Official TypeScript SDK for [NOMOS](https://www.nomosprotocol.com) — ask a public authority a question from your code and get back a deterministic, cryptographically verifiable verdict.
3
+ Official TypeScript SDK for [NOMOS](https://www.nomosprotocol.com) — ask "can I do this?" from your code and get back a deterministic, cryptographically verifiable verdict.
4
4
 
5
5
  ```bash
6
6
  npm install @nomosprotocol/sdk
7
7
  ```
8
8
 
9
- ## `nomos.can()` — the keyless primitive
9
+ ## `can()` — one function, three ways to ask
10
10
 
11
- Every public authority on the [NOMOS Exchange](https://www.nomosprotocol.com/exchange) is queryable with one call. No API key, no setup — this is the front door.
11
+ Same pattern as Stripe's PaymentIntents API: one function, routed entirely by what you pass it, one verdict vocabulary back regardless of which one ran.
12
+
13
+ | You ask about... | Call it as | Needs an API key? |
14
+ |---|---|---|
15
+ | A public authority on the [NOMOS Exchange](https://www.nomosprotocol.com/exchange) | `nomos.can({ authority, ...facts })` | No |
16
+ | Your own sealed artifact | `client.can({ artifact_id, ...facts })` | Yes |
17
+ | An artifact someone handed you directly — NOMOS has never seen it | `nomos.can({ artifact, key_certs, root_public_key_pem, ...facts })` | No |
18
+
19
+ ### Public Exchange authority (keyless)
20
+
21
+ No API key, no setup — this is the front door.
12
22
 
13
23
  ```ts
14
24
  import { nomos } from "@nomosprotocol/sdk";
@@ -35,9 +45,44 @@ const verdict = await nomos.can({
35
45
  });
36
46
  ```
37
47
 
48
+ A paid authority you haven't purchased throws `NomosPaymentRequiredError` (with price + purchase URL attached) instead of a generic failure — NOMOS never auto-charges on your behalf. See [Error handling](#error-handling).
49
+
50
+ ### Your own artifact (authenticated)
51
+
52
+ Same function, same verdict shape — swap `authority` for `artifact_id` and use the authenticated client:
53
+
54
+ ```ts
55
+ import { Nomos } from "@nomosprotocol/sdk";
56
+
57
+ const client = new Nomos("nms_live_..."); // or "nms_test_..." for test mode
58
+
59
+ const verdict = await client.can({
60
+ artifact_id: "loan_approval_v1",
61
+ credit_score: 720,
62
+ loan_amount: 50_000,
63
+ });
64
+ ```
65
+
66
+ ### Chain-of-trust (keyless, prototype)
67
+
68
+ For an artifact you received directly — from an agent, another system, anywhere — that NOMOS has never seen or registered. You supply the artifact, the key certificates presented alongside it, and the root public key **you've** independently decided to trust (there's deliberately no default). NOMOS verifies the chain resolves to that root, then evaluates the artifact's own rules against your facts — one call, no prior lookup:
69
+
70
+ ```ts
71
+ const verdict = await nomos.can({
72
+ artifact: theArtifactYouWereHanded,
73
+ key_certs: theCertificatesTheyIncluded,
74
+ root_public_key_pem: yourPinnedRootKey,
75
+ credit_score: 720,
76
+ });
77
+ ```
78
+
79
+ If the chain doesn't resolve — unrecognized issuer, revoked key, tampered artifact — this throws `NomosIssuerNotTrustedError` rather than a fake verdict; "the rules say no" and "we never established who's asking" are different claims that call for different next steps. See [Error handling](#error-handling).
80
+
81
+ This rail is a working **prototype**, not yet a numbered NOMOS spec — the primitive is in production use but hasn't been through a second independent implementation.
82
+
38
83
  ### The verdict
39
84
 
40
- `nomos.can()` always returns the authority's own verdict, verbatim — nothing invented, nothing paraphrased:
85
+ `can()` always returns the authority's own verdict, verbatim — nothing invented, nothing paraphrased — normalized into the same shape regardless of which rail answered:
41
86
 
42
87
  | Field | Type | Meaning |
43
88
  |---|---|---|
@@ -45,27 +90,44 @@ const verdict = await nomos.can({
45
90
  | `verdict` | `"AUTHORIZED" \| "DENIED" \| "ESCALATED"` | The authority's own answer |
46
91
  | `reason` | `string` | Human-readable explanation |
47
92
  | `rule` | `string \| null` | The rule id that decided it, if any |
48
- | `query_id` | `string` | Permanent, addressable transcript id |
49
- | `url` | `string` | Path to the transcript's permalink page |
50
- | `authority` | `{ id, title, standing }` | Which authority answered, and its standing |
93
+ | `query_id` | `string` | Permanent transcript id — Exchange rail only; absent (not faked) elsewhere |
94
+ | `url` | `string` | Path to the transcript's permalink page — same availability as `query_id` |
95
+ | `authority` | `{ id, title, standing, attestation? }` | Which authority answered, its standing, and — if a regulator/auditor/issuer has co-signed this exact version — who, in what role, and their statement |
96
+ | `version` | `string` | The artifact's own declared `meta.version`, when it has one |
51
97
  | `missing_inputs` | `string[]` | Fields the authority needed but didn't get — present on `ESCALATED` |
98
+ | `obligations` | `Array<{ kind, rule_id, rule_name }>` | Notify/log/flag-style duties that fired alongside the verdict — can accompany an `AUTHORIZED` result, not just a denial |
99
+ | `revoked` | `boolean` | `true` only if the issuer has revoked this exact sealed version — forces `verdict` to `DENIED` regardless of what the rules say. Absent (not `false`) when revocation doesn't apply here |
100
+ | `revocation_reason` | `string` | Present only alongside `revoked: true` |
101
+ | `max_age` | `number` | Recommended seconds to hold this verdict before re-checking — advisory, absent when not structurally revocable |
102
+ | `audit` | `{ hash, timestamp }` | Present only on the private-artifact rail — a hash you can store for compliance |
52
103
 
53
104
  `ESCALATED` means the authority needs more facts to decide — not a flat no. Check `missing_inputs` for what to supply.
54
105
 
55
- Every call mints a permanent, cryptographically sealed transcript — open `query_id` any time at `nomosprotocol.com/queries/<query_id>` to replay exactly what was asked and answered, bound to the exact authority version that responded.
106
+ The Exchange rail mints a permanent, cryptographically sealed transcript on every call — open `query_id` any time at `nomosprotocol.com/queries/<query_id>` to replay exactly what was asked and answered, bound to the exact authority version that responded. The other two rails are stateless by design (asking about your own artifact, or one NOMOS has never seen, has no transcript to point to) — `audit.hash` is the private-artifact rail's own provenance instead.
56
107
 
57
108
  ### Error handling
58
109
 
59
- A failed call (unknown authority, network issue, upstream error) rejects with a typed `NomosError` subclass — never a bare `Error` — so you can branch on `instanceof` or the stable `.code` string:
110
+ A failed call rejects with a typed `NomosError` subclass — never a bare `Error` — so you can branch on `instanceof` or the stable `.code` string:
60
111
 
61
112
  ```ts
62
- import { nomos, NomosNotFoundError, NomosNetworkError } from "@nomosprotocol/sdk";
113
+ import {
114
+ nomos,
115
+ NomosNotFoundError,
116
+ NomosNetworkError,
117
+ NomosPaymentRequiredError,
118
+ NomosIssuerNotTrustedError,
119
+ } from "@nomosprotocol/sdk";
63
120
 
64
121
  try {
65
122
  const verdict = await nomos.can({ authority: "eu-ai-act.nomos", ...facts });
66
123
  } catch (err) {
67
124
  if (err instanceof NomosNotFoundError) {
68
125
  // authority slug/id doesn't exist — err.code === 'not_found'
126
+ } else if (err instanceof NomosPaymentRequiredError) {
127
+ // paid, unpurchased — err.priceUsd / err.purchaseUrl
128
+ } else if (err instanceof NomosIssuerNotTrustedError) {
129
+ // chain-of-trust rail only — err.reason is one of
130
+ // ISSUER_NOT_RECOGNIZED | KEY_REVOKED | SEAL_INVALID
69
131
  } else if (err instanceof NomosNetworkError) {
70
132
  // request timed out or the network failed
71
133
  } else {
@@ -88,13 +150,15 @@ await nomos.can(
88
150
 
89
151
  ## `Nomos` — authenticated client
90
152
 
91
- For private/custom artifacts, governance generation, and webhook verification, use the authenticated client:
153
+ Beyond `client.can()`, the authenticated client covers the rest of the platform — the raw (richer) decision-verification shape, governance generation, and webhook verification:
92
154
 
93
155
  ```ts
94
156
  import { Nomos } from "@nomosprotocol/sdk";
95
157
 
96
158
  const client = new Nomos("nms_live_..."); // or "nms_test_..." for test mode
97
159
 
160
+ // Lower-level than client.can() — same evaluation, but returns the full raw shape
161
+ // (evaluation counts, confidence tier, paths_to_approval) instead of the normalized verdict.
98
162
  const result = await client.decisions.verify({
99
163
  artifact_id: "your_artifact_id",
100
164
  decision_context: { /* facts */ },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomosprotocol/sdk",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Official TypeScript SDK for the NOMOS governance runtime",
5
5
  "publishConfig": {
6
6
  "access": "public"