@nomosprotocol/sdk 2.5.0 → 2.7.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 +92 -1
- package/dist/index.cjs +465 -13
- package/dist/index.d.cts +161 -2
- package/dist/index.d.ts +161 -2
- package/dist/index.js +463 -13
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -97,6 +97,39 @@ can return their own chains with what they sign (`keyCerts`). On the relying par
|
|
|
97
97
|
(NOMOS-SPEC-007 rev. 1.10). Revocations are never forgotten, and without a current list
|
|
98
98
|
`accept()` answers 503 instead of committing.
|
|
99
99
|
|
|
100
|
+
**Which laws govern the act (2.7.0).** An Act carries one authority, so on its own `accept()` checks
|
|
101
|
+
the law the carrier chose. Pin registrars and `accept()` works out every law that governs the act here,
|
|
102
|
+
now, and commits only if the Act carries every one (NOMOS-SPEC-014, Draft):
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { accept, registrarSource } from '@nomosprotocol/sdk';
|
|
106
|
+
|
|
107
|
+
const platform = registrarSource({
|
|
108
|
+
id: 'platform',
|
|
109
|
+
url: 'https://www.nomosprotocol.com',
|
|
110
|
+
publicKeyPem: PLATFORM_KEY_PEM, // pinned by you; heads signed by any other key are refused
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const rp = accept({
|
|
114
|
+
// ...relyingPartyId, root, authorities (with registrarName), commit, as above
|
|
115
|
+
resolution: {
|
|
116
|
+
registrars: [platform],
|
|
117
|
+
// From YOUR knowledge and state, never from the Act: a carrier that stated its own
|
|
118
|
+
// jurisdiction would choose the law again.
|
|
119
|
+
context: (act, localFacts) => ({ jurisdiction: 'AE', established_in: 'DIFC', subjects_in: 'AE', output_used_in: 'AE' }),
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
If another law also governs the act, the Act is held (`422 INCOMPLETE`, `reason_code:
|
|
125
|
+
'laws_not_presented'`, the laws named) and nothing is committed. A context fact you leave out holds it
|
|
126
|
+
too (`resolution_incomplete`, naming the fact). A registrar that cannot be read, a head older than
|
|
127
|
+
`maxHeadAgeSeconds`, a head signed by a key you did not pin, or a log whose history was rewritten
|
|
128
|
+
answers 503 with Retry-After. Receipts record the resolution (status, context, laws, log heads).
|
|
129
|
+
Create each `registrarSource()` once and reuse it: the check that a registrar's history was only ever
|
|
130
|
+
added to spans the source's lifetime (pass `initialHead` to carry the last head across restarts).
|
|
131
|
+
Without `resolution`, `accept()` is unchanged.
|
|
132
|
+
|
|
100
133
|
**The other roles** are one call each:
|
|
101
134
|
- `issuer()` publishes your sealed policies and certificates;
|
|
102
135
|
- `witness()` turns an existing lookup into signed statements;
|
|
@@ -122,9 +155,55 @@ It abstracts three different authority situations behind one call and one verdic
|
|
|
122
155
|
| A public authority published on the NOMOS Exchange | `nomos.can({ authority, ...facts })` | No |
|
|
123
156
|
| Your organization's sealed artifact | `client.can({ artifact_id, ...facts })` | Yes |
|
|
124
157
|
| A sealed artifact presented directly by an agent or system | `nomos.can({ artifact, key_certs, root_public_key_pem, ...facts })` | No |
|
|
158
|
+
| An act, and you don't know which laws govern it | `nomos.can({ context, ...facts })` | No |
|
|
125
159
|
|
|
126
160
|
The caller does not need to know which evaluation rail is being used. `can()` routes internally based on what you provide.
|
|
127
161
|
|
|
162
|
+
### 0. Ask by context: let NOMOS find the laws (2.6.0)
|
|
163
|
+
|
|
164
|
+
Naming a law lets the caller choose which law is checked, and leave out the strict one. Describe
|
|
165
|
+
the act instead, and NOMOS works out which laws govern it, asks every one, and combines the answers:
|
|
166
|
+
any deny denies, and a yes needs every law to say yes.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { can } from '@nomosprotocol/sdk';
|
|
170
|
+
|
|
171
|
+
const v = await can({
|
|
172
|
+
context: {
|
|
173
|
+
jurisdiction: 'AE', // where the act takes effect
|
|
174
|
+
established_in: 'DIFC', // where your organisation is incorporated or established
|
|
175
|
+
subjects_in: 'AE', // where the people it concerns are
|
|
176
|
+
output_used_in: 'AE', // where any AI output is used
|
|
177
|
+
},
|
|
178
|
+
action: 'share_customer_data_with_analytics_vendor',
|
|
179
|
+
processing_fair_and_transparent: false,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
v.mode; // 'resolution'
|
|
183
|
+
v.verdict; // 'DENIED': a DIFC firm acting in mainland Dubai answers to DIFC law
|
|
184
|
+
v.answered_under; // ['difc-data-protection-law-difc-law-no-5-of-2020']
|
|
185
|
+
v.coverage; // what the answer covers, in words
|
|
186
|
+
v.members; // each law's own answer, each a signed record (query_id)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
What can come back besides a verdict:
|
|
190
|
+
|
|
191
|
+
- `INSUFFICIENT_DATA` with `open_facts`: a fact that decides which law applies was not stated
|
|
192
|
+
(for example `established_in`). It is asked for, never assumed.
|
|
193
|
+
- `INSUFFICIENT_DATA` for a place the registrar does not cover (Saudi Arabia, the US, an ADGM or
|
|
194
|
+
QFC firm today). "No law found" is never read as "no law applies".
|
|
195
|
+
- `CONFLICT`: two registrars each claim exclusive precedence. A person decides.
|
|
196
|
+
|
|
197
|
+
Which laws apply where comes from the NOMOS registrar: a signed, append-only list in the public
|
|
198
|
+
log at `/.well-known/nomos-exchange-log`, verifiable offline. Each claim states the provision it
|
|
199
|
+
rests on. It currently covers the EU AI Act, Qatar Law No. 13 of 2016, UAE Federal Decree-Law
|
|
200
|
+
No. 45 of 2021 and DIFC Law No. 5 of 2020, and lists only its own laws, so other law may also
|
|
201
|
+
apply. Only want the list of laws? `POST /api/v1/resolve { context }` returns it without asking
|
|
202
|
+
them, and records nothing.
|
|
203
|
+
|
|
204
|
+
The system that commits the change can resolve too, from registrars it pins and a context it supplies
|
|
205
|
+
itself: see `accept({ resolution })` above (2.7.0).
|
|
206
|
+
|
|
128
207
|
### 1. Public authority
|
|
129
208
|
|
|
130
209
|
Ask a published authority directly:
|
|
@@ -187,7 +266,11 @@ import { Nomos } from "@nomosprotocol/sdk";
|
|
|
187
266
|
|
|
188
267
|
const client = new Nomos(process.env.NOMOS_API_KEY!);
|
|
189
268
|
const r = await client.can(
|
|
190
|
-
{ authority: "data-protection-law-difc-law-no-5-of-2020",
|
|
269
|
+
{ authority: "difc-data-protection-law-difc-law-no-5-of-2020",
|
|
270
|
+
...allTwelveNo, // the law's intake questions, listed on its page
|
|
271
|
+
q_individual_request: true, // "yes": a request from a person
|
|
272
|
+
access_request_received: true, days_since_access_request: 45,
|
|
273
|
+
identity_doubt_unresolved: false, response_period_extended_with_notice: false },
|
|
191
274
|
{ awaitApproval: { timeoutMs: 10 * 60_000, onApproval: (a) => console.log("waiting on", a.url) } },
|
|
192
275
|
);
|
|
193
276
|
|
|
@@ -196,6 +279,14 @@ else console.log(r.verdict, r.approval?.status); // DENIED, or rejected / timed_
|
|
|
196
279
|
```
|
|
197
280
|
|
|
198
281
|
The approval is bound to the authority, the action and the facts: different facts need a new one.
|
|
282
|
+
|
|
283
|
+
A large law carries a few yes/no **intake questions** (listed on its page). Each "no" rules out the
|
|
284
|
+
articles it covers, so an ordinary action gets a firm answer in one call: on the DIFC Data Protection
|
|
285
|
+
Law, all twelve "no" is `AUTHORIZED`.
|
|
286
|
+
|
|
287
|
+
When a listing is replaced by a newer version and retired, calls to the old address throw a
|
|
288
|
+
`NomosAPIError` with status 410: the message names the new version's address. Move to it; the old
|
|
289
|
+
address is never answered from the old rules.
|
|
199
290
|
When the law gets a new version, you get an email with what changed. Turn either email off on the
|
|
200
291
|
same page.
|
|
201
292
|
|