@suveren/gateway 0.35.1 → 0.36.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.
@@ -14,7 +14,7 @@
14
14
  <meta name="apple-mobile-web-app-title" content="Suveren" />
15
15
  <meta name="theme-color" content="#111111" />
16
16
  <title>Suveren</title>
17
- <script type="module" crossorigin src="/assets/index-BHxzXFpf.js"></script>
17
+ <script type="module" crossorigin src="/assets/index-BQ5Pr6As.js"></script>
18
18
  <link rel="stylesheet" crossorigin href="/assets/index-XiOgY6b5.css">
19
19
  </head>
20
20
  <body>
@@ -43,3 +43,10 @@ export declare function buildWindowsTaskXml(opts: {
43
43
  command?: string;
44
44
  args?: string;
45
45
  }): string;
46
+ export declare function declaredDataDir(definitionText: string): string | null;
47
+ export declare function serviceOwnsInstall(opts: {
48
+ definitionText: string | null;
49
+ dataDir: string;
50
+ envDataDir: string | undefined;
51
+ same: (a: string, b: string) => boolean;
52
+ }): boolean;
@@ -244,3 +244,33 @@ ${principalUser} <LogonType>InteractiveToken</LogonType>
244
244
  </Task>
245
245
  `;
246
246
  }
247
+
248
+ /**
249
+ * The data folder a login-service definition (launchd plist or systemd unit,
250
+ * as built above) pins with SUVEREN_DATA_DIR — or null when it pins none (the
251
+ * service then resolves the folder the default way, without that variable).
252
+ */
253
+ export function declaredDataDir(definitionText) {
254
+ const plist = /<key>SUVEREN_DATA_DIR<\/key>\s*<string>([^<]*)<\/string>/.exec(definitionText);
255
+ if (plist) return plist[1];
256
+ const unit = /Environment="SUVEREN_DATA_DIR=([^"]*)"/.exec(definitionText);
257
+ return unit ? unit[1] : null;
258
+ }
259
+
260
+ /**
261
+ * Does the login service run THIS installation (the one the CLI resolved)?
262
+ * A second gateway under the same OS user — its own SUVEREN_DATA_DIR and
263
+ * ports — must never stop, restart or replace the other one's service
264
+ * (2026-10-19: a test gateway's `restart` restarted the real one and locked it).
265
+ *
266
+ * @param definitionText the service definition, or null if there is none / it is unreadable
267
+ * @param dataDir the data folder this CLI resolved
268
+ * @param envDataDir process.env.SUVEREN_DATA_DIR of this CLI
269
+ * @param same path comparison (normalising)
270
+ */
271
+ export function serviceOwnsInstall({ definitionText, dataDir, envDataDir, same }) {
272
+ if (definitionText == null) return !envDataDir;
273
+ const declared = declaredDataDir(definitionText);
274
+ if (declared) return same(declared, dataDir);
275
+ return !envDataDir;
276
+ }
@@ -384,7 +384,23 @@ interface ContentBinding {
384
384
  * Absent → the binding applies to every gated action under the profile.
385
385
  */
386
386
  appliesTo?: string[];
387
+ /**
388
+ * v2 only — what kind of value each bound field holds, so a verifier (or any
389
+ * view) can collect and show it without guessing from the field's name:
390
+ * - `text` — one string (an email body);
391
+ * - `list` — an array of strings (recipients);
392
+ * - `files` — the sealed fingerprints of documents sent by reference:
393
+ * `[{ filename, sha256 }]` — never the bytes. A verifier asks for the
394
+ * files themselves and computes each SHA-256 locally.
395
+ *
396
+ * A hint only: it never changes what is hashed. Keys MUST be a subset of
397
+ * {@link fields}; a field without an entry is unspecified (a verifier may
398
+ * offer a choice, as before).
399
+ */
400
+ field_kinds?: Record<string, ContentFieldKind>;
387
401
  }
402
+ /** See {@link ContentBinding.field_kinds}. */
403
+ type ContentFieldKind = 'text' | 'list' | 'files';
388
404
  /**
389
405
  * Scope field definition within a profile (renamed from `ProfileContextField`
390
406
  * in v0.7 — protocol.md → *Migration from v0.6*, `contextSchema` → `scopeSchema`).
@@ -831,6 +847,14 @@ declare function selectBoundFields(binding: ContentBinding, args: Record<string,
831
847
  * {@link selectBoundFields} + {@link computeContentHash} for the common path.
832
848
  */
833
849
  declare function computeFieldsContentHash(binding: ContentBinding, args: Record<string, unknown>): string;
850
+ /**
851
+ * Why a binding's `field_kinds` is malformed, or null when it is fine (or
852
+ * absent). For profile validation — a malformed hint is a profile error, not
853
+ * a call-time refusal, because it never changes what is hashed.
854
+ */
855
+ declare function invalidFieldKindsReason(binding: ContentBinding): string | null;
856
+ /** The bound fields declared as `files` — sealed document fingerprints. */
857
+ declare function filesFields(binding: ContentBinding): string[];
834
858
 
835
859
  /**
836
860
  * Intent hashing + intent-disclosure binding (HAP v0.5).
@@ -1477,4 +1501,4 @@ declare function decodeDidKey(did: string): Uint8Array;
1477
1501
  /** True iff the DID decodes as a key-bearing Ed25519 did:key. Never throws. */
1478
1502
  declare function isKeyBearingDid(did: string): boolean;
1479
1503
 
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 };
1504
+ export { type AgentBoundsParams, type AgentProfile, type AgentScopeParams, type ApprovalObject, type BoundType, CanonicalValueError, type ContentBinding, ContentBindingError, type ContentBindingErrorCode, type ContentFieldKind, 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, filesFields, fromBase64Url, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, invalidFieldKindsReason, 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 };
@@ -384,7 +384,23 @@ interface ContentBinding {
384
384
  * Absent → the binding applies to every gated action under the profile.
385
385
  */
386
386
  appliesTo?: string[];
387
+ /**
388
+ * v2 only — what kind of value each bound field holds, so a verifier (or any
389
+ * view) can collect and show it without guessing from the field's name:
390
+ * - `text` — one string (an email body);
391
+ * - `list` — an array of strings (recipients);
392
+ * - `files` — the sealed fingerprints of documents sent by reference:
393
+ * `[{ filename, sha256 }]` — never the bytes. A verifier asks for the
394
+ * files themselves and computes each SHA-256 locally.
395
+ *
396
+ * A hint only: it never changes what is hashed. Keys MUST be a subset of
397
+ * {@link fields}; a field without an entry is unspecified (a verifier may
398
+ * offer a choice, as before).
399
+ */
400
+ field_kinds?: Record<string, ContentFieldKind>;
387
401
  }
402
+ /** See {@link ContentBinding.field_kinds}. */
403
+ type ContentFieldKind = 'text' | 'list' | 'files';
388
404
  /**
389
405
  * Scope field definition within a profile (renamed from `ProfileContextField`
390
406
  * in v0.7 — protocol.md → *Migration from v0.6*, `contextSchema` → `scopeSchema`).
@@ -831,6 +847,14 @@ declare function selectBoundFields(binding: ContentBinding, args: Record<string,
831
847
  * {@link selectBoundFields} + {@link computeContentHash} for the common path.
832
848
  */
833
849
  declare function computeFieldsContentHash(binding: ContentBinding, args: Record<string, unknown>): string;
850
+ /**
851
+ * Why a binding's `field_kinds` is malformed, or null when it is fine (or
852
+ * absent). For profile validation — a malformed hint is a profile error, not
853
+ * a call-time refusal, because it never changes what is hashed.
854
+ */
855
+ declare function invalidFieldKindsReason(binding: ContentBinding): string | null;
856
+ /** The bound fields declared as `files` — sealed document fingerprints. */
857
+ declare function filesFields(binding: ContentBinding): string[];
834
858
 
835
859
  /**
836
860
  * Intent hashing + intent-disclosure binding (HAP v0.5).
@@ -1477,4 +1501,4 @@ declare function decodeDidKey(did: string): Uint8Array;
1477
1501
  /** True iff the DID decodes as a key-bearing Ed25519 did:key. Never throws. */
1478
1502
  declare function isKeyBearingDid(did: string): boolean;
1479
1503
 
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 };
1504
+ export { type AgentBoundsParams, type AgentProfile, type AgentScopeParams, type ApprovalObject, type BoundType, CanonicalValueError, type ContentBinding, ContentBindingError, type ContentBindingErrorCode, type ContentFieldKind, 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, filesFields, fromBase64Url, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, invalidFieldKindsReason, 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 };
@@ -65,10 +65,12 @@ __export(index_exports, {
65
65
  deriveIdentityLine: () => deriveIdentityLine,
66
66
  encodeDidKey: () => encodeDidKey,
67
67
  encodeMandateBlob: () => encodeMandateBlob,
68
+ filesFields: () => filesFields,
68
69
  fromBase64Url: () => fromBase64Url,
69
70
  getAllProfiles: () => getAllProfiles,
70
71
  getProfile: () => getProfile,
71
72
  intentDisclosureCanonicalBytes: () => intentDisclosureCanonicalBytes,
73
+ invalidFieldKindsReason: () => invalidFieldKindsReason,
72
74
  isCommitmentModeAllowed: () => isCommitmentModeAllowed,
73
75
  isFieldBinding: () => isFieldBinding,
74
76
  isKeyBearingDid: () => isKeyBearingDid,
@@ -315,6 +317,20 @@ function selectBoundFields(binding, args) {
315
317
  function computeFieldsContentHash(binding, args) {
316
318
  return computeContentHash(binding, selectBoundFields(binding, args));
317
319
  }
320
+ var FIELD_KINDS = /* @__PURE__ */ new Set(["text", "list", "files"]);
321
+ function invalidFieldKindsReason(binding) {
322
+ const kinds = binding.field_kinds;
323
+ if (kinds === void 0) return null;
324
+ if (!kinds || typeof kinds !== "object" || Array.isArray(kinds)) return "field_kinds must be an object";
325
+ for (const [field, kind] of Object.entries(kinds)) {
326
+ if (!(binding.fields ?? []).includes(field)) return `field_kinds names "${field}", which is not in fields`;
327
+ if (!FIELD_KINDS.has(kind)) return `field_kinds.${field} must be one of text, list, files`;
328
+ }
329
+ return null;
330
+ }
331
+ function filesFields(binding) {
332
+ return Object.entries(binding.field_kinds ?? {}).filter(([, k]) => k === "files").map(([f]) => f);
333
+ }
318
334
 
319
335
  // src/intent-disclosure.ts
320
336
  var import_crypto2 = require("crypto");
@@ -1359,10 +1375,12 @@ function checkScopeConstraints(scope, execution, profile) {
1359
1375
  deriveIdentityLine,
1360
1376
  encodeDidKey,
1361
1377
  encodeMandateBlob,
1378
+ filesFields,
1362
1379
  fromBase64Url,
1363
1380
  getAllProfiles,
1364
1381
  getProfile,
1365
1382
  intentDisclosureCanonicalBytes,
1383
+ invalidFieldKindsReason,
1366
1384
  isCommitmentModeAllowed,
1367
1385
  isFieldBinding,
1368
1386
  isKeyBearingDid,
@@ -214,6 +214,20 @@ function selectBoundFields(binding, args) {
214
214
  function computeFieldsContentHash(binding, args) {
215
215
  return computeContentHash(binding, selectBoundFields(binding, args));
216
216
  }
217
+ var FIELD_KINDS = /* @__PURE__ */ new Set(["text", "list", "files"]);
218
+ function invalidFieldKindsReason(binding) {
219
+ const kinds = binding.field_kinds;
220
+ if (kinds === void 0) return null;
221
+ if (!kinds || typeof kinds !== "object" || Array.isArray(kinds)) return "field_kinds must be an object";
222
+ for (const [field, kind] of Object.entries(kinds)) {
223
+ if (!(binding.fields ?? []).includes(field)) return `field_kinds names "${field}", which is not in fields`;
224
+ if (!FIELD_KINDS.has(kind)) return `field_kinds.${field} must be one of text, list, files`;
225
+ }
226
+ return null;
227
+ }
228
+ function filesFields(binding) {
229
+ return Object.entries(binding.field_kinds ?? {}).filter(([, k]) => k === "files").map(([f]) => f);
230
+ }
217
231
 
218
232
  // src/intent-disclosure.ts
219
233
  import { createHash as createHash2 } from "crypto";
@@ -1257,10 +1271,12 @@ export {
1257
1271
  deriveIdentityLine,
1258
1272
  encodeDidKey,
1259
1273
  encodeMandateBlob,
1274
+ filesFields,
1260
1275
  fromBase64Url,
1261
1276
  getAllProfiles,
1262
1277
  getProfile,
1263
1278
  intentDisclosureCanonicalBytes,
1279
+ invalidFieldKindsReason,
1264
1280
  isCommitmentModeAllowed,
1265
1281
  isFieldBinding,
1266
1282
  isKeyBearingDid,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humanagencyp/hap-core",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Core types, cryptographic primitives, and verification logic for the Human Agency Protocol",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
 
32
32
  import { createHash } from 'crypto';
33
33
  import { canonicalize } from './canonicalize';
34
- import type { ContentBinding } from './types';
34
+ import type { ContentBinding, ContentFieldKind } from './types';
35
35
 
36
36
  /**
37
37
  * Canonicalize free text per the v0.5 'text' rule. Idempotent.
@@ -249,3 +249,28 @@ export function computeFieldsContentHash(
249
249
  ): string {
250
250
  return computeContentHash(binding, selectBoundFields(binding, args));
251
251
  }
252
+
253
+ // ─── Field kinds (display / verification hint) ───────────────────────────────
254
+
255
+ const FIELD_KINDS = new Set<ContentFieldKind>(['text', 'list', 'files']);
256
+
257
+ /**
258
+ * Why a binding's `field_kinds` is malformed, or null when it is fine (or
259
+ * absent). For profile validation — a malformed hint is a profile error, not
260
+ * a call-time refusal, because it never changes what is hashed.
261
+ */
262
+ export function invalidFieldKindsReason(binding: ContentBinding): string | null {
263
+ const kinds = binding.field_kinds;
264
+ if (kinds === undefined) return null;
265
+ if (!kinds || typeof kinds !== 'object' || Array.isArray(kinds)) return 'field_kinds must be an object';
266
+ for (const [field, kind] of Object.entries(kinds)) {
267
+ if (!(binding.fields ?? []).includes(field)) return `field_kinds names "${field}", which is not in fields`;
268
+ if (!FIELD_KINDS.has(kind)) return `field_kinds.${field} must be one of text, list, files`;
269
+ }
270
+ return null;
271
+ }
272
+
273
+ /** The bound fields declared as `files` — sealed document fingerprints. */
274
+ export function filesFields(binding: ContentBinding): string[] {
275
+ return Object.entries(binding.field_kinds ?? {}).filter(([, k]) => k === 'files').map(([f]) => f);
276
+ }
@@ -359,8 +359,25 @@ export interface ContentBinding {
359
359
  * Absent → the binding applies to every gated action under the profile.
360
360
  */
361
361
  appliesTo?: string[];
362
+ /**
363
+ * v2 only — what kind of value each bound field holds, so a verifier (or any
364
+ * view) can collect and show it without guessing from the field's name:
365
+ * - `text` — one string (an email body);
366
+ * - `list` — an array of strings (recipients);
367
+ * - `files` — the sealed fingerprints of documents sent by reference:
368
+ * `[{ filename, sha256 }]` — never the bytes. A verifier asks for the
369
+ * files themselves and computes each SHA-256 locally.
370
+ *
371
+ * A hint only: it never changes what is hashed. Keys MUST be a subset of
372
+ * {@link fields}; a field without an entry is unspecified (a verifier may
373
+ * offer a choice, as before).
374
+ */
375
+ field_kinds?: Record<string, ContentFieldKind>;
362
376
  }
363
377
 
378
+ /** See {@link ContentBinding.field_kinds}. */
379
+ export type ContentFieldKind = 'text' | 'list' | 'files';
380
+
364
381
  /**
365
382
  * Scope field definition within a profile (renamed from `ProfileContextField`
366
383
  * in v0.7 — protocol.md → *Migration from v0.6*, `contextSchema` → `scopeSchema`).
@@ -7,7 +7,7 @@ let Root = require('./root')
7
7
 
8
8
  class Processor {
9
9
  constructor(plugins = []) {
10
- this.version = '8.5.30'
10
+ this.version = '8.5.31'
11
11
  this.plugins = this.normalize(plugins)
12
12
  }
13
13
 
@@ -10,8 +10,30 @@ function escapeHTMLInCSS(str) {
10
10
  return str.replace(STYLE_TAG, '\\3c $2').replace(COMMENT_OPEN, '\\3c $2')
11
11
  }
12
12
 
13
+ function cutEscaped(chunks, css, escaped) {
14
+ let parts = []
15
+ let at = 0
16
+ let into = 0
17
+ for (let i = 0; i < chunks.length; i += 3) {
18
+ let from = into
19
+ let end = at + chunks[i].length
20
+ while (at < end) {
21
+ if (css[at] === escaped[into]) {
22
+ at += 1
23
+ into += 1
24
+ } else {
25
+ // The `<` of this pair was replaced by the `\3c ` in front of it
26
+ at += 1
27
+ into += 4
28
+ }
29
+ }
30
+ parts.push(escaped.slice(from, into))
31
+ }
32
+ return parts
33
+ }
34
+
13
35
  class SafeStringifier extends Stringifier {
14
- escapeHTML(node, print) {
36
+ escapeHTML(print) {
15
37
  let builder = this.builder
16
38
  let chunks, css
17
39
  this.builder = (str, child, type) => {
@@ -39,20 +61,20 @@ class SafeStringifier extends Stringifier {
39
61
  builder(chunks[i], chunks[i + 1], chunks[i + 2])
40
62
  }
41
63
  } else {
42
- // Escaping happens only on a hack attempt, source map is not important.
43
- // Map only the node start: the end mapping expects the node’s last
44
- // char at the end of the string, which is wrong for Root raws.after.
45
- builder(escaped, node, 'start')
64
+ let parts = cutEscaped(chunks, css, escaped)
65
+ for (let i = 0; i < chunks.length; i += 3) {
66
+ builder(parts[i / 3], chunks[i + 1], chunks[i + 2])
67
+ }
46
68
  }
47
69
  }
48
70
 
49
71
  root(node) {
50
72
  if (node.parent && node.parent.type === 'document') {
51
73
  // Document raws around the Root hold markup and are kept as is since CSS in Document can be marked with <style>
52
- this.escapeHTML(node, () => this.body(node))
74
+ this.escapeHTML(() => this.body(node))
53
75
  if (node.raws.after) this.builder(node.raws.after)
54
76
  } else {
55
- this.escapeHTML(node, () => super.root(node))
77
+ this.escapeHTML(() => super.root(node))
56
78
  }
57
79
  }
58
80
  }
@@ -63,7 +85,7 @@ function stringify(node, builder) {
63
85
  if (node.type === 'root' || node.type === 'document') {
64
86
  str.stringify(node)
65
87
  } else {
66
- str.escapeHTML(node, () => str.stringify(node))
88
+ str.escapeHTML(() => str.stringify(node))
67
89
  }
68
90
  }
69
91
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postcss",
3
- "version": "8.5.30",
3
+ "version": "8.5.31",
4
4
  "description": "Tool for transforming styles with JS plugins",
5
5
  "keywords": [
6
6
  "css",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suveren/gateway",
3
- "version": "0.35.1",
3
+ "version": "0.36.0",
4
4
  "description": "Suveren gateway — local agent gateway built in compliance with the Human Agency Protocol (HAP). Runs the UI, control plane, and MCP server in one Node process.",
5
5
  "type": "module",
6
6
  "main": "server.js",