@beechcms/core 0.6.3 → 0.6.5

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 (49) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/content/demo-data.repository.d.ts +4 -2
  3. package/dist/content/demo-data.repository.d.ts.map +1 -1
  4. package/dist/content/demo-data.repository.js +0 -2
  5. package/dist/engine/ddl.d.ts +5 -0
  6. package/dist/engine/ddl.d.ts.map +1 -1
  7. package/dist/engine/ddl.js +38 -9
  8. package/dist/engine/policies.d.ts +52 -4
  9. package/dist/engine/policies.d.ts.map +1 -1
  10. package/dist/engine/policies.js +144 -14
  11. package/dist/engine/privacy.service.d.ts +65 -0
  12. package/dist/engine/privacy.service.d.ts.map +1 -0
  13. package/dist/engine/privacy.service.js +114 -0
  14. package/dist/engine/query.d.ts.map +1 -1
  15. package/dist/engine/query.js +22 -3
  16. package/dist/engine/seed-registry.d.ts.map +1 -1
  17. package/dist/engine/seed-registry.js +5 -0
  18. package/dist/engine/seed-validation.d.ts.map +1 -1
  19. package/dist/engine/seed-validation.js +25 -1
  20. package/dist/engine/sql-reserved-words.d.ts +2 -0
  21. package/dist/engine/sql-reserved-words.d.ts.map +1 -0
  22. package/dist/engine/sql-reserved-words.js +21 -0
  23. package/dist/engine/types.d.ts +11 -1
  24. package/dist/engine/types.d.ts.map +1 -1
  25. package/dist/engine/validation/index.d.ts.map +1 -1
  26. package/dist/engine/validation/index.js +10 -3
  27. package/dist/engine/validation/richtext-sanitizer.d.ts.map +1 -1
  28. package/dist/engine/validation/richtext-sanitizer.js +26 -2
  29. package/dist/engine/validation/schema-builders.js +6 -6
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +1 -0
  33. package/dist/media/file-types.d.ts.map +1 -1
  34. package/dist/media/file-types.js +13 -5
  35. package/dist/notifications/notification-service.d.ts +12 -6
  36. package/dist/notifications/notification-service.d.ts.map +1 -1
  37. package/dist/notifications/notification-service.js +16 -1
  38. package/dist/queue/queue.interface.d.ts +6 -2
  39. package/dist/queue/queue.interface.d.ts.map +1 -1
  40. package/dist/queue/queue.stub.d.ts +1 -1
  41. package/dist/queue/queue.stub.d.ts.map +1 -1
  42. package/dist/queue/queue.stub.js +2 -1
  43. package/package.json +1 -1
  44. package/dist/queue.interface.d.ts +0 -39
  45. package/dist/queue.interface.d.ts.map +0 -1
  46. package/dist/queue.interface.js +0 -3
  47. package/dist/queue.stub.d.ts +0 -6
  48. package/dist/queue.stub.d.ts.map +0 -1
  49. package/dist/queue.stub.js +0 -8
@@ -1 +1 @@
1
- {"version":3,"file":"policies.d.ts","sourceRoot":"","sources":["../../src/engine/policies.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK9D;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEzF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAgBzF"}
1
+ {"version":3,"file":"policies.d.ts","sourceRoot":"","sources":["../../src/engine/policies.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEhF;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK9D;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEzF;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,cAAc,EAAE,kBAAkB,CAAA;IAClC,6FAA6F;IAC7F,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;IACrC,6FAA6F;IAC7F,gBAAgB,EAAE,MAAM,GAAG,QAAQ,CAAA;IACnC,oFAAoF;IACpF,cAAc,EAAE,MAAM,GAAG,QAAQ,CAAA;CAClC;AAED,0EAA0E;AAC1E,wBAAgB,uBAAuB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAQxE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,sBAAsB,CAmC5E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAqBzF;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,EAAE,IAAI,EACV,KAAK,GAAE,YAAwC,GAC9C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgDzB"}
@@ -1,33 +1,163 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  // Copyright (c) 2024–2026 Flavio De Musso
3
+ /**
4
+ * Computes an un-salted SHA-256 hex digest of a string value.
5
+ * Used for basic digest operations.
6
+ * @param value - The raw string value to hash.
7
+ * @returns A Promise resolving to a 64-character hex string.
8
+ */
3
9
  export async function sha256hex(value) {
4
10
  const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value));
5
11
  return Array.from(new Uint8Array(buf))
6
12
  .map((b) => b.toString(16).padStart(2, '0'))
7
13
  .join('');
8
14
  }
15
+ /**
16
+ * Verifies if a candidate string matches a stored SHA-256 hash digest.
17
+ * @param stored - The expected 64-character SHA-256 hex digest.
18
+ * @param candidate - The raw candidate string to verify.
19
+ * @returns A Promise resolving to true if candidate matches stored digest, false otherwise.
20
+ */
9
21
  export async function verifyHashField(stored, candidate) {
10
22
  return stored === (await sha256hex(candidate));
11
23
  }
24
+ /** Normalizes raw policy strings to canonical DataClassification enum. */
25
+ export function normalizeClassification(raw) {
26
+ if (!raw)
27
+ return 'public';
28
+ const lower = raw.toLowerCase();
29
+ if (lower === 'confidential')
30
+ return 'confidential';
31
+ if (lower === 'restricted' || lower === 'hash')
32
+ return 'restricted';
33
+ if (lower === 'encrypt')
34
+ return 'confidential';
35
+ if (lower === 'internal')
36
+ return 'internal';
37
+ return 'public';
38
+ }
12
39
  /**
13
- * Risolve le policy di un branch applicando i valori di default.
14
- * Tutta la logica di accesso ai campi deve passare per questa funzione,
15
- * mai con inline `branch.policies?.x ?? default`.
40
+ * Resolves the 4-tier DataClassification for a branch, bundling its storage
41
+ * strategy at rest and its API visibility rules (public vs auth context).
42
+ * @param branch - The seed branch definition to inspect.
43
+ * @returns The resolved classification details and visibility rules.
44
+ */
45
+ export function resolveClassification(branch) {
46
+ const rawClassification = branch.policies?.classification ?? branch.policies?.privacy;
47
+ const classification = normalizeClassification(rawClassification);
48
+ switch (classification) {
49
+ case 'confidential':
50
+ return {
51
+ classification: 'confidential',
52
+ storage: 'encrypt',
53
+ publicVisibility: 'hidden',
54
+ authVisibility: 'full',
55
+ };
56
+ case 'restricted':
57
+ return {
58
+ classification: 'restricted',
59
+ storage: 'hash',
60
+ publicVisibility: 'hidden',
61
+ authVisibility: 'hidden',
62
+ };
63
+ case 'internal':
64
+ return {
65
+ classification: 'internal',
66
+ storage: 'plain',
67
+ publicVisibility: 'hidden',
68
+ authVisibility: 'full',
69
+ };
70
+ case 'public':
71
+ default:
72
+ return {
73
+ classification: 'public',
74
+ storage: 'plain',
75
+ publicVisibility: 'full',
76
+ authVisibility: 'full',
77
+ };
78
+ }
79
+ }
80
+ /**
81
+ * Resolves branch policies applying all defaults and classification rules.
82
+ * @param branch - The seed branch definition to inspect.
83
+ * @returns Complete required policies object for the branch.
16
84
  */
17
85
  export function resolvePolicies(branch) {
18
- const privacy = branch.policies?.privacy ?? 'plain';
19
- // Non-plain privacy implies hidden by default: the CMS hashes/encrypts on write,
20
- // so returning the stored value would leak the digest to readers.
21
- const defaultVisibility = privacy !== 'plain' ? 'hidden' : 'full';
22
- // Repeaters live in a single JSON column — never filterable, sortable, or
23
- // searchable/facetable in v1, regardless of what's set on the branch.
86
+ const resolved = resolveClassification(branch);
24
87
  const isRepeater = branch.type === 'repeater';
88
+ const isEncryptedOrHashed = resolved.storage !== 'plain';
89
+ const defaultVisibility = resolved.authVisibility;
90
+ const isPublicAllowed = branch.policies?.public ?? (resolved.publicVisibility === 'full');
91
+ const defaultFilter = isRepeater || resolved.storage === 'hash' ? false : branch.policies?.filter ?? true;
92
+ const defaultSort = isRepeater || isEncryptedOrHashed ? false : branch.policies?.sort ?? true;
93
+ const defaultSearch = isRepeater || isEncryptedOrHashed ? false : branch.policies?.search ?? true;
25
94
  return {
26
- privacy,
95
+ classification: resolved.classification,
96
+ privacy: resolved.storage,
27
97
  visibility: branch.policies?.visibility ?? defaultVisibility,
28
- search: isRepeater ? false : branch.policies?.search ?? true,
29
- filter: isRepeater ? false : branch.policies?.filter ?? true,
30
- sort: isRepeater ? false : branch.policies?.sort ?? true,
31
- public: branch.policies?.public ?? true,
98
+ search: defaultSearch,
99
+ filter: defaultFilter,
100
+ sort: defaultSort,
101
+ public: isPublicAllowed,
32
102
  };
33
103
  }
104
+ const SYSTEM_FIELDS = new Set(['id', 'slug', 'status', 'created_at', 'updated_at', 'version', 'has_pending_draft']);
105
+ /**
106
+ * Filters entry payload fields based on the caller's {@link ActorContext} and branch classification tier.
107
+ *
108
+ * Rules:
109
+ * - Public actor: receives `public` fields; `internal`, `confidential`, and `restricted` fields are omitted.
110
+ * - Authenticated actor: receives `public`, `internal`, and `confidential` fields; `restricted` fields are ALWAYS omitted.
111
+ * - System actor: receives all fields including `restricted` (used for internal worker/automation orchestration).
112
+ *
113
+ * @param data - Raw record fields object.
114
+ * @param seed - Content type seed definition containing branch definitions.
115
+ * @param actor - Context of the caller requesting the entry payload (defaults to authenticated).
116
+ * @returns Filtered data record containing only authorized fields for the given actor context.
117
+ */
118
+ export function filterEntryForActor(data, seed, actor = { type: 'authenticated' }) {
119
+ const result = {};
120
+ for (const [key, value] of Object.entries(data)) {
121
+ if (SYSTEM_FIELDS.has(key)) {
122
+ result[key] = value;
123
+ continue;
124
+ }
125
+ const branch = seed.branches.find((b) => b.alias === key);
126
+ if (!branch) {
127
+ // Pass through unknown/extra fields unless actor is public
128
+ if (actor.type !== 'public') {
129
+ result[key] = value;
130
+ }
131
+ continue;
132
+ }
133
+ const resolved = resolveClassification(branch);
134
+ const isPublicActor = actor.type === 'public';
135
+ const isSystemActor = actor.type === 'system';
136
+ // System actor sees all fields including restricted
137
+ if (isSystemActor) {
138
+ result[key] = value;
139
+ continue;
140
+ }
141
+ // Public actor check
142
+ if (isPublicActor) {
143
+ if (resolved.publicVisibility === 'hidden')
144
+ continue;
145
+ }
146
+ else {
147
+ // Authenticated actor check
148
+ if (resolved.authVisibility === 'hidden')
149
+ continue;
150
+ }
151
+ // Explicit visibility override check
152
+ if (branch.policies?.visibility === 'hidden')
153
+ continue;
154
+ // Masking rule check
155
+ if (branch.policies?.visibility === 'masked') {
156
+ result[key] = typeof value === 'string' && value.length > 0 ? '••••••••' : null;
157
+ }
158
+ else {
159
+ result[key] = value;
160
+ }
161
+ }
162
+ return result;
163
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Contract for the Application-Level Encryption (ALE) and hashing privacy service.
3
+ * Used by the Botanical Engine to secure fields classified as `confidential` or `restricted`.
4
+ */
5
+ export interface IPrivacyService {
6
+ /**
7
+ * Symmetrically encrypts a plaintext string using AES-256-GCM.
8
+ * @param plaintext - The raw string value to encrypt.
9
+ * @returns A Promise resolving to formatted ciphertext (`v1:<iv_base64>:<ciphertext_base64>`).
10
+ */
11
+ encrypt(plaintext: string): Promise<string>;
12
+ /**
13
+ * Decrypts a formatted AES-256-GCM ciphertext payload.
14
+ * @param ciphertext - The formatted ciphertext string (`v1:<iv_base64>:<ciphertext_base64>`).
15
+ * @returns A Promise resolving to the original plaintext string.
16
+ * @throws Error if the ciphertext format is invalid or decryption fails (authentication tag mismatch).
17
+ */
18
+ decrypt(ciphertext: string): Promise<string>;
19
+ /**
20
+ * Computes a deterministic HMAC SHA-256 digest of a plaintext string.
21
+ * Used for blind-indexing and one-way field digests (`restricted` classification).
22
+ * @param plaintext - The raw string value to hash.
23
+ * @returns A Promise resolving to a 64-character hexadecimal digest string.
24
+ */
25
+ hash(plaintext: string): Promise<string>;
26
+ }
27
+ /**
28
+ * Concrete Edge-native implementation of {@link IPrivacyService}.
29
+ * Employs Web Crypto API (`crypto.subtle`) for zero-dependency execution in Cloudflare Workers.
30
+ */
31
+ export declare class PrivacyService implements IPrivacyService {
32
+ private readonly masterKey;
33
+ private aesKeyPromise?;
34
+ private hmacKeyPromise?;
35
+ /**
36
+ * Initializes the PrivacyService with a Master Encryption Key.
37
+ * @param masterKey - Secret key used to derive cryptographic keys for AES-GCM and HMAC.
38
+ * @throws Error if `masterKey` is empty or undefined.
39
+ */
40
+ constructor(masterKey: string);
41
+ /**
42
+ * Lazy-loads and caches the derived AES-256-GCM {@link CryptoKey}.
43
+ * Derives a 256-bit key from `masterKey` via SHA-256 digest.
44
+ */
45
+ private getAesKey;
46
+ /**
47
+ * Lazy-loads and caches the derived HMAC SHA-256 {@link CryptoKey}.
48
+ */
49
+ private getHmacKey;
50
+ /**
51
+ * Encrypts a plaintext string with AES-256-GCM and a fresh 96-bit (12-byte) IV.
52
+ * Output is formatted as `v1:<iv_base64>:<ciphertext_base64>`.
53
+ */
54
+ encrypt(plaintext: string): Promise<string>;
55
+ /**
56
+ * Decrypts a `v1:<iv_base64>:<ciphertext_base64>` string back to its plaintext value.
57
+ * If the input string is not prefixed with `v1:`, returns the raw string as unencrypted legacy data.
58
+ */
59
+ decrypt(ciphertext: string): Promise<string>;
60
+ /**
61
+ * Computes a deterministic HMAC SHA-256 hex digest for blind index generation.
62
+ */
63
+ hash(plaintext: string): Promise<string>;
64
+ }
65
+ //# sourceMappingURL=privacy.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privacy.service.d.ts","sourceRoot":"","sources":["../../src/engine/privacy.service.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAE3C;;;;;OAKG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAE5C;;;;;OAKG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACzC;AA4BD;;;GAGG;AACH,qBAAa,cAAe,YAAW,eAAe;IACpD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,aAAa,CAAC,CAAoB;IAC1C,OAAO,CAAC,cAAc,CAAC,CAAoB;IAE3C;;;;OAIG;IACH,YAAY,SAAS,EAAE,MAAM,EAK5B;IAED;;;OAGG;YACW,SAAS;IAmBvB;;OAEG;YACW,UAAU;IAexB;;;OAGG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYhD;IAED;;;OAGG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBjD;IAED;;OAEG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY7C;CACF"}
@@ -0,0 +1,114 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ /**
4
+ * Converts a Uint8Array byte sequence to a Base64-encoded string.
5
+ * Native Edge-compatible implementation without Node.js Buffer dependencies.
6
+ */
7
+ function bytesToBase64(bytes) {
8
+ let binary = '';
9
+ const len = bytes.byteLength;
10
+ for (let i = 0; i < len; i++) {
11
+ binary += String.fromCharCode(bytes[i]);
12
+ }
13
+ return btoa(binary);
14
+ }
15
+ /**
16
+ * Converts a Base64-encoded string back to a Uint8Array byte sequence.
17
+ * Native Edge-compatible implementation without Node.js Buffer dependencies.
18
+ */
19
+ function base64ToBytes(base64) {
20
+ const binary = atob(base64);
21
+ const bytes = new Uint8Array(binary.length);
22
+ for (let i = 0; i < binary.length; i++) {
23
+ bytes[i] = binary.charCodeAt(i);
24
+ }
25
+ return bytes;
26
+ }
27
+ /**
28
+ * Concrete Edge-native implementation of {@link IPrivacyService}.
29
+ * Employs Web Crypto API (`crypto.subtle`) for zero-dependency execution in Cloudflare Workers.
30
+ */
31
+ export class PrivacyService {
32
+ masterKey;
33
+ aesKeyPromise;
34
+ hmacKeyPromise;
35
+ /**
36
+ * Initializes the PrivacyService with a Master Encryption Key.
37
+ * @param masterKey - Secret key used to derive cryptographic keys for AES-GCM and HMAC.
38
+ * @throws Error if `masterKey` is empty or undefined.
39
+ */
40
+ constructor(masterKey) {
41
+ if (!masterKey) {
42
+ throw new Error('PrivacyService requires a non-empty masterKey');
43
+ }
44
+ this.masterKey = masterKey;
45
+ }
46
+ /**
47
+ * Lazy-loads and caches the derived AES-256-GCM {@link CryptoKey}.
48
+ * Derives a 256-bit key from `masterKey` via SHA-256 digest.
49
+ */
50
+ async getAesKey() {
51
+ if (!this.aesKeyPromise) {
52
+ this.aesKeyPromise = (async () => {
53
+ const keyData = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(this.masterKey));
54
+ return crypto.subtle.importKey('raw', keyData, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']);
55
+ })();
56
+ }
57
+ return this.aesKeyPromise;
58
+ }
59
+ /**
60
+ * Lazy-loads and caches the derived HMAC SHA-256 {@link CryptoKey}.
61
+ */
62
+ async getHmacKey() {
63
+ if (!this.hmacKeyPromise) {
64
+ this.hmacKeyPromise = (async () => {
65
+ return crypto.subtle.importKey('raw', new TextEncoder().encode(this.masterKey), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
66
+ })();
67
+ }
68
+ return this.hmacKeyPromise;
69
+ }
70
+ /**
71
+ * Encrypts a plaintext string with AES-256-GCM and a fresh 96-bit (12-byte) IV.
72
+ * Output is formatted as `v1:<iv_base64>:<ciphertext_base64>`.
73
+ */
74
+ async encrypt(plaintext) {
75
+ const key = await this.getAesKey();
76
+ const iv = crypto.getRandomValues(new Uint8Array(12));
77
+ const encodedText = new TextEncoder().encode(plaintext);
78
+ const encryptedBuffer = await crypto.subtle.encrypt({ name: 'AES-GCM', iv: iv }, key, encodedText);
79
+ const ivBase64 = bytesToBase64(iv);
80
+ const ciphertextBase64 = bytesToBase64(new Uint8Array(encryptedBuffer));
81
+ return `v1:${ivBase64}:${ciphertextBase64}`;
82
+ }
83
+ /**
84
+ * Decrypts a `v1:<iv_base64>:<ciphertext_base64>` string back to its plaintext value.
85
+ * If the input string is not prefixed with `v1:`, returns the raw string as unencrypted legacy data.
86
+ */
87
+ async decrypt(ciphertext) {
88
+ if (!ciphertext || !ciphertext.startsWith('v1:')) {
89
+ return ciphertext;
90
+ }
91
+ const parts = ciphertext.split(':');
92
+ if (parts.length !== 3) {
93
+ throw new Error('Invalid ciphertext format');
94
+ }
95
+ const [, ivBase64, cipherBase64] = parts;
96
+ const iv = base64ToBytes(ivBase64);
97
+ const cipherBytes = base64ToBytes(cipherBase64);
98
+ const key = await this.getAesKey();
99
+ const decryptedBuffer = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: iv }, key, cipherBytes);
100
+ return new TextDecoder().decode(decryptedBuffer);
101
+ }
102
+ /**
103
+ * Computes a deterministic HMAC SHA-256 hex digest for blind index generation.
104
+ */
105
+ async hash(plaintext) {
106
+ const key = await this.getHmacKey();
107
+ const encodedText = new TextEncoder().encode(plaintext);
108
+ const signatureBuffer = await crypto.subtle.sign('HMAC', key, encodedText);
109
+ const hashBytes = new Uint8Array(signatureBuffer);
110
+ return Array.from(hashBytes)
111
+ .map((b) => b.toString(16).padStart(2, '0'))
112
+ .join('');
113
+ }
114
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/engine/query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,IAAI,EAMJ,aAAa,EACb,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAIpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,aAAkB,GAAG,kBAAkB,CAoF5F"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/engine/query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,IAAI,EAMJ,aAAa,EACb,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAKpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,aAAkB,GAAG,kBAAkB,CAoG5F"}
@@ -1,4 +1,5 @@
1
1
  import { tableName, ftsTableName, isValidColumn, indexableSearchBranches, SYSTEM_COLUMNS } from './ddl.js';
2
+ import { resolveClassification } from './policies.js';
2
3
  /**
3
4
  * Builds a parameterized SQL SELECT query and bindings for a given Seed based on search, filtering, status, and ordering options.
4
5
  *
@@ -47,14 +48,32 @@ export function buildSelectQuery(seed, options = {}) {
47
48
  for (const group of filters) {
48
49
  if (!isValidColumn(seed, group.column))
49
50
  continue;
51
+ const branch = seed.branches.find(b => b.alias === group.column);
52
+ const isEncrypted = branch ? resolveClassification(branch).storage === 'encrypt' : false;
50
53
  const col = SYSTEM_COLUMNS.has(group.column)
51
54
  ? `${table}.${group.column}`
52
55
  : group.column;
53
56
  const condClauses = [];
54
57
  for (const cond of group.conditions) {
55
- const clause = buildFilterCondition(col, group.type, cond, bindings);
56
- if (clause)
57
- condClauses.push(clause);
58
+ if (isEncrypted) {
59
+ const { op } = cond;
60
+ if (op === 'eq' || op === 'neq' || op === 'in' || op === 'not_in') {
61
+ const targetCol = `${table}.${group.column}_bidx`;
62
+ const clause = buildFilterCondition(targetCol, group.type, cond, bindings);
63
+ if (clause)
64
+ condClauses.push(clause);
65
+ }
66
+ else if (op === 'is_empty' || op === 'is_not_empty') {
67
+ const clause = buildFilterCondition(col, group.type, cond, bindings);
68
+ if (clause)
69
+ condClauses.push(clause);
70
+ }
71
+ }
72
+ else {
73
+ const clause = buildFilterCondition(col, group.type, cond, bindings);
74
+ if (clause)
75
+ condClauses.push(clause);
76
+ }
58
77
  }
59
78
  if (condClauses.length > 0) {
60
79
  groupClauses.push(condClauses.length > 1 ? `(${condClauses.join(' AND ')})` : condClauses[0]);
@@ -1 +1 @@
1
- {"version":3,"file":"seed-registry.d.ts","sourceRoot":"","sources":["../../src/engine/seed-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAG9C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,GAAG,IAAI,IAAI,EAAE,CAAA;IAEb;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAE9B;;;;;OAKG;IACH,kBAAkB,IAAI,IAAI,EAAE,CAAA;IAE5B;;;OAGG;IACH,cAAc,IAAI,IAAI,EAAE,CAAA;IAExB;;;OAGG;IACH,YAAY,IAAI,IAAI,EAAE,CAAA;CACvB;AAID,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IAErC,YAAY,KAAK,EAAE,IAAI,EAAE,EA0BxB;IAED,GAAG,IAAI,IAAI,EAAE,CAEZ;IAED,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE7B;IAED,kBAAkB,IAAI,IAAI,EAAE,CAE3B;IAED,cAAc,IAAI,IAAI,EAAE,CAEvB;IAED,YAAY,IAAI,IAAI,EAAE,CAErB;CACF;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;CAAG;AAEzD,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,MAAM,CAQjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAsE1E"}
1
+ {"version":3,"file":"seed-registry.d.ts","sourceRoot":"","sources":["../../src/engine/seed-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAI9C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,GAAG,IAAI,IAAI,EAAE,CAAA;IAEb;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAE9B;;;;;OAKG;IACH,kBAAkB,IAAI,IAAI,EAAE,CAAA;IAE5B;;;OAGG;IACH,cAAc,IAAI,IAAI,EAAE,CAAA;IAExB;;;OAGG;IACH,YAAY,IAAI,IAAI,EAAE,CAAA;CACvB;AAID,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IAErC,YAAY,KAAK,EAAE,IAAI,EAAE,EAgCxB;IAED,GAAG,IAAI,IAAI,EAAE,CAEZ;IAED,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE7B;IAED,kBAAkB,IAAI,IAAI,EAAE,CAE3B;IAED,cAAc,IAAI,IAAI,EAAE,CAEvB;IAED,YAAY,IAAI,IAAI,EAAE,CAErB;CACF;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;CAAG;AAEzD,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,MAAM,CAQjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAsE1E"}
@@ -1,6 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  // Copyright (c) 2024–2026 Flavio De Musso
3
3
  import { AUTOMATION_RESERVED_WORDS } from '../automations/automations-grammar-words.js';
4
+ import { SQL_RESERVED_WORDS } from './sql-reserved-words.js';
4
5
  const BRANCH_ID_RE = /^br_[A-Za-z0-9]+$/;
5
6
  export class SeedRegistry {
6
7
  seedMap;
@@ -13,6 +14,10 @@ export class SeedRegistry {
13
14
  throw new Error(`Seed "${seed.slug}" uses reserved alias "${branch.alias}". `
14
15
  + `Pick a different alias — this word is used by the automation template grammar.`);
15
16
  }
17
+ if (SQL_RESERVED_WORDS.has(branch.alias.toLowerCase())) {
18
+ throw new Error(`Seed "${seed.slug}" uses SQL reserved keyword "${branch.alias}". `
19
+ + `Please pick a different alias to prevent database errors.`);
20
+ }
16
21
  if (!branch.id || !BRANCH_ID_RE.test(branch.id)) {
17
22
  throw new Error(`Seed "${seed.slug}" branch "${branch.alias}" has invalid id "${branch.id}". `
18
23
  + `Expected format ^br_[A-Za-z0-9]+$.`);
@@ -1 +1 @@
1
- {"version":3,"file":"seed-validation.d.ts","sourceRoot":"","sources":["../../src/engine/seed-validation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAMtC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,QAAyB,CAAA;AAErD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;CACf;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,mBAAmB,EAAE,CAwO5E;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAErD"}
1
+ {"version":3,"file":"seed-validation.d.ts","sourceRoot":"","sources":["../../src/engine/seed-validation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAOtC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,QAAyB,CAAA;AAErD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;CACf;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,mBAAmB,EAAE,CA8P5E;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAErD"}
@@ -2,6 +2,7 @@
2
2
  // Copyright (c) 2024–2026 Flavio De Musso
3
3
  import { AUTOMATION_RESERVED_WORDS } from '../automations/automations-grammar-words.js';
4
4
  import { sortSeedsByDependencies } from './seed-registry.js';
5
+ import { SQL_RESERVED_WORDS } from './sql-reserved-words.js';
5
6
  const BRANCH_ID_RE = /^br_[A-Za-z0-9]+$/;
6
7
  /**
7
8
  * Allowed charset for a branch alias. An alias becomes a raw SQL column name in
@@ -73,7 +74,16 @@ export function validateSeedDefinitions(seeds) {
73
74
  }
74
75
  catch (err) {
75
76
  const msg = err instanceof Error ? err.message : String(err);
76
- result.push({ slug: '<graph>', messages: [msg], fatal: true });
77
+ const cycleMatch = msg.match(/Cyclic dependency detected among seeds: (.*)/);
78
+ if (cycleMatch) {
79
+ const cycleSlugs = cycleMatch[1].split(', ');
80
+ for (const slug of cycleSlugs) {
81
+ result.push({ slug, messages: [msg], fatal: true });
82
+ }
83
+ }
84
+ else {
85
+ result.push({ slug: '<graph>', messages: [msg], fatal: true });
86
+ }
77
87
  }
78
88
  }
79
89
  // ── Fatal 5: branch id format / uniqueness ───────────────────────────────
@@ -107,6 +117,10 @@ export function validateSeedDefinitions(seeds) {
107
117
  messages.push(`branch '${branch.alias}' uses reserved alias. ` +
108
118
  `This word is used by the automation template grammar.`);
109
119
  }
120
+ else if (SQL_RESERVED_WORDS.has(branch.alias.toLowerCase())) {
121
+ messages.push(`branch '${branch.alias}' uses SQL reserved keyword. ` +
122
+ `Please pick a different alias to prevent database errors.`);
123
+ }
110
124
  }
111
125
  if (messages.length > 0)
112
126
  result.push({ slug: seed.slug, messages, fatal: true });
@@ -228,6 +242,16 @@ export function validateSeedDefinitions(seeds) {
228
242
  fatal: true,
229
243
  });
230
244
  }
245
+ else if (SQL_RESERVED_WORDS.has(seed.displayNameAlias.toLowerCase())) {
246
+ result.push({
247
+ slug: seed.slug,
248
+ messages: [
249
+ `displayNameAlias '${seed.displayNameAlias}' uses SQL reserved keyword. ` +
250
+ `Please pick a different alias to prevent database errors.`,
251
+ ],
252
+ fatal: true,
253
+ });
254
+ }
231
255
  }
232
256
  return result;
233
257
  }
@@ -0,0 +1,2 @@
1
+ export declare const SQL_RESERVED_WORDS: Set<string>;
2
+ //# sourceMappingURL=sql-reserved-words.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-reserved-words.d.ts","sourceRoot":"","sources":["../../src/engine/sql-reserved-words.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,kBAAkB,aAkB7B,CAAA"}
@@ -0,0 +1,21 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ export const SQL_RESERVED_WORDS = new Set([
4
+ 'abort', 'action', 'add', 'after', 'all', 'alter', 'always', 'analyze', 'and', 'anti',
5
+ 'any', 'as', 'asc', 'attach', 'autoincrement', 'before', 'begin', 'between', 'by', 'cascade',
6
+ 'case', 'cast', 'check', 'collate', 'column', 'commit', 'conflict', 'constraint', 'create',
7
+ 'cross', 'current', 'current_date', 'current_time', 'current_timestamp', 'database', 'default',
8
+ 'deferrable', 'deferred', 'delete', 'desc', 'detach', 'distinct', 'do', 'drop', 'each',
9
+ 'else', 'end', 'escape', 'except', 'exclude', 'exclusive', 'exists', 'explain', 'fail',
10
+ 'filter', 'first', 'following', 'for', 'foreign', 'from', 'full', 'generated', 'glob',
11
+ 'group', 'groups', 'having', 'if', 'ignore', 'immediate', 'in', 'index', 'indexed',
12
+ 'initially', 'inner', 'insert', 'instead', 'intersect', 'into', 'is', 'isnull', 'join',
13
+ 'key', 'last', 'left', 'like', 'limit', 'match', 'materialized', 'natural', 'no', 'not',
14
+ 'nothing', 'notnull', 'null', 'nulls', 'of', 'offset', 'on', 'or', 'order', 'others',
15
+ 'outer', 'over', 'partition', 'plan', 'pragma', 'preceding', 'primary', 'query', 'raise',
16
+ 'range', 'recursive', 'references', 'regexp', 'reindex', 'release', 'rename', 'replace',
17
+ 'restrict', 'returning', 'right', 'rollback', 'row', 'rows', 'savepoint', 'select', 'set',
18
+ 'table', 'temp', 'temporary', 'then', 'ties', 'to', 'transaction', 'trigger', 'unbounded',
19
+ 'union', 'unique', 'update', 'using', 'vacuum', 'values', 'view', 'virtual', 'when', 'where',
20
+ 'window', 'with', 'without'
21
+ ]);
@@ -49,6 +49,14 @@ export interface FileFieldOptions {
49
49
  */
50
50
  maxSize?: number;
51
51
  }
52
+ /** 4-tier Data Classification matrix (Public, Internal, Confidential, Restricted). */
53
+ export type DataClassification = 'public' | 'internal' | 'confidential' | 'restricted';
54
+ /** Context representing the caller/actor executing an operation or reading API data. */
55
+ export interface ActorContext {
56
+ type: 'public' | 'authenticated' | 'system';
57
+ userId?: string;
58
+ role?: string;
59
+ }
52
60
  /** Branch: definition of a single field. `alias` is the SQL column name. */
53
61
  export interface Branch {
54
62
  /**
@@ -94,8 +102,10 @@ export interface Branch {
94
102
  * All values are optional — `resolvePolicies(branch)` supplies the defaults.
95
103
  */
96
104
  policies?: {
105
+ /** 4-tier data classification level. Default: 'public'. */
106
+ classification?: DataClassification | 'Public' | 'Internal' | 'Confidential' | 'Restricted';
97
107
  /** How the value is stored. Default: 'plain'. */
98
- privacy?: 'plain' | 'hash' | 'encrypt';
108
+ privacy?: 'plain' | 'hash' | 'encrypt' | DataClassification | 'Public' | 'Internal' | 'Confidential' | 'Restricted';
99
109
  /** How the value is returned in API responses. Default: 'full'. */
100
110
  visibility?: 'full' | 'masked' | 'hidden';
101
111
  /** Whether the field is included in full-text search queries. Default: true. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/engine/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/engine/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/validation/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAOhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAErD;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb,0GAA0G;IAC1G,QAAQ,EAAE,MAAM,CAAA;IAChB,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAA;IAChB,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC/B;;;OAGG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,YAAY,CAAA;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,+EAA+E;IAC/E,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,8FAA8F;IAC9F,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,4FAA4F;IAC5F,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,sEAAsE;IACtE,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,uFAAuF;IACvF,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC9B,2BAA2B,EAAE,OAAO,CAAA;IACpC,qBAAqB,EAAE,OAAO,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,YAAY,GAAG,SAAS,CAAA;CACtC,CAAA;AAKD,0CAA0C;AAC1C,QAAA,MAAM,aAAa,YAAI,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAU,CAAA;AAqR/D;;;;;;;;;;;GAWG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAqD3B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAE5F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/validation/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAOhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAErD;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb,0GAA0G;IAC1G,QAAQ,EAAE,MAAM,CAAA;IAChB,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAA;IAChB,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC/B;;;OAGG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,YAAY,CAAA;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,+EAA+E;IAC/E,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,8FAA8F;IAC9F,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,4FAA4F;IAC5F,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,sEAAsE;IACtE,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,uFAAuF;IACvF,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC9B,2BAA2B,EAAE,OAAO,CAAA;IACpC,qBAAqB,EAAE,OAAO,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,YAAY,GAAG,SAAS,CAAA;CACtC,CAAA;AAKD,0CAA0C;AAC1C,QAAA,MAAM,aAAa,YAAI,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAU,CAAA;AA+R/D;;;;;;;;;;;GAWG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAqD3B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAE5F"}
@@ -147,9 +147,9 @@ function expectedFromIssue(issue) {
147
147
  if (issue.code === 'invalid_type')
148
148
  return issue.expected;
149
149
  const message = issue.message;
150
- if (typeof message !== 'string')
150
+ if (typeof message !== 'string' || message.trim() === '')
151
151
  return 'valid-field-value';
152
- return message.startsWith('Expected ') ? message.slice('Expected '.length) : 'valid-field-value';
152
+ return message.startsWith('Expected ') ? message.slice('Expected '.length) : message;
153
153
  }
154
154
  /**
155
155
  * Separates known fields (present in seed definition) from unknown fields in a raw payload.
@@ -233,12 +233,19 @@ function processZodIssues(seed, issues, filtered, options) {
233
233
  continue;
234
234
  }
235
235
  const issuePath = issue.path;
236
+ const valByPath = resolveByPath(filtered, issuePath);
237
+ // Skip dummy invalid_type (expected: null) issues produced by Zod union when input is not null
238
+ if (issue.code === 'invalid_type' &&
239
+ issue.expected === 'null' &&
240
+ valByPath !== null) {
241
+ continue;
242
+ }
236
243
  // detectMissingRequired() already reports top-level required-and-missing branches;
237
244
  // skip the redundant native invalid_type/undefined issue Zod v4 raises for the same field.
238
245
  if (issue.code === 'invalid_type' &&
239
246
  options.enforceRequiredFields &&
240
247
  issuePath.length === 1 &&
241
- resolveByPath(filtered, issuePath) === undefined) {
248
+ valByPath === undefined) {
242
249
  continue;
243
250
  }
244
251
  const field = buildFieldPath(issuePath);
@@ -1 +1 @@
1
- {"version":3,"file":"richtext-sanitizer.d.ts","sourceRoot":"","sources":["../../../src/engine/validation/richtext-sanitizer.ts"],"names":[],"mappings":"AA0BA,+DAA+D;AAC/D,UAAU,sBAAsB;IAC9B,2CAA2C;IAC3C,KAAK,EAAE,OAAO,CAAA;IACd,6DAA6D;IAC7D,SAAS,EAAE,OAAO,CAAA;IAClB,mEAAmE;IACnE,KAAK,EAAE,OAAO,CAAA;IACd,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AA4GD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAgCvF;AA2BD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAS1D"}
1
+ {"version":3,"file":"richtext-sanitizer.d.ts","sourceRoot":"","sources":["../../../src/engine/validation/richtext-sanitizer.ts"],"names":[],"mappings":"AA0BA,+DAA+D;AAC/D,UAAU,sBAAsB;IAC9B,2CAA2C;IAC3C,KAAK,EAAE,OAAO,CAAA;IACd,6DAA6D;IAC7D,SAAS,EAAE,OAAO,CAAA;IAClB,mEAAmE;IACnE,KAAK,EAAE,OAAO,CAAA;IACd,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAoID;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAgCvF;AA2BD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAS1D"}