@nomosprotocol/sdk 2.3.2 → 2.5.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 CHANGED
@@ -176,6 +176,29 @@ If a paid authority has not been purchased, NOMOS throws `NomosPaymentRequiredEr
176
176
 
177
177
  NOMOS never auto-charges on your behalf.
178
178
 
179
+ ### Escalations that reach a person
180
+
181
+ Click **Use this law** on an authority's Exchange page (signed in). From then on, when that law
182
+ answers ESCALATED to a call made with your API key, your approvers get an email and approve on a
183
+ page. An API key can never approve, so an agent can't approve itself. Your code can wait for the answer:
184
+
185
+ ```ts
186
+ import { Nomos } from "@nomosprotocol/sdk";
187
+
188
+ const client = new Nomos(process.env.NOMOS_API_KEY!);
189
+ const r = await client.can(
190
+ { authority: "data-protection-law-difc-law-no-5-of-2020", days_since_access_request: 45 },
191
+ { awaitApproval: { timeoutMs: 10 * 60_000, onApproval: (a) => console.log("waiting on", a.url) } },
192
+ );
193
+
194
+ if (r.allowed) proceed(); // AUTHORIZED, or a person approved this exact call (spent once)
195
+ else console.log(r.verdict, r.approval?.status); // DENIED, or rejected / timed_out
196
+ ```
197
+
198
+ The approval is bound to the authority, the action and the facts: different facts need a new one.
199
+ When the law gets a new version, you get an email with what changed. Turn either email off on the
200
+ same page.
201
+
179
202
  ### 2. Your organization's authority
180
203
 
181
204
  Use an authenticated client for artifacts belonging to your organization:
package/dist/index.cjs CHANGED
@@ -191,7 +191,7 @@ function isRetryable(status) {
191
191
  }
192
192
 
193
193
  // src/http-client.ts
194
- var SDK_VERSION = "2.3.2";
194
+ var SDK_VERSION = "2.5.0";
195
195
  var HttpClient = class {
196
196
  constructor(opts) {
197
197
  this.opts = opts;
@@ -721,7 +721,9 @@ function normalizeAuthorityQueryResult(data, authority) {
721
721
  // NOMOS-SPEC-006 — present only when the issuer has actually revoked this exact sealed
722
722
  // version; omitted (not false) when revocation doesn't structurally apply here, so "checked
723
723
  // and clean" and "couldn't check" never look the same to a caller.
724
- ...data.revoked === true ? { revoked: true, revocation_reason: data.revocation_reason } : {}
724
+ ...data.revoked === true ? { revoked: true, revocation_reason: data.revocation_reason } : {},
725
+ ...data.signature ? { signature: data.signature } : {},
726
+ ...data.evaluator_version ? { evaluator_version: data.evaluator_version } : {}
725
727
  };
726
728
  }
727
729
  function callerHeaders(c) {
@@ -751,9 +753,34 @@ async function canViaExchange(authority, facts, action, opts) {
751
753
  if (!res.ok) mapHttpError(res.status, data, requestId);
752
754
  return normalizeAuthorityQueryResult(data, authority);
753
755
  }
754
- async function canViaExchangeAuthenticated(http, authority, facts, action, caller) {
755
- const { data } = await http.post("/api/v1/can", { artifact: authority, action, ...facts }, { headers: callerHeaders(caller) });
756
- return normalizeAuthorityQueryResult(data, authority);
756
+ async function canViaExchangeAuthenticated(http, authority, facts, action, opts) {
757
+ const ask = async () => (await http.post("/api/v1/can", { artifact: authority, action, ...facts }, { headers: callerHeaders(opts?.caller) })).data;
758
+ const data = await ask();
759
+ const result = normalizeAuthorityQueryResult(data, authority);
760
+ const approval = data?.approval;
761
+ if (!approval) return result;
762
+ result.approval = { id: approval.id, url: approval.url, status: approval.status };
763
+ if (!opts?.awaitApproval || result.verdict !== "ESCALATED") return result;
764
+ return awaitApproval(http, result, typeof opts.awaitApproval === "object" ? opts.awaitApproval : {});
765
+ }
766
+ var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
767
+ async function awaitApproval(http, result, o) {
768
+ const a = result.approval;
769
+ o.onApproval?.({ id: a.id, url: a.url });
770
+ const deadline = Date.now() + (o.timeoutMs ?? 6e5);
771
+ let status = a.status;
772
+ while (status === "pending" && Date.now() < deadline) {
773
+ await sleep2(Math.max(500, o.pollMs ?? 3e3));
774
+ status = (await http.get(`/api/v1/approvals/${a.id}`)).data?.status ?? "pending";
775
+ }
776
+ if (status === "pending") return { ...result, approval: { ...a, status: "timed_out" } };
777
+ if (status !== "approved") return { ...result, approval: { ...a, status: "rejected" } };
778
+ try {
779
+ await http.post(`/api/v1/approvals/${a.id}/consume`, {});
780
+ } catch {
781
+ return { ...result, approval: { ...a, status: "not_usable" } };
782
+ }
783
+ return { ...result, allowed: true, approval: { ...a, status: "approved" } };
757
784
  }
758
785
  async function canViaArtifact(http, artifactId, facts, action) {
759
786
  const isPublic = artifactId.startsWith("pub_");
@@ -857,7 +884,7 @@ async function canAuthenticated(http, params, opts) {
857
884
  return canViaChain(params.artifact, params.key_certs, params.root_public_key_pem, facts, action, opts);
858
885
  }
859
886
  if (params.artifact_id) return canViaArtifact(http, params.artifact_id, facts, action);
860
- if (params.authority) return canViaExchangeAuthenticated(http, params.authority, facts, action, opts?.caller);
887
+ if (params.authority) return canViaExchangeAuthenticated(http, params.authority, facts, action, opts);
861
888
  throw new Error("can(): `authority` (a public Exchange artifact), `artifact_id` (your own artifact), or `artifact` (chain-of-trust) is required.");
862
889
  }
863
890
  var nomos = { can };
package/dist/index.d.cts CHANGED
@@ -92,6 +92,32 @@ interface CanOptions {
92
92
  * `purpose: 'test'` queries are answered and sealed but kept out of the authority's public
93
93
  * history and counts — set it from tests and CI. Exchange authorities only. */
94
94
  caller?: CanCaller;
95
+ /**
96
+ * Wait for a person when the answer is ESCALATED (client.can() with an API key, on a law you
97
+ * follow with "Use this law" on the Exchange). Your approvers get an email; when one approves this
98
+ * exact action and these facts, the approval is spent once and the result comes back with
99
+ * `allowed: true`. A rejection or the timeout returns `allowed: false`. `true` waits up to 10 minutes.
100
+ */
101
+ awaitApproval?: boolean | AwaitApprovalOptions;
102
+ }
103
+ interface AwaitApprovalOptions {
104
+ /** How long to wait for an answer, ms. Default 600000 (10 minutes). */
105
+ timeoutMs?: number;
106
+ /** How often to check, ms. Default 3000. */
107
+ pollMs?: number;
108
+ /** Called once when the request is made, with the page your approver answers on. */
109
+ onApproval?: (approval: {
110
+ id: number;
111
+ url: string;
112
+ }) => void;
113
+ }
114
+ /** A person's decision on an ESCALATED answer (see CanOptions.awaitApproval). */
115
+ interface CanApproval {
116
+ id: number;
117
+ /** The page a signed-in approver answers on. */
118
+ url: string;
119
+ /** pending until answered; approved means spent for this call; timed_out means nobody answered in time. */
120
+ status: 'pending' | 'approved' | 'rejected' | 'timed_out' | 'not_usable';
95
121
  }
96
122
  interface CanCaller {
97
123
  /** A stable name for your agent, e.g. "acme-credit-agent". */
@@ -101,8 +127,11 @@ interface CanCaller {
101
127
  purpose?: 'production' | 'test';
102
128
  }
103
129
  interface CanResult {
104
- /** True only for an AUTHORIZED verdict. DENIED and ESCALATED are both `false`. */
130
+ /** True for an AUTHORIZED verdict, or for an ESCALATED one a person approved for this exact call
131
+ * (awaitApproval; the approval is then spent). Otherwise `false`. */
105
132
  allowed: boolean;
133
+ /** Present when an ESCALATED answer became an approval request (a law you follow, with a key). */
134
+ approval?: CanApproval;
106
135
  /** The authority's own verdict, verbatim, in ONE consistent vocabulary regardless of which
107
136
  * rail answered it — the public Exchange or your own authenticated artifact. */
108
137
  verdict: CanVerdict;
@@ -167,6 +196,18 @@ interface CanResult {
167
196
  * `"unchecked"` (neither — e.g. the pinned root, which nothing else can vouch for). Omitted
168
197
  * (not a guess) on the Exchange/private-artifact rails, where this concept doesn't apply. */
169
198
  revocation_checked?: 'live' | 'staple' | 'unchecked';
199
+ /** Exchange rail: the platform's Ed25519 signature over what was decided, made when the query was
200
+ * answered (docs/design-notes/signed-query-records.md). Check the full record offline with
201
+ * `node verify-nomos.mjs <record.json> --pubkey <key.pem>` (record from `url`). Absent on records
202
+ * answered by a deployment with no signing key. */
203
+ signature?: {
204
+ algorithm: 'Ed25519';
205
+ kid: string;
206
+ value: string;
207
+ statement: Record<string, unknown>;
208
+ };
209
+ /** Exchange rail: the evaluator version that decided this, as named in the signed statement. */
210
+ evaluator_version?: string;
170
211
  }
171
212
  interface ConservedStateInfo {
172
213
  artifact_id: string;
@@ -1635,4 +1676,4 @@ declare function approver(o: ApproverOptions): {
1635
1676
  pending: Map<string, Pending>;
1636
1677
  };
1637
1678
 
1638
- 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 BindingProposal, type BindingSuggestion, type BuildActOptions, type CanCaller, type CanOptions, type CanParams, type CanResult, type CanVerdict, type CertificateRegistry, type ChainVerdictDecision, type ConservedStateInfo, type ConservedStateReceipt, type Contradiction, type DetectContradictionsParams, type DetectContradictionsResult, type EnrolmentClaims, type FactBinding, type GenerateGovernanceParams, type GenerateGovernanceResult, type IssueOptions, type IssuerDocument, type IssuerOptions, type KeyCertificate$1 as KeyCertificate, type ListArtifactsParams, MAX_PRESENTED, 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 PasskeyApproverOptions, type PasskeyCredential, type PasskeyStore, type PendingApproval, type PgClient, type PgPool, type PolicyField, type PostgresStoreOptions, type Receipt, RegistryError, type RegistryStore, type RelyingPartyDocument, type RequestOptions, type Reservation, type ReserveByActParams, type ReserveByQueryParams, type ReserveParams, type RevocationSourceOptions, RevocationUnavailable, type SignatureSuite, type Signer, type ToolBindings, type ToolDescription, type UnresolvedFact, type Verdict, type VerifyChainOptions, type VerifyChainParams, type VerifyChainResult, type VerifyDecisionParams, type VerifyDecisionResult, WELL_KNOWN, type WithLastResponse, type WitnessDocument, type WitnessOptions, accept, act, applyToolBindings, approver, buildAct, can, certificateRegistry, certify, describeSuggestion, fetchDocument, generateSigner, issuer, kidOf, localSigner, memoryPasskeyStore, memoryRegistryStore, memoryStore, nomos, originOf, parseToolBindings, passkeyApprover, postgresPasskeyStore, postgresRegistryStore, postgresStore, presentedCertificates, readAttestation, reliedKids, revocationListCertificates, revocationSource, seal, seededSigner, signConsent, signEnrolmentToken, signInForce, signRevocation, signRevocationList, signTestimony, statusFor, suggestToolBindings, verifyChain, verifyEnrolmentToken, witness };
1679
+ 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 AwaitApprovalOptions, type BindingProposal, type BindingSuggestion, type BuildActOptions, type CanApproval, type CanCaller, type CanOptions, type CanParams, type CanResult, type CanVerdict, type CertificateRegistry, type ChainVerdictDecision, type ConservedStateInfo, type ConservedStateReceipt, type Contradiction, type DetectContradictionsParams, type DetectContradictionsResult, type EnrolmentClaims, type FactBinding, type GenerateGovernanceParams, type GenerateGovernanceResult, type IssueOptions, type IssuerDocument, type IssuerOptions, type KeyCertificate$1 as KeyCertificate, type ListArtifactsParams, MAX_PRESENTED, 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 PasskeyApproverOptions, type PasskeyCredential, type PasskeyStore, type PendingApproval, type PgClient, type PgPool, type PolicyField, type PostgresStoreOptions, type Receipt, RegistryError, type RegistryStore, type RelyingPartyDocument, type RequestOptions, type Reservation, type ReserveByActParams, type ReserveByQueryParams, type ReserveParams, type RevocationSourceOptions, RevocationUnavailable, type SignatureSuite, type Signer, type ToolBindings, type ToolDescription, type UnresolvedFact, type Verdict, type VerifyChainOptions, type VerifyChainParams, type VerifyChainResult, type VerifyDecisionParams, type VerifyDecisionResult, WELL_KNOWN, type WithLastResponse, type WitnessDocument, type WitnessOptions, accept, act, applyToolBindings, approver, buildAct, can, certificateRegistry, certify, describeSuggestion, fetchDocument, generateSigner, issuer, kidOf, localSigner, memoryPasskeyStore, memoryRegistryStore, memoryStore, nomos, originOf, parseToolBindings, passkeyApprover, postgresPasskeyStore, postgresRegistryStore, postgresStore, presentedCertificates, readAttestation, reliedKids, revocationListCertificates, revocationSource, seal, seededSigner, signConsent, signEnrolmentToken, signInForce, signRevocation, signRevocationList, signTestimony, statusFor, suggestToolBindings, verifyChain, verifyEnrolmentToken, witness };
package/dist/index.d.ts CHANGED
@@ -92,6 +92,32 @@ interface CanOptions {
92
92
  * `purpose: 'test'` queries are answered and sealed but kept out of the authority's public
93
93
  * history and counts — set it from tests and CI. Exchange authorities only. */
94
94
  caller?: CanCaller;
95
+ /**
96
+ * Wait for a person when the answer is ESCALATED (client.can() with an API key, on a law you
97
+ * follow with "Use this law" on the Exchange). Your approvers get an email; when one approves this
98
+ * exact action and these facts, the approval is spent once and the result comes back with
99
+ * `allowed: true`. A rejection or the timeout returns `allowed: false`. `true` waits up to 10 minutes.
100
+ */
101
+ awaitApproval?: boolean | AwaitApprovalOptions;
102
+ }
103
+ interface AwaitApprovalOptions {
104
+ /** How long to wait for an answer, ms. Default 600000 (10 minutes). */
105
+ timeoutMs?: number;
106
+ /** How often to check, ms. Default 3000. */
107
+ pollMs?: number;
108
+ /** Called once when the request is made, with the page your approver answers on. */
109
+ onApproval?: (approval: {
110
+ id: number;
111
+ url: string;
112
+ }) => void;
113
+ }
114
+ /** A person's decision on an ESCALATED answer (see CanOptions.awaitApproval). */
115
+ interface CanApproval {
116
+ id: number;
117
+ /** The page a signed-in approver answers on. */
118
+ url: string;
119
+ /** pending until answered; approved means spent for this call; timed_out means nobody answered in time. */
120
+ status: 'pending' | 'approved' | 'rejected' | 'timed_out' | 'not_usable';
95
121
  }
96
122
  interface CanCaller {
97
123
  /** A stable name for your agent, e.g. "acme-credit-agent". */
@@ -101,8 +127,11 @@ interface CanCaller {
101
127
  purpose?: 'production' | 'test';
102
128
  }
103
129
  interface CanResult {
104
- /** True only for an AUTHORIZED verdict. DENIED and ESCALATED are both `false`. */
130
+ /** True for an AUTHORIZED verdict, or for an ESCALATED one a person approved for this exact call
131
+ * (awaitApproval; the approval is then spent). Otherwise `false`. */
105
132
  allowed: boolean;
133
+ /** Present when an ESCALATED answer became an approval request (a law you follow, with a key). */
134
+ approval?: CanApproval;
106
135
  /** The authority's own verdict, verbatim, in ONE consistent vocabulary regardless of which
107
136
  * rail answered it — the public Exchange or your own authenticated artifact. */
108
137
  verdict: CanVerdict;
@@ -167,6 +196,18 @@ interface CanResult {
167
196
  * `"unchecked"` (neither — e.g. the pinned root, which nothing else can vouch for). Omitted
168
197
  * (not a guess) on the Exchange/private-artifact rails, where this concept doesn't apply. */
169
198
  revocation_checked?: 'live' | 'staple' | 'unchecked';
199
+ /** Exchange rail: the platform's Ed25519 signature over what was decided, made when the query was
200
+ * answered (docs/design-notes/signed-query-records.md). Check the full record offline with
201
+ * `node verify-nomos.mjs <record.json> --pubkey <key.pem>` (record from `url`). Absent on records
202
+ * answered by a deployment with no signing key. */
203
+ signature?: {
204
+ algorithm: 'Ed25519';
205
+ kid: string;
206
+ value: string;
207
+ statement: Record<string, unknown>;
208
+ };
209
+ /** Exchange rail: the evaluator version that decided this, as named in the signed statement. */
210
+ evaluator_version?: string;
170
211
  }
171
212
  interface ConservedStateInfo {
172
213
  artifact_id: string;
@@ -1635,4 +1676,4 @@ declare function approver(o: ApproverOptions): {
1635
1676
  pending: Map<string, Pending>;
1636
1677
  };
1637
1678
 
1638
- 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 BindingProposal, type BindingSuggestion, type BuildActOptions, type CanCaller, type CanOptions, type CanParams, type CanResult, type CanVerdict, type CertificateRegistry, type ChainVerdictDecision, type ConservedStateInfo, type ConservedStateReceipt, type Contradiction, type DetectContradictionsParams, type DetectContradictionsResult, type EnrolmentClaims, type FactBinding, type GenerateGovernanceParams, type GenerateGovernanceResult, type IssueOptions, type IssuerDocument, type IssuerOptions, type KeyCertificate$1 as KeyCertificate, type ListArtifactsParams, MAX_PRESENTED, 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 PasskeyApproverOptions, type PasskeyCredential, type PasskeyStore, type PendingApproval, type PgClient, type PgPool, type PolicyField, type PostgresStoreOptions, type Receipt, RegistryError, type RegistryStore, type RelyingPartyDocument, type RequestOptions, type Reservation, type ReserveByActParams, type ReserveByQueryParams, type ReserveParams, type RevocationSourceOptions, RevocationUnavailable, type SignatureSuite, type Signer, type ToolBindings, type ToolDescription, type UnresolvedFact, type Verdict, type VerifyChainOptions, type VerifyChainParams, type VerifyChainResult, type VerifyDecisionParams, type VerifyDecisionResult, WELL_KNOWN, type WithLastResponse, type WitnessDocument, type WitnessOptions, accept, act, applyToolBindings, approver, buildAct, can, certificateRegistry, certify, describeSuggestion, fetchDocument, generateSigner, issuer, kidOf, localSigner, memoryPasskeyStore, memoryRegistryStore, memoryStore, nomos, originOf, parseToolBindings, passkeyApprover, postgresPasskeyStore, postgresRegistryStore, postgresStore, presentedCertificates, readAttestation, reliedKids, revocationListCertificates, revocationSource, seal, seededSigner, signConsent, signEnrolmentToken, signInForce, signRevocation, signRevocationList, signTestimony, statusFor, suggestToolBindings, verifyChain, verifyEnrolmentToken, witness };
1679
+ 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 AwaitApprovalOptions, type BindingProposal, type BindingSuggestion, type BuildActOptions, type CanApproval, type CanCaller, type CanOptions, type CanParams, type CanResult, type CanVerdict, type CertificateRegistry, type ChainVerdictDecision, type ConservedStateInfo, type ConservedStateReceipt, type Contradiction, type DetectContradictionsParams, type DetectContradictionsResult, type EnrolmentClaims, type FactBinding, type GenerateGovernanceParams, type GenerateGovernanceResult, type IssueOptions, type IssuerDocument, type IssuerOptions, type KeyCertificate$1 as KeyCertificate, type ListArtifactsParams, MAX_PRESENTED, 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 PasskeyApproverOptions, type PasskeyCredential, type PasskeyStore, type PendingApproval, type PgClient, type PgPool, type PolicyField, type PostgresStoreOptions, type Receipt, RegistryError, type RegistryStore, type RelyingPartyDocument, type RequestOptions, type Reservation, type ReserveByActParams, type ReserveByQueryParams, type ReserveParams, type RevocationSourceOptions, RevocationUnavailable, type SignatureSuite, type Signer, type ToolBindings, type ToolDescription, type UnresolvedFact, type Verdict, type VerifyChainOptions, type VerifyChainParams, type VerifyChainResult, type VerifyDecisionParams, type VerifyDecisionResult, WELL_KNOWN, type WithLastResponse, type WitnessDocument, type WitnessOptions, accept, act, applyToolBindings, approver, buildAct, can, certificateRegistry, certify, describeSuggestion, fetchDocument, generateSigner, issuer, kidOf, localSigner, memoryPasskeyStore, memoryRegistryStore, memoryStore, nomos, originOf, parseToolBindings, passkeyApprover, postgresPasskeyStore, postgresRegistryStore, postgresStore, presentedCertificates, readAttestation, reliedKids, revocationListCertificates, revocationSource, seal, seededSigner, signConsent, signEnrolmentToken, signInForce, signRevocation, signRevocationList, signTestimony, statusFor, suggestToolBindings, verifyChain, verifyEnrolmentToken, witness };
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.3.2";
110
+ var SDK_VERSION = "2.5.0";
111
111
  var HttpClient = class {
112
112
  constructor(opts) {
113
113
  this.opts = opts;
@@ -637,7 +637,9 @@ function normalizeAuthorityQueryResult(data, authority) {
637
637
  // NOMOS-SPEC-006 — present only when the issuer has actually revoked this exact sealed
638
638
  // version; omitted (not false) when revocation doesn't structurally apply here, so "checked
639
639
  // and clean" and "couldn't check" never look the same to a caller.
640
- ...data.revoked === true ? { revoked: true, revocation_reason: data.revocation_reason } : {}
640
+ ...data.revoked === true ? { revoked: true, revocation_reason: data.revocation_reason } : {},
641
+ ...data.signature ? { signature: data.signature } : {},
642
+ ...data.evaluator_version ? { evaluator_version: data.evaluator_version } : {}
641
643
  };
642
644
  }
643
645
  function callerHeaders(c) {
@@ -667,9 +669,34 @@ async function canViaExchange(authority, facts, action, opts) {
667
669
  if (!res.ok) mapHttpError(res.status, data, requestId);
668
670
  return normalizeAuthorityQueryResult(data, authority);
669
671
  }
670
- async function canViaExchangeAuthenticated(http, authority, facts, action, caller) {
671
- const { data } = await http.post("/api/v1/can", { artifact: authority, action, ...facts }, { headers: callerHeaders(caller) });
672
- return normalizeAuthorityQueryResult(data, authority);
672
+ async function canViaExchangeAuthenticated(http, authority, facts, action, opts) {
673
+ const ask = async () => (await http.post("/api/v1/can", { artifact: authority, action, ...facts }, { headers: callerHeaders(opts?.caller) })).data;
674
+ const data = await ask();
675
+ const result = normalizeAuthorityQueryResult(data, authority);
676
+ const approval = data?.approval;
677
+ if (!approval) return result;
678
+ result.approval = { id: approval.id, url: approval.url, status: approval.status };
679
+ if (!opts?.awaitApproval || result.verdict !== "ESCALATED") return result;
680
+ return awaitApproval(http, result, typeof opts.awaitApproval === "object" ? opts.awaitApproval : {});
681
+ }
682
+ var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
683
+ async function awaitApproval(http, result, o) {
684
+ const a = result.approval;
685
+ o.onApproval?.({ id: a.id, url: a.url });
686
+ const deadline = Date.now() + (o.timeoutMs ?? 6e5);
687
+ let status = a.status;
688
+ while (status === "pending" && Date.now() < deadline) {
689
+ await sleep2(Math.max(500, o.pollMs ?? 3e3));
690
+ status = (await http.get(`/api/v1/approvals/${a.id}`)).data?.status ?? "pending";
691
+ }
692
+ if (status === "pending") return { ...result, approval: { ...a, status: "timed_out" } };
693
+ if (status !== "approved") return { ...result, approval: { ...a, status: "rejected" } };
694
+ try {
695
+ await http.post(`/api/v1/approvals/${a.id}/consume`, {});
696
+ } catch {
697
+ return { ...result, approval: { ...a, status: "not_usable" } };
698
+ }
699
+ return { ...result, allowed: true, approval: { ...a, status: "approved" } };
673
700
  }
674
701
  async function canViaArtifact(http, artifactId, facts, action) {
675
702
  const isPublic = artifactId.startsWith("pub_");
@@ -773,7 +800,7 @@ async function canAuthenticated(http, params, opts) {
773
800
  return canViaChain(params.artifact, params.key_certs, params.root_public_key_pem, facts, action, opts);
774
801
  }
775
802
  if (params.artifact_id) return canViaArtifact(http, params.artifact_id, facts, action);
776
- if (params.authority) return canViaExchangeAuthenticated(http, params.authority, facts, action, opts?.caller);
803
+ if (params.authority) return canViaExchangeAuthenticated(http, params.authority, facts, action, opts);
777
804
  throw new Error("can(): `authority` (a public Exchange artifact), `artifact_id` (your own artifact), or `artifact` (chain-of-trust) is required.");
778
805
  }
779
806
  var nomos = { can };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomosprotocol/sdk",
3
- "version": "2.3.2",
3
+ "version": "2.5.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"
@@ -32,7 +32,9 @@
32
32
  "build": "tsup",
33
33
  "dev": "tsup --watch",
34
34
  "clean": "rm -rf dist",
35
- "type-check": "tsc --noEmit"
35
+ "type-check": "tsc --noEmit",
36
+ "check:verify": "npm --prefix ../packages/verify run build && node scripts/check-bundled-verify.mjs",
37
+ "prepublishOnly": "npm run check:verify && npm run build"
36
38
  },
37
39
  "tsup": {
38
40
  "entry": [