@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/dist/index.js
CHANGED
|
@@ -107,7 +107,7 @@ function isRetryable(status) {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// src/http-client.ts
|
|
110
|
-
var SDK_VERSION = "2.
|
|
110
|
+
var SDK_VERSION = "2.7.0";
|
|
111
111
|
var HttpClient = class {
|
|
112
112
|
constructor(opts) {
|
|
113
113
|
this.opts = opts;
|
|
@@ -774,6 +774,50 @@ async function canViaChain(artifact, keyCerts, rootPublicKeyPem, facts, action,
|
|
|
774
774
|
if (data?.decision === "MALFORMED") throw new NomosValidationError(message, data, requestId);
|
|
775
775
|
mapHttpError(res.status, data, requestId);
|
|
776
776
|
}
|
|
777
|
+
function normalizeResolutionResult(data) {
|
|
778
|
+
return {
|
|
779
|
+
mode: "resolution",
|
|
780
|
+
allowed: data.verdict === "AUTHORIZED",
|
|
781
|
+
verdict: data.verdict,
|
|
782
|
+
reason: data.reason ?? "",
|
|
783
|
+
resolution: data.resolution ?? { status: "INCOMPLETE", proof: null },
|
|
784
|
+
members: Array.isArray(data.members) ? data.members : [],
|
|
785
|
+
deciding_authorities: Array.isArray(data.deciding_authorities) ? data.deciding_authorities : [],
|
|
786
|
+
escalations: Array.isArray(data.escalations) ? data.escalations : [],
|
|
787
|
+
open_facts: Array.isArray(data.open_facts) ? data.open_facts : [],
|
|
788
|
+
...Array.isArray(data.answered_under) ? { answered_under: data.answered_under } : {},
|
|
789
|
+
...typeof data.coverage === "string" ? { coverage: data.coverage } : {}
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
function resolutionBody(params) {
|
|
793
|
+
const { authority, artifact_id, artifact, key_certs, root_public_key_pem, action, inputs, context, ...flat } = params;
|
|
794
|
+
void authority;
|
|
795
|
+
void artifact_id;
|
|
796
|
+
void artifact;
|
|
797
|
+
void key_certs;
|
|
798
|
+
void root_public_key_pem;
|
|
799
|
+
const facts = inputs && typeof inputs === "object" ? inputs : flat;
|
|
800
|
+
return { context, ...action ? { action } : {}, ...facts };
|
|
801
|
+
}
|
|
802
|
+
async function canViaResolution(params, opts) {
|
|
803
|
+
const base = (opts?.baseUrl ?? DEFAULT_EXCHANGE_BASE).replace(/\/$/, "");
|
|
804
|
+
let res;
|
|
805
|
+
try {
|
|
806
|
+
res = await fetch(`${base}/api/v1/can`, {
|
|
807
|
+
method: "POST",
|
|
808
|
+
headers: { "Content-Type": "application/json", "User-Agent": `nomos-node/${SDK_VERSION}`, ...callerHeaders(opts?.caller) },
|
|
809
|
+
body: JSON.stringify(resolutionBody(params)),
|
|
810
|
+
signal: opts?.signal
|
|
811
|
+
});
|
|
812
|
+
} catch (err) {
|
|
813
|
+
if (err?.name === "AbortError") throw new NomosNetworkError("Request aborted");
|
|
814
|
+
throw new NomosNetworkError(err?.message ?? "Network error");
|
|
815
|
+
}
|
|
816
|
+
const requestId = res.headers.get("x-request-id") ?? "";
|
|
817
|
+
const data = await res.json().catch(() => null);
|
|
818
|
+
if (!res.ok) mapHttpError(res.status, data, requestId);
|
|
819
|
+
return normalizeResolutionResult(data);
|
|
820
|
+
}
|
|
777
821
|
async function can(params, opts) {
|
|
778
822
|
if (params.artifact !== void 0) {
|
|
779
823
|
if (!params.key_certs || !params.root_public_key_pem) {
|
|
@@ -785,8 +829,11 @@ async function can(params, opts) {
|
|
|
785
829
|
if (params.artifact_id) {
|
|
786
830
|
throw new Error("can(): `artifact_id` requires an API key \u2014 use `client.can(...)` on an authenticated Nomos instance, not the free `can()` export.");
|
|
787
831
|
}
|
|
832
|
+
if (!params.authority && params.context && typeof params.context === "object" && !Array.isArray(params.context)) {
|
|
833
|
+
return canViaResolution(params, opts);
|
|
834
|
+
}
|
|
788
835
|
if (!params.authority || typeof params.authority !== "string") {
|
|
789
|
-
throw new Error("can(): `authority` (an Exchange artifact id or slug), `artifact_id` (via client.can()),
|
|
836
|
+
throw new Error("can(): `authority` (an Exchange artifact id or slug), `artifact_id` (via client.can()), `artifact` (chain-of-trust), or `context` (resolution, NOMOS-SPEC-014) is required.");
|
|
790
837
|
}
|
|
791
838
|
const { facts, action } = splitFacts(params);
|
|
792
839
|
return canViaExchange(params.authority, facts, action, opts);
|
|
@@ -801,7 +848,11 @@ async function canAuthenticated(http, params, opts) {
|
|
|
801
848
|
}
|
|
802
849
|
if (params.artifact_id) return canViaArtifact(http, params.artifact_id, facts, action);
|
|
803
850
|
if (params.authority) return canViaExchangeAuthenticated(http, params.authority, facts, action, opts);
|
|
804
|
-
|
|
851
|
+
if (params.context && typeof params.context === "object" && !Array.isArray(params.context)) {
|
|
852
|
+
const data = (await http.post("/api/v1/can", resolutionBody(params), { headers: callerHeaders(opts?.caller) })).data;
|
|
853
|
+
return normalizeResolutionResult(data);
|
|
854
|
+
}
|
|
855
|
+
throw new Error("can(): `authority` (a public Exchange artifact), `artifact_id` (your own artifact), `artifact` (chain-of-trust), or `context` (resolution, NOMOS-SPEC-014) is required.");
|
|
805
856
|
}
|
|
806
857
|
var nomos = { can };
|
|
807
858
|
|
|
@@ -5123,7 +5174,7 @@ function verifyUnsafe(a, o) {
|
|
|
5123
5174
|
const now = (o.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
5124
5175
|
const nowDate = new Date(now);
|
|
5125
5176
|
const revokedKids = o.revokedKids ?? /* @__PURE__ */ new Set(), revokedCerts = o.revokedCerts ?? /* @__PURE__ */ new Set();
|
|
5126
|
-
const localFacts = o.localFacts ?? {},
|
|
5177
|
+
const localFacts = o.localFacts ?? {}, inForce2 = o.inForce ?? {};
|
|
5127
5178
|
const need = ["act_version", "act_id", "nonce", "issued_at", "expires_at", "relying_party", "action", "authority"];
|
|
5128
5179
|
if (!isObject(a) || need.some((k) => !(k in a)) || a.act_version !== "1" || !isObject(a.authority))
|
|
5129
5180
|
return { decision: "MALFORMED", reason_code: "bad_envelope" };
|
|
@@ -5167,9 +5218,9 @@ function verifyUnsafe(a, o) {
|
|
|
5167
5218
|
if (o.revokedArtifacts?.has(seal2.hash))
|
|
5168
5219
|
return { decision: "ARTIFACT_REVOKED", artifact_id: artId };
|
|
5169
5220
|
let inForceSource;
|
|
5170
|
-
if (typeof artId === "string" && Object.prototype.hasOwnProperty.call(
|
|
5171
|
-
if (
|
|
5172
|
-
return { decision: "SUPERSEDED", artifact_id: artId, in_force_seal_hash:
|
|
5221
|
+
if (typeof artId === "string" && Object.prototype.hasOwnProperty.call(inForce2, artId)) {
|
|
5222
|
+
if (inForce2[artId] !== seal2.hash)
|
|
5223
|
+
return { decision: "SUPERSEDED", artifact_id: artId, in_force_seal_hash: inForce2[artId] };
|
|
5173
5224
|
inForceSource = "record";
|
|
5174
5225
|
} else if (o.currencyPolicy === "record") {
|
|
5175
5226
|
return { decision: "VERSION_UNVERIFIED", artifact_id: artId, reason_code: "not_in_record" };
|
|
@@ -5386,6 +5437,288 @@ function verifyRevocationList(list, o) {
|
|
|
5386
5437
|
return out;
|
|
5387
5438
|
}
|
|
5388
5439
|
|
|
5440
|
+
// node_modules/@nomosprotocol/verify/dist/resolution.js
|
|
5441
|
+
var DEFAULT_CLOSURE_MAX_AGE_DAYS = 90;
|
|
5442
|
+
function evaluateScope(condition, context) {
|
|
5443
|
+
if (condition === "always" || condition === "all")
|
|
5444
|
+
return { value: "TRUE", openFacts: [] };
|
|
5445
|
+
let out;
|
|
5446
|
+
try {
|
|
5447
|
+
out = evaluate({
|
|
5448
|
+
logic: {
|
|
5449
|
+
resolution: { conflict_policy: "highest_priority", tie_breaker: "deny_wins", default_outcome: "escalate" },
|
|
5450
|
+
decisions: [
|
|
5451
|
+
{ id: "scope-when-true", when: condition, priority: 1, then: [{ type: "allow" }] },
|
|
5452
|
+
{ id: "scope", when: condition, priority: 2, then: [{ type: "block" }] }
|
|
5453
|
+
]
|
|
5454
|
+
}
|
|
5455
|
+
}, context);
|
|
5456
|
+
} catch {
|
|
5457
|
+
return { value: "UNDECIDED", openFacts: ["__scope_unparseable__"] };
|
|
5458
|
+
}
|
|
5459
|
+
if (out.outcome === "block")
|
|
5460
|
+
return { value: "TRUE", openFacts: [] };
|
|
5461
|
+
if (out.outcome === "undecided")
|
|
5462
|
+
return { value: "UNDECIDED", openFacts: [...out.open_facts] };
|
|
5463
|
+
return { value: "FALSE", openFacts: [] };
|
|
5464
|
+
}
|
|
5465
|
+
var inForce = (c, at) => (!c.from || c.from <= at) && (!c.until || c.until > at);
|
|
5466
|
+
var closureFresh = (c, at) => {
|
|
5467
|
+
const ageMs = Date.parse(at) - Date.parse(c.at);
|
|
5468
|
+
if (!Number.isFinite(ageMs) || ageMs < 0)
|
|
5469
|
+
return false;
|
|
5470
|
+
return ageMs <= (c.max_age_days ?? DEFAULT_CLOSURE_MAX_AGE_DAYS) * 864e5;
|
|
5471
|
+
};
|
|
5472
|
+
var closureReplaced = (c, all, at) => {
|
|
5473
|
+
const t = Date.parse(c.at), now = Date.parse(at);
|
|
5474
|
+
return all.some((d) => d !== c && Date.parse(d.at) > t && Date.parse(d.at) <= now && (d.scope === c.scope || !!c.label && d.label === c.label));
|
|
5475
|
+
};
|
|
5476
|
+
function resolveApplicableSet(world, query, opts = {}) {
|
|
5477
|
+
const at = query.at;
|
|
5478
|
+
const ctx = query.context ?? {};
|
|
5479
|
+
const proof = { at, pins: [...world.pins].sort(), heads: {}, closures: [], conflicts: [], dropped: [] };
|
|
5480
|
+
if (opts.ablate === "C5") {
|
|
5481
|
+
const applicable2 = (opts.presented ?? []).map((a) => ({ authority: a, version: null, registrar: "carrier", scope: "always" })).sort((x, y) => x.authority < y.authority ? -1 : 1);
|
|
5482
|
+
return { status: "RESOLVED", applicable: applicable2, proof };
|
|
5483
|
+
}
|
|
5484
|
+
const openFacts = /* @__PURE__ */ new Set();
|
|
5485
|
+
const unreachable = [];
|
|
5486
|
+
const staleClosures = [];
|
|
5487
|
+
const disagreements = [];
|
|
5488
|
+
const staleHeads = [];
|
|
5489
|
+
const memberAt = opts.ablate === "C7" && opts.snapshot ? opts.snapshot : at;
|
|
5490
|
+
const candidates2 = [];
|
|
5491
|
+
const visited = /* @__PURE__ */ new Set();
|
|
5492
|
+
const queue = [...world.pins].sort();
|
|
5493
|
+
while (queue.length > 0) {
|
|
5494
|
+
const id = queue.shift();
|
|
5495
|
+
if (visited.has(id))
|
|
5496
|
+
continue;
|
|
5497
|
+
visited.add(id);
|
|
5498
|
+
const reg = world.registrars[id];
|
|
5499
|
+
if (!reg) {
|
|
5500
|
+
if (opts.ablate !== "C8")
|
|
5501
|
+
unreachable.push(id);
|
|
5502
|
+
continue;
|
|
5503
|
+
}
|
|
5504
|
+
proof.heads[id] = reg.head ?? null;
|
|
5505
|
+
if (opts.ablate !== "C8" && typeof world.max_head_age_seconds === "number") {
|
|
5506
|
+
const age = reg.head_at ? Date.parse(at) - Date.parse(reg.head_at) : NaN;
|
|
5507
|
+
if (!Number.isFinite(age) || age > world.max_head_age_seconds * 1e3)
|
|
5508
|
+
staleHeads.push(id);
|
|
5509
|
+
}
|
|
5510
|
+
const cert = evaluateScope(reg.certified_scope, ctx);
|
|
5511
|
+
for (const f of cert.openFacts)
|
|
5512
|
+
openFacts.add(f);
|
|
5513
|
+
for (const e of [...reg.recognitions ?? []].sort((a, b) => a.to < b.to ? -1 : 1)) {
|
|
5514
|
+
const s = evaluateScope(e.scope, ctx);
|
|
5515
|
+
if (s.value === "TRUE")
|
|
5516
|
+
queue.push(e.to);
|
|
5517
|
+
for (const f of s.openFacts)
|
|
5518
|
+
openFacts.add(f);
|
|
5519
|
+
}
|
|
5520
|
+
const closedLists = [];
|
|
5521
|
+
if (opts.ablate !== "C8") {
|
|
5522
|
+
let covered = false;
|
|
5523
|
+
for (const c of reg.closures) {
|
|
5524
|
+
if (closureReplaced(c, reg.closures, at))
|
|
5525
|
+
continue;
|
|
5526
|
+
const s = evaluateScope(c.scope, ctx);
|
|
5527
|
+
for (const f of s.openFacts)
|
|
5528
|
+
openFacts.add(f);
|
|
5529
|
+
if (s.value !== "TRUE")
|
|
5530
|
+
continue;
|
|
5531
|
+
const fresh = closureFresh(c, at);
|
|
5532
|
+
proof.closures.push({ registrar: id, scope: c.scope, at: c.at, fresh });
|
|
5533
|
+
if (fresh) {
|
|
5534
|
+
covered = true;
|
|
5535
|
+
closedLists.push(c.authorities);
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
if (!covered)
|
|
5539
|
+
staleClosures.push(id);
|
|
5540
|
+
}
|
|
5541
|
+
const supersededNow = new Set((reg.supersessions ?? []).filter((s) => s.from <= memberAt).map((s) => s.superseded));
|
|
5542
|
+
const revoked = new Set(reg.revoked ?? []);
|
|
5543
|
+
const liveAuthorities = /* @__PURE__ */ new Set();
|
|
5544
|
+
const trueAuthorities = /* @__PURE__ */ new Set();
|
|
5545
|
+
for (const claim of reg.claims) {
|
|
5546
|
+
if (opts.ablate !== "C7" || opts.snapshot) {
|
|
5547
|
+
if (!inForce(claim, memberAt)) {
|
|
5548
|
+
proof.dropped.push({ authority: claim.authority, registrar: id, reason: "not_in_force" });
|
|
5549
|
+
continue;
|
|
5550
|
+
}
|
|
5551
|
+
if (supersededNow.has(claim.authority)) {
|
|
5552
|
+
proof.dropped.push({ authority: claim.authority, registrar: id, reason: "superseded" });
|
|
5553
|
+
continue;
|
|
5554
|
+
}
|
|
5555
|
+
if (revoked.has(claim.authority)) {
|
|
5556
|
+
proof.dropped.push({ authority: claim.authority, registrar: id, reason: "revoked" });
|
|
5557
|
+
continue;
|
|
5558
|
+
}
|
|
5559
|
+
}
|
|
5560
|
+
liveAuthorities.add(claim.authority);
|
|
5561
|
+
const s = evaluateScope(claim.scope, ctx);
|
|
5562
|
+
for (const f of s.openFacts)
|
|
5563
|
+
openFacts.add(f);
|
|
5564
|
+
if (s.value === "TRUE")
|
|
5565
|
+
trueAuthorities.add(claim.authority);
|
|
5566
|
+
if (s.value === "FALSE")
|
|
5567
|
+
continue;
|
|
5568
|
+
const within = opts.ablate === "C6" ? { value: "TRUE", openFacts: [] } : cert;
|
|
5569
|
+
if (s.value === "UNDECIDED" || within.value === "UNDECIDED")
|
|
5570
|
+
continue;
|
|
5571
|
+
if (within.value === "FALSE")
|
|
5572
|
+
continue;
|
|
5573
|
+
candidates2.push({ authority: claim.authority, version: claim.version ?? null, registrar: id, scope: claim.scope, exclusive: claim.exclusive === true });
|
|
5574
|
+
}
|
|
5575
|
+
if (opts.ablate !== "C8" && closedLists.length > 0) {
|
|
5576
|
+
for (const a of new Set(closedLists.flat())) {
|
|
5577
|
+
if (!liveAuthorities.has(a))
|
|
5578
|
+
disagreements.push({ registrar: id, authority: a, reason: "closed_but_not_claimed" });
|
|
5579
|
+
}
|
|
5580
|
+
for (const a of trueAuthorities) {
|
|
5581
|
+
if (!closedLists.some((l) => l.includes(a)))
|
|
5582
|
+
disagreements.push({ registrar: id, authority: a, reason: "claimed_but_not_closed" });
|
|
5583
|
+
}
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
proof.dropped.sort((a, b) => a.authority + a.registrar < b.authority + b.registrar ? -1 : 1);
|
|
5587
|
+
proof.closures.sort((a, b) => a.registrar + a.scope + a.at < b.registrar + b.scope + b.at ? -1 : 1);
|
|
5588
|
+
if (openFacts.size > 0 || unreachable.length > 0 || staleClosures.length > 0 || disagreements.length > 0 || staleHeads.length > 0) {
|
|
5589
|
+
return {
|
|
5590
|
+
status: "INCOMPLETE",
|
|
5591
|
+
missing: {
|
|
5592
|
+
context_facts: [...openFacts].sort(),
|
|
5593
|
+
unreachable_registrars: unreachable.sort(),
|
|
5594
|
+
stale_closures: staleClosures.sort(),
|
|
5595
|
+
stale_heads: staleHeads.sort(),
|
|
5596
|
+
closure_disagreements: disagreements.sort((a, b) => a.registrar + "\0" + a.authority < b.registrar + "\0" + b.authority ? -1 : 1)
|
|
5597
|
+
},
|
|
5598
|
+
proof
|
|
5599
|
+
};
|
|
5600
|
+
}
|
|
5601
|
+
const exclusives = candidates2.filter((c) => c.exclusive);
|
|
5602
|
+
const conflictPairs = exclusives.filter((c) => exclusives.some((o) => o.registrar !== c.registrar));
|
|
5603
|
+
if (conflictPairs.length > 0) {
|
|
5604
|
+
proof.conflicts.push({
|
|
5605
|
+
context_covered_by: conflictPairs.map((c) => ({ registrar: c.registrar, authority: c.authority, scope: c.scope })).sort((a, b) => a.registrar + a.authority < b.registrar + b.authority ? -1 : 1)
|
|
5606
|
+
});
|
|
5607
|
+
return { status: "CONFLICT", conflicts: proof.conflicts, proof };
|
|
5608
|
+
}
|
|
5609
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5610
|
+
const applicable = [];
|
|
5611
|
+
for (const c of [...candidates2].sort((a, b) => a.authority + "\0" + a.registrar < b.authority + "\0" + b.registrar ? -1 : 1)) {
|
|
5612
|
+
const key = c.authority + "\0" + c.registrar;
|
|
5613
|
+
if (seen.has(key))
|
|
5614
|
+
continue;
|
|
5615
|
+
seen.add(key);
|
|
5616
|
+
applicable.push({ authority: c.authority, version: c.version, registrar: c.registrar, scope: c.scope });
|
|
5617
|
+
}
|
|
5618
|
+
return { status: "RESOLVED", applicable, proof };
|
|
5619
|
+
}
|
|
5620
|
+
|
|
5621
|
+
// node_modules/@nomosprotocol/verify/dist/registrar.js
|
|
5622
|
+
var LOG_GENESIS = "0".repeat(64);
|
|
5623
|
+
var registrarHeadPayload = (h, log = "nomos-exchange-log") => jcs({ log, size: h.size, hash: h.hash, at: h.at });
|
|
5624
|
+
function verifyLogChain(entries) {
|
|
5625
|
+
let prev = LOG_GENESIS;
|
|
5626
|
+
const hashAt = /* @__PURE__ */ new Map([[0, LOG_GENESIS]]);
|
|
5627
|
+
for (const [i, e] of entries.entries()) {
|
|
5628
|
+
if (e.seq !== i + 1)
|
|
5629
|
+
return { ok: false, detail: `entry ${i + 1}: its seq is ${e.seq}` };
|
|
5630
|
+
if (e.prev_hash !== prev)
|
|
5631
|
+
return { ok: false, detail: `entry ${e.seq}: prev_hash does not match entry ${e.seq - 1}` };
|
|
5632
|
+
const { hash, ...body } = e;
|
|
5633
|
+
if (sha256Hex(jcs(body)) !== hash)
|
|
5634
|
+
return { ok: false, detail: `entry ${e.seq}: its hash does not match its contents` };
|
|
5635
|
+
prev = hash;
|
|
5636
|
+
hashAt.set(e.seq, hash);
|
|
5637
|
+
}
|
|
5638
|
+
return { ok: true, hashAt };
|
|
5639
|
+
}
|
|
5640
|
+
function verifyRegistrarLog(o) {
|
|
5641
|
+
const fail2 = (reason, detail) => ({ ok: false, reason, detail });
|
|
5642
|
+
const chain = verifyLogChain(o.entries);
|
|
5643
|
+
if (!chain.ok)
|
|
5644
|
+
return fail2("chain_broken", chain.detail);
|
|
5645
|
+
const h = o.head;
|
|
5646
|
+
if (!h || typeof h.size !== "number" || h.size > o.entries.length || chain.hashAt.get(h.size) !== h.hash) {
|
|
5647
|
+
return fail2("head_mismatch", `the head (size ${h?.size}) does not name an entry of this chain`);
|
|
5648
|
+
}
|
|
5649
|
+
if (!h.signature || !h.kid)
|
|
5650
|
+
return fail2("head_unsigned", "the head is not signed");
|
|
5651
|
+
const pinnedKid = kidOf(o.publicKeyPem);
|
|
5652
|
+
if (!pinnedKid || h.kid !== pinnedKid)
|
|
5653
|
+
return fail2("wrong_key", `the head is signed by ${h.kid}, not the pinned key ${pinnedKid ?? "(unreadable)"}`);
|
|
5654
|
+
if (!verifySuite("Ed25519", o.publicKeyPem, registrarHeadPayload(h, o.log), { signature: h.signature }).ok)
|
|
5655
|
+
return fail2("bad_signature", "the head signature does not verify under the pinned key");
|
|
5656
|
+
const age = o.now.getTime() - Date.parse(h.at);
|
|
5657
|
+
if (!Number.isFinite(age))
|
|
5658
|
+
return fail2("head_stale", "the head carries no time");
|
|
5659
|
+
if (age < -6e4)
|
|
5660
|
+
return fail2("head_in_future", `the head is dated ${h.at}, after now`);
|
|
5661
|
+
if (age > o.maxHeadAgeSeconds * 1e3)
|
|
5662
|
+
return fail2("head_stale", `the head is ${Math.round(age / 1e3)} s old; the bound is ${o.maxHeadAgeSeconds} s`);
|
|
5663
|
+
if (o.previous && chain.hashAt.get(o.previous.size) !== o.previous.hash) {
|
|
5664
|
+
return fail2("history_rewritten", `the head kept earlier (${o.previous.size}:${o.previous.hash.slice(0, 12)}\u2026) is not part of this log`);
|
|
5665
|
+
}
|
|
5666
|
+
return { ok: true, size: o.entries.length, head: { size: h.size, hash: h.hash, at: h.at, kid: h.kid } };
|
|
5667
|
+
}
|
|
5668
|
+
function foldRegistrarLog(entries, o) {
|
|
5669
|
+
const open = /* @__PURE__ */ new Map();
|
|
5670
|
+
const closedClaims = [];
|
|
5671
|
+
const closures = [];
|
|
5672
|
+
const recognitions = [];
|
|
5673
|
+
const supersessions = [];
|
|
5674
|
+
const revoked = /* @__PURE__ */ new Set();
|
|
5675
|
+
let head = null;
|
|
5676
|
+
for (const e of entries) {
|
|
5677
|
+
head = e.hash;
|
|
5678
|
+
if (e.kind === "applies") {
|
|
5679
|
+
const prior = open.get(e.name);
|
|
5680
|
+
if (prior)
|
|
5681
|
+
closedClaims.push({ ...prior, until: e.at });
|
|
5682
|
+
open.set(e.name, {
|
|
5683
|
+
authority: e.name,
|
|
5684
|
+
version: e.version ?? null,
|
|
5685
|
+
scope: typeof e.entry?.scope === "string" ? e.entry.scope : "always",
|
|
5686
|
+
exclusive: e.entry?.exclusive === true,
|
|
5687
|
+
from: e.at,
|
|
5688
|
+
until: typeof e.entry?.until === "string" ? e.entry.until : null,
|
|
5689
|
+
...typeof e.entry?.basis === "string" ? { basis: e.entry.basis } : {}
|
|
5690
|
+
});
|
|
5691
|
+
} else if (e.kind === "withdrawn") {
|
|
5692
|
+
const prior = open.get(e.name);
|
|
5693
|
+
if (prior) {
|
|
5694
|
+
closedClaims.push({ ...prior, until: e.at });
|
|
5695
|
+
open.delete(e.name);
|
|
5696
|
+
}
|
|
5697
|
+
} else if (e.kind === "revoked") {
|
|
5698
|
+
revoked.add(e.name);
|
|
5699
|
+
} else if (e.kind === "closed") {
|
|
5700
|
+
const scope = typeof e.entry?.scope === "string" ? e.entry.scope : "always";
|
|
5701
|
+
const authorities = Array.isArray(e.entry?.authorities) ? e.entry.authorities.filter((a) => typeof a === "string") : [];
|
|
5702
|
+
closures.push({ scope, authorities, at: e.at, label: e.name, ...typeof e.entry?.max_age_days === "number" ? { max_age_days: e.entry.max_age_days } : {} });
|
|
5703
|
+
} else if (e.kind === "recognizes") {
|
|
5704
|
+
recognitions.push({ to: e.name, scope: typeof e.entry?.scope === "string" ? e.entry.scope : "always" });
|
|
5705
|
+
} else if (e.kind === "superseded") {
|
|
5706
|
+
if (typeof e.entry?.by === "string")
|
|
5707
|
+
supersessions.push({ superseded: e.name, by: e.entry.by, from: e.at });
|
|
5708
|
+
}
|
|
5709
|
+
}
|
|
5710
|
+
return {
|
|
5711
|
+
id: o.id,
|
|
5712
|
+
certified_scope: o.certifiedScope ?? "always",
|
|
5713
|
+
claims: [...closedClaims, ...open.values()],
|
|
5714
|
+
closures,
|
|
5715
|
+
recognitions,
|
|
5716
|
+
supersessions,
|
|
5717
|
+
revoked: [...revoked].sort(),
|
|
5718
|
+
head
|
|
5719
|
+
};
|
|
5720
|
+
}
|
|
5721
|
+
|
|
5389
5722
|
// src/verify-chain.ts
|
|
5390
5723
|
var CHAIN_PROTOCOL_VERSION2 = "1";
|
|
5391
5724
|
var DEFAULT_BASE = "https://www.nomosprotocol.com";
|
|
@@ -5562,6 +5895,68 @@ ${tool}`);
|
|
|
5562
5895
|
return lines.join("\n");
|
|
5563
5896
|
}
|
|
5564
5897
|
|
|
5898
|
+
// src/act/registrars.ts
|
|
5899
|
+
var RegistrarUnavailable = class extends Error {
|
|
5900
|
+
constructor(message, retryAfterSeconds, registrar) {
|
|
5901
|
+
super(message);
|
|
5902
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
5903
|
+
this.registrar = registrar;
|
|
5904
|
+
this.name = "RegistrarUnavailable";
|
|
5905
|
+
}
|
|
5906
|
+
};
|
|
5907
|
+
var PAGE = 1e3;
|
|
5908
|
+
function registrarSource(o) {
|
|
5909
|
+
const f = o.fetch ?? fetch, now = o.now ?? (() => /* @__PURE__ */ new Date());
|
|
5910
|
+
const base = o.url.replace(/\/$/, "");
|
|
5911
|
+
const maxHeadAge = o.maxHeadAgeSeconds ?? 600, refresh = (o.refreshSeconds ?? 60) * 1e3;
|
|
5912
|
+
let view = null, kept = o.initialHead ?? null;
|
|
5913
|
+
let fetchedAt = 0, inFlight = null, lastError = "";
|
|
5914
|
+
async function getJson2(path) {
|
|
5915
|
+
const res = await f(`${base}${path}`, { headers: { accept: "application/json" } });
|
|
5916
|
+
if (!res.ok) throw new Error(`${base}${path} answered ${res.status}`);
|
|
5917
|
+
return res.json();
|
|
5918
|
+
}
|
|
5919
|
+
async function load() {
|
|
5920
|
+
fetchedAt = now().getTime();
|
|
5921
|
+
try {
|
|
5922
|
+
const head = await getJson2("/.well-known/nomos-exchange-log/head");
|
|
5923
|
+
const entries = [];
|
|
5924
|
+
for (let after = 0; ; ) {
|
|
5925
|
+
const page2 = await getJson2(`/.well-known/nomos-exchange-log?after=${after}&limit=${PAGE}`);
|
|
5926
|
+
const got = Array.isArray(page2?.entries) ? page2.entries : [];
|
|
5927
|
+
entries.push(...got);
|
|
5928
|
+
if (got.length < PAGE || !page2.next) break;
|
|
5929
|
+
after = got[got.length - 1].seq;
|
|
5930
|
+
}
|
|
5931
|
+
const vouched = entries.slice(0, Math.min(entries.length, Number(head?.size) || 0));
|
|
5932
|
+
const check = verifyRegistrarLog({ entries: vouched, head, publicKeyPem: o.publicKeyPem, now: now(), maxHeadAgeSeconds: maxHeadAge, previous: kept });
|
|
5933
|
+
if (!check.ok) {
|
|
5934
|
+
lastError = `${check.reason}: ${check.detail}`;
|
|
5935
|
+
if (check.reason === "history_rewritten" || check.reason === "wrong_key" || check.reason === "bad_signature" || check.reason === "chain_broken") view = null;
|
|
5936
|
+
return;
|
|
5937
|
+
}
|
|
5938
|
+
view = { record: foldRegistrarLog(vouched, { id: o.id, certifiedScope: o.certifiedScope }), head: check.head };
|
|
5939
|
+
kept = { size: check.head.size, hash: check.head.hash };
|
|
5940
|
+
lastError = "";
|
|
5941
|
+
} catch (e) {
|
|
5942
|
+
lastError = String(e?.message ?? e);
|
|
5943
|
+
}
|
|
5944
|
+
}
|
|
5945
|
+
const source = (async () => {
|
|
5946
|
+
const t = now().getTime();
|
|
5947
|
+
if (!inFlight && t - fetchedAt >= refresh) inFlight = load().finally(() => {
|
|
5948
|
+
inFlight = null;
|
|
5949
|
+
});
|
|
5950
|
+
if (inFlight) await inFlight;
|
|
5951
|
+
if (!view || t - Date.parse(view.head.at) > maxHeadAge * 1e3) {
|
|
5952
|
+
throw new RegistrarUnavailable(`Registrar ${o.id} (${base}) has no current, verified log${lastError ? `: ${lastError}` : ""}. Not committing until the law that applies can be read.`, Math.max(1, Math.ceil(refresh / 1e3)), o.id);
|
|
5953
|
+
}
|
|
5954
|
+
return view;
|
|
5955
|
+
});
|
|
5956
|
+
source.id = o.id;
|
|
5957
|
+
return source;
|
|
5958
|
+
}
|
|
5959
|
+
|
|
5565
5960
|
// src/act/bytes.ts
|
|
5566
5961
|
var utf82 = (s) => new TextEncoder().encode(s);
|
|
5567
5962
|
var fromUtf82 = (b) => new TextDecoder().decode(b);
|
|
@@ -5842,7 +6237,7 @@ var STATUS = { AUTHORIZED: 201, ESCALATED: 202, INCOMPLETE: 422, DENIED: 403, RE
|
|
|
5842
6237
|
var statusFor = (decision) => STATUS[decision] ?? 400;
|
|
5843
6238
|
var ACT_MEDIA_TYPE = "application/nomos-act+json";
|
|
5844
6239
|
var HINTS = {
|
|
5845
|
-
INCOMPLETE: (v) => `Missing facts that could change the outcome: ${(v.open_facts ?? []).join(", ")}. Bring them as testimony from a witness certified for each claim, or as the channel the authority declares.`,
|
|
6240
|
+
INCOMPLETE: (v) => v.reason_code === "laws_not_presented" ? `Other law also governs this act here: ${(v.laws ?? []).join(", ")}. This system commits only when every governing law is carried; this Act carries one.` : v.reason_code === "resolution_incomplete" ? `This system cannot yet establish which law governs this act${v.missing?.context_facts?.length ? `: its own knowledge of the act lacks ${v.missing.context_facts.join(", ")}` : v.missing?.stale_closures?.length ? ": a registrar it honours does not cover this case" : ""}. Nothing the carrier sends can supply this; nothing is committed while the governing law is unknown.` : v.reason_code === "resolution_conflict" ? "Two registrars each claim exclusive precedence over this act. A person must settle which law governs before it can be committed." : `Missing facts that could change the outcome: ${(v.open_facts ?? []).join(", ")}. Bring them as testimony from a witness certified for each claim, or as the channel the authority declares.`,
|
|
5846
6241
|
ESCALATED: (v) => `Needs ${v.consents_required} approval(s) from role ${v.role}. Request consent over act_digest ${v.act_digest} and resubmit this same Act before ${v.retry_until}.`,
|
|
5847
6242
|
DENIED: (v) => `Rule ${v.rule ?? "(default)"} refuses this action. No approval can change a denial.`,
|
|
5848
6243
|
WRONG_RELYING_PARTY: () => "The Act is addressed to another system. Build it with this relying_party_id.",
|
|
@@ -5955,6 +6350,24 @@ function accept(o) {
|
|
|
5955
6350
|
maxWindowSeconds
|
|
5956
6351
|
});
|
|
5957
6352
|
}
|
|
6353
|
+
async function resolveFor(act2, authority, facts, at, reuse) {
|
|
6354
|
+
if (!o.resolution) return null;
|
|
6355
|
+
const views = reuse ?? await Promise.all(o.resolution.registrars.map(async (src) => [src.id, await src()]));
|
|
6356
|
+
const context = { ...await o.resolution.context(act2, facts) };
|
|
6357
|
+
const r = resolveApplicableSet(
|
|
6358
|
+
{ pins: views.map(([id]) => id), registrars: Object.fromEntries(views.map(([id, v]) => [id, v.record])) },
|
|
6359
|
+
{ context, at: at.toISOString() }
|
|
6360
|
+
);
|
|
6361
|
+
const heads = Object.fromEntries(views.map(([id, v]) => [id, v.head.hash]));
|
|
6362
|
+
const applicable = r.status === "RESOLVED" ? [...new Set(r.applicable.map((m) => m.authority))].sort() : [];
|
|
6363
|
+
const info = { status: r.status, context, applicable, heads };
|
|
6364
|
+
if (r.status === "INCOMPLETE") return { ok: false, info, views, verdict: { decision: "INCOMPLETE", reason_code: "resolution_incomplete", missing: r.missing } };
|
|
6365
|
+
if (r.status === "CONFLICT") return { ok: false, info, views, verdict: { decision: "INCOMPLETE", reason_code: "resolution_conflict", conflicts: r.conflicts } };
|
|
6366
|
+
const carried = new Set([authority.registrarName, authority.artifactId].filter((x) => !!x));
|
|
6367
|
+
const notCarried = applicable.filter((a) => !carried.has(a));
|
|
6368
|
+
if (notCarried.length) return { ok: false, info: { ...info, laws_not_presented: notCarried }, views, verdict: { decision: "INCOMPLETE", reason_code: "laws_not_presented", laws: notCarried } };
|
|
6369
|
+
return { ok: true, info, views };
|
|
6370
|
+
}
|
|
5958
6371
|
async function handle(req) {
|
|
5959
6372
|
const ctype = String(req.headers["content-type"] ?? "").split(";")[0].trim().toLowerCase();
|
|
5960
6373
|
if ((req.method ?? "POST").toUpperCase() !== "POST") return { status: 405, headers: { allow: "POST", "content-type": "application/json" }, body: { error: "POST an Act here." } };
|
|
@@ -6001,8 +6414,31 @@ function accept(o) {
|
|
|
6001
6414
|
if (verdict.decision === "REPLAYED") {
|
|
6002
6415
|
return answer(verdict, { act_id: act2.act_id, receipt: await store.receiptFor(act2.nonce) });
|
|
6003
6416
|
}
|
|
6417
|
+
let resolved = null;
|
|
6418
|
+
if (verdict.decision === "AUTHORIZED" && o.resolution) {
|
|
6419
|
+
try {
|
|
6420
|
+
resolved = await resolveFor(act2, authority, facts, verifiedAt);
|
|
6421
|
+
} catch (e) {
|
|
6422
|
+
if (!(e instanceof RegistrarUnavailable)) throw e;
|
|
6423
|
+
return {
|
|
6424
|
+
status: 503,
|
|
6425
|
+
headers: { "content-type": "application/json", "retry-after": String(e.retryAfterSeconds) },
|
|
6426
|
+
body: { error: "The law that governs this act cannot be read right now, so nothing is committed. Resubmit this same Act later.", detail: e.message, registrar: e.registrar, retry_after: e.retryAfterSeconds }
|
|
6427
|
+
};
|
|
6428
|
+
}
|
|
6429
|
+
if (resolved && !resolved.ok) {
|
|
6430
|
+
const held = { ...resolved.verdict, act_id: act2.act_id, act_digest: verdict.act_digest, resolution: resolved.info };
|
|
6431
|
+
await o.onVerdict?.(held, { ...receiptOf(held, facts), resolution: resolved.info });
|
|
6432
|
+
if (o.mode === "shadow") {
|
|
6433
|
+
const a = answer(held);
|
|
6434
|
+
return { ...a, status: 200, body: { ...a.body, shadow: true } };
|
|
6435
|
+
}
|
|
6436
|
+
return answer(held);
|
|
6437
|
+
}
|
|
6438
|
+
}
|
|
6439
|
+
const withResolution = (r) => resolved?.ok ? { ...r, resolution: resolved.info } : r;
|
|
6004
6440
|
if (verdict.decision !== "AUTHORIZED" || o.mode === "shadow") {
|
|
6005
|
-
await o.onVerdict?.(verdict, receiptOf(verdict, facts));
|
|
6441
|
+
await o.onVerdict?.(verdict, withResolution(receiptOf(verdict, facts)));
|
|
6006
6442
|
if (verdict.decision === "ESCALATED") {
|
|
6007
6443
|
const esc3 = (act2.authority.artifact.governance?.escalations ?? []).find((e) => e?.id === verdict.escalation_id);
|
|
6008
6444
|
return answer(verdict, { role: esc3?.role_required ?? null, retry_until: act2.expires_at });
|
|
@@ -6020,17 +6456,23 @@ function accept(o) {
|
|
|
6020
6456
|
finalFacts = fresh;
|
|
6021
6457
|
final = verifyWith(act2, authority, fresh, verifiedAt, false, rev);
|
|
6022
6458
|
if (final.decision !== "AUTHORIZED") throw new Rollback(answer(final));
|
|
6459
|
+
if (o.resolution) {
|
|
6460
|
+
const again = await resolveFor(act2, authority, fresh, verifiedAt, resolved?.views);
|
|
6461
|
+
if (again && !again.ok) throw new Rollback(answer({ ...again.verdict, act_id: act2.act_id, resolution: again.info }));
|
|
6462
|
+
resolved = again;
|
|
6463
|
+
}
|
|
6023
6464
|
}
|
|
6024
6465
|
}
|
|
6025
6466
|
const action = structuredClone({ type: act2.action.type, ...act2.action.subject !== void 0 ? { subject: act2.action.subject } : {}, params: act2.action.params ?? {} });
|
|
6026
6467
|
const result = await o.commit(action, { tx: t.tx, actId: act2.act_id });
|
|
6027
|
-
const receipt = receiptOf(final, finalFacts, now());
|
|
6468
|
+
const receipt = withResolution(receiptOf(final, finalFacts, now()));
|
|
6028
6469
|
await t.putReceipt(act2.nonce, receipt, act2);
|
|
6029
6470
|
await o.onVerdict?.(final, receipt);
|
|
6030
6471
|
return answer(final, { receipt, ...result !== void 0 ? { result } : {} });
|
|
6031
6472
|
});
|
|
6032
6473
|
} catch (e) {
|
|
6033
6474
|
if (e instanceof Rollback) return e.answer;
|
|
6475
|
+
if (e instanceof RegistrarUnavailable) return { status: 503, headers: { "content-type": "application/json", "retry-after": String(e.retryAfterSeconds) }, body: { error: "The law that governs this act cannot be read right now, so nothing is committed. Resubmit this same Act later.", detail: e.message, registrar: e.registrar, retry_after: e.retryAfterSeconds } };
|
|
6034
6476
|
if (e instanceof LostRace) return answer({ decision: "REPLAYED" }, { act_id: act2.act_id, receipt: await store.receiptFor(act2.nonce) });
|
|
6035
6477
|
return { status: 500, headers: { "content-type": "application/json" }, body: { error: "The commit failed and was rolled back; nothing was applied.", detail: String(e?.message ?? e) } };
|
|
6036
6478
|
}
|
|
@@ -6795,6 +7237,7 @@ var scriptHash = (js) => `'sha256-${btoa(String.fromCharCode(...sha256(utf82(js)
|
|
|
6795
7237
|
var CSP = () => `default-src 'none'; script-src ${scriptHash(APPROVE_JS)} ${scriptHash(ENROL_JS)}; style-src 'unsafe-inline'; connect-src 'self'; form-action 'none'; frame-ancestors 'none'; base-uri 'none'`;
|
|
6796
7238
|
|
|
6797
7239
|
// src/act/carrier.ts
|
|
7240
|
+
var RESOLUTION_HOLDS = /* @__PURE__ */ new Set(["laws_not_presented", "resolution_incomplete", "resolution_conflict"]);
|
|
6798
7241
|
var STATUS_OF = { AUTHORIZED: "committed", ESCALATED: "escalated", INCOMPLETE: "incomplete", DENIED: "denied", REPLAYED: "replayed" };
|
|
6799
7242
|
var NomosActError = class extends Error {
|
|
6800
7243
|
constructor(message) {
|
|
@@ -6814,9 +7257,9 @@ async function act(o) {
|
|
|
6814
7257
|
const entry = issuer2.authorities.find((a) => a.artifact_id === accepted.artifact_id);
|
|
6815
7258
|
if (!entry) throw new NomosActError(`The issuer at ${accepted.issuer} does not publish ${accepted.artifact_id}.`);
|
|
6816
7259
|
const artifact = await getJson(f, entry.artifact_url, "the authority");
|
|
6817
|
-
let
|
|
7260
|
+
let inForce2;
|
|
6818
7261
|
if (accepted.currency_policy === "record_or_statement" && !accepted.in_force_seal_hash && entry.in_force_url) {
|
|
6819
|
-
|
|
7262
|
+
inForce2 = await getJson(f, entry.in_force_url, "the in-force statement").catch(() => void 0);
|
|
6820
7263
|
}
|
|
6821
7264
|
const inputs = artifact?.data_contract?.inputs ?? {};
|
|
6822
7265
|
const witnessed = Object.entries(inputs).filter(([, i]) => i?.source === "testimony").map(([n]) => n);
|
|
@@ -6856,7 +7299,7 @@ async function act(o) {
|
|
|
6856
7299
|
testimony.push(t);
|
|
6857
7300
|
if (Array.isArray(body2.key_certs)) available.push(...body2.key_certs);
|
|
6858
7301
|
}
|
|
6859
|
-
const theAct = buildAct({ relyingParty: rp.relying_party_id, action: o.action, artifact, keyCerts: [], testimony, presenterFacts: o.presenterFacts, inForce, windowSeconds });
|
|
7302
|
+
const theAct = buildAct({ relyingParty: rp.relying_party_id, action: o.action, artifact, keyCerts: [], testimony, presenterFacts: o.presenterFacts, inForce: inForce2, windowSeconds });
|
|
6860
7303
|
present(theAct, available);
|
|
6861
7304
|
let { status, body } = await submit(f, rp.act_endpoint, theAct);
|
|
6862
7305
|
let approvalUrl;
|
|
@@ -6884,6 +7327,10 @@ async function act(o) {
|
|
|
6884
7327
|
}
|
|
6885
7328
|
}
|
|
6886
7329
|
const kind = STATUS_OF[body.decision] ?? "refused";
|
|
7330
|
+
if (kind === "incomplete" && RESOLUTION_HOLDS.has(body.reason_code)) {
|
|
7331
|
+
const laws = Array.isArray(body.laws) ? body.laws : [];
|
|
7332
|
+
return done("incomplete", body, theAct, { missing: [], summary: body.reason_code === "laws_not_presented" ? `Not committed: other law also governs this act at ${rp.relying_party_id} (${laws.join(", ")}), and this Act carries only ${theAct.authority?.artifact?.meta?.artifact_id ?? "one authority"}.` : `Not committed: ${body.hint ?? `${rp.relying_party_id} cannot yet settle which law governs this act (${body.reason_code}).`}` });
|
|
7333
|
+
}
|
|
6887
7334
|
if (kind === "incomplete") {
|
|
6888
7335
|
const missing = (body.open_facts ?? []).map((fact) => {
|
|
6889
7336
|
const why = unavailable.find((u) => u.fact === fact || fact.startsWith(u.fact + "."));
|
|
@@ -6915,6 +7362,7 @@ async function getJson(f, url, what) {
|
|
|
6915
7362
|
async function submit(f, endpoint, theAct) {
|
|
6916
7363
|
const res = await f(endpoint, { method: "POST", headers: { "content-type": ACT_MEDIA_TYPE }, body: JSON.stringify(theAct) });
|
|
6917
7364
|
const body = await res.json().catch(() => ({ decision: "MALFORMED", reason_code: "unreadable_response" }));
|
|
7365
|
+
if (res.status === 503) throw new NomosActError(`The relying party is not committing right now (503): ${body?.error ?? ""}${body?.retry_after ? ` Resubmit this same Act after ${body.retry_after} s.` : ""}`);
|
|
6918
7366
|
if (res.status >= 500) throw new NomosActError(`The relying party failed to commit (${res.status}): ${body?.error ?? ""}`);
|
|
6919
7367
|
return { status: res.status, body };
|
|
6920
7368
|
}
|
|
@@ -7117,6 +7565,7 @@ export {
|
|
|
7117
7565
|
NomosRateLimitError,
|
|
7118
7566
|
NomosValidationError,
|
|
7119
7567
|
NomosWebhookSignatureError,
|
|
7568
|
+
RegistrarUnavailable,
|
|
7120
7569
|
RegistryError,
|
|
7121
7570
|
RevocationUnavailable,
|
|
7122
7571
|
WELL_KNOWN,
|
|
@@ -7147,6 +7596,7 @@ export {
|
|
|
7147
7596
|
postgresStore,
|
|
7148
7597
|
presentedCertificates,
|
|
7149
7598
|
readAttestation,
|
|
7599
|
+
registrarSource,
|
|
7150
7600
|
reliedKids,
|
|
7151
7601
|
revocationListCertificates,
|
|
7152
7602
|
revocationSource,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nomosprotocol/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "NOMOS for TypeScript: accept() for the system that makes a change, act() for the agent that asks, the issuer, witness and approver roles, and the Exchange client. Verification is local (@nomosprotocol/verify).",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -83,6 +83,6 @@
|
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"@noble/curves": "^2.4.0",
|
|
85
85
|
"@noble/hashes": "^2.4.0",
|
|
86
|
-
"@nomosprotocol/verify": "^1.
|
|
86
|
+
"@nomosprotocol/verify": "^1.4.0"
|
|
87
87
|
}
|
|
88
88
|
}
|