@suveren/gateway 0.19.4 → 0.20.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.
Files changed (51) hide show
  1. package/content/guides/1-interview.md +6 -0
  2. package/content/guides/2-package.md +4 -1
  3. package/content/guides/3-mandates.md +3 -0
  4. package/content/guides/6-risks.md +2 -0
  5. package/content/integrations/crm.json +1 -1
  6. package/content/integrations/deploy-github.json +1 -1
  7. package/content/integrations/erp.json +1 -1
  8. package/content/integrations/mail.json +1 -1
  9. package/content/integrations/records.json +1 -1
  10. package/dist/control-plane/index.mjs +21 -13
  11. package/dist/mcp-server/{chunk-ZRRZFGRL.mjs → chunk-APIQIEUA.mjs} +39 -27
  12. package/dist/mcp-server/http.mjs +382 -97
  13. package/dist/mcp-server/report-verify-cli.mjs +1 -1
  14. package/dist/ui/assets/index-1gCMlbLl.js +116 -0
  15. package/dist/ui/assets/{index-RCFQUjaF.css → index-blnpvM2g.css} +1 -1
  16. package/dist/ui/index.html +2 -2
  17. package/node_modules/@hap/core/README.md +92 -29
  18. package/node_modules/@hap/core/dist/index.d.mts +614 -593
  19. package/node_modules/@hap/core/dist/index.d.ts +614 -593
  20. package/node_modules/@hap/core/dist/index.js +774 -749
  21. package/node_modules/@hap/core/dist/index.mjs +744 -724
  22. package/node_modules/@hap/core/package.json +1 -1
  23. package/node_modules/@hap/core/src/base64url.ts +39 -0
  24. package/node_modules/@hap/core/src/commitment-modes.ts +0 -21
  25. package/node_modules/@hap/core/src/errors.ts +76 -0
  26. package/node_modules/@hap/core/src/frame.ts +47 -178
  27. package/node_modules/@hap/core/src/gatekeeper.ts +219 -600
  28. package/node_modules/@hap/core/src/identity.ts +9 -12
  29. package/node_modules/@hap/core/src/index.ts +8 -4
  30. package/node_modules/@hap/core/src/mandate.ts +177 -166
  31. package/node_modules/@hap/core/src/owner-signature.ts +282 -0
  32. package/node_modules/@hap/core/src/profile.ts +234 -0
  33. package/node_modules/@hap/core/src/ticket.ts +148 -0
  34. package/node_modules/@hap/core/src/types.ts +191 -344
  35. package/node_modules/@hap/core/src/versions.ts +47 -0
  36. package/package.json +2 -2
  37. package/profiles/calendar/0.6.profile.json +191 -0
  38. package/profiles/charge/0.6.profile.json +211 -0
  39. package/profiles/customers/0.9.profile.json +182 -0
  40. package/profiles/delegation/0.3.profile.json +118 -0
  41. package/profiles/deploy/0.11.profile.json +177 -0
  42. package/profiles/email/0.8.profile.json +226 -0
  43. package/profiles/index.json +12 -1
  44. package/profiles/publish/0.6.profile.json +187 -0
  45. package/profiles/purchase/0.7.profile.json +235 -0
  46. package/profiles/records/0.6.profile.json +118 -0
  47. package/profiles/reporting/0.3.profile.json +98 -0
  48. package/profiles/sales/0.4.profile.json +291 -0
  49. package/dist/ui/assets/index-BseWI4iJ.js +0 -116
  50. package/node_modules/@hap/core/src/attestation.ts +0 -173
  51. package/node_modules/@hap/core/src/receipt.ts +0 -74
@@ -1,123 +1,97 @@
1
1
  /**
2
- * HAP Core Types — Agent Demo
2
+ * Canonical v0.7 error codes — protocol.md → *Error Codes*.
3
+ *
4
+ * "Error codes are canonical across the protocol. Implementations MUST emit
5
+ * exactly these codes and MUST NOT alias them under different names." This
6
+ * module is the single list both the Gatekeeper (local checks) and any AS
7
+ * client built on this library read from, so the two cannot drift.
8
+ *
9
+ * v0.7 renamed every code that carried a retired word (attestation → mandate,
10
+ * context → scope, receipt → ticket) — see protocol.md → *Migration from
11
+ * v0.6* → "Error-code renames" for the old→new map. There is no alias: a v0.6
12
+ * code name is simply gone from this list, by design (no backward
13
+ * compatibility — CLAUDE.md "Decided by the owner").
14
+ */
15
+ /** Codes an Authority Server (or a local Gatekeeper check) emits refusing a mandate request. */
16
+ declare const MANDATE_ERROR_CODES: readonly ["BOUNDS_HASH_MISMATCH", "SCOPE_HASH_MISMATCH", "INVALID_SIGNATURE", "OWNER_NOT_COVERED", "TTL_EXPIRED", "PROFILE_NOT_FOUND", "PROFILE_INVALID", "PROFILE_HASH_MISMATCH", "COVERAGE_INSUFFICIENT", "MALFORMED_MANDATE", "VERSION_UNSUPPORTED", "OWNER_NOT_APPROVER", "BOUNDS_INVALID_VALUE", "SCOPE_INVALID_VALUE", "ABOVE_CAP_CONFIG_INVALID", "OWNER_SIGNATURE_REQUIRED", "OWNER_SIGNATURE_INVALID"];
17
+ /** Codes an Authority Server emits refusing a ticket request. */
18
+ declare const TICKET_ERROR_CODES: readonly ["MANDATE_NOT_FOUND", "MANDATE_EXPIRED", "MANDATE_REVOKED", "BOUND_EXCEEDED", "CUMULATIVE_LIMIT_EXCEEDED", "COVERAGE_INSUFFICIENT", "PROFILE_NOT_FOUND", "INVALID_ACTION_TYPE", "APPROVAL_REQUIRED", "PROPOSAL_REQUIRED", "PROPOSAL_NOT_FOUND", "PROPOSAL_NOT_APPROVED", "PROPOSAL_EXPIRED", "PROPOSAL_REJECTED", "PROPOSAL_MISMATCH", "PROPOSAL_MANDATE_MISMATCH", "PROPOSAL_ALREADY_EXECUTED", "MALFORMED_TICKET_REQUEST", "IDEMPOTENCY_KEY_REQUIRED", "IDEMPOTENCY_MISMATCH", "APPROVAL_SIGNATURE_REQUIRED", "APPROVAL_SIGNATURE_INVALID"];
19
+ /** The full canonical surface — every code a conformant implementation may emit. */
20
+ type HapErrorCode = (typeof MANDATE_ERROR_CODES)[number] | (typeof TICKET_ERROR_CODES)[number];
21
+ /**
22
+ * A refusal carrying one of the canonical codes above. Thrown by local
23
+ * (Gatekeeper-side, no-wire-round-trip) checks in this library; an AS client
24
+ * built on hap-core maps a wire `{ code, message }` error onto the same type.
25
+ */
26
+ declare class HapError extends Error {
27
+ readonly code: HapErrorCode;
28
+ constructor(code: HapErrorCode, message: string);
29
+ }
30
+
31
+ /**
32
+ * HAP Core Types — v0.7 ("mandate" / "ticket" / "scope" / "Mandate Owner")
3
33
  *
4
- * Types for agent-oriented profiles with bounded execution.
34
+ * v0.7 is a vocabulary release (protocol.md → *Migration from v0.6*): the
35
+ * wire renames *attestation* → *mandate*, *context* → *scope*, *execution
36
+ * receipt* → *mandate ticket*, and *Decision Owner* → *Mandate Owner*. There
37
+ * is no backward-compat alias here — v0.6 and earlier artifacts are
38
+ * verification-only history outside this package (CLAUDE.md "Decided by the
39
+ * owner": no verify path for 0.5/0.6, no old→new code map).
5
40
  */
6
- interface AttestationHeader {
7
- typ: 'HAP-attestation';
41
+ interface MandateHeader {
42
+ typ: 'HAP-mandate';
8
43
  alg: 'EdDSA';
9
- kid?: string;
10
- }
11
- interface ResolvedDomain {
12
- domain: string;
13
- did: string;
14
- }
15
- interface AttestationPayload {
16
- attestation_id: string;
17
- version: '0.3' | '0.4' | '0.5' | '0.6';
18
- profile_id: string;
19
- /** v0.3 (deprecated) — hash of the authorization frame */
20
- frame_hash?: string;
21
- /** v0.4 — hash of the bounds parameters */
22
- bounds_hash?: string;
23
- /** v0.4 — hash of the context parameters */
24
- context_hash?: string;
25
- execution_context_hash: string;
26
- /**
27
- * v0.4 (deprecated in v0.5) — domain-scoped owners. Optional so v0.5
28
- * attestations that carry only `resolved_owners` remain valid. During the
29
- * transition the AS emits BOTH `resolved_domains` (internal coverage) and
30
- * `resolved_owners` (the v0.5 signed wire field).
31
- */
32
- resolved_domains?: ResolvedDomain[];
33
- /**
34
- * v0.5 — the Decision Owner DIDs this attestation covers (person-centric
35
- * model; replaces the abstract domain in `resolved_domains`). Carried in the
36
- * signed payload so verifiers bind the action to the human(s) who authorized it.
37
- */
38
- resolved_owners?: string[];
39
- gate_content_hashes: Record<string, string>;
40
44
  /**
41
- * v0.5 (companion spec `intent-disclosure@0.1`) — present iff the attestation
42
- * carries an encrypted-intent disclosure object. `sha256:`-prefixed hash that
43
- * binds the disclosure's `intent_ciphertext` + `approvers_frozen` into the
44
- * signed payload (see {@link computeIntentDisclosureHash}), so a compromised
45
- * AS cannot swap the ciphertext/wrapped keys or alter the approver set
46
- * without invalidating the attestation signature (companion invariant C2).
45
+ * When present MUST identify the same key as `issuer` (for a `did:key`
46
+ * issuer, the multibase key fingerprint) — Mandate rule 8. The field a
47
+ * party writes (`kid`) loses to the field a party cannot forge (`issuer`).
47
48
  */
48
- intent_disclosure_hash?: string;
49
- /**
50
- * v0.6 (Identity Assurance) — optional signed overlay carrying the verified
51
- * real-world identity of the Decision Owner(s), one entry per owner. Present
52
- * only when identity is disclosed; an attestation with no `subjects` renders
53
- * as `low` (pseudonymous, no name). See {@link Subject} and
54
- * {@link deriveIdentityLine}.
55
- */
56
- subjects?: Subject[];
57
- /**
58
- * v0.4 — commitment mode chosen by the decision owner at attestation time.
59
- * - 'automatic': agent may invoke bounded tools without per-action review.
60
- * - 'review': every tool call requires an approved proposal before the
61
- * receipt route will sign a receipt.
62
- *
63
- * Cryptographically bound in the signed payload so a compromised SP cannot
64
- * silently flip 'review' → 'automatic'. Absent on v0.3 attestations.
65
- * `review_above_cap` (v0.5): automatic below the signed caps, proposal above.
66
- */
67
- commitment_mode?: 'automatic' | 'review' | 'review_above_cap';
68
- /**
69
- * v0.6 (Owner Mandate Signatures) — the Decision Owner's own signature(s)
70
- * over the mandate projection ({@link MandateProjection}), one entry per
71
- * co-signing owner. Carried INSIDE the AS-signed payload, so the AS attests
72
- * to having received it and cannot strip it without invalidating its own
73
- * signature. Optional and additive: an attestation without it behaves as
74
- * before (the v0.5 posture — the AS asserts, nobody co-signs).
75
- */
76
- owner_mandates?: OwnerMandate[];
77
- issued_at: number;
78
- expires_at: number;
49
+ kid?: string;
79
50
  }
80
- /** Mandate-assurance axis — what custody signed the mandate. Independent of
81
- * identity assurance ({@link Subject.method}). */
82
- type MandateBinding = 'raw' | 'webauthn' | 'eudi';
51
+ /** Signature-assurance axis — what custody signed the mandate projection or
52
+ * approval. Independent of identity assurance ({@link Subject.method}). */
53
+ type OwnerSignatureBinding = 'raw' | 'webauthn' | 'eudi';
83
54
  /** Which surface showed the owner what they signed. A DECLARATION, not a proof
84
- * — no verifier can check it; see protocol.md → Owner Mandate Signatures. */
55
+ * — no verifier can check it; see protocol.md → *Owner Signatures*. */
85
56
  type SigningSurface = 'gatekeeper_local' | 'as_web' | 'wallet_display';
86
57
  /**
87
- * v0.6 — one owner's signature over the mandate projection.
58
+ * v0.7 `mandate_owners` entry (protocol.md → *Mandate field: mandate_owners*).
59
+ * `did` is required; the remaining fields are present together when the
60
+ * owner co-signed and absent together when they did not (Mandate rule 7).
88
61
  *
89
62
  * There is deliberately NO `public_key` field, and it MUST NOT be added: the
90
63
  * verification key is carried in the DID itself (key-bearing `did:key`), so a
91
64
  * non-key-bearing DID fails STRUCTURALLY instead of validating against a key
92
- * the AS could have substituted. `alg` is kept only as curve-confusion
93
- * hygiene; if it disagrees with the DID's key type, the DID is authoritative.
65
+ * the AS could have substituted.
94
66
  */
95
- interface OwnerMandate {
96
- /** The signing owner's key-bearing DID. MUST be a member of `resolved_owners`. */
67
+ interface MandateOwnerEntry {
68
+ /** The Mandate Owner's DID. For a co-signing entry, MUST be key-bearing. */
97
69
  did: string;
98
70
  /** Signature algorithm hint. The DID's multicodec wins on any disagreement. */
99
- alg: 'EdDSA' | 'ES256';
71
+ alg?: 'EdDSA' | 'ES256';
100
72
  /** base64url (no padding) signature over the JCS bytes of the mandate projection. */
101
- signature: string;
73
+ signature?: string;
102
74
  /** When the owner signed (unix seconds). */
103
- signed_at: number;
75
+ signed_at?: number;
104
76
  /** Defence-in-depth against duplicate issuance by an HONEST AS only —
105
77
  * AS-side nonce enforcement is no defence against the AS itself. */
106
- nonce: string;
107
- binding: MandateBinding;
78
+ nonce?: string;
79
+ /** Required-present, value-open when a signature is carried: an AS MUST
80
+ * NOT reject an entry for a `binding` value it does not recognize. */
81
+ binding?: OwnerSignatureBinding;
108
82
  signing_surface?: SigningSurface;
109
83
  }
110
84
  /**
111
- * v0.6 Identity Assurance — a signed overlay binding a Decision Owner's verified
112
- * real-world identity to the attestation, gated by HOW the identity was verified.
85
+ * v0.6 Identity Assurance — a signed overlay binding a Mandate Owner's verified
86
+ * real-world identity to the mandate, gated by HOW the identity was verified.
113
87
  *
114
88
  * Two display levels (`assurance`): `low` discloses no name; `high` MAY disclose a
115
89
  * name. At `high`, two trust roots: `as` (the AS operator vouches — valid only
116
90
  * within its own domain) and `external` (an external eID such as EUDI — carries the
117
- * owner's own signature, AS-independent). See review.md → "Identity Assurance".
91
+ * owner's own signature, AS-independent).
118
92
  */
119
93
  interface Subject {
120
- /** The Decision Owner DID this subject describes (matches an entry in resolved_owners). */
94
+ /** The Mandate Owner DID this subject describes (matches the `mandate_owners` entry). */
121
95
  did: string;
122
96
  /** `low` → no name shown; `high` → the name MAY be shown. */
123
97
  assurance: 'low' | 'high';
@@ -133,18 +107,53 @@ interface Subject {
133
107
  };
134
108
  /** When the underlying verification was performed (unix seconds). */
135
109
  verified_at?: number;
110
+ }
111
+ /** protocol.md → *Mandate Payload (v0.7)*. */
112
+ interface MandatePayload {
113
+ mandate_id: string;
114
+ version: '0.7';
115
+ profile_id: string;
116
+ /** Hash of the canonical bounds string. */
117
+ bounds_hash: string;
118
+ /** Hash of the canonical scope string (sha256 of "" when scope is empty). */
119
+ scope_hash: string;
120
+ execution_context_hash: string;
121
+ /** `sha256` over the JCS serialization of the profile the Gatekeeper
122
+ * provisioned for `profile_id` — the content address of the rulebook this
123
+ * mandate was issued under (new in v0.7). */
124
+ profile_hash: string;
125
+ /** The Authority Server's DID — SHOULD be the `did:key` of the signing key
126
+ * itself (new in v0.7). */
127
+ issuer: string;
128
+ /** Exactly one entry in v0.7 (Mandate rule 7). */
129
+ mandate_owners: MandateOwnerEntry[];
130
+ gate_content_hashes: Record<string, string>;
131
+ commitment_mode: 'automatic' | 'review' | 'review_above_cap';
132
+ /** Required, together with `above_cap_approvers`, iff `commitment_mode === "review_above_cap"`. */
133
+ above_cap_caps?: Record<string, number>;
134
+ above_cap_approvers?: string[];
135
+ /**
136
+ * Present iff the mandate carries an encrypted-intent disclosure object
137
+ * (companion spec `intent-disclosure@0.1`) — `sha256:`-prefixed hash
138
+ * binding `intent_ciphertext` + `approvers_frozen` into the signed payload.
139
+ */
140
+ intent_disclosure_hash?: string;
141
+ /** Signed identity-assurance block, one entry per owner — present iff the
142
+ * Mandate Owner disclosed identity. */
143
+ subjects?: Subject[];
136
144
  /**
137
- * @deprecated v0.6 — replaced by {@link AttestationPayload.owner_mandates}.
138
- * This field signed the wrong object (the identity claim, not what was
139
- * committed to) and was welded to one method. Implementations MUST NOT emit
140
- * it; verifiers MAY ignore it on artifacts that carry it. Kept readable for
141
- * audit of pre-0.6 artifacts only.
145
+ * The owner's narrowing of the profile's `disclose_fields` list (new in
146
+ * v0.7) — a subset of the profile's own list. See *Ticket Disclosure Is
147
+ * Declared*.
142
148
  */
143
- owner_signature?: string | null;
149
+ disclose_fields?: string[];
150
+ issued_at: number;
151
+ expires_at: number;
144
152
  }
145
- interface Attestation {
146
- header: AttestationHeader;
147
- payload: AttestationPayload;
153
+ interface Mandate {
154
+ header: MandateHeader;
155
+ payload: MandatePayload;
156
+ /** base64url (no padding) Ed25519 signature over the JCS-canonical payload. */
148
157
  signature: string;
149
158
  }
150
159
  /**
@@ -179,24 +188,13 @@ interface FieldConstraint {
179
188
  requiredFor?: string[];
180
189
  }
181
190
  /**
182
- * Frame field definition within a profile.
183
- */
184
- interface ProfileFrameField {
185
- type: 'string' | 'number';
186
- required: boolean;
187
- description?: string;
188
- constraint?: FieldConstraint;
189
- enum?: string[];
190
- }
191
- /**
192
- * Bound enforcement semantics — how a v0.4 bound is checked.
191
+ * Bound enforcement semantics — how a bound is checked.
193
192
  *
194
- * Every bounds field in a v0.4 profile declares a `boundType` so the SP
195
- * receipt route and hap-core gatekeeper can dispatch on it directly,
196
- * without parsing field names or guessing conventions. This is the
197
- * single source of truth for "what does this bound mean at enforcement
198
- * time" — if a new kind is needed, add a variant here and update the
199
- * dispatch sites.
193
+ * Every bounds field in a profile declares a `boundType` so the AS and
194
+ * hap-core gatekeeper can dispatch on it directly, without parsing field
195
+ * names or guessing conventions. This is the single source of truth for
196
+ * "what does this bound mean at enforcement time" — if a new kind is needed,
197
+ * add a variant here and update the dispatch sites.
200
198
  *
201
199
  * See `ProfileBoundsField.boundType`.
202
200
  */
@@ -206,23 +204,15 @@ type BoundType =
206
204
  * satisfy `execution[of] <= bound` for the current call. No cumulative
207
205
  * tracking. Used by: amount_max, recipient_max, booking_duration_max, etc.
208
206
  *
209
- * `requiredFor` (v0.8+) closes the converse: without it, a call that does
210
- * not carry `of` at all is simply skipped — a 5,000 cap refuses 6,000 but
207
+ * `requiredFor` closes the converse: without it, a call that does not
208
+ * carry `of` at all is simply skipped — a 5,000 cap refuses 6,000 but
211
209
  * permits a call that declares no value whatsoever, which is indistinguishable
212
- * from an unenforced bound. The same hole, and the same fix, as
213
- * `FieldConstraint.requiredFor` on a scope constraint (below): values drawn
214
- * from the profile's `boundsSchema.actionTypes` registry. For a listed
215
- * `action_type`, an execution whose context lacks `of` — or whose value is
216
- * not a finite number — MUST be refused rather than skipped. For an
217
- * unlisted (or when `requiredFor` is absent) action type, today's
218
- * skip-on-absence behaviour is unchanged. Meaningful only on
219
- * `per_transaction`; the other `BoundType` kinds have no per-call "value
220
- * exposed or not" question — `cumulative_sum`/`cumulative_count` always read
221
- * from the execution log regardless of what this call declares, and `enum`
222
- * is a capability flag, not a runtime value — so the field does not exist
223
- * on those variants and a profile that puts it there has it silently
224
- * ignored by every enforcement point (TypeScript also refuses it when the
225
- * profile is authored against this type rather than raw JSON).
210
+ * from an unenforced bound. Values are drawn from the profile's
211
+ * `boundsSchema.actionTypes` registry. For a listed `action_type`, an
212
+ * execution whose context lacks `of` — or whose value is not a finite
213
+ * number — MUST be refused rather than skipped. `appliesTo` MUST NOT be
214
+ * declared on a `per_transaction` bound (protocol.md → Bounds Schema rule 7)
215
+ * — it applies wherever `of` is present in the execution context.
226
216
  */
227
217
  {
228
218
  kind: 'per_transaction';
@@ -230,10 +220,12 @@ type BoundType =
230
220
  requiredFor?: string[];
231
221
  }
232
222
  /**
233
- * Cumulative sum within a time window. The SP maintains a running sum
234
- * of `execution[of]` across all prior executions in the window; the
223
+ * Cumulative sum within a time window. The AS maintains a running sum
224
+ * of `execution[of]` across all prior tickets in the window; the
235
225
  * current call is approved iff `running_sum + execution[of] <= bound`.
236
- * Used by: amount_daily_max, spend_monthly_max, etc.
226
+ * AS-only enforcement (protocol.md → *Enforcement Authority*); the
227
+ * Gatekeeper MUST NOT enforce this locally. Used by: amount_daily_max,
228
+ * spend_monthly_max, etc.
237
229
  */
238
230
  | {
239
231
  kind: 'cumulative_sum';
@@ -241,10 +233,14 @@ type BoundType =
241
233
  window: CumulativeWindow;
242
234
  }
243
235
  /**
244
- * Cumulative count within a time window. Every qualifying execution
236
+ * Cumulative count within a time window. Every qualifying ticket
245
237
  * counts as +1; the current call is approved iff
246
238
  * `running_count + 1 <= bound`. No execution context field is read.
247
- * Used by: write_daily_max, post_monthly_max, booking_daily_max, etc.
239
+ * AS-only enforcement. `appliesTo` is REQUIRED on a profile published
240
+ * under v0.7 or later (Bounds Schema rule 7) — absence would mean
241
+ * "governs every action type", so a forgotten declaration silently
242
+ * throttles every action. Used by: write_daily_max, post_monthly_max,
243
+ * booking_daily_max, etc.
248
244
  */
249
245
  | {
250
246
  kind: 'cumulative_count';
@@ -252,11 +248,12 @@ type BoundType =
252
248
  }
253
249
  /**
254
250
  * String bound restricted to a fixed set of allowed values. The bound's
255
- * value must be one of `values` at attestation time. The gateway
251
+ * value must be one of `values` at mandate time. The gateway
256
252
  * tool-proxy gates tool calls based on the stored bound (via the
257
253
  * integration manifest's `boundField` + `requiredValue`). Not cumulated,
258
- * not checked by the SP receipt route — it's a capability flag.
259
- * Used by: read_access, delete_access, archive_access.
254
+ * not checked by the AS ticket route — it's a capability flag.
255
+ * `appliesTo` MUST NOT be declared here (it is a capability flag, not an
256
+ * action-scoped limit). Used by: read_access, delete_access, archive_access.
260
257
  */
261
258
  | {
262
259
  kind: 'enum';
@@ -274,11 +271,11 @@ type BoundType =
274
271
  */
275
272
  type FieldUnit = 'count' | 'minutes' | 'hours' | 'days' | `currency:${string}` | 'percent';
276
273
  /**
277
- * Bounds field definition within a v0.4 profile.
274
+ * Bounds field definition within a profile.
278
275
  *
279
- * v0.4 adds the required `boundType` — an explicit declaration of how
280
- * the bound is enforced. The older `constraint.enforceable` pattern is
281
- * deprecated and superseded by `boundType`.
276
+ * Every non-metadata bounds field MUST declare `boundType` — an explicit
277
+ * declaration of how the bound is enforced. Implementations MUST fail
278
+ * closed on any bounds field that omits it (Bounds Schema rule 2).
282
279
  */
283
280
  interface ProfileBoundsField {
284
281
  type: 'string' | 'number';
@@ -286,26 +283,18 @@ interface ProfileBoundsField {
286
283
  description?: string;
287
284
  displayName?: string;
288
285
  format?: 'email' | 'domain' | 'url' | 'currency';
289
- /**
290
- * v0.4 enforcement semantics. Required for all new profiles.
291
- * Optional here only so the type stays backward compatible with v0.3
292
- * profiles that predate the boundType convention — consumers must
293
- * treat a missing boundType as an error when running in v0.4 mode.
294
- */
286
+ /** Enforcement semantics. REQUIRED on every bounds field except `profile`. */
295
287
  boundType?: BoundType;
296
288
  /**
297
289
  * Which execution action types this bound governs, e.g. `["write"]`.
298
290
  *
299
- * When present, this is authoritative. When absent, enforcement falls back to
300
- * inferring the action type from the FIELD NAME (`send_daily_max` → `send`),
301
- * which is a convention rather than a contract: a profile that names a bound
302
- * after the domain concept instead of the action — calendar's
303
- * `booking_daily_max` against an action type of `write` — matches nothing and
304
- * is skipped, so a limit the user set is never applied and nothing says so.
305
- *
306
- * Declaring it removes the guess. Deliberately additive: profiles migrate one
307
- * at a time, and every remaining fallback is logged, so the cases still
308
- * relying on the naming convention become visible instead of staying silent.
291
+ * When present, this is authoritative. When absent, a `cumulative_sum` bound
292
+ * (or any bound on a profile published before v0.7) governs every action
293
+ * type in the profile's `actionTypes` registry; a `cumulative_count` bound
294
+ * on a v0.7+ profile MUST declare it (Bounds Schema rule 7). MUST NOT be
295
+ * declared on a `per_transaction` bound (it applies wherever its `of`
296
+ * field is present in the execution context) or on an `enum` bound (a
297
+ * capability flag, not an action-scoped limit).
309
298
  */
310
299
  appliesTo?: string[];
311
300
  /**
@@ -328,18 +317,14 @@ interface ProfileBoundsField {
328
317
  * min(value, maximum). Absent → no ceiling.
329
318
  */
330
319
  maximum?: number;
331
- /** @deprecated v0.4: use boundType instead. */
332
- constraint?: FieldConstraint;
333
- /** @deprecated v0.4: use boundType: { kind: 'enum', values: [...] }. */
334
- enum?: string[];
335
320
  }
336
321
  /**
337
322
  * v0.5 Content Provenance — how a profile's action content is hashed into a
338
- * signed receipt (`contentHash`). The ephemeral-content analog of Output
323
+ * signed ticket (`contentHash`). The ephemeral-content analog of Output
339
324
  * Provenance: it binds the *bytes* of the action rather than a location.
340
325
  *
341
326
  * Profile-bound and OPTIONAL. Absent → no content hash is produced (full
342
- * backward compatibility). The gateway computes the hash; the SP only ever
327
+ * backward compatibility). The gateway computes the hash; the AS only ever
343
328
  * receives the hash, never the content, so HAP's privacy-minimal design holds.
344
329
  *
345
330
  * At `version:"1"` the profile declares only the *policy* — whether to bind and
@@ -401,16 +386,17 @@ interface ContentBinding {
401
386
  appliesTo?: string[];
402
387
  }
403
388
  /**
404
- * Context field definition within a v0.4 profile.
389
+ * Scope field definition within a profile (renamed from `ProfileContextField`
390
+ * in v0.7 — protocol.md → *Migration from v0.6*, `contextSchema` → `scopeSchema`).
405
391
  */
406
- interface ProfileContextField {
392
+ interface ProfileScopeField {
407
393
  type: 'string' | 'number';
408
394
  required: boolean;
409
395
  description?: string;
410
396
  displayName?: string;
411
397
  format?: 'email' | 'domain' | 'url' | 'currency';
412
398
  /**
413
- * v0.6 — what this field NAMES on the read path. `counterparty` = the other
399
+ * What this field NAMES on the read path. `counterparty` = the other
414
400
  * party to a communication (matched against an item's participants);
415
401
  * `resource` = the container an item belongs to (a direct attribute match —
416
402
  * and a resource scope enforced on writes MUST also bind reads). Absent →
@@ -419,7 +405,6 @@ interface ProfileContextField {
419
405
  */
420
406
  scopeKind?: 'counterparty' | 'resource';
421
407
  constraint?: FieldConstraint;
422
- enum?: string[];
423
408
  }
424
409
  /**
425
410
  * Execution context field definition — declared source (value comes from the agent's tool call).
@@ -435,13 +420,11 @@ interface DeclaredFieldDef {
435
420
  */
436
421
  type CumulativeWindow = 'daily' | 'weekly' | 'monthly';
437
422
  /**
438
- * Execution context field definition — cumulative source (resolved from execution log).
423
+ * Execution context field definition — cumulative source (resolved from the
424
+ * AS's ticket history; see protocol.md → *Cumulative State*).
439
425
  *
440
- * The gatekeeper resolves these by querying the execution log:
441
426
  * - `cumulativeField`: which declared field to sum (use "_count" for plain counting)
442
427
  * - `window`: time window for aggregation (daily, weekly, monthly)
443
- *
444
- * The resolved value = running total within window + current call value.
445
428
  */
446
429
  interface CumulativeFieldDef {
447
430
  source: 'cumulative';
@@ -456,35 +439,21 @@ interface CumulativeFieldDef {
456
439
  */
457
440
  type ExecutionContextFieldDef = DeclaredFieldDef | CumulativeFieldDef;
458
441
  /**
459
- * Gate question definition.
460
- * @deprecated v0.4 uses a single intent gate with no profile-specific questions.
461
- */
462
- interface GateQuestion {
463
- question: string;
464
- required: boolean;
465
- }
466
- /**
467
- * @deprecated Execution paths removed in v0.4. Kept for backward compatibility.
468
- */
469
- interface ExecutionPath {
470
- description: string;
471
- requiredDomains?: string[];
472
- ttl?: {
473
- default: number;
474
- max: number;
475
- };
476
- }
477
- /**
478
- * Agent Profile — defines constraint types, execution paths, gate questions,
479
- * and the frame/bounds/context schemas for bounded execution.
480
- *
481
- * Supports both v0.3 (frameSchema) and v0.4 (boundsSchema + contextSchema).
442
+ * Agent Profile — defines the bounds/scope/execution-context schemas, gates,
443
+ * TTL policy, and retention for a bounded authority (protocol.md → *Profiles*).
482
444
  */
483
445
  /**
484
446
  * A commitment mode a person can choose when signing a mandate. (`review_above_cap`
485
447
  * is not chosen by the signer — it follows from team caps.)
486
448
  */
487
449
  type SignableCommitmentMode = 'automatic' | 'review';
450
+ /** protocol.md → *Owner Signatures* → "Where the requirement lives" — the
451
+ * profile-floor tier: `minBinding` names the weakest `OwnerSignatureBinding`
452
+ * this profile accepts for a co-signing owner. */
453
+ interface ProfileOwnerSignatureFloor {
454
+ required: boolean;
455
+ minBinding?: OwnerSignatureBinding;
456
+ }
488
457
  interface AgentProfile {
489
458
  id: string;
490
459
  name?: string;
@@ -505,9 +474,10 @@ interface AgentProfile {
505
474
  */
506
475
  whatsNew?: string;
507
476
  /**
508
- * Whether receipts under this profile may be looked up BY THEIR CONTENT — a
509
- * verifier holding the content supplies its hash and learns which receipts
510
- * bind it, without needing a receipt id.
477
+ * Whether tickets under this profile may be looked up BY THEIR CONTENT — a
478
+ * verifier holding the content supplies its hash and learns which tickets
479
+ * bind it, without needing a ticket id. (Renamed from `receipt_lookup` in
480
+ * v0.7.)
511
481
  *
512
482
  * OFF unless declared, and that default is the point. The lookup is a
513
483
  * confirmation oracle: given a guess at the content it says whether that
@@ -519,13 +489,8 @@ interface AgentProfile {
519
489
  * Enable only when the bound content is unguessable enough that producing it
520
490
  * is equivalent to already having it: prose, an artifact URL, a whole record
521
491
  * payload. Never for a binding over a short value drawn from a small set.
522
- *
523
- * Why it must exist at all: most consequential actions cannot carry their
524
- * receipt id. A released build was built before the receipt existed, a
525
- * content-addressed artifact would change identity if the id were added, and
526
- * a forwarded message has usually lost the footer that carried it.
527
492
  */
528
- receipt_lookup?: boolean;
493
+ ticket_lookup?: boolean;
529
494
  /**
530
495
  * The commitment modes a mandate under this profile may be signed with.
531
496
  * Absent → every mode (`automatic`, `review`), as before this field existed.
@@ -539,21 +504,14 @@ interface AgentProfile {
539
504
  */
540
505
  commitment_modes?: readonly SignableCommitmentMode[];
541
506
  /**
542
- * v0.3 frame schema (deprecated, kept for backward compat).
543
- * Used when boundsSchema is not present.
544
- */
545
- frameSchema?: {
546
- keyOrder: string[];
547
- fields: Record<string, ProfileFrameField>;
548
- };
549
- /**
550
- * v0.4 bounds schema — defines the authorization bounds parameters.
507
+ * The bounds schema — the enforceable parameters (protocol.md → *Bounds
508
+ * Schema*).
551
509
  */
552
510
  boundsSchema?: {
553
511
  keyOrder: string[];
554
512
  fields: Record<string, ProfileBoundsField>;
555
513
  /**
556
- * v0.5+ registry of the action types this profile recognizes (e.g.
514
+ * Registry of the action types this profile recognizes (e.g.
557
515
  * `["send", "delete", "setup"]`). Every `execution.action_type` the
558
516
  * Authority Server and gateway accept for this profile MUST be a member
559
517
  * when the registry is declared (protocol.md → Bounds Schema, rule 2);
@@ -564,92 +522,45 @@ interface AgentProfile {
564
522
  actionTypes?: readonly string[];
565
523
  };
566
524
  /**
567
- * v0.4 context schema — defines the execution context parameters (e.g., currency, action_type).
568
- * May be absent or empty for profiles with no static context.
525
+ * The scope schema — operational scoping fields that stay local (renamed
526
+ * from `contextSchema` in v0.7). May be absent or empty for profiles with
527
+ * no static scope.
569
528
  */
570
- contextSchema?: {
529
+ scopeSchema?: {
571
530
  keyOrder: string[];
572
- fields: Record<string, ProfileContextField>;
531
+ fields: Record<string, ProfileScopeField>;
573
532
  };
574
533
  executionContextSchema: {
575
534
  fields: Record<string, ExecutionContextFieldDef>;
576
535
  };
577
- /** @deprecated Execution paths removed in v0.4. Kept for backward compatibility. */
578
- executionPaths?: Record<string, ExecutionPath>;
579
536
  requiredGates: string[];
580
- /**
581
- * v0.4: no gateQuestions — intent prompt is universal, defined in the gateway UI.
582
- * v0.3: profile-specific gate questions (deprecated).
583
- */
584
- gateQuestions?: {
585
- problem?: GateQuestion;
586
- objective?: GateQuestion;
587
- tradeoffs?: GateQuestion;
588
- };
589
537
  ttl: {
590
538
  default: number;
591
539
  max: number;
592
540
  };
593
541
  retention_minimum: number;
594
542
  /**
595
- * v0.5 Content Provenance (OPTIONAL, profile-bound). When present, the
543
+ * Content Provenance (OPTIONAL, profile-bound). When present, the
596
544
  * gateway computes a `contentHash` for gated writes under this profile and
597
- * passes it (hash only) to the SP, which signs it into the receipt. Absent
545
+ * passes it (hash only) to the AS, which signs it into the ticket. Absent
598
546
  * → no content hash. See {@link ContentBinding}.
599
547
  */
600
548
  content_binding?: ContentBinding;
601
549
  /**
602
- * Tool gating configuration — how MCP tools map to execution context.
603
- * @deprecated Tool gating now lives in integration manifests (content/integrations/*.json).
604
- * Kept for backward compatibility with profiles that still include it.
550
+ * The execution-context fields a ticket under this profile MAY disclose
551
+ * (new in v0.7 — protocol.md → *Ticket Disclosure Is Declared*). Absent →
552
+ * nothing is disclosed by default. A mandate's own `disclose_fields` (when
553
+ * present) MUST be a subset of this list — a mandate may narrow disclosure,
554
+ * never widen it.
605
555
  */
606
- toolGating?: ProfileToolGating;
607
- }
608
- /**
609
- * Available transforms for array-aware execution mappings.
610
- * - length: array length → number
611
- * - join: array items joined by comma → string
612
- * - join_domains: extract email domains, deduplicate, sort, join → string
613
- */
614
- type ExecutionMappingTransform = 'join' | 'join_domains' | 'length';
615
- /**
616
- * Execution mapping value — how a tool argument maps to execution context field(s).
617
- * - string: direct copy (argName → fieldName)
618
- * - { field, divisor }: numeric division (e.g., cents ÷ 100 → EUR)
619
- * - { field, transform }: array transform (e.g., join_domains)
620
- * - Array form: one argument maps to multiple execution fields
621
- */
622
- type ExecutionMappingValue = string | {
623
- field: string;
624
- divisor: number;
625
- } | {
626
- field: string;
627
- transform: ExecutionMappingTransform;
628
- } | Array<{
629
- field: string;
630
- divisor?: number;
631
- transform?: ExecutionMappingTransform;
632
- }>;
633
- /**
634
- * Tool gating entry — how a tool's calls map to execution context fields.
635
- * Read-only tools use { category: "read" } — they require authorization
636
- * but skip execution context verification.
637
- */
638
- interface ProfileToolGatingEntry {
639
- executionMapping: Record<string, ExecutionMappingValue>;
640
- staticExecution?: Record<string, string | number>;
641
- /** Read-only tools: require authorization but no execution context checks */
642
- category?: 'read';
643
- }
644
- /**
645
- * Profile-level tool gating configuration.
646
- * - default: applied to all tools not listed in overrides
647
- * - overrides: per-tool configs keyed by original MCP tool name
648
- * Use { category: "read" } for read-only tools (null is deprecated)
649
- */
650
- interface ProfileToolGating {
651
- default: ProfileToolGatingEntry;
652
- overrides?: Record<string, ProfileToolGatingEntry | null>;
556
+ disclose_fields?: string[];
557
+ /**
558
+ * Profile-floor requirement for an owner signature on a mandate under this
559
+ * profile (protocol.md → *Owner Signatures* → "Where the requirement
560
+ * lives"). Reserved for domains that cannot mean anything without a
561
+ * signature — used more freely it forks `charge` from `charge-with-cosign`.
562
+ */
563
+ ownerSignature?: ProfileOwnerSignatureFloor;
653
564
  }
654
565
  /**
655
566
  * A recorded execution — stored after gatekeeper approval for cumulative tracking.
@@ -685,51 +596,47 @@ interface ExecutionLogQuery {
685
596
  */
686
597
  actionTypes?: readonly string[]): number;
687
598
  }
688
- /**
689
- * Agent frame parameters — mixed types (strings and numbers).
690
- * Keys and values come from the profile's frameSchema.
691
- */
692
- type AgentFrameParams = Record<string, string | number>;
693
599
  /**
694
600
  * Agent bounds parameters — mixed types (strings and numbers).
695
- * Keys and values come from the profile's boundsSchema (v0.4).
601
+ * Keys and values come from the profile's boundsSchema.
696
602
  */
697
603
  type AgentBoundsParams = Record<string, string | number>;
698
604
  /**
699
- * Agent context parameters — mixed types (strings and numbers).
700
- * Keys and values come from the profile's contextSchema (v0.4).
605
+ * Agent scope parameters — mixed types (strings and numbers). Keys and
606
+ * values come from the profile's scopeSchema (renamed from
607
+ * `AgentContextParams` in v0.7).
701
608
  */
702
- type AgentContextParams = Record<string, string | number>;
609
+ type AgentScopeParams = Record<string, string | number>;
703
610
  /**
704
611
  * Request to the Gatekeeper for bounded execution verification.
705
612
  */
706
613
  interface GatekeeperRequest {
707
- /** The authorization frame (what was attested to) — v0.3 */
708
- frame: AgentFrameParams;
709
- /** Attestation blobs (base64url) for each domain */
710
- attestations: string[];
711
- /** The agent's execution values for this specific action */
614
+ /** The bounds the mandate(s) committed to. */
615
+ bounds: AgentBoundsParams;
616
+ /** Mandate blobs (base64url) to verify against. */
617
+ mandates: string[];
618
+ /** The agent's execution values for this specific action. */
712
619
  execution: Record<string, string | number>;
713
- /** v0.4: context parameters (currency, action_type, etc.) */
714
- context?: AgentContextParams;
620
+ /** Scope parameters (currency, action_type, allowed recipients, etc.) —
621
+ * enforced locally only; never sent to the Authority Server. */
622
+ scope?: AgentScopeParams;
715
623
  /**
716
- * Authorization path used to scope cumulative lookups in the execution log.
717
- *
718
- * Deliberately OUTSIDE `frame`: the frame is hashed and validated against the
719
- * profile's boundsSchema, so an extra key there is rejected as an unknown
720
- * field and breaks attestation verification outright. Cumulative checks
721
- * previously read the path from the frame, where callers cannot legally put
722
- * it — so it resolved to "" while the log stored real paths, no entry ever
723
- * matched, and every running total read zero. The local gate existed but
724
- * could never fire.
624
+ * Authorization path used to scope cumulative lookups in the execution log
625
+ * (display only — see {@link ExecutionLogQuery}; the Gatekeeper MUST NOT
626
+ * enforce cumulative bounds locally, protocol.md → *Enforcement Authority*).
725
627
  */
726
628
  path?: string;
727
629
  }
728
630
  /**
729
- * Structured error from Gatekeeper verification.
631
+ * Structured error from Gatekeeper verification. Codes are the canonical
632
+ * v0.7 surface ({@link HapErrorCode}, `src/errors.ts`) plus the two
633
+ * Gatekeeper-local-only codes that never reach the wire (`FRAME_MISMATCH`
634
+ * is retired with v0.3; a Gatekeeper reports `BOUNDS_HASH_MISMATCH` /
635
+ * `SCOPE_HASH_MISMATCH` for both its own local mismatch and the AS's wire
636
+ * refusal, per protocol.md → *Error Codes*, "Gatekeeper · local").
730
637
  */
731
638
  interface GatekeeperError {
732
- code: 'BOUND_EXCEEDED' | 'CUMULATIVE_LIMIT_EXCEEDED' | 'INVALID_SIGNATURE' | 'TTL_EXPIRED' | 'FRAME_MISMATCH' | 'BOUNDS_MISMATCH' | 'CONTEXT_MISMATCH' | 'DOMAIN_NOT_COVERED' | 'INVALID_PROFILE' | 'MALFORMED_ATTESTATION' | 'INVALID_ACTION_TYPE' | 'ATTESTATION_REVOKED' | 'APPROVAL_REQUIRED' | 'IDEMPOTENCY_MISMATCH' | 'MANDATE_SIGNATURE_REQUIRED' | 'MANDATE_SIGNATURE_INVALID' | 'APPROVAL_SIGNATURE_REQUIRED' | 'APPROVAL_SIGNATURE_INVALID' | 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE';
639
+ code: HapErrorCode;
733
640
  field?: string;
734
641
  message: string;
735
642
  bound?: string | number;
@@ -780,6 +687,46 @@ type GatekeeperResult = {
780
687
  */
781
688
  declare function canonicalize(value: unknown): string;
782
689
 
690
+ /**
691
+ * base64url (RFC 4648 §5), strict — no padding, no standard-base64 characters.
692
+ *
693
+ * protocol.md → *Mandate Payload* rule 3: "Signatures MUST be encoded as
694
+ * base64url without padding ... Implementations MUST NOT use standard base64
695
+ * (which differs in `+`/`/` vs `-`/`_` and in padding) — third-party verifiers
696
+ * reading the spec literally will reject standard-base64 signatures."
697
+ *
698
+ * Earlier hap-core verifiers were lenient: they translated `+`/`/` back from
699
+ * `-`/`_` and re-added padding before decoding, so a standard-base64 signature
700
+ * verified exactly as well as a base64url one — silently accepting the wire
701
+ * format the spec forbids. v0.7 closes that: decoding a string that is not
702
+ * strict base64url throws, never silently repairs it.
703
+ */
704
+ /** Encode bytes as base64url with no padding. */
705
+ declare function toBase64Url(bytes: Uint8Array): string;
706
+ /**
707
+ * Decode a STRICT base64url string (no padding, no `+`/`/`/`=`).
708
+ *
709
+ * @throws Error (no protocol code — the caller knows which artifact it was
710
+ * decoding and assigns the code) when the input carries a `+`, `/`, `=`, or
711
+ * any other byte outside the base64url alphabet.
712
+ */
713
+ declare function fromBase64Url(s: string): Uint8Array;
714
+
715
+ /** The protocol version this package issues and verifies. */
716
+ declare const PROTOCOL_VERSION = "0.7";
717
+ /** The protocol versions this package can verify and enforce. */
718
+ declare const SUPPORTED_VERSIONS: readonly string[];
719
+ /**
720
+ * The highest version both the requester and this implementation support.
721
+ *
722
+ * @param requested `supported_versions` from the mandate request. Absent →
723
+ * read as `["0.6"]` (protocol.md rule 1) — which, against this package's
724
+ * `SUPPORTED_VERSIONS`, has no overlap and refuses honestly rather than
725
+ * silently assuming `0.7`.
726
+ * @throws HapError `VERSION_UNSUPPORTED` when no version is common to both.
727
+ */
728
+ declare function negotiateVersion(requested: readonly string[] | undefined, supported?: readonly string[]): string;
729
+
783
730
  /**
784
731
  * Content binding — Level 2 content proof (HAP v0.5 Content Provenance).
785
732
  *
@@ -950,20 +897,17 @@ interface SubjectValidation {
950
897
  * - `self_declared` ⇒ `low` / `self`, no disclosed name.
951
898
  * - `as_vouched` ⇒ `high` / `as`, `verifier` required.
952
899
  * - `eudi` ⇒ `high` / `external`, `verifier` required — and, when the
953
- * carrying attestation's `owner_mandates` are supplied, a corresponding
900
+ * carrying mandate's `mandate_owners` are supplied, a corresponding
954
901
  * entry with `binding:"eudi"` for this subject's DID.
955
902
  * - `disclose.name` only at `assurance:"high"`.
956
903
  *
957
- * v0.6: `Subject.owner_signature` is deprecated and IGNORED here — it signed
958
- * the identity claim, not the mandate (see the field's deprecation note). The
959
- * signature-bearing object is the attestation's `owner_mandates` entry, which
904
+ * The signature-bearing object is the mandate's `mandate_owners` entry, which
960
905
  * is payload-level context this per-subject check cannot see on its own; pass
961
- * `opts.ownerMandates` to enforce the eudi ⇒ mandate-entry rule, omit it to
962
- * validate subject shape alone (pre-0.6 callers keep their behaviour minus
963
- * the retired owner_signature requirement).
906
+ * `opts.mandateOwners` to enforce the eudi ⇒ mandate-owner-entry rule, omit it
907
+ * to validate subject shape alone.
964
908
  */
965
909
  declare function validateSubject(subject: Subject, opts?: {
966
- ownerMandates?: OwnerMandate[];
910
+ mandateOwners?: MandateOwnerEntry[];
967
911
  }): SubjectValidation;
968
912
  /**
969
913
  * The footer line for a subject — the ONE place this wording lives.
@@ -991,76 +935,38 @@ declare function deriveIdentityLine(subject: Subject | undefined | null, { opera
991
935
  }): string;
992
936
 
993
937
  /**
994
- * Frame Canonicalization for Agent Profiles
938
+ * Bounds & Scope Canonicalization (protocol.md → *Bounds & Scope
939
+ * Canonicalization*).
995
940
  *
996
- * Agent profiles support mixed-type fields (strings and numbers).
997
941
  * Canonical form: `key=value` records joined with LF, keys in the profile's
998
942
  * keyOrder. Values are stringified with String(value) — the shortest
999
943
  * round-trippable form for numbers — then percent-encoded per protocol.md
1000
944
  * (`=`, `%`, and every byte outside printable ASCII); a value carrying a raw
1001
945
  * LF/CR is refused, never normalized. See `canonicalRecords` below.
1002
946
  *
1003
- * v0.3: frameSchema
1004
- * v0.4: boundsSchema + contextSchema (separate hashes)
947
+ * v0.3's `frameSchema` / `canonicalFrame` / `computeFrameHash` are retired
948
+ * with the rest of v0.3 (CLAUDE.md "Decided by the owner": no backward
949
+ * compatibility). v0.7 renames `contextSchema` → `scopeSchema` and
950
+ * `AgentContextParams` → `AgentScopeParams` (protocol.md → *Migration from
951
+ * v0.6*); the functions below follow suit (`canonicalContext` →
952
+ * `canonicalScope`, `computeContextHash` → `computeScopeHash`,
953
+ * `validateContextParams` → `validateScopeParams`).
1005
954
  */
1006
955
 
1007
956
  /**
1008
- * Validates frame parameters against the profile's frame schema.
1009
- */
1010
- declare function validateFrameParams(params: AgentFrameParams, profile: AgentProfile): {
1011
- valid: boolean;
1012
- errors: string[];
1013
- };
1014
- /**
1015
- * Builds the canonical frame string from parameters.
1016
- * All values are converted to strings. Keys are ordered per profile's keyOrder.
1017
- *
1018
- * @throws Error if any field fails validation
1019
- */
1020
- declare function canonicalFrame(params: AgentFrameParams, profile: AgentProfile): string;
1021
- /**
1022
- * Computes the frame hash from a canonical frame string.
1023
- *
1024
- * @returns Hash in format "sha256:<64 hex chars>"
1025
- */
1026
- declare function frameHash(canonicalFrameString: string): string;
1027
- /**
1028
- * Convenience: builds canonical frame and computes hash in one step.
1029
- */
1030
- declare function computeFrameHash(params: AgentFrameParams, profile: AgentProfile): string;
1031
- /**
1032
- * Validates bounds parameters against the profile's boundsSchema (v0.4).
957
+ * Validates bounds parameters against the profile's boundsSchema.
1033
958
  */
1034
959
  declare function validateBoundsParams(params: AgentBoundsParams, profile: AgentProfile): {
1035
960
  valid: boolean;
1036
961
  errors: string[];
1037
962
  };
1038
963
  /**
1039
- * Validates context parameters against the profile's contextSchema (v0.4).
964
+ * Validates scope parameters against the profile's scopeSchema.
1040
965
  */
1041
- declare function validateContextParams(params: AgentContextParams, profile: AgentProfile): {
966
+ declare function validateScopeParams(params: AgentScopeParams, profile: AgentProfile): {
1042
967
  valid: boolean;
1043
968
  errors: string[];
1044
969
  };
1045
- /**
1046
- * Authoring-time check for `per_transaction` bound `requiredFor` (v0.8+):
1047
- * entries must name a real `action_type` from the profile's declared
1048
- * `boundsSchema.actionTypes` registry, and the field is only meaningful on
1049
- * `per_transaction` bounds (see `BoundType`'s doc comment for why the other
1050
- * kinds don't carry it).
1051
- *
1052
- * This is NOT wired into `registerProfile` or any enforcement path — nothing
1053
- * in hap-core validates profile JSON at load time today (the pre-existing
1054
- * `requiredFor` on a context/scope constraint has the same gap), so adding
1055
- * an automatic refusal here would be new behaviour beyond this change's
1056
- * scope. Call it explicitly from an authoring tool, a hap-profiles CI check,
1057
- * or a test, to catch a `requiredFor` entry that can never match (misspelled
1058
- * action type) or is attached to a bound kind that silently ignores it.
1059
- *
1060
- * Returns an empty array when the profile has no boundsSchema or nothing to
1061
- * check — never throws.
1062
- */
1063
- declare function validateBoundsRequiredFor(profile: AgentProfile): string[];
1064
970
  /**
1065
971
  * Thrown when a value cannot be canonicalized at all — currently only for raw
1066
972
  * LF/CR inside a value. Carries the protocol error code so callers can map it
@@ -1073,9 +979,9 @@ declare function validateBoundsRequiredFor(profile: AgentProfile): string[];
1073
979
  * does not faithfully represent the input."
1074
980
  */
1075
981
  declare class CanonicalValueError extends Error {
1076
- readonly code: 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE';
982
+ readonly code: 'BOUNDS_INVALID_VALUE' | 'SCOPE_INVALID_VALUE';
1077
983
  readonly field: string;
1078
- constructor(code: 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE', field: string, message: string);
984
+ constructor(code: 'BOUNDS_INVALID_VALUE' | 'SCOPE_INVALID_VALUE', field: string, message: string);
1079
985
  }
1080
986
  /**
1081
987
  * Builds the canonical bounds string from parameters.
@@ -1087,29 +993,29 @@ declare class CanonicalValueError extends Error {
1087
993
  */
1088
994
  declare function canonicalBounds(params: AgentBoundsParams, profile: AgentProfile): string;
1089
995
  /**
1090
- * Builds the canonical context string from parameters.
1091
- * Keys are ordered per profile's contextSchema.keyOrder; values are encoded per
996
+ * Builds the canonical scope string from parameters.
997
+ * Keys are ordered per profile's scopeSchema.keyOrder; values are encoded per
1092
998
  * protocol.md → *Value encoding* (see `canonicalRecords`).
1093
- * For empty context (no contextSchema or no fields), returns "".
999
+ * For empty scope (no scopeSchema or no fields), returns "".
1094
1000
  *
1095
1001
  * @throws Error if any field fails validation
1096
- * @throws CanonicalValueError (code CONTEXT_INVALID_VALUE) if a value carries a raw LF/CR
1002
+ * @throws CanonicalValueError (code SCOPE_INVALID_VALUE) if a value carries a raw LF/CR
1097
1003
  */
1098
- declare function canonicalContext(params: AgentContextParams, profile: AgentProfile): string;
1004
+ declare function canonicalScope(params: AgentScopeParams, profile: AgentProfile): string;
1099
1005
  /**
1100
- * Computes the bounds hash from bounds parameters (v0.4).
1006
+ * Computes the bounds hash from bounds parameters.
1101
1007
  *
1102
1008
  * @returns Hash in format "sha256:<64 hex chars>"
1103
1009
  */
1104
1010
  declare function computeBoundsHash(params: AgentBoundsParams, profile: AgentProfile): string;
1105
1011
  /**
1106
- * Computes the context hash from context parameters (v0.4).
1107
- * For empty context {}, returns the sha256 of "":
1012
+ * Computes the scope hash from scope parameters.
1013
+ * For empty scope {}, returns the sha256 of "":
1108
1014
  * "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
1109
1015
  *
1110
1016
  * @returns Hash in format "sha256:<64 hex chars>"
1111
1017
  */
1112
- declare function computeContextHash(params: AgentContextParams, profile: AgentProfile): string;
1018
+ declare function computeScopeHash(params: AgentScopeParams, profile: AgentProfile): string;
1113
1019
 
1114
1020
  /**
1115
1021
  * Which commitment modes a profile allows its mandates to be signed with
@@ -1128,248 +1034,208 @@ declare const SIGNABLE_COMMITMENT_MODES: readonly SignableCommitmentMode[];
1128
1034
  declare function allowedCommitmentModes(profile: AgentProfile): readonly SignableCommitmentMode[];
1129
1035
  /** Whether a mandate under this profile may be signed with `mode`. */
1130
1036
  declare function isCommitmentModeAllowed(profile: AgentProfile, mode: string): boolean;
1131
- /**
1132
- * Authoring check for a profile's `commitment_modes` declaration — for
1133
- * hap-profiles CI, an authoring tool or a test. Like `validateBoundsRequiredFor`
1134
- * it is not wired into profile loading; enforcement reads the declaration
1135
- * fail-closed through `allowedCommitmentModes`. Empty array = nothing to fix.
1136
- */
1137
- declare function validateCommitmentModes(profile: AgentProfile): string[];
1138
-
1139
- /**
1140
- * Attestation Encoding, Decoding, and Verification
1141
- *
1142
- * Supports both v0.3 (frame_hash) and v0.4 (bounds_hash + context_hash).
1143
- */
1144
1037
 
1038
+ /** One authoring-time finding. `code` is always a canonical v0.7 code — in
1039
+ * practice always `PROFILE_INVALID`, since that is the only mandate-request
1040
+ * refusal the protocol attributes to "the profile fails validation"
1041
+ * (protocol.md → Error Codes). */
1042
+ interface ProfileValidationError {
1043
+ code: HapErrorCode;
1044
+ field?: string;
1045
+ message: string;
1046
+ }
1145
1047
  /**
1146
- * Decodes a base64url-encoded attestation blob.
1147
- */
1148
- declare function decodeAttestationBlob(blob: string): Attestation;
1149
- /**
1150
- * Encodes an attestation as a base64url blob (no padding).
1151
- */
1152
- declare function encodeAttestationBlob(attestation: Attestation): string;
1153
- /**
1154
- * Computes the attestation ID (hash of the blob).
1155
- */
1156
- declare function attestationId(blob: string): string;
1157
- /**
1158
- * Verifies an attestation signature using the SP public key.
1159
- *
1160
- * @returns true if valid
1161
- * @throws Error with code prefix if invalid
1048
+ * `profile_hash` — `"sha256:" + sha256(JCS(parsed))`, over the PARSED
1049
+ * profile document. Formatting, key order, and a trailing newline on disk
1050
+ * never change it (protocol.md → *Profile hash*; conformance vector set
1051
+ * `profile-hash.json`).
1162
1052
  */
1163
- declare function verifyAttestationSignature(attestation: Attestation, publicKeyHex: string): Promise<void>;
1053
+ declare function computeProfileHash(parsed: unknown): string;
1164
1054
  /**
1165
- * Checks if an attestation has expired.
1166
- *
1167
- * @throws Error if expired
1055
+ * Authoring-time structural validation (protocol.md → *Bounds Schema*,
1056
+ * *Owner Signatures* → "Where the requirement lives", *Migration from
1057
+ * v0.6*). Returns `[]` for a clean profile; never throws.
1168
1058
  */
1169
- declare function checkAttestationExpiry(payload: AttestationPayload, now?: number): void;
1059
+ declare function validateProfile(profile: AgentProfile): ProfileValidationError[];
1170
1060
  /**
1171
- * Verifies that the frame hash in the attestation matches the expected hash (v0.3).
1061
+ * A mandate's `disclose_fields` MUST be a subset of the profile's own list
1062
+ * (protocol.md → *Mandate Payload*, conditional field `disclose_fields`: "a
1063
+ * subset of the profile's `disclose_fields` list"). A mandate may narrow
1064
+ * disclosure, never widen it.
1172
1065
  *
1173
- * @throws Error if frame hash doesn't match
1066
+ * @throws Error prefixed `MALFORMED_MANDATE:` when it is not a subset.
1174
1067
  */
1175
- declare function verifyFrameHash(attestation: Attestation, expectedFrameHash: string): void;
1068
+ declare function checkDiscloseSubset(mandateDiscloseFields: readonly string[] | undefined, profileDiscloseFields: readonly string[] | undefined): void;
1069
+
1176
1070
  /**
1177
- * Detects whether an attestation is v0.4 (has bounds_hash + context_hash)
1178
- * or v0.3 (has frame_hash).
1071
+ * Mandate encoding, decoding, signing, and verification (v0.7).
1179
1072
  *
1180
- * Migration rule: if attestation has frame_hash but not bounds_hash, it is v0.3.
1073
+ * Renamed from `attestation.ts` (protocol.md → *Migration from v0.6*:
1074
+ * `header.typ: "HAP-attestation"` → `"HAP-mandate"`, `attestation_id` →
1075
+ * `mandate_id`). v0.3's frame-hash path and v0.4's dual frame/bounds
1076
+ * verification are retired with the rest of pre-v0.5 — this module issues
1077
+ * and verifies `version: "0.7"` mandates only (CLAUDE.md "Decided by the
1078
+ * owner": no backward-compat verify path for 0.5/0.6).
1181
1079
  */
1182
- declare function isV4Attestation(attestation: Attestation): boolean;
1080
+
1183
1081
  /**
1184
- * Verifies that the bounds hash in the attestation matches the expected hash (v0.4).
1185
- *
1186
- * @throws Error if bounds hash doesn't match
1082
+ * Decodes a base64url-encoded mandate blob.
1083
+ * @throws HapError `MALFORMED_MANDATE` on anything that is not a strict
1084
+ * base64url-encoded JSON mandate.
1187
1085
  */
1188
- declare function verifyBoundsHash(attestation: Attestation, expectedBoundsHash: string): void;
1086
+ declare function decodeMandateBlob(blob: string): Mandate;
1189
1087
  /**
1190
- * Verifies that the context hash in the attestation matches the expected hash (v0.4).
1191
- *
1192
- * @throws Error if context hash doesn't match
1088
+ * Encodes a mandate as a base64url blob (no padding).
1193
1089
  */
1194
- declare function verifyContextHash(attestation: Attestation, expectedContextHash: string): void;
1090
+ declare function encodeMandateBlob(mandate: Mandate): string;
1195
1091
  /**
1196
- * Full attestation verification (signature + expiry + frame hash) — v0.3.
1197
- *
1198
- * @returns The decoded attestation payload
1199
- * @throws Error on any validation failure
1092
+ * Computes the mandate blob id (hash of the blob) — renamed from
1093
+ * `attestationId`.
1200
1094
  */
1201
- declare function verifyAttestation(blob: string, publicKeyHex: string, expectedFrameHash: string): Promise<AttestationPayload>;
1095
+ declare function mandateBlobId(blob: string): string;
1202
1096
  /**
1203
- * Full attestation verification for v0.4 (signature + expiry + bounds_hash + context_hash).
1097
+ * Sign a mandate payload with the Authority Server's Ed25519 private key.
1204
1098
  *
1205
- * @returns The decoded attestation payload
1206
- * @throws Error on any validation failure
1099
+ * @param opts.kid Optional key id for the envelope header. When present it
1100
+ * MUST identify the same key as `payload.issuer` (Mandate rule 8) — this
1101
+ * function does not enforce that on the signer's side; `verifyMandateSignature`
1102
+ * enforces it on the verifier's side, where a mismatch is actually dangerous.
1207
1103
  */
1208
- declare function verifyAttestationV4(blob: string, publicKeyHex: string, expectedBoundsHash: string, expectedContextHash: string): Promise<AttestationPayload>;
1209
-
1104
+ declare function signMandate(payload: MandatePayload, privateKey: Uint8Array, opts?: {
1105
+ kid?: string;
1106
+ }): Promise<Mandate>;
1210
1107
  /**
1211
- * Gatekeeper — Stateless Verification for Bounded Execution
1212
- *
1213
- * Supports both v0.3 (frameSchema / frame_hash) and v0.4 (boundsSchema + contextSchema /
1214
- * bounds_hash + context_hash).
1108
+ * Verifies a mandate's Ed25519 signature. The verification key is resolved
1109
+ * from `payload.issuer` itself — never from a key offered alongside the
1110
+ * artifact (protocol.md → *Ticket Verification* step 1, which states the
1111
+ * same rule for tickets; mandates follow it identically).
1215
1112
  *
1216
- * v0.3 flow (§8.6):
1217
- * 1. Resolve profile from frame
1218
- * 2. Recompute frame_hash
1219
- * 3. For each required domain: find attestation, verify signature, verify frame_hash, verify TTL
1220
- * 4. Check bounds: max → actual <= bound, enum → actual in allowed
1221
- * 5. Return { approved } or { approved: false, errors: [...] }
1222
- *
1223
- * v0.4 flow:
1224
- * 1. Resolve profile from bounds.profile
1225
- * 2. Recompute bounds_hash and context_hash
1226
- * 3. For each required domain: find attestation, verify signature, verify bounds_hash + context_hash, verify TTL
1227
- * 4. Check bounds (from boundsSchema), check context constraints (from contextSchema)
1228
- * 5. Resolve cumulative fields, check cumulative limits
1229
- * 6. Return { approved } or { approved: false, errors: [...] }
1113
+ * @param opts.trustedIssuers When supplied, an `issuer` not in this list is
1114
+ * rejected before any cryptography runs — "a verifier MUST reject a [...]
1115
+ * whose `issuer` it does not trust" (protocol.md → *Ticket Verification*).
1116
+ * @throws Error prefixed `INVALID_SIGNATURE:` on any verification failure.
1230
1117
  */
1231
-
1118
+ declare function verifyMandateSignature(mandate: Mandate, opts?: {
1119
+ trustedIssuers?: readonly string[];
1120
+ }): Promise<void>;
1232
1121
  /**
1233
- * Verify an execution request against attested authorization.
1234
- *
1235
- * For v0.4 profiles (have boundsSchema), the `frame` param is interpreted as `bounds`,
1236
- * and the optional `context` param is used for the context hash check.
1122
+ * Checks a mandate payload's time rules (Mandate rule 9): `expires_at` is
1123
+ * authoritative, with a {@link CLOCK_SKEW_SECONDS} tolerance that never
1124
+ * extends life past `expires_at + 300s`.
1237
1125
  *
1238
- * For v0.3 profiles (have frameSchema only), existing logic is used unchanged.
1239
- *
1240
- * @param request - The frame/bounds, attestations, execution values, and optional context
1241
- * @param publicKeyHex - The SP's public key in hex (cached locally by MCP server)
1242
- * @param now - Current timestamp in seconds (for testing)
1243
- * @param executionLog - Optional execution log for resolving cumulative fields
1126
+ * @throws Error prefixed `TTL_EXPIRED:` when expired.
1244
1127
  */
1245
- declare function verify(request: GatekeeperRequest, publicKeyHex: string, now?: number, executionLog?: ExecutionLogQuery): Promise<GatekeeperResult>;
1128
+ declare function checkMandateExpiry(payload: MandatePayload, now?: number): void;
1246
1129
  /**
1247
- * Which action types' executions count toward this cumulative bound's running
1248
- * total. `undefined` means all of them.
1249
- *
1250
- * `boundGovernsAction` decides whether a bound applies to the current call; this
1251
- * decides what the bound's total is made of. Both are needed: selecting the right
1252
- * bound and then feeding it the profile's combined total is still wrong — sales'
1253
- * "orders per day" was checked only on orders, but counted every quote and send.
1254
- * Consumption is partitioned by action type (*Cumulative Tracking* rule 4), as
1255
- * the Authority Server already does.
1130
+ * Validates the structural shape of `mandate_owners` (Mandate rule 7):
1131
+ * exactly one entry, `did` required, and the signature fields present
1132
+ * together or absent together. A co-signing entry's `did` MUST be key-bearing.
1256
1133
  *
1257
- * Same answer, same order of preference as `boundGovernsAction`: the declared
1258
- * `appliesTo`; else, for a count bound named for an action (`delete_daily_max`),
1259
- * that action; else every action type. Exported so display surfaces report the
1260
- * same totals the gate enforces.
1261
- */
1262
- declare function boundActionTypes(fieldName: string, fieldDef: ProfileBoundsField): readonly string[] | undefined;
1263
-
1264
- /**
1265
- * Profile Registry — dynamically populated from git-hosted profile sources.
1134
+ * @throws HapError `MALFORMED_MANDATE` on a cardinality or completeness
1135
+ * violation; `OWNER_SIGNATURE_INVALID` when a co-signing DID is not key-bearing.
1266
1136
  */
1267
-
1268
- declare function registerProfile(profileId: string, profile: AgentProfile): void;
1269
- declare function getProfile(profileId: string): AgentProfile | undefined;
1270
- declare function listProfiles(): string[];
1271
- declare function getAllProfiles(): AgentProfile[];
1272
- declare function clearProfiles(): void;
1273
-
1137
+ declare function validateMandateOwners(payload: MandatePayload): void;
1274
1138
  /**
1275
- * did:key — encode/decode for KEY-BEARING DIDs (HAP v0.6).
1139
+ * Full mandate verification: decode, check `version`, verify the AS
1140
+ * signature, check expiry, validate `mandate_owners` shape.
1276
1141
  *
1277
- * A real `did:key` is self-certifying: the public key IS the identifier, so
1278
- * substituting the key produces a DIFFERENT DID and no key directory is ever
1279
- * consulted. That property is what the Owner Mandate design stands on
1280
- * (protocol.md → "Identity DIDs vs signing DIDs"): a signing DID MUST be
1281
- * key-bearing, and verification uses the key carried in the identifier —
1282
- * deliberately, there is no `public_key` field anywhere on the wire.
1283
- *
1284
- * Format (W3C did:key method, Ed25519):
1285
- * did:key:z<base58btc( 0xed 0x01 ‖ 32-byte-public-key )>
1286
- * `z` is the multibase prefix for base58btc; `0xed 0x01` is the multicodec
1287
- * varint for ed25519-pub. The result always starts `did:key:z6Mk`.
1288
- *
1289
- * Scope: Ed25519 only — the one signing curve this protocol version uses.
1290
- * Anything else (including the reference implementation's legacy decorative
1291
- * `did:key:<uuid-fragment>` identifiers) decodes as NOT key-bearing.
1292
- */
1293
- /** Encode a 32-byte Ed25519 public key as a key-bearing `did:key:z6Mk…`. */
1294
- declare function encodeDidKey(publicKey: Uint8Array): string;
1295
- /**
1296
- * Decode a key-bearing `did:key` to its Ed25519 public key bytes.
1142
+ * Deliberately does NOT verify any `mandate_owners` co-signature — that is
1143
+ * `verifyOwnerSignature` in `owner-signature.ts`, a separate trust axis the
1144
+ * caller opts into.
1297
1145
  *
1298
- * @throws Error prefixed `NOT_KEY_BEARING:` for anything that is not a valid
1299
- * base58btc-multibase Ed25519 did:key — including the legacy decorative
1300
- * `did:key:<uuid-fragment>` identifiers, other multibase prefixes, and other
1301
- * key types. The error name is the point: under the mandate design, a
1302
- * non-key-bearing signing DID must fail STRUCTURALLY, never fall back.
1146
+ * @throws HapError `VERSION_UNSUPPORTED` for anything other than `"0.7"`.
1147
+ * @throws Error (`INVALID_SIGNATURE:` / `TTL_EXPIRED:` / `MALFORMED_MANDATE:`
1148
+ * prefixed, or `OWNER_SIGNATURE_INVALID` as a HapError) on any other failure.
1303
1149
  */
1304
- declare function decodeDidKey(did: string): Uint8Array;
1305
- /** True iff the DID decodes as a key-bearing Ed25519 did:key. Never throws. */
1306
- declare function isKeyBearingDid(did: string): boolean;
1150
+ declare function verifyMandate(blob: string, opts?: {
1151
+ trustedIssuers?: readonly string[];
1152
+ now?: number;
1153
+ }): Promise<MandatePayload>;
1307
1154
 
1308
1155
  /**
1309
- * Owner Mandate Signatures (HAP v0.6) — the `HAP-mandate` projection, the
1156
+ * Owner Signatures (v0.7) — the `HAP-mandate-projection` object, the
1310
1157
  * `HAP-approval` object, and their verification.
1311
1158
  *
1159
+ * Renamed from `mandate.ts` (protocol.md → *Migration from v0.6*: the
1160
+ * owner-signed projection's `typ` moves from `"HAP-mandate"` to
1161
+ * `"HAP-mandate-projection"`, disambiguating it from the AS-signed mandate
1162
+ * itself, which now legitimately owns the name `"HAP-mandate"`).
1163
+ *
1312
1164
  * The human signs BEFORE the AS does, so they cannot sign the finished
1313
- * attestation (`attestation_id`/`issued_at` do not exist yet). They sign a
1314
- * mandate PROJECTION: a canonical object every field of which is known at
1315
- * approval time and reconstructible from the finished attestation — so a
1316
- * verifier rebuilds it from the attestation it already holds and checks the
1317
- * signature with the key carried in the owner's DID. No side channel, no
1318
- * second fetch, no key directory. See protocol.md → "Owner Mandate Signatures".
1319
- *
1320
- * Verification here requires NO trust in the AS. What it cannot do is tell the
1321
- * verifier WHOSE key signed — confirming the DID belongs to the expected
1322
- * person is the out-of-band step (protocol.md → "Identity DIDs vs signing
1323
- * DIDs"), and it is the honest cost of cold verification.
1165
+ * mandate (`mandate_id`/`issued_at` do not exist yet). They sign a mandate
1166
+ * PROJECTION: a canonical object every field of which is known at approval
1167
+ * time and reconstructible from the finished mandate — so a verifier
1168
+ * rebuilds it from the mandate it already holds and checks the signature
1169
+ * with the key carried in the owner's DID. No side channel, no second
1170
+ * fetch, no key directory. See protocol.md → "Owner Signatures".
1171
+ *
1172
+ * Verification here requires NO trust in the AS. What it cannot do is tell
1173
+ * the verifier WHOSE key signed — confirming the DID belongs to the
1174
+ * expected person is the out-of-band step (protocol.md → "Verification
1175
+ * procedure" step 5), and it is the honest cost of cold verification.
1324
1176
  */
1325
1177
 
1326
- /** The object the owner signs — a canonical projection of the mandate. */
1178
+ /** The object the owner signs — a canonical projection of the mandate.
1179
+ * Field absence is defined, not incidental (protocol.md → *The signed
1180
+ * object: HAP-mandate-projection*): each conditional field is included
1181
+ * exactly when the mandate carries it and omitted otherwise. */
1327
1182
  interface MandateProjection {
1328
- typ: 'HAP-mandate';
1183
+ typ: 'HAP-mandate-projection';
1329
1184
  /** Projection/canonicalization version. A verifier MUST pin it. */
1330
- version: '0.6';
1185
+ version: '0.7';
1331
1186
  profile_id: string;
1332
- /** The signing owner's own DID. MUST be a member of `resolved_owners`. */
1187
+ /** Covered deliberately: the owner signs the profile's BYTES, not only its id. */
1188
+ profile_hash: string;
1189
+ /** The signing owner's own DID. MUST equal the carrying mandate's `mandate_owners[0].did`. */
1333
1190
  owner_did: string;
1334
1191
  bounds_hash: string;
1335
- context_hash: string;
1192
+ scope_hash: string;
1336
1193
  execution_context_hash: string;
1337
1194
  gate_content_hashes: Record<string, string>;
1338
- /** Included iff the attestation carries one — binds ciphertext AND the
1195
+ /** Included iff the mandate carries one — binds ciphertext AND the
1339
1196
  * frozen approver set, the swap this mechanism exists to stop. */
1340
1197
  intent_disclosure_hash?: string;
1341
1198
  commitment_mode: string;
1199
+ /** Included together, iff `commitment_mode === "review_above_cap"`. */
1200
+ above_cap_caps?: Record<string, number>;
1201
+ above_cap_approvers?: string[];
1202
+ /** Included iff the mandate narrows the profile's disclose_fields. */
1203
+ disclose_fields?: string[];
1342
1204
  /** The replay defence: the human signs how long the authority lives. */
1343
1205
  expires_at: number;
1344
1206
  nonce: string;
1345
1207
  }
1346
1208
  /** Per-action approval, signed by the owner in `review` mode. Signing a
1347
- * `reject` matters as much as a `commit`: a rejection the AS can discard is a
1348
- * rejection that never happened. */
1209
+ * `reject` matters as much as a `commit`: a rejection the AS can discard is
1210
+ * a rejection that never happened. */
1349
1211
  interface ApprovalObject {
1350
1212
  typ: 'HAP-approval';
1351
- version: '0.6';
1213
+ version: '0.7';
1352
1214
  proposal_id: string;
1353
- attestation_id: string;
1215
+ /** Renamed from `attestation_id` in v0.7. */
1216
+ mandate_id: string;
1354
1217
  decision: 'commit' | 'reject';
1355
- /** What was approved: the receipt's contentHash where the profile binds
1218
+ /** What was approved: the ticket's contentHash where the profile binds
1356
1219
  * content; otherwise sha256 over the JCS of the proposal's argument set. */
1357
1220
  content_hash: string;
1358
1221
  decided_at: number;
1359
1222
  nonce: string;
1360
1223
  }
1361
- declare class MandateError extends Error {
1362
- code: 'MANDATE_SIGNATURE_INVALID' | 'APPROVAL_SIGNATURE_INVALID' | 'NOT_KEY_BEARING' | 'OWNER_NOT_RESOLVED' | 'MALFORMED_ATTESTATION';
1363
- constructor(code: 'MANDATE_SIGNATURE_INVALID' | 'APPROVAL_SIGNATURE_INVALID' | 'NOT_KEY_BEARING' | 'OWNER_NOT_RESOLVED' | 'MALFORMED_ATTESTATION', message: string);
1224
+ /** Renamed from `MandateError` in v0.7 — carries a canonical {@link HapErrorCode}. */
1225
+ declare class OwnerSignatureError extends Error {
1226
+ code: HapErrorCode;
1227
+ constructor(code: HapErrorCode, message: string);
1364
1228
  }
1365
1229
  /**
1366
- * Rebuild the projection a given `owner_mandates` entry signed, from the
1367
- * attestation's own signed fields. Field absence is defined, not incidental:
1368
- * `intent_disclosure_hash` is included iff the attestation carries one.
1230
+ * Rebuild the projection a given `mandate_owners` entry signed, from the
1231
+ * mandate's own signed fields. Field absence is defined, not incidental:
1232
+ * `intent_disclosure_hash`, `above_cap_caps`/`above_cap_approvers`, and
1233
+ * `disclose_fields` are included iff the mandate carries them.
1369
1234
  */
1370
- declare function buildMandateProjection(payload: AttestationPayload, entry: Pick<OwnerMandate, 'did' | 'nonce'>): MandateProjection;
1371
- /** The exact bytes an owner signs: RFC 8785 (JCS) canonical UTF-8. */
1372
- declare function mandateSigningBytes(projection: MandateProjection): Uint8Array;
1235
+ declare function buildMandateProjection(payload: MandatePayload, entry: Pick<MandateOwnerEntry, 'did' | 'nonce'>): MandateProjection;
1236
+ /** The exact bytes an owner signs: RFC 8785 (JCS) canonical UTF-8. Renamed
1237
+ * from `mandateSigningBytes` in v0.7. */
1238
+ declare function projectionSigningBytes(projection: MandateProjection): Uint8Array;
1373
1239
  /** The exact bytes an owner signs for a per-action approval. */
1374
1240
  declare function approvalSigningBytes(approval: ApprovalObject): Uint8Array;
1375
1241
  /**
@@ -1382,40 +1248,61 @@ declare function signMandateProjection(projection: MandateProjection, privateKey
1382
1248
  /** Sign an approval object with a raw Ed25519 private key (`raw` binding). */
1383
1249
  declare function signApproval(approval: ApprovalObject, privateKey: Uint8Array): Promise<string>;
1384
1250
  /**
1385
- * Verify ONE `owner_mandates` entry against the attestation that carries it.
1251
+ * Verify ONE `mandate_owners` entry against the mandate that carries it.
1386
1252
  *
1387
- * Steps (protocol.md → "Verification procedure", steps 4 of 6): membership in
1388
- * `resolved_owners`, key-bearing DID, projection reconstruction, Ed25519 over
1389
- * JCS bytes. The DID is authoritative over `alg` — a disagreement is
1390
- * MANDATE_SIGNATURE_INVALID, never a fallback to the claimed algorithm.
1253
+ * Steps (protocol.md → "Verification procedure", step 4 of 6): the entry
1254
+ * names this mandate's sole owner, its signing DID is key-bearing,
1255
+ * projection reconstruction, Ed25519 over JCS bytes. The DID is
1256
+ * authoritative over `alg` — a disagreement is `OWNER_SIGNATURE_INVALID`,
1257
+ * never a fallback to the claimed algorithm.
1391
1258
  *
1392
- * What this deliberately does NOT verify: that the DID belongs to the person
1393
- * the verifier expects (out-of-band, step 5) and the AS's own signature over
1394
- * the attestation (verifyAttestationSignature, step 1).
1259
+ * What this deliberately does NOT verify: that the DID belongs to the
1260
+ * person the verifier expects (out-of-band, step 5) and the AS's own
1261
+ * signature over the mandate (`verifyMandateSignature`, step 1).
1395
1262
  */
1396
- declare function verifyOwnerMandate(attestation: Attestation, entry: OwnerMandate): Promise<void>;
1397
- /** Verify every `owner_mandates` entry an attestation carries. Resolves to the
1398
- * verified entries; an attestation with none resolves to `[]` (the v0.5
1399
- * posture — nothing to check, and nothing claimed). */
1400
- declare function verifyOwnerMandates(attestation: Attestation): Promise<OwnerMandate[]>;
1263
+ declare function verifyOwnerSignature(mandate: Mandate, entry: MandateOwnerEntry): Promise<void>;
1264
+ /** Verify every co-signing `mandate_owners` entry a mandate carries (i.e.
1265
+ * every entry that carries a signature). Resolves to the verified entries;
1266
+ * a mandate with none resolves to `[]` — nothing to check, nothing claimed. */
1267
+ declare function verifyOwnerSignatures(mandate: Mandate): Promise<MandateOwnerEntry[]>;
1401
1268
  /** Verify an approval signature against a signer's key-bearing DID. */
1402
1269
  declare function verifyApproval(approval: ApprovalObject, signature: string, signerDid: string): Promise<void>;
1270
+ /**
1271
+ * Enforce a profile's `ownerSignature` floor (protocol.md → *Owner
1272
+ * Signatures* → "Where the requirement lives" — the profile-floor tier,
1273
+ * checkable without trusting the AS: `profile_id`/`profile_hash` are in the
1274
+ * signed payload AND in the owner-signed projection).
1275
+ *
1276
+ * An unknown `binding` value is treated as rank 0 (weakest) rather than
1277
+ * rejected outright — "an AS MUST NOT reject a mandate_owners entry solely
1278
+ * because it does not recognize its binding value" extends naturally to a
1279
+ * verifier ranking it, since crediting an unrecognized binding with
1280
+ * unearned strength would be the more dangerous failure mode.
1281
+ *
1282
+ * @throws OwnerSignatureError `OWNER_SIGNATURE_REQUIRED` when the floor is
1283
+ * unmet — "MUST fail, not warn" (protocol.md, same section).
1284
+ */
1285
+ declare function checkOwnerSignatureRequirement(payload: MandatePayload, floor: ProfileOwnerSignatureFloor | undefined): void;
1403
1286
 
1404
1287
  /**
1405
- * Execution receipts (HAP v0.5/v0.6) — the wire type and holder-side
1406
- * verification. Until v0.6 this library had no receipt surface at all; every
1407
- * verifier hand-assembled the strip→canonicalize→verify dance. This module is
1408
- * that dance, once.
1288
+ * Mandate tickets (v0.7) — the wire type, signing, and holder-side
1289
+ * verification. Renamed from `receipt.ts` (protocol.md → *Mandate Tickets*:
1290
+ * "v0.4 introduced the object under the name execution receipt; v0.7 renames
1291
+ * it because the tense was wrong — a receipt follows payment, and the ticket
1292
+ * must come first").
1409
1293
  *
1410
- * Receipt payloads are camelCase on the wire (unlike the snake_case
1411
- * attestation payload) — a shipped inconsistency v0.6 chose to document
1412
- * rather than break (changelog.md → "Renames and terminology").
1294
+ * Ticket payloads are camelCase on the wire (unlike the snake_case mandate
1295
+ * payload) — a shipped inconsistency the spec documents rather than breaks
1296
+ * (protocol.md → *Migration from v0.6*, "Unchanged on purpose").
1413
1297
  */
1414
1298
 
1415
- /** Signed execution receipt — protocol.md → "Receipt Payload Schema". */
1416
- interface ReceiptPayload {
1299
+ /** Signed mandate ticket — protocol.md → *Ticket Payload Schema*. */
1300
+ interface TicketPayload {
1417
1301
  id: string;
1418
- groupId?: string | null;
1302
+ /** The mandate this ticket was issued under (new in v0.7). Audit and
1303
+ * chain-of-custody only — `boundsHash` remains the AS's lookup key. */
1304
+ mandateId: string;
1305
+ groupId: string | null;
1419
1306
  userId?: string;
1420
1307
  boundsHash: string;
1421
1308
  profileId: string;
@@ -1425,35 +1312,169 @@ interface ReceiptPayload {
1425
1312
  actionType: string;
1426
1313
  executionContext: Record<string, unknown>;
1427
1314
  cumulativeState?: Record<string, unknown>;
1428
- limits?: Record<string, unknown>;
1315
+ /** The mandate's plaintext bounds object, exactly as the AS enforced them
1316
+ * for this ticket (new in v0.7 — required). */
1317
+ limits: Record<string, unknown>;
1318
+ /** Protocol version of the ticket — the version of the mandate it was
1319
+ * issued under (new in v0.7). */
1320
+ version: string;
1321
+ /** The AS DID, as in the mandate (new in v0.7). */
1322
+ issuer: string;
1429
1323
  timestamp: number;
1430
- /** v0.6 — hash of the bound content, computed by the Gatekeeper, copied
1324
+ /** Hash of the bound content, computed by the Gatekeeper, copied
1431
1325
  * verbatim by the AS. The AS never sees the content. */
1432
1326
  contentHash?: string;
1433
- /** v0.6 — the binding declaration echoed into the signed receipt, so a
1327
+ /** The binding declaration echoed into the signed ticket, so a
1434
1328
  * verifier knows exactly what `contentHash` covers. */
1435
1329
  contentBinding?: Pick<ContentBinding, 'version' | 'kind' | 'fields' | 'required_fields' | 'appliesTo'>;
1436
- /** v0.6 — disclosed subset of the attestation's identity overlay. */
1330
+ /** Disclosed subset of the mandate's identity overlay. */
1437
1331
  subjects?: Subject[];
1438
- /** v0.6 — review path: the proposal this receipt executed. */
1332
+ /** Review path: the proposal this ticket executed. */
1439
1333
  proposalId?: string;
1440
- /** v0.6 — review path: the owner's HAP-approval signature (or its sha256)
1441
- * for the executed proposal. */
1442
- approvalSignature?: string;
1334
+ /** Review path: the owner's HAP-approval signature for the executed
1335
+ * proposal, as the object itself — never a hash of it, which a holder
1336
+ * could check only by asking the AS. */
1337
+ approvalSignature?: {
1338
+ alg: 'EdDSA' | 'ES256';
1339
+ signature: string;
1340
+ nonce: string;
1341
+ decided_at: number;
1342
+ };
1443
1343
  /** Ed25519 over the JCS-canonical payload (this field excluded), base64url. */
1444
1344
  signature: string;
1445
1345
  }
1446
1346
  /**
1447
- * Verify a receipt's AS signature: strip `signature`, JCS-canonicalize the
1448
- * rest, Ed25519-verify against the AS public key (hex). This is holder-side
1449
- * verification — it needs the COMPLETE receipt; a redacted public view cannot
1450
- * be re-verified this way (protocol.md → "Receipt Verification").
1347
+ * Sign a ticket payload with the Authority Server's Ed25519 private key —
1348
+ * the same key used for mandates.
1349
+ */
1350
+ declare function signTicket(payload: Omit<TicketPayload, 'signature'>, privateKey: Uint8Array): Promise<TicketPayload>;
1351
+ /**
1352
+ * Verify a ticket's AS signature: strip `signature`, JCS-canonicalize the
1353
+ * rest, Ed25519-verify against the key resolved from `issuer` — never
1354
+ * against a key offered alongside the ticket (protocol.md → *Ticket
1355
+ * Verification* step 1). This is holder-side verification — it needs the
1356
+ * COMPLETE ticket; a redacted public view cannot be re-verified this way
1357
+ * (see {@link publicTicketView}).
1451
1358
  *
1452
- * Content is checked separately: where `contentHash` is present, recompute it
1453
- * from the held artifact via the content-binding module and compare.
1359
+ * Content is checked separately: where `contentHash` is present, recompute
1360
+ * it from the held artifact via the content-binding module and compare.
1454
1361
  *
1362
+ * @param opts.trustedIssuers When supplied, an `issuer` not in this list is
1363
+ * rejected before any cryptography runs.
1455
1364
  * @throws Error prefixed `INVALID_SIGNATURE:` when verification fails.
1456
1365
  */
1457
- declare function verifyReceiptSignature(receipt: ReceiptPayload, publicKeyHex: string): Promise<void>;
1366
+ declare function verifyTicketSignature(ticket: TicketPayload, opts?: {
1367
+ trustedIssuers?: readonly string[];
1368
+ }): Promise<void>;
1369
+ /**
1370
+ * A redacted public view of a ticket (new in v0.7 — protocol.md → *Ticket
1371
+ * Disclosure Is Declared*, *Ticket Verification*). Hides `userId`,
1372
+ * `cumulativeState`, and `limits` unconditionally, and narrows
1373
+ * `executionContext` to exactly the keys named by `governingDiscloseFields`
1374
+ * (the mandate's `disclose_fields` where present, otherwise the profile's).
1375
+ *
1376
+ * Disclose NOTHING by default: an empty or absent `governingDiscloseFields`
1377
+ * strips `executionContext` entirely. "The holder is the verifier" — this
1378
+ * view is NOT independently re-verifiable against `signature` (it is missing
1379
+ * signed fields); a "signature valid" indicator on a page showing only this
1380
+ * view is the AS re-verifying its own signature, and implementations MUST
1381
+ * NOT present it as independently verified.
1382
+ */
1383
+ declare function publicTicketView(ticket: TicketPayload, governingDiscloseFields?: readonly string[]): Omit<TicketPayload, 'userId' | 'cumulativeState' | 'limits'>;
1384
+
1385
+ /**
1386
+ * Gatekeeper — local (Phase 1) verification for bounded execution (v0.7).
1387
+ *
1388
+ * protocol.md → *Validation Steps* (Phase 1, never reaches the wire):
1389
+ * 1. Resolve profile from bounds.profile
1390
+ * 2. Recompute bounds_hash and scope_hash
1391
+ * 3. For each mandate: decode, verify AS signature, verify version,
1392
+ * verify bounds_hash / scope_hash / profile_hash, verify expiry
1393
+ * 4. Check actionType registry membership
1394
+ * 5. Check per_transaction bounds and enum capability flags locally
1395
+ * (Enforcement Authority: this is what makes per_transaction
1396
+ * compromise-resistant — *Enforcement classes*)
1397
+ * 6. Check scope constraints (enum, subset, requiredFor) locally — the AS
1398
+ * never sees scope plaintext, so the Gatekeeper is the sole enforcer
1399
+ * 7. Return { approved } or { approved: false, errors: [...] }
1400
+ *
1401
+ * What this module deliberately does NOT do (protocol.md → *Enforcement
1402
+ * Authority*, *Migration from v0.6* semantic change 9): enforce
1403
+ * `cumulative_sum` / `cumulative_count` bounds. "Local cumulative
1404
+ * enforcement is removed, not merely deprecated: a Gatekeeper MUST NOT
1405
+ * refuse an execution on a cumulative bound from its own records" — only
1406
+ * the Authority Server's ticket history is authoritative for a running
1407
+ * total across every Gatekeeper exercising the bucket. v0.3/v0.4's
1408
+ * frame-based path is retired entirely (CLAUDE.md "Decided by the owner").
1409
+ */
1410
+
1411
+ /** Options for {@link verify}. */
1412
+ interface VerifyOptions {
1413
+ /** Restricts mandate-signature verification to these Authority Server
1414
+ * DIDs — protocol.md → *Ticket Verification* step 1 applies identically
1415
+ * to mandates: "a verifier MUST reject a [...] whose issuer it does not
1416
+ * trust." Omitted → any issuer that resolves a valid did:key is accepted
1417
+ * (appropriate for a Gatekeeper that has not yet pinned an AS). */
1418
+ trustedIssuers?: readonly string[];
1419
+ now?: number;
1420
+ }
1421
+ /**
1422
+ * Verify an execution request against the mandates supplied.
1423
+ *
1424
+ * @param request bounds, mandate blobs, execution values, and optional scope
1425
+ */
1426
+ declare function verify(request: GatekeeperRequest, opts?: VerifyOptions): Promise<GatekeeperResult>;
1427
+ /**
1428
+ * Which action types' executions count toward this cumulative bound's
1429
+ * running total — `undefined` means all of them. Display-only now that
1430
+ * local cumulative enforcement is removed (protocol.md → *Enforcement
1431
+ * Authority*: cumulative bounds are AS-only). Exported so a gateway's own
1432
+ * usage display partitions totals the same way the Authority Server does.
1433
+ */
1434
+ declare function boundActionTypes(fieldName: string, fieldDef: ProfileBoundsField): readonly string[] | undefined;
1435
+
1436
+ /**
1437
+ * Profile Registry — dynamically populated from git-hosted profile sources.
1438
+ */
1439
+
1440
+ declare function registerProfile(profileId: string, profile: AgentProfile): void;
1441
+ declare function getProfile(profileId: string): AgentProfile | undefined;
1442
+ declare function listProfiles(): string[];
1443
+ declare function getAllProfiles(): AgentProfile[];
1444
+ declare function clearProfiles(): void;
1445
+
1446
+ /**
1447
+ * did:key — encode/decode for KEY-BEARING DIDs (HAP v0.6).
1448
+ *
1449
+ * A real `did:key` is self-certifying: the public key IS the identifier, so
1450
+ * substituting the key produces a DIFFERENT DID and no key directory is ever
1451
+ * consulted. That property is what the Owner Mandate design stands on
1452
+ * (protocol.md → "Identity DIDs vs signing DIDs"): a signing DID MUST be
1453
+ * key-bearing, and verification uses the key carried in the identifier —
1454
+ * deliberately, there is no `public_key` field anywhere on the wire.
1455
+ *
1456
+ * Format (W3C did:key method, Ed25519):
1457
+ * did:key:z<base58btc( 0xed 0x01 ‖ 32-byte-public-key )>
1458
+ * `z` is the multibase prefix for base58btc; `0xed 0x01` is the multicodec
1459
+ * varint for ed25519-pub. The result always starts `did:key:z6Mk`.
1460
+ *
1461
+ * Scope: Ed25519 only — the one signing curve this protocol version uses.
1462
+ * Anything else (including the reference implementation's legacy decorative
1463
+ * `did:key:<uuid-fragment>` identifiers) decodes as NOT key-bearing.
1464
+ */
1465
+ /** Encode a 32-byte Ed25519 public key as a key-bearing `did:key:z6Mk…`. */
1466
+ declare function encodeDidKey(publicKey: Uint8Array): string;
1467
+ /**
1468
+ * Decode a key-bearing `did:key` to its Ed25519 public key bytes.
1469
+ *
1470
+ * @throws Error prefixed `NOT_KEY_BEARING:` for anything that is not a valid
1471
+ * base58btc-multibase Ed25519 did:key — including the legacy decorative
1472
+ * `did:key:<uuid-fragment>` identifiers, other multibase prefixes, and other
1473
+ * key types. The error name is the point: under the mandate design, a
1474
+ * non-key-bearing signing DID must fail STRUCTURALLY, never fall back.
1475
+ */
1476
+ declare function decodeDidKey(did: string): Uint8Array;
1477
+ /** True iff the DID decodes as a key-bearing Ed25519 did:key. Never throws. */
1478
+ declare function isKeyBearingDid(did: string): boolean;
1458
1479
 
1459
- export { type AgentBoundsParams, type AgentContextParams, type AgentFrameParams, type AgentProfile, type ApprovalObject, type Attestation, type AttestationHeader, type AttestationPayload, type BoundType, CanonicalValueError, type ContentBinding, ContentBindingError, type ContentBindingErrorCode, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type ExecutionMappingTransform, type ExecutionMappingValue, type ExecutionPath, type FieldConstraint, type FieldUnit, type GateQuestion, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, type MandateBinding, MandateError, type MandateProjection, type OwnerMandate, type ProfileBoundsField, type ProfileContextField, type ProfileFrameField, type ProfileToolGating, type ProfileToolGatingEntry, type ReceiptPayload, type ResolvedDomain, SIGNABLE_COMMITMENT_MODES, type SignableCommitmentMode, type SigningSurface, type Subject, type SubjectValidation, allowedCommitmentModes, approvalSigningBytes, attestationId, bindingAppliesTo, boundActionTypes, buildMandateProjection, canonicalBounds, canonicalContext, canonicalFrame, canonicalize, canonicalizeText, checkAttestationExpiry, clearProfiles, computeBoundsHash, computeContentHash, computeContextHash, computeFieldsContentHash, computeFrameHash, computeIntentDisclosureHash, computeIntentHash, contentCanonicalBytes, decodeAttestationBlob, decodeDidKey, deriveIdentityLine, encodeAttestationBlob, encodeDidKey, frameHash, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, isCommitmentModeAllowed, isFieldBinding, isKeyBearingDid, isV4Attestation, listProfiles, mandateSigningBytes, registerProfile, selectBoundFields, signApproval, signMandateProjection, validateBoundsParams, validateBoundsRequiredFor, validateCommitmentModes, validateContextParams, validateFrameParams, validateSubject, verify, verifyApproval, verifyAttestation, verifyAttestationSignature, verifyAttestationV4, verifyBoundsHash, verifyContextHash, verifyFrameHash, verifyOwnerMandate, verifyOwnerMandates, verifyReceiptSignature };
1480
+ export { type AgentBoundsParams, type AgentProfile, type AgentScopeParams, type ApprovalObject, type BoundType, CanonicalValueError, type ContentBinding, ContentBindingError, type ContentBindingErrorCode, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type FieldConstraint, type FieldUnit, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, HapError, type HapErrorCode, MANDATE_ERROR_CODES, type Mandate, type MandateHeader, type MandateOwnerEntry, type MandatePayload, type MandateProjection, type OwnerSignatureBinding, OwnerSignatureError, PROTOCOL_VERSION, type ProfileBoundsField, type ProfileOwnerSignatureFloor, type ProfileScopeField, type ProfileValidationError, SIGNABLE_COMMITMENT_MODES, SUPPORTED_VERSIONS, type SignableCommitmentMode, type SigningSurface, type Subject, type SubjectValidation, TICKET_ERROR_CODES, type TicketPayload, type VerifyOptions, allowedCommitmentModes, approvalSigningBytes, bindingAppliesTo, boundActionTypes, buildMandateProjection, canonicalBounds, canonicalScope, canonicalize, canonicalizeText, checkDiscloseSubset, checkMandateExpiry, checkOwnerSignatureRequirement, clearProfiles, computeBoundsHash, computeContentHash, computeFieldsContentHash, computeIntentDisclosureHash, computeIntentHash, computeProfileHash, computeScopeHash, contentCanonicalBytes, decodeDidKey, decodeMandateBlob, deriveIdentityLine, encodeDidKey, encodeMandateBlob, fromBase64Url, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, isCommitmentModeAllowed, isFieldBinding, isKeyBearingDid, listProfiles, mandateBlobId, negotiateVersion, projectionSigningBytes, publicTicketView, registerProfile, selectBoundFields, signApproval, signMandate, signMandateProjection, signTicket, toBase64Url, validateBoundsParams, validateMandateOwners, validateProfile, validateScopeParams, validateSubject, verify, verifyApproval, verifyMandate, verifyMandateSignature, verifyOwnerSignature, verifyOwnerSignatures, verifyTicketSignature };