@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.
- package/content/guides/1-interview.md +6 -0
- package/content/guides/2-package.md +4 -1
- package/content/guides/3-mandates.md +3 -0
- package/content/guides/6-risks.md +2 -0
- package/content/integrations/crm.json +1 -1
- package/content/integrations/deploy-github.json +1 -1
- package/content/integrations/erp.json +1 -1
- package/content/integrations/mail.json +1 -1
- package/content/integrations/records.json +1 -1
- package/dist/control-plane/index.mjs +21 -13
- package/dist/mcp-server/{chunk-ZRRZFGRL.mjs → chunk-APIQIEUA.mjs} +39 -27
- package/dist/mcp-server/http.mjs +382 -97
- package/dist/mcp-server/report-verify-cli.mjs +1 -1
- package/dist/ui/assets/index-1gCMlbLl.js +116 -0
- package/dist/ui/assets/{index-RCFQUjaF.css → index-blnpvM2g.css} +1 -1
- package/dist/ui/index.html +2 -2
- package/node_modules/@hap/core/README.md +92 -29
- package/node_modules/@hap/core/dist/index.d.mts +614 -593
- package/node_modules/@hap/core/dist/index.d.ts +614 -593
- package/node_modules/@hap/core/dist/index.js +774 -749
- package/node_modules/@hap/core/dist/index.mjs +744 -724
- package/node_modules/@hap/core/package.json +1 -1
- package/node_modules/@hap/core/src/base64url.ts +39 -0
- package/node_modules/@hap/core/src/commitment-modes.ts +0 -21
- package/node_modules/@hap/core/src/errors.ts +76 -0
- package/node_modules/@hap/core/src/frame.ts +47 -178
- package/node_modules/@hap/core/src/gatekeeper.ts +219 -600
- package/node_modules/@hap/core/src/identity.ts +9 -12
- package/node_modules/@hap/core/src/index.ts +8 -4
- package/node_modules/@hap/core/src/mandate.ts +177 -166
- package/node_modules/@hap/core/src/owner-signature.ts +282 -0
- package/node_modules/@hap/core/src/profile.ts +234 -0
- package/node_modules/@hap/core/src/ticket.ts +148 -0
- package/node_modules/@hap/core/src/types.ts +191 -344
- package/node_modules/@hap/core/src/versions.ts +47 -0
- package/package.json +2 -2
- package/profiles/calendar/0.6.profile.json +191 -0
- package/profiles/charge/0.6.profile.json +211 -0
- package/profiles/customers/0.9.profile.json +182 -0
- package/profiles/delegation/0.3.profile.json +118 -0
- package/profiles/deploy/0.11.profile.json +177 -0
- package/profiles/email/0.8.profile.json +226 -0
- package/profiles/index.json +12 -1
- package/profiles/publish/0.6.profile.json +187 -0
- package/profiles/purchase/0.7.profile.json +235 -0
- package/profiles/records/0.6.profile.json +118 -0
- package/profiles/reporting/0.3.profile.json +98 -0
- package/profiles/sales/0.4.profile.json +291 -0
- package/dist/ui/assets/index-BseWI4iJ.js +0 -116
- package/node_modules/@hap/core/src/attestation.ts +0 -173
- package/node_modules/@hap/core/src/receipt.ts +0 -74
|
@@ -1,132 +1,74 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HAP Core Types —
|
|
2
|
+
* HAP Core Types — v0.7 ("mandate" / "ticket" / "scope" / "Mandate Owner")
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* v0.7 is a vocabulary release (protocol.md → *Migration from v0.6*): the
|
|
5
|
+
* wire renames *attestation* → *mandate*, *context* → *scope*, *execution
|
|
6
|
+
* receipt* → *mandate ticket*, and *Decision Owner* → *Mandate Owner*. There
|
|
7
|
+
* is no backward-compat alias here — v0.6 and earlier artifacts are
|
|
8
|
+
* verification-only history outside this package (CLAUDE.md "Decided by the
|
|
9
|
+
* owner": no verify path for 0.5/0.6, no old→new code map).
|
|
5
10
|
*/
|
|
6
11
|
|
|
7
|
-
// ───
|
|
12
|
+
// ─── Mandate Types ────────────────────────────────────────────────────────────
|
|
8
13
|
|
|
9
|
-
export interface
|
|
10
|
-
typ: 'HAP-
|
|
14
|
+
export interface MandateHeader {
|
|
15
|
+
typ: 'HAP-mandate';
|
|
11
16
|
alg: 'EdDSA';
|
|
12
|
-
kid?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ResolvedDomain {
|
|
16
|
-
domain: string;
|
|
17
|
-
did: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface AttestationPayload {
|
|
21
|
-
attestation_id: string;
|
|
22
|
-
version: '0.3' | '0.4' | '0.5' | '0.6';
|
|
23
|
-
profile_id: string;
|
|
24
|
-
/** v0.3 (deprecated) — hash of the authorization frame */
|
|
25
|
-
frame_hash?: string;
|
|
26
|
-
/** v0.4 — hash of the bounds parameters */
|
|
27
|
-
bounds_hash?: string;
|
|
28
|
-
/** v0.4 — hash of the context parameters */
|
|
29
|
-
context_hash?: string;
|
|
30
|
-
execution_context_hash: string;
|
|
31
|
-
/**
|
|
32
|
-
* v0.4 (deprecated in v0.5) — domain-scoped owners. Optional so v0.5
|
|
33
|
-
* attestations that carry only `resolved_owners` remain valid. During the
|
|
34
|
-
* transition the AS emits BOTH `resolved_domains` (internal coverage) and
|
|
35
|
-
* `resolved_owners` (the v0.5 signed wire field).
|
|
36
|
-
*/
|
|
37
|
-
resolved_domains?: ResolvedDomain[];
|
|
38
|
-
/**
|
|
39
|
-
* v0.5 — the Decision Owner DIDs this attestation covers (person-centric
|
|
40
|
-
* model; replaces the abstract domain in `resolved_domains`). Carried in the
|
|
41
|
-
* signed payload so verifiers bind the action to the human(s) who authorized it.
|
|
42
|
-
*/
|
|
43
|
-
resolved_owners?: string[];
|
|
44
|
-
gate_content_hashes: Record<string, string>;
|
|
45
|
-
/**
|
|
46
|
-
* v0.5 (companion spec `intent-disclosure@0.1`) — present iff the attestation
|
|
47
|
-
* carries an encrypted-intent disclosure object. `sha256:`-prefixed hash that
|
|
48
|
-
* binds the disclosure's `intent_ciphertext` + `approvers_frozen` into the
|
|
49
|
-
* signed payload (see {@link computeIntentDisclosureHash}), so a compromised
|
|
50
|
-
* AS cannot swap the ciphertext/wrapped keys or alter the approver set
|
|
51
|
-
* without invalidating the attestation signature (companion invariant C2).
|
|
52
|
-
*/
|
|
53
|
-
intent_disclosure_hash?: string;
|
|
54
|
-
/**
|
|
55
|
-
* v0.6 (Identity Assurance) — optional signed overlay carrying the verified
|
|
56
|
-
* real-world identity of the Decision Owner(s), one entry per owner. Present
|
|
57
|
-
* only when identity is disclosed; an attestation with no `subjects` renders
|
|
58
|
-
* as `low` (pseudonymous, no name). See {@link Subject} and
|
|
59
|
-
* {@link deriveIdentityLine}.
|
|
60
|
-
*/
|
|
61
|
-
subjects?: Subject[];
|
|
62
|
-
/**
|
|
63
|
-
* v0.4 — commitment mode chosen by the decision owner at attestation time.
|
|
64
|
-
* - 'automatic': agent may invoke bounded tools without per-action review.
|
|
65
|
-
* - 'review': every tool call requires an approved proposal before the
|
|
66
|
-
* receipt route will sign a receipt.
|
|
67
|
-
*
|
|
68
|
-
* Cryptographically bound in the signed payload so a compromised SP cannot
|
|
69
|
-
* silently flip 'review' → 'automatic'. Absent on v0.3 attestations.
|
|
70
|
-
* `review_above_cap` (v0.5): automatic below the signed caps, proposal above.
|
|
71
|
-
*/
|
|
72
|
-
commitment_mode?: 'automatic' | 'review' | 'review_above_cap';
|
|
73
17
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* to having received it and cannot strip it without invalidating its own
|
|
78
|
-
* signature. Optional and additive: an attestation without it behaves as
|
|
79
|
-
* before (the v0.5 posture — the AS asserts, nobody co-signs).
|
|
18
|
+
* When present MUST identify the same key as `issuer` (for a `did:key`
|
|
19
|
+
* issuer, the multibase key fingerprint) — Mandate rule 8. The field a
|
|
20
|
+
* party writes (`kid`) loses to the field a party cannot forge (`issuer`).
|
|
80
21
|
*/
|
|
81
|
-
|
|
82
|
-
issued_at: number;
|
|
83
|
-
expires_at: number;
|
|
22
|
+
kid?: string;
|
|
84
23
|
}
|
|
85
24
|
|
|
86
|
-
/**
|
|
87
|
-
* identity assurance ({@link Subject.method}). */
|
|
88
|
-
export type
|
|
25
|
+
/** Signature-assurance axis — what custody signed the mandate projection or
|
|
26
|
+
* approval. Independent of identity assurance ({@link Subject.method}). */
|
|
27
|
+
export type OwnerSignatureBinding = 'raw' | 'webauthn' | 'eudi';
|
|
89
28
|
|
|
90
29
|
/** Which surface showed the owner what they signed. A DECLARATION, not a proof
|
|
91
|
-
* — no verifier can check it; see protocol.md → Owner
|
|
30
|
+
* — no verifier can check it; see protocol.md → *Owner Signatures*. */
|
|
92
31
|
export type SigningSurface = 'gatekeeper_local' | 'as_web' | 'wallet_display';
|
|
93
32
|
|
|
94
33
|
/**
|
|
95
|
-
* v0.
|
|
34
|
+
* v0.7 `mandate_owners` entry (protocol.md → *Mandate field: mandate_owners*).
|
|
35
|
+
* `did` is required; the remaining fields are present together when the
|
|
36
|
+
* owner co-signed and absent together when they did not (Mandate rule 7).
|
|
96
37
|
*
|
|
97
38
|
* There is deliberately NO `public_key` field, and it MUST NOT be added: the
|
|
98
39
|
* verification key is carried in the DID itself (key-bearing `did:key`), so a
|
|
99
40
|
* non-key-bearing DID fails STRUCTURALLY instead of validating against a key
|
|
100
|
-
* the AS could have substituted.
|
|
101
|
-
* hygiene; if it disagrees with the DID's key type, the DID is authoritative.
|
|
41
|
+
* the AS could have substituted.
|
|
102
42
|
*/
|
|
103
|
-
export interface
|
|
104
|
-
/** The
|
|
43
|
+
export interface MandateOwnerEntry {
|
|
44
|
+
/** The Mandate Owner's DID. For a co-signing entry, MUST be key-bearing. */
|
|
105
45
|
did: string;
|
|
106
46
|
/** Signature algorithm hint. The DID's multicodec wins on any disagreement. */
|
|
107
|
-
alg
|
|
47
|
+
alg?: 'EdDSA' | 'ES256';
|
|
108
48
|
/** base64url (no padding) signature over the JCS bytes of the mandate projection. */
|
|
109
|
-
signature
|
|
49
|
+
signature?: string;
|
|
110
50
|
/** When the owner signed (unix seconds). */
|
|
111
|
-
signed_at
|
|
51
|
+
signed_at?: number;
|
|
112
52
|
/** Defence-in-depth against duplicate issuance by an HONEST AS only —
|
|
113
53
|
* AS-side nonce enforcement is no defence against the AS itself. */
|
|
114
|
-
nonce
|
|
115
|
-
|
|
54
|
+
nonce?: string;
|
|
55
|
+
/** Required-present, value-open when a signature is carried: an AS MUST
|
|
56
|
+
* NOT reject an entry for a `binding` value it does not recognize. */
|
|
57
|
+
binding?: OwnerSignatureBinding;
|
|
116
58
|
signing_surface?: SigningSurface;
|
|
117
59
|
}
|
|
118
60
|
|
|
119
61
|
/**
|
|
120
|
-
* v0.6 Identity Assurance — a signed overlay binding a
|
|
121
|
-
* real-world identity to the
|
|
62
|
+
* v0.6 Identity Assurance — a signed overlay binding a Mandate Owner's verified
|
|
63
|
+
* real-world identity to the mandate, gated by HOW the identity was verified.
|
|
122
64
|
*
|
|
123
65
|
* Two display levels (`assurance`): `low` discloses no name; `high` MAY disclose a
|
|
124
66
|
* name. At `high`, two trust roots: `as` (the AS operator vouches — valid only
|
|
125
67
|
* within its own domain) and `external` (an external eID such as EUDI — carries the
|
|
126
|
-
* owner's own signature, AS-independent).
|
|
68
|
+
* owner's own signature, AS-independent).
|
|
127
69
|
*/
|
|
128
70
|
export interface Subject {
|
|
129
|
-
/** The
|
|
71
|
+
/** The Mandate Owner DID this subject describes (matches the `mandate_owners` entry). */
|
|
130
72
|
did: string;
|
|
131
73
|
/** `low` → no name shown; `high` → the name MAY be shown. */
|
|
132
74
|
assurance: 'low' | 'high';
|
|
@@ -140,19 +82,55 @@ export interface Subject {
|
|
|
140
82
|
disclose?: { name: string };
|
|
141
83
|
/** When the underlying verification was performed (unix seconds). */
|
|
142
84
|
verified_at?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** protocol.md → *Mandate Payload (v0.7)*. */
|
|
88
|
+
export interface MandatePayload {
|
|
89
|
+
mandate_id: string;
|
|
90
|
+
version: '0.7';
|
|
91
|
+
profile_id: string;
|
|
92
|
+
/** Hash of the canonical bounds string. */
|
|
93
|
+
bounds_hash: string;
|
|
94
|
+
/** Hash of the canonical scope string (sha256 of "" when scope is empty). */
|
|
95
|
+
scope_hash: string;
|
|
96
|
+
execution_context_hash: string;
|
|
97
|
+
/** `sha256` over the JCS serialization of the profile the Gatekeeper
|
|
98
|
+
* provisioned for `profile_id` — the content address of the rulebook this
|
|
99
|
+
* mandate was issued under (new in v0.7). */
|
|
100
|
+
profile_hash: string;
|
|
101
|
+
/** The Authority Server's DID — SHOULD be the `did:key` of the signing key
|
|
102
|
+
* itself (new in v0.7). */
|
|
103
|
+
issuer: string;
|
|
104
|
+
/** Exactly one entry in v0.7 (Mandate rule 7). */
|
|
105
|
+
mandate_owners: MandateOwnerEntry[];
|
|
106
|
+
gate_content_hashes: Record<string, string>;
|
|
107
|
+
commitment_mode: 'automatic' | 'review' | 'review_above_cap';
|
|
108
|
+
/** Required, together with `above_cap_approvers`, iff `commitment_mode === "review_above_cap"`. */
|
|
109
|
+
above_cap_caps?: Record<string, number>;
|
|
110
|
+
above_cap_approvers?: string[];
|
|
111
|
+
/**
|
|
112
|
+
* Present iff the mandate carries an encrypted-intent disclosure object
|
|
113
|
+
* (companion spec `intent-disclosure@0.1`) — `sha256:`-prefixed hash
|
|
114
|
+
* binding `intent_ciphertext` + `approvers_frozen` into the signed payload.
|
|
115
|
+
*/
|
|
116
|
+
intent_disclosure_hash?: string;
|
|
117
|
+
/** Signed identity-assurance block, one entry per owner — present iff the
|
|
118
|
+
* Mandate Owner disclosed identity. */
|
|
119
|
+
subjects?: Subject[];
|
|
143
120
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* it; verifiers MAY ignore it on artifacts that carry it. Kept readable for
|
|
148
|
-
* audit of pre-0.6 artifacts only.
|
|
121
|
+
* The owner's narrowing of the profile's `disclose_fields` list (new in
|
|
122
|
+
* v0.7) — a subset of the profile's own list. See *Ticket Disclosure Is
|
|
123
|
+
* Declared*.
|
|
149
124
|
*/
|
|
150
|
-
|
|
125
|
+
disclose_fields?: string[];
|
|
126
|
+
issued_at: number;
|
|
127
|
+
expires_at: number;
|
|
151
128
|
}
|
|
152
129
|
|
|
153
|
-
export interface
|
|
154
|
-
header:
|
|
155
|
-
payload:
|
|
130
|
+
export interface Mandate {
|
|
131
|
+
header: MandateHeader;
|
|
132
|
+
payload: MandatePayload;
|
|
133
|
+
/** base64url (no padding) Ed25519 signature over the JCS-canonical payload. */
|
|
156
134
|
signature: string;
|
|
157
135
|
}
|
|
158
136
|
|
|
@@ -191,25 +169,13 @@ export interface FieldConstraint {
|
|
|
191
169
|
}
|
|
192
170
|
|
|
193
171
|
/**
|
|
194
|
-
*
|
|
195
|
-
*/
|
|
196
|
-
export interface ProfileFrameField {
|
|
197
|
-
type: 'string' | 'number';
|
|
198
|
-
required: boolean;
|
|
199
|
-
description?: string;
|
|
200
|
-
constraint?: FieldConstraint;
|
|
201
|
-
enum?: string[];
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Bound enforcement semantics — how a v0.4 bound is checked.
|
|
172
|
+
* Bound enforcement semantics — how a bound is checked.
|
|
206
173
|
*
|
|
207
|
-
* Every bounds field in a
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* dispatch sites.
|
|
174
|
+
* Every bounds field in a profile declares a `boundType` so the AS and
|
|
175
|
+
* hap-core gatekeeper can dispatch on it directly, without parsing field
|
|
176
|
+
* names or guessing conventions. This is the single source of truth for
|
|
177
|
+
* "what does this bound mean at enforcement time" — if a new kind is needed,
|
|
178
|
+
* add a variant here and update the dispatch sites.
|
|
213
179
|
*
|
|
214
180
|
* See `ProfileBoundsField.boundType`.
|
|
215
181
|
*/
|
|
@@ -219,46 +185,45 @@ export type BoundType =
|
|
|
219
185
|
* satisfy `execution[of] <= bound` for the current call. No cumulative
|
|
220
186
|
* tracking. Used by: amount_max, recipient_max, booking_duration_max, etc.
|
|
221
187
|
*
|
|
222
|
-
* `requiredFor`
|
|
223
|
-
*
|
|
188
|
+
* `requiredFor` closes the converse: without it, a call that does not
|
|
189
|
+
* carry `of` at all is simply skipped — a 5,000 cap refuses 6,000 but
|
|
224
190
|
* permits a call that declares no value whatsoever, which is indistinguishable
|
|
225
|
-
* from an unenforced bound.
|
|
226
|
-
* `
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
* skip-on-absence behaviour is unchanged. Meaningful only on
|
|
232
|
-
* `per_transaction`; the other `BoundType` kinds have no per-call "value
|
|
233
|
-
* exposed or not" question — `cumulative_sum`/`cumulative_count` always read
|
|
234
|
-
* from the execution log regardless of what this call declares, and `enum`
|
|
235
|
-
* is a capability flag, not a runtime value — so the field does not exist
|
|
236
|
-
* on those variants and a profile that puts it there has it silently
|
|
237
|
-
* ignored by every enforcement point (TypeScript also refuses it when the
|
|
238
|
-
* profile is authored against this type rather than raw JSON).
|
|
191
|
+
* from an unenforced bound. Values are drawn from the profile's
|
|
192
|
+
* `boundsSchema.actionTypes` registry. For a listed `action_type`, an
|
|
193
|
+
* execution whose context lacks `of` — or whose value is not a finite
|
|
194
|
+
* number — MUST be refused rather than skipped. `appliesTo` MUST NOT be
|
|
195
|
+
* declared on a `per_transaction` bound (protocol.md → Bounds Schema rule 7)
|
|
196
|
+
* — it applies wherever `of` is present in the execution context.
|
|
239
197
|
*/
|
|
240
198
|
| { kind: 'per_transaction'; of: string; requiredFor?: string[] }
|
|
241
199
|
/**
|
|
242
|
-
* Cumulative sum within a time window. The
|
|
243
|
-
* of `execution[of]` across all prior
|
|
200
|
+
* Cumulative sum within a time window. The AS maintains a running sum
|
|
201
|
+
* of `execution[of]` across all prior tickets in the window; the
|
|
244
202
|
* current call is approved iff `running_sum + execution[of] <= bound`.
|
|
245
|
-
*
|
|
203
|
+
* AS-only enforcement (protocol.md → *Enforcement Authority*); the
|
|
204
|
+
* Gatekeeper MUST NOT enforce this locally. Used by: amount_daily_max,
|
|
205
|
+
* spend_monthly_max, etc.
|
|
246
206
|
*/
|
|
247
207
|
| { kind: 'cumulative_sum'; of: string; window: CumulativeWindow }
|
|
248
208
|
/**
|
|
249
|
-
* Cumulative count within a time window. Every qualifying
|
|
209
|
+
* Cumulative count within a time window. Every qualifying ticket
|
|
250
210
|
* counts as +1; the current call is approved iff
|
|
251
211
|
* `running_count + 1 <= bound`. No execution context field is read.
|
|
252
|
-
*
|
|
212
|
+
* AS-only enforcement. `appliesTo` is REQUIRED on a profile published
|
|
213
|
+
* under v0.7 or later (Bounds Schema rule 7) — absence would mean
|
|
214
|
+
* "governs every action type", so a forgotten declaration silently
|
|
215
|
+
* throttles every action. Used by: write_daily_max, post_monthly_max,
|
|
216
|
+
* booking_daily_max, etc.
|
|
253
217
|
*/
|
|
254
218
|
| { kind: 'cumulative_count'; window: CumulativeWindow }
|
|
255
219
|
/**
|
|
256
220
|
* String bound restricted to a fixed set of allowed values. The bound's
|
|
257
|
-
* value must be one of `values` at
|
|
221
|
+
* value must be one of `values` at mandate time. The gateway
|
|
258
222
|
* tool-proxy gates tool calls based on the stored bound (via the
|
|
259
223
|
* integration manifest's `boundField` + `requiredValue`). Not cumulated,
|
|
260
|
-
* not checked by the
|
|
261
|
-
*
|
|
224
|
+
* not checked by the AS ticket route — it's a capability flag.
|
|
225
|
+
* `appliesTo` MUST NOT be declared here (it is a capability flag, not an
|
|
226
|
+
* action-scoped limit). Used by: read_access, delete_access, archive_access.
|
|
262
227
|
*/
|
|
263
228
|
| { kind: 'enum'; values: readonly string[] };
|
|
264
229
|
|
|
@@ -279,11 +244,11 @@ export type FieldUnit =
|
|
|
279
244
|
| 'percent';
|
|
280
245
|
|
|
281
246
|
/**
|
|
282
|
-
* Bounds field definition within a
|
|
247
|
+
* Bounds field definition within a profile.
|
|
283
248
|
*
|
|
284
|
-
*
|
|
285
|
-
* the bound is enforced.
|
|
286
|
-
*
|
|
249
|
+
* Every non-metadata bounds field MUST declare `boundType` — an explicit
|
|
250
|
+
* declaration of how the bound is enforced. Implementations MUST fail
|
|
251
|
+
* closed on any bounds field that omits it (Bounds Schema rule 2).
|
|
287
252
|
*/
|
|
288
253
|
export interface ProfileBoundsField {
|
|
289
254
|
type: 'string' | 'number';
|
|
@@ -291,26 +256,18 @@ export interface ProfileBoundsField {
|
|
|
291
256
|
description?: string;
|
|
292
257
|
displayName?: string;
|
|
293
258
|
format?: 'email' | 'domain' | 'url' | 'currency';
|
|
294
|
-
/**
|
|
295
|
-
* v0.4 enforcement semantics. Required for all new profiles.
|
|
296
|
-
* Optional here only so the type stays backward compatible with v0.3
|
|
297
|
-
* profiles that predate the boundType convention — consumers must
|
|
298
|
-
* treat a missing boundType as an error when running in v0.4 mode.
|
|
299
|
-
*/
|
|
259
|
+
/** Enforcement semantics. REQUIRED on every bounds field except `profile`. */
|
|
300
260
|
boundType?: BoundType;
|
|
301
261
|
/**
|
|
302
262
|
* Which execution action types this bound governs, e.g. `["write"]`.
|
|
303
263
|
*
|
|
304
|
-
* When present, this is authoritative. When absent,
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
* `
|
|
309
|
-
* is
|
|
310
|
-
*
|
|
311
|
-
* Declaring it removes the guess. Deliberately additive: profiles migrate one
|
|
312
|
-
* at a time, and every remaining fallback is logged, so the cases still
|
|
313
|
-
* relying on the naming convention become visible instead of staying silent.
|
|
264
|
+
* When present, this is authoritative. When absent, a `cumulative_sum` bound
|
|
265
|
+
* (or any bound on a profile published before v0.7) governs every action
|
|
266
|
+
* type in the profile's `actionTypes` registry; a `cumulative_count` bound
|
|
267
|
+
* on a v0.7+ profile MUST declare it (Bounds Schema rule 7). MUST NOT be
|
|
268
|
+
* declared on a `per_transaction` bound (it applies wherever its `of`
|
|
269
|
+
* field is present in the execution context) or on an `enum` bound (a
|
|
270
|
+
* capability flag, not an action-scoped limit).
|
|
314
271
|
*/
|
|
315
272
|
appliesTo?: string[];
|
|
316
273
|
/**
|
|
@@ -333,19 +290,15 @@ export interface ProfileBoundsField {
|
|
|
333
290
|
* min(value, maximum). Absent → no ceiling.
|
|
334
291
|
*/
|
|
335
292
|
maximum?: number;
|
|
336
|
-
/** @deprecated v0.4: use boundType instead. */
|
|
337
|
-
constraint?: FieldConstraint;
|
|
338
|
-
/** @deprecated v0.4: use boundType: { kind: 'enum', values: [...] }. */
|
|
339
|
-
enum?: string[];
|
|
340
293
|
}
|
|
341
294
|
|
|
342
295
|
/**
|
|
343
296
|
* v0.5 Content Provenance — how a profile's action content is hashed into a
|
|
344
|
-
* signed
|
|
297
|
+
* signed ticket (`contentHash`). The ephemeral-content analog of Output
|
|
345
298
|
* Provenance: it binds the *bytes* of the action rather than a location.
|
|
346
299
|
*
|
|
347
300
|
* Profile-bound and OPTIONAL. Absent → no content hash is produced (full
|
|
348
|
-
* backward compatibility). The gateway computes the hash; the
|
|
301
|
+
* backward compatibility). The gateway computes the hash; the AS only ever
|
|
349
302
|
* receives the hash, never the content, so HAP's privacy-minimal design holds.
|
|
350
303
|
*
|
|
351
304
|
* At `version:"1"` the profile declares only the *policy* — whether to bind and
|
|
@@ -409,16 +362,17 @@ export interface ContentBinding {
|
|
|
409
362
|
}
|
|
410
363
|
|
|
411
364
|
/**
|
|
412
|
-
*
|
|
365
|
+
* Scope field definition within a profile (renamed from `ProfileContextField`
|
|
366
|
+
* in v0.7 — protocol.md → *Migration from v0.6*, `contextSchema` → `scopeSchema`).
|
|
413
367
|
*/
|
|
414
|
-
export interface
|
|
368
|
+
export interface ProfileScopeField {
|
|
415
369
|
type: 'string' | 'number';
|
|
416
370
|
required: boolean;
|
|
417
371
|
description?: string;
|
|
418
372
|
displayName?: string;
|
|
419
373
|
format?: 'email' | 'domain' | 'url' | 'currency';
|
|
420
374
|
/**
|
|
421
|
-
*
|
|
375
|
+
* What this field NAMES on the read path. `counterparty` = the other
|
|
422
376
|
* party to a communication (matched against an item's participants);
|
|
423
377
|
* `resource` = the container an item belongs to (a direct attribute match —
|
|
424
378
|
* and a resource scope enforced on writes MUST also bind reads). Absent →
|
|
@@ -427,7 +381,6 @@ export interface ProfileContextField {
|
|
|
427
381
|
*/
|
|
428
382
|
scopeKind?: 'counterparty' | 'resource';
|
|
429
383
|
constraint?: FieldConstraint;
|
|
430
|
-
enum?: string[];
|
|
431
384
|
}
|
|
432
385
|
|
|
433
386
|
/**
|
|
@@ -446,13 +399,11 @@ export interface DeclaredFieldDef {
|
|
|
446
399
|
export type CumulativeWindow = 'daily' | 'weekly' | 'monthly';
|
|
447
400
|
|
|
448
401
|
/**
|
|
449
|
-
* Execution context field definition — cumulative source (resolved from
|
|
402
|
+
* Execution context field definition — cumulative source (resolved from the
|
|
403
|
+
* AS's ticket history; see protocol.md → *Cumulative State*).
|
|
450
404
|
*
|
|
451
|
-
* The gatekeeper resolves these by querying the execution log:
|
|
452
405
|
* - `cumulativeField`: which declared field to sum (use "_count" for plain counting)
|
|
453
406
|
* - `window`: time window for aggregation (daily, weekly, monthly)
|
|
454
|
-
*
|
|
455
|
-
* The resolved value = running total within window + current call value.
|
|
456
407
|
*/
|
|
457
408
|
export interface CumulativeFieldDef {
|
|
458
409
|
source: 'cumulative';
|
|
@@ -469,28 +420,8 @@ export interface CumulativeFieldDef {
|
|
|
469
420
|
export type ExecutionContextFieldDef = DeclaredFieldDef | CumulativeFieldDef;
|
|
470
421
|
|
|
471
422
|
/**
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*/
|
|
475
|
-
export interface GateQuestion {
|
|
476
|
-
question: string;
|
|
477
|
-
required: boolean;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* @deprecated Execution paths removed in v0.4. Kept for backward compatibility.
|
|
482
|
-
*/
|
|
483
|
-
export interface ExecutionPath {
|
|
484
|
-
description: string;
|
|
485
|
-
requiredDomains?: string[];
|
|
486
|
-
ttl?: { default: number; max: number };
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* Agent Profile — defines constraint types, execution paths, gate questions,
|
|
491
|
-
* and the frame/bounds/context schemas for bounded execution.
|
|
492
|
-
*
|
|
493
|
-
* Supports both v0.3 (frameSchema) and v0.4 (boundsSchema + contextSchema).
|
|
423
|
+
* Agent Profile — defines the bounds/scope/execution-context schemas, gates,
|
|
424
|
+
* TTL policy, and retention for a bounded authority (protocol.md → *Profiles*).
|
|
494
425
|
*/
|
|
495
426
|
/**
|
|
496
427
|
* A commitment mode a person can choose when signing a mandate. (`review_above_cap`
|
|
@@ -498,6 +429,14 @@ export interface ExecutionPath {
|
|
|
498
429
|
*/
|
|
499
430
|
export type SignableCommitmentMode = 'automatic' | 'review';
|
|
500
431
|
|
|
432
|
+
/** protocol.md → *Owner Signatures* → "Where the requirement lives" — the
|
|
433
|
+
* profile-floor tier: `minBinding` names the weakest `OwnerSignatureBinding`
|
|
434
|
+
* this profile accepts for a co-signing owner. */
|
|
435
|
+
export interface ProfileOwnerSignatureFloor {
|
|
436
|
+
required: boolean;
|
|
437
|
+
minBinding?: OwnerSignatureBinding;
|
|
438
|
+
}
|
|
439
|
+
|
|
501
440
|
export interface AgentProfile {
|
|
502
441
|
id: string;
|
|
503
442
|
name?: string;
|
|
@@ -520,9 +459,10 @@ export interface AgentProfile {
|
|
|
520
459
|
whatsNew?: string;
|
|
521
460
|
|
|
522
461
|
/**
|
|
523
|
-
* Whether
|
|
524
|
-
* verifier holding the content supplies its hash and learns which
|
|
525
|
-
* bind it, without needing a
|
|
462
|
+
* Whether tickets under this profile may be looked up BY THEIR CONTENT — a
|
|
463
|
+
* verifier holding the content supplies its hash and learns which tickets
|
|
464
|
+
* bind it, without needing a ticket id. (Renamed from `receipt_lookup` in
|
|
465
|
+
* v0.7.)
|
|
526
466
|
*
|
|
527
467
|
* OFF unless declared, and that default is the point. The lookup is a
|
|
528
468
|
* confirmation oracle: given a guess at the content it says whether that
|
|
@@ -534,13 +474,8 @@ export interface AgentProfile {
|
|
|
534
474
|
* Enable only when the bound content is unguessable enough that producing it
|
|
535
475
|
* is equivalent to already having it: prose, an artifact URL, a whole record
|
|
536
476
|
* payload. Never for a binding over a short value drawn from a small set.
|
|
537
|
-
*
|
|
538
|
-
* Why it must exist at all: most consequential actions cannot carry their
|
|
539
|
-
* receipt id. A released build was built before the receipt existed, a
|
|
540
|
-
* content-addressed artifact would change identity if the id were added, and
|
|
541
|
-
* a forwarded message has usually lost the footer that carried it.
|
|
542
477
|
*/
|
|
543
|
-
|
|
478
|
+
ticket_lookup?: boolean;
|
|
544
479
|
|
|
545
480
|
/**
|
|
546
481
|
* The commitment modes a mandate under this profile may be signed with.
|
|
@@ -556,22 +491,14 @@ export interface AgentProfile {
|
|
|
556
491
|
commitment_modes?: readonly SignableCommitmentMode[];
|
|
557
492
|
|
|
558
493
|
/**
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*/
|
|
562
|
-
frameSchema?: {
|
|
563
|
-
keyOrder: string[];
|
|
564
|
-
fields: Record<string, ProfileFrameField>;
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
* v0.4 bounds schema — defines the authorization bounds parameters.
|
|
494
|
+
* The bounds schema — the enforceable parameters (protocol.md → *Bounds
|
|
495
|
+
* Schema*).
|
|
569
496
|
*/
|
|
570
497
|
boundsSchema?: {
|
|
571
498
|
keyOrder: string[];
|
|
572
499
|
fields: Record<string, ProfileBoundsField>;
|
|
573
500
|
/**
|
|
574
|
-
*
|
|
501
|
+
* Registry of the action types this profile recognizes (e.g.
|
|
575
502
|
* `["send", "delete", "setup"]`). Every `execution.action_type` the
|
|
576
503
|
* Authority Server and gateway accept for this profile MUST be a member
|
|
577
504
|
* when the registry is declared (protocol.md → Bounds Schema, rule 2);
|
|
@@ -583,96 +510,48 @@ export interface AgentProfile {
|
|
|
583
510
|
};
|
|
584
511
|
|
|
585
512
|
/**
|
|
586
|
-
*
|
|
587
|
-
* May be absent or empty for profiles with
|
|
513
|
+
* The scope schema — operational scoping fields that stay local (renamed
|
|
514
|
+
* from `contextSchema` in v0.7). May be absent or empty for profiles with
|
|
515
|
+
* no static scope.
|
|
588
516
|
*/
|
|
589
|
-
|
|
517
|
+
scopeSchema?: {
|
|
590
518
|
keyOrder: string[];
|
|
591
|
-
fields: Record<string,
|
|
519
|
+
fields: Record<string, ProfileScopeField>;
|
|
592
520
|
};
|
|
593
521
|
|
|
594
522
|
executionContextSchema: {
|
|
595
523
|
fields: Record<string, ExecutionContextFieldDef>;
|
|
596
524
|
};
|
|
597
525
|
|
|
598
|
-
/** @deprecated Execution paths removed in v0.4. Kept for backward compatibility. */
|
|
599
|
-
executionPaths?: Record<string, ExecutionPath>;
|
|
600
|
-
|
|
601
526
|
requiredGates: string[];
|
|
602
527
|
|
|
603
|
-
/**
|
|
604
|
-
* v0.4: no gateQuestions — intent prompt is universal, defined in the gateway UI.
|
|
605
|
-
* v0.3: profile-specific gate questions (deprecated).
|
|
606
|
-
*/
|
|
607
|
-
gateQuestions?: {
|
|
608
|
-
problem?: GateQuestion;
|
|
609
|
-
objective?: GateQuestion;
|
|
610
|
-
tradeoffs?: GateQuestion;
|
|
611
|
-
};
|
|
612
|
-
|
|
613
528
|
ttl: { default: number; max: number };
|
|
614
529
|
retention_minimum: number;
|
|
615
530
|
|
|
616
531
|
/**
|
|
617
|
-
*
|
|
532
|
+
* Content Provenance (OPTIONAL, profile-bound). When present, the
|
|
618
533
|
* gateway computes a `contentHash` for gated writes under this profile and
|
|
619
|
-
* passes it (hash only) to the
|
|
534
|
+
* passes it (hash only) to the AS, which signs it into the ticket. Absent
|
|
620
535
|
* → no content hash. See {@link ContentBinding}.
|
|
621
536
|
*/
|
|
622
537
|
content_binding?: ContentBinding;
|
|
623
538
|
|
|
624
539
|
/**
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
540
|
+
* The execution-context fields a ticket under this profile MAY disclose
|
|
541
|
+
* (new in v0.7 — protocol.md → *Ticket Disclosure Is Declared*). Absent →
|
|
542
|
+
* nothing is disclosed by default. A mandate's own `disclose_fields` (when
|
|
543
|
+
* present) MUST be a subset of this list — a mandate may narrow disclosure,
|
|
544
|
+
* never widen it.
|
|
628
545
|
*/
|
|
629
|
-
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// ─── Tool Gating Types ───────────────────────────────────────────────────
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Available transforms for array-aware execution mappings.
|
|
636
|
-
* - length: array length → number
|
|
637
|
-
* - join: array items joined by comma → string
|
|
638
|
-
* - join_domains: extract email domains, deduplicate, sort, join → string
|
|
639
|
-
*/
|
|
640
|
-
export type ExecutionMappingTransform = 'join' | 'join_domains' | 'length';
|
|
641
|
-
|
|
642
|
-
/**
|
|
643
|
-
* Execution mapping value — how a tool argument maps to execution context field(s).
|
|
644
|
-
* - string: direct copy (argName → fieldName)
|
|
645
|
-
* - { field, divisor }: numeric division (e.g., cents ÷ 100 → EUR)
|
|
646
|
-
* - { field, transform }: array transform (e.g., join_domains)
|
|
647
|
-
* - Array form: one argument maps to multiple execution fields
|
|
648
|
-
*/
|
|
649
|
-
export type ExecutionMappingValue =
|
|
650
|
-
| string
|
|
651
|
-
| { field: string; divisor: number }
|
|
652
|
-
| { field: string; transform: ExecutionMappingTransform }
|
|
653
|
-
| Array<{ field: string; divisor?: number; transform?: ExecutionMappingTransform }>;
|
|
546
|
+
disclose_fields?: string[];
|
|
654
547
|
|
|
655
|
-
/**
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
staticExecution?: Record<string, string | number>;
|
|
663
|
-
/** Read-only tools: require authorization but no execution context checks */
|
|
664
|
-
category?: 'read';
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/**
|
|
668
|
-
* Profile-level tool gating configuration.
|
|
669
|
-
* - default: applied to all tools not listed in overrides
|
|
670
|
-
* - overrides: per-tool configs keyed by original MCP tool name
|
|
671
|
-
* Use { category: "read" } for read-only tools (null is deprecated)
|
|
672
|
-
*/
|
|
673
|
-
export interface ProfileToolGating {
|
|
674
|
-
default: ProfileToolGatingEntry;
|
|
675
|
-
overrides?: Record<string, ProfileToolGatingEntry | null>;
|
|
548
|
+
/**
|
|
549
|
+
* Profile-floor requirement for an owner signature on a mandate under this
|
|
550
|
+
* profile (protocol.md → *Owner Signatures* → "Where the requirement
|
|
551
|
+
* lives"). Reserved for domains that cannot mean anything without a
|
|
552
|
+
* signature — used more freely it forks `charge` from `charge-with-cosign`.
|
|
553
|
+
*/
|
|
554
|
+
ownerSignature?: ProfileOwnerSignatureFloor;
|
|
676
555
|
}
|
|
677
556
|
|
|
678
557
|
// ─── Execution Log Types ─────────────────────────────────────────────────────
|
|
@@ -719,25 +598,20 @@ export interface ExecutionLogQuery {
|
|
|
719
598
|
): number;
|
|
720
599
|
}
|
|
721
600
|
|
|
722
|
-
// ───
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* Agent frame parameters — mixed types (strings and numbers).
|
|
726
|
-
* Keys and values come from the profile's frameSchema.
|
|
727
|
-
*/
|
|
728
|
-
export type AgentFrameParams = Record<string, string | number>;
|
|
601
|
+
// ─── Bounds / Scope param types ──────────────────────────────────────────────
|
|
729
602
|
|
|
730
603
|
/**
|
|
731
604
|
* Agent bounds parameters — mixed types (strings and numbers).
|
|
732
|
-
* Keys and values come from the profile's boundsSchema
|
|
605
|
+
* Keys and values come from the profile's boundsSchema.
|
|
733
606
|
*/
|
|
734
607
|
export type AgentBoundsParams = Record<string, string | number>;
|
|
735
608
|
|
|
736
609
|
/**
|
|
737
|
-
* Agent
|
|
738
|
-
*
|
|
610
|
+
* Agent scope parameters — mixed types (strings and numbers). Keys and
|
|
611
|
+
* values come from the profile's scopeSchema (renamed from
|
|
612
|
+
* `AgentContextParams` in v0.7).
|
|
739
613
|
*/
|
|
740
|
-
export type
|
|
614
|
+
export type AgentScopeParams = Record<string, string | number>;
|
|
741
615
|
|
|
742
616
|
// ─── Gatekeeper Types ────────────────────────────────────────────────────────
|
|
743
617
|
|
|
@@ -745,60 +619,33 @@ export type AgentContextParams = Record<string, string | number>;
|
|
|
745
619
|
* Request to the Gatekeeper for bounded execution verification.
|
|
746
620
|
*/
|
|
747
621
|
export interface GatekeeperRequest {
|
|
748
|
-
/** The
|
|
749
|
-
|
|
750
|
-
/**
|
|
751
|
-
|
|
752
|
-
/** The agent's execution values for this specific action */
|
|
622
|
+
/** The bounds the mandate(s) committed to. */
|
|
623
|
+
bounds: AgentBoundsParams;
|
|
624
|
+
/** Mandate blobs (base64url) to verify against. */
|
|
625
|
+
mandates: string[];
|
|
626
|
+
/** The agent's execution values for this specific action. */
|
|
753
627
|
execution: Record<string, string | number>;
|
|
754
|
-
/**
|
|
755
|
-
|
|
628
|
+
/** Scope parameters (currency, action_type, allowed recipients, etc.) —
|
|
629
|
+
* enforced locally only; never sent to the Authority Server. */
|
|
630
|
+
scope?: AgentScopeParams;
|
|
756
631
|
/**
|
|
757
|
-
* Authorization path used to scope cumulative lookups in the execution log
|
|
758
|
-
*
|
|
759
|
-
*
|
|
760
|
-
* profile's boundsSchema, so an extra key there is rejected as an unknown
|
|
761
|
-
* field and breaks attestation verification outright. Cumulative checks
|
|
762
|
-
* previously read the path from the frame, where callers cannot legally put
|
|
763
|
-
* it — so it resolved to "" while the log stored real paths, no entry ever
|
|
764
|
-
* matched, and every running total read zero. The local gate existed but
|
|
765
|
-
* could never fire.
|
|
632
|
+
* Authorization path used to scope cumulative lookups in the execution log
|
|
633
|
+
* (display only — see {@link ExecutionLogQuery}; the Gatekeeper MUST NOT
|
|
634
|
+
* enforce cumulative bounds locally, protocol.md → *Enforcement Authority*).
|
|
766
635
|
*/
|
|
767
636
|
path?: string;
|
|
768
637
|
}
|
|
769
638
|
|
|
770
639
|
/**
|
|
771
|
-
* Structured error from Gatekeeper verification.
|
|
640
|
+
* Structured error from Gatekeeper verification. Codes are the canonical
|
|
641
|
+
* v0.7 surface ({@link HapErrorCode}, `src/errors.ts`) plus the two
|
|
642
|
+
* Gatekeeper-local-only codes that never reach the wire (`FRAME_MISMATCH`
|
|
643
|
+
* is retired with v0.3; a Gatekeeper reports `BOUNDS_HASH_MISMATCH` /
|
|
644
|
+
* `SCOPE_HASH_MISMATCH` for both its own local mismatch and the AS's wire
|
|
645
|
+
* refusal, per protocol.md → *Error Codes*, "Gatekeeper · local").
|
|
772
646
|
*/
|
|
773
647
|
export interface GatekeeperError {
|
|
774
|
-
code:
|
|
775
|
-
| 'BOUND_EXCEEDED'
|
|
776
|
-
| 'CUMULATIVE_LIMIT_EXCEEDED'
|
|
777
|
-
| 'INVALID_SIGNATURE'
|
|
778
|
-
| 'TTL_EXPIRED'
|
|
779
|
-
| 'FRAME_MISMATCH'
|
|
780
|
-
| 'BOUNDS_MISMATCH'
|
|
781
|
-
| 'CONTEXT_MISMATCH'
|
|
782
|
-
| 'DOMAIN_NOT_COVERED'
|
|
783
|
-
| 'INVALID_PROFILE'
|
|
784
|
-
| 'MALFORMED_ATTESTATION'
|
|
785
|
-
// v0.5/v0.6 receipt-path codes a Gatekeeper must recognize as definitive
|
|
786
|
-
// rejections (protocol.md → Pre-flight Receipt Request):
|
|
787
|
-
| 'INVALID_ACTION_TYPE'
|
|
788
|
-
| 'ATTESTATION_REVOKED'
|
|
789
|
-
| 'APPROVAL_REQUIRED'
|
|
790
|
-
| 'IDEMPOTENCY_MISMATCH'
|
|
791
|
-
// v0.6 owner-mandate codes (protocol.md → Owner Mandate Signatures):
|
|
792
|
-
| 'MANDATE_SIGNATURE_REQUIRED'
|
|
793
|
-
| 'MANDATE_SIGNATURE_INVALID'
|
|
794
|
-
| 'APPROVAL_SIGNATURE_REQUIRED'
|
|
795
|
-
| 'APPROVAL_SIGNATURE_INVALID'
|
|
796
|
-
// Canonicalization refusals (protocol.md → Bounds & Scope Canonicalization
|
|
797
|
-
// → Value encoding). Raised when a value cannot be canonicalized at all —
|
|
798
|
-
// a raw LF/CR, or a profile `constraint.pattern` violation. Distinct from
|
|
799
|
-
// BOUNDS_MISMATCH / CONTEXT_MISMATCH, which mean the hashes disagree.
|
|
800
|
-
| 'BOUNDS_INVALID_VALUE'
|
|
801
|
-
| 'CONTEXT_INVALID_VALUE';
|
|
648
|
+
code: import('./errors').HapErrorCode;
|
|
802
649
|
field?: string;
|
|
803
650
|
message: string;
|
|
804
651
|
bound?: string | number;
|