@stndrds/schema 1.0.0-alpha.256 → 1.0.0-alpha.258

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 (63) hide show
  1. package/dist/{attributes-Jji7TfFG.d.mts → attributes-Cmkc7UgJ.d.mts} +14 -367
  2. package/dist/{attributes-C-iyjLqJ.d.ts → attributes-_6tvjbyl.d.ts} +14 -367
  3. package/dist/{chunk-RHNSWKMJ.js → chunk-44EVNHSR.js} +5 -8
  4. package/dist/{chunk-VKJVBXHS.mjs → chunk-7VSOCVN7.mjs} +5 -8
  5. package/dist/{chunk-NSM2JPC3.js → chunk-L4U5QEQL.js} +4 -17
  6. package/dist/{chunk-AAXJJNY6.mjs → chunk-UXCJ3NI4.mjs} +4 -17
  7. package/dist/helpers-BO10yqih.d.mts +316 -0
  8. package/dist/helpers-BTC6TsKH.d.ts +316 -0
  9. package/dist/index.d.mts +137 -57
  10. package/dist/index.d.ts +137 -57
  11. package/dist/index.js +104 -180
  12. package/dist/index.mjs +20 -91
  13. package/dist/{types-D7VH7GrO.d.ts → types-B_UZK_6m.d.ts} +1 -1
  14. package/dist/{types-DgpsvFnh.d.mts → types-CVswgCx9.d.mts} +1 -1
  15. package/dist/validation/all.d.mts +3 -3
  16. package/dist/validation/all.d.ts +3 -3
  17. package/dist/validation/all.js +11 -12
  18. package/dist/validation/all.mjs +4 -5
  19. package/dist/validation/complex/currency.d.mts +2 -2
  20. package/dist/validation/complex/currency.d.ts +2 -2
  21. package/dist/validation/complex/location.d.mts +2 -2
  22. package/dist/validation/complex/location.d.ts +2 -2
  23. package/dist/validation/complex/phone.d.mts +2 -2
  24. package/dist/validation/complex/phone.d.ts +2 -2
  25. package/dist/validation/complex/relation.d.mts +2 -2
  26. package/dist/validation/complex/relation.d.ts +2 -2
  27. package/dist/validation/complex/richtext.d.mts +2 -2
  28. package/dist/validation/complex/richtext.d.ts +2 -2
  29. package/dist/validation/complex/select.d.mts +2 -2
  30. package/dist/validation/complex/select.d.ts +2 -2
  31. package/dist/validation/complex/user.d.mts +2 -2
  32. package/dist/validation/complex/user.d.ts +2 -2
  33. package/dist/validation/computed/formula.d.mts +2 -2
  34. package/dist/validation/computed/formula.d.ts +2 -2
  35. package/dist/validation/computed/rollup.d.mts +2 -2
  36. package/dist/validation/computed/rollup.d.ts +2 -2
  37. package/dist/validation/config/index.d.mts +1 -1
  38. package/dist/validation/config/index.d.ts +1 -1
  39. package/dist/validation/config/index.js +4 -4
  40. package/dist/validation/config/index.mjs +1 -1
  41. package/dist/validation/core/index.d.mts +3 -3
  42. package/dist/validation/core/index.d.ts +3 -3
  43. package/dist/validation/object/index.d.mts +4 -3
  44. package/dist/validation/object/index.d.ts +4 -3
  45. package/dist/validation/object/index.js +15 -16
  46. package/dist/validation/object/index.mjs +3 -4
  47. package/dist/validation/primitives/checkbox.d.mts +2 -2
  48. package/dist/validation/primitives/checkbox.d.ts +2 -2
  49. package/dist/validation/primitives/date.d.mts +2 -2
  50. package/dist/validation/primitives/date.d.ts +2 -2
  51. package/dist/validation/primitives/number.d.mts +2 -2
  52. package/dist/validation/primitives/number.d.ts +2 -2
  53. package/dist/validation/primitives/text.d.mts +2 -2
  54. package/dist/validation/primitives/text.d.ts +2 -2
  55. package/package.json +2 -7
  56. package/dist/chunk-CI6EGLL6.mjs +0 -18
  57. package/dist/chunk-Q5DIOYUE.js +0 -20
  58. package/dist/helpers-CMryP45K.d.mts +0 -75
  59. package/dist/helpers-Chppkv0E.d.ts +0 -75
  60. package/dist/validation/complex/file.d.mts +0 -13
  61. package/dist/validation/complex/file.d.ts +0 -13
  62. package/dist/validation/complex/file.js +0 -11
  63. package/dist/validation/complex/file.mjs +0 -2
@@ -0,0 +1,316 @@
1
+ import { z } from 'zod';
2
+ import { A as Attribute, g as AttributeType, h as ComputedAttributeState } from './attributes-Cmkc7UgJ.mjs';
3
+ import { V as ValidationMessages, a as ValidationResult } from './types-CVswgCx9.mjs';
4
+ import { IconName } from '@stndrds/constants';
5
+ import { Uuid } from './utils.mjs';
6
+
7
+ interface DocumentLayout {
8
+ /** Named sub-folders auto-created at the top of the record's drive when first used via attach --variant. */
9
+ variants?: Record<string, DocumentLayoutVariant>;
10
+ /** Dev-declared folder structures the user can instantiate via the UI inside a record's drive. */
11
+ presets?: FolderPreset[];
12
+ }
13
+ interface DocumentLayoutVariant {
14
+ /** Display title for the auto-created sub-folder. */
15
+ title: string;
16
+ description?: string;
17
+ }
18
+ interface FolderPreset {
19
+ id: string;
20
+ label: string;
21
+ icon?: IconName;
22
+ description?: string;
23
+ structure: PresetNode[];
24
+ /** When true, this preset is auto-instantiated on every new record's drive for the owning object. */
25
+ autoInstantiate?: boolean;
26
+ }
27
+ interface PresetNode {
28
+ title: string;
29
+ description?: string;
30
+ children?: PresetNode[];
31
+ }
32
+ /** Max depth allowed for preset.structure to keep instantiation predictable. */
33
+ declare const MAX_PRESET_DEPTH = 5;
34
+
35
+ type BuiltInTransform = "toString" | "toNumber" | "toDate" | "toBoolean" | "toISOString";
36
+ type SchemaOperation = {
37
+ type: "add_attribute";
38
+ attribute: Attribute;
39
+ } | {
40
+ type: "remove_attribute";
41
+ name: string;
42
+ backup_config: Attribute;
43
+ } | {
44
+ type: "rename_attribute";
45
+ from: string;
46
+ to: string;
47
+ } | {
48
+ type: "change_type";
49
+ name: string;
50
+ from: AttributeType;
51
+ to: AttributeType;
52
+ transform?: BuiltInTransform;
53
+ } | {
54
+ type: "update_config";
55
+ name: string;
56
+ from: Partial<Record<string, unknown>>;
57
+ to: Partial<Record<string, unknown>>;
58
+ } | {
59
+ type: "remove_object";
60
+ backup: Record<string, unknown>;
61
+ } | {
62
+ type: "rename_object";
63
+ from: string;
64
+ to: string;
65
+ };
66
+ interface MigrationDefinition {
67
+ version: number;
68
+ operations: SchemaOperation[];
69
+ }
70
+
71
+ /**
72
+ * Timestamps for tracking creation and updates
73
+ */
74
+ interface Timestamps {
75
+ createdAt: Date;
76
+ updatedAt: Date;
77
+ }
78
+ /**
79
+ * Object definition - Represents a database table/entity
80
+ */
81
+ interface ObjectDefinition {
82
+ id?: Uuid;
83
+ name: string;
84
+ label: string;
85
+ pluralLabel?: string;
86
+ description?: string;
87
+ icon?: IconName;
88
+ /**
89
+ * Template expression used to compute the object's display label.
90
+ * Supports variable interpolation and pipes for formatting.
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * // Simple attribute reference
95
+ * labelExpression: "{{ name }}"
96
+ *
97
+ * // Multiple attributes
98
+ * labelExpression: "{{ firstName }} {{ lastName }}"
99
+ *
100
+ * // With pipes for formatting
101
+ * labelExpression: "{{ code | UPPER }} - {{ name | capitalize }}"
102
+ * ```
103
+ *
104
+ * Available pipes: UPPER, LOWER, capitalize, trim
105
+ */
106
+ labelExpression: string;
107
+ /**
108
+ * Optional template expression used to compute the semantic text sent to
109
+ * Meilisearch for vector generation. When absent, records opt out of semantic
110
+ * embedding generation.
111
+ */
112
+ embeddingExpression?: string;
113
+ attributes: Attribute[];
114
+ system?: boolean;
115
+ /**
116
+ * If true, no custom (user-created) attributes are allowed on this object.
117
+ * `standards diff` will report an error if any custom attribute is found.
118
+ * Use .sealed() on the ObjectBuilder to set this.
119
+ */
120
+ sealed?: boolean;
121
+ /**
122
+ * List of custom attribute names explicitly acknowledged by the developer.
123
+ * On a sealed object, these names will NOT trigger a CI failure.
124
+ * On an extensible object, this is purely documentary.
125
+ * Use .tolerate(["name"]) on the ObjectBuilder to set this.
126
+ */
127
+ toleratedAttributes?: string[];
128
+ metadata?: Record<string, unknown>;
129
+ /** Current schema version (incremented with each migration) */
130
+ schema_version: number;
131
+ /** Ordered list of migrations applied to this object's schema */
132
+ migrations: MigrationDefinition[];
133
+ /** Smart-folder layout convention for documents attached to records of this object. */
134
+ documentLayout?: DocumentLayout;
135
+ }
136
+ /**
137
+ * Links an attribute to an object
138
+ */
139
+ interface ObjectAttribute {
140
+ objectId: Uuid;
141
+ attributeId: Uuid;
142
+ order?: number;
143
+ required?: boolean;
144
+ }
145
+ /**
146
+ * Record - Instance of an Object (a row in the database)
147
+ */
148
+ interface ObjectRecord<TValues extends Record<string, unknown> = Record<string, unknown>> extends Timestamps {
149
+ id: Uuid;
150
+ objectId: Uuid;
151
+ /**
152
+ * Display label computed from the object's labelExpression.
153
+ * Computed dynamically based on record values.
154
+ *
155
+ * @example "John Doe" (from "{{ firstName }} {{ lastName }}")
156
+ */
157
+ label: string;
158
+ /**
159
+ * Semantic text computed from the object's embeddingExpression and persisted
160
+ * for Meilisearch documentTemplate-based vector generation.
161
+ */
162
+ embeddingText?: string;
163
+ values: TValues;
164
+ /** Per-computed-attribute state keyed by attribute name. */
165
+ computedStates?: Record<string, ComputedAttributeState>;
166
+ /**
167
+ * Custom metadata for the record.
168
+ * Use this for UI/UX state, feature flags, or any application-specific data.
169
+ * Unlike system fields (id, createdAt, updatedAt), metadata can be updated.
170
+ */
171
+ metadata?: Record<string, unknown>;
172
+ /**
173
+ * Soft delete timestamp.
174
+ * If set, the record is considered deleted but can be restored.
175
+ * Queries exclude soft-deleted records by default.
176
+ */
177
+ deletedAt?: Date | null;
178
+ /**
179
+ * Actor ID who soft-deleted this record.
180
+ * Set alongside deletedAt when a record is soft-deleted.
181
+ */
182
+ deletedBy?: string | null;
183
+ /**
184
+ * Actor ID who created this record.
185
+ * Automatically set by RecordService when actorId is configured.
186
+ * Optional for backward compatibility with existing records.
187
+ */
188
+ createdBy?: string;
189
+ /**
190
+ * Actor ID who last updated this record.
191
+ * Automatically set by RecordService when actorId is configured.
192
+ * Optional for backward compatibility with existing records.
193
+ */
194
+ lastUpdatedBy?: string;
195
+ /** Schema version at the time this record was last migrated */
196
+ schemaVersion: number;
197
+ }
198
+ /**
199
+ * System-managed field names on ObjectRecord.
200
+ * These are stored as SQL columns (not in JSONB `values`).
201
+ *
202
+ * Use this in adapters to determine if a filter/sort attribute is a table column
203
+ * vs. a JSONB value field.
204
+ *
205
+ * @example
206
+ * ```typescript
207
+ * if (SYSTEM_FIELD_NAMES.includes(filter.attribute)) {
208
+ * // Filter on SQL column (e.g., WHERE created_at > ...)
209
+ * } else {
210
+ * // Filter on JSONB field (e.g., WHERE values->>'name' = ...)
211
+ * }
212
+ * ```
213
+ */
214
+ declare const SYSTEM_FIELD_NAMES: readonly ["id", "createdAt", "updatedAt", "createdBy", "lastUpdatedBy"];
215
+ /**
216
+ * Type for system field names
217
+ */
218
+ type SystemFieldName = (typeof SYSTEM_FIELD_NAMES)[number];
219
+ /**
220
+ * Reserved attribute names that cannot be used for custom attributes.
221
+ * These names conflict with ObjectRecord properties.
222
+ *
223
+ * Includes:
224
+ * - System fields (id, createdAt, updatedAt, createdBy, lastUpdatedBy)
225
+ * - Other ObjectRecord properties (objectId, label, values, metadata, deletedAt)
226
+ *
227
+ * @example
228
+ * ```typescript
229
+ * if (RESERVED_ATTRIBUTE_NAMES.includes(attributeName)) {
230
+ * throw new Error(`"${attributeName}" is a reserved name`);
231
+ * }
232
+ * ```
233
+ */
234
+ declare const RESERVED_ATTRIBUTE_NAMES: readonly ["id", "createdAt", "updatedAt", "createdBy", "lastUpdatedBy", "objectId", "label", "embeddingText", "values", "metadata", "deletedAt", "deletedBy", "schemaVersion"];
235
+ /**
236
+ * Type for reserved attribute names
237
+ */
238
+ type ReservedAttributeName = (typeof RESERVED_ATTRIBUTE_NAMES)[number];
239
+ /**
240
+ * Reserved object names that cannot be used for user-created (runtime) objects.
241
+ * These are owned by the framework as sealed system objects.
242
+ */
243
+ declare const RESERVED_OBJECT_NAMES: readonly ["skill"];
244
+ type ReservedObjectName = (typeof RESERVED_OBJECT_NAMES)[number];
245
+
246
+ /**
247
+ * Create a Zod schema for any attribute type.
248
+ * Returns a strict validator that does NOT handle optional fields.
249
+ * Use createFormAttributeValidator for form validation with optional support.
250
+ *
251
+ * @param attr - The attribute to create a validator for
252
+ * @param messages - Custom validation messages for i18n support
253
+ */
254
+ declare function createAttributeValidator(attr: Attribute, messages?: ValidationMessages): z.ZodTypeAny;
255
+ /**
256
+ * Create a Zod schema for form validation.
257
+ * - Normalizes empty values (empty strings, empty objects) to null for optional fields
258
+ * - Accepts custom messages for i18n support
259
+ *
260
+ * Use this in UI forms where optional fields may have null/undefined values.
261
+ *
262
+ * @param attr - The attribute to create a validator for
263
+ * @param messages - Custom validation messages for i18n support
264
+ */
265
+ declare function createFormAttributeValidator(attr: Attribute, messages?: ValidationMessages): z.ZodTypeAny;
266
+
267
+ /**
268
+ * Validate data against an attribute schema
269
+ */
270
+ declare function validateAttribute(attr: Attribute, value: unknown): ValidationResult;
271
+ /**
272
+ * Validate data against an object schema
273
+ */
274
+ declare function validateObject(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
275
+ /**
276
+ * Validate and throw if invalid.
277
+ *
278
+ * Throws `ValidationError` (code `SCHEMA_VALIDATION_FAILED`) on failure so HTTP
279
+ * adapters can map it to 400. Generic `Error` would bubble up to a 500.
280
+ */
281
+ declare function validateObjectOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
282
+ /**
283
+ * Validate data in draft mode.
284
+ * - All attributes are treated as optional (no required validation)
285
+ * - Provided values are still validated for format/type correctness
286
+ */
287
+ declare function validateDraft(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
288
+ /**
289
+ * Validate draft data and throw if format validation fails.
290
+ *
291
+ * Same contract as `validateObjectOrThrow` but skips `required()` checks.
292
+ * Throws `ValidationError` so HTTP adapters map it to 400.
293
+ */
294
+ declare function validateDraftOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
295
+ /**
296
+ * Throw a `ValidationError` when `data` contains keys that do not correspond
297
+ * to any attribute declared on `objectDef`.
298
+ *
299
+ * Call this on **client-supplied input** before Zod validation so the error
300
+ * message clearly names every offending key. Do NOT call on merged data that
301
+ * includes existing record values — older records may legitimately carry stale
302
+ * keys that predate this guard (see issue #658).
303
+ *
304
+ * Maps to HTTP 400 via `SchemaExceptionFilter` (code SCHEMA_VALIDATION_FAILED).
305
+ */
306
+ declare function rejectUnknownAttributesOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): void;
307
+ /**
308
+ * Get the list of required attributes that are missing values.
309
+ */
310
+ declare function getMissingRequiredAttributes(objectDef: ObjectDefinition, data: Record<string, unknown>): Attribute[];
311
+ /**
312
+ * Check if a record is complete (all required attributes have valid values).
313
+ */
314
+ declare function isRecordComplete(objectDef: ObjectDefinition, data: Record<string, unknown>): boolean;
315
+
316
+ export { type BuiltInTransform as B, type DocumentLayout as D, type FolderPreset as F, type MigrationDefinition as M, type ObjectDefinition as O, type PresetNode as P, RESERVED_ATTRIBUTE_NAMES as R, type SchemaOperation as S, type Timestamps as T, validateDraftOrThrow as a, validateObject as b, createFormAttributeValidator as c, validateObjectOrThrow as d, createAttributeValidator as e, validateAttribute as f, getMissingRequiredAttributes as g, type DocumentLayoutVariant as h, isRecordComplete as i, MAX_PRESET_DEPTH as j, type ObjectAttribute as k, type ObjectRecord as l, RESERVED_OBJECT_NAMES as m, type ReservedAttributeName as n, type ReservedObjectName as o, SYSTEM_FIELD_NAMES as p, type SystemFieldName as q, rejectUnknownAttributesOrThrow as r, validateDraft as v };
@@ -0,0 +1,316 @@
1
+ import { z } from 'zod';
2
+ import { A as Attribute, g as AttributeType, h as ComputedAttributeState } from './attributes-_6tvjbyl.js';
3
+ import { V as ValidationMessages, a as ValidationResult } from './types-B_UZK_6m.js';
4
+ import { IconName } from '@stndrds/constants';
5
+ import { Uuid } from './utils.js';
6
+
7
+ interface DocumentLayout {
8
+ /** Named sub-folders auto-created at the top of the record's drive when first used via attach --variant. */
9
+ variants?: Record<string, DocumentLayoutVariant>;
10
+ /** Dev-declared folder structures the user can instantiate via the UI inside a record's drive. */
11
+ presets?: FolderPreset[];
12
+ }
13
+ interface DocumentLayoutVariant {
14
+ /** Display title for the auto-created sub-folder. */
15
+ title: string;
16
+ description?: string;
17
+ }
18
+ interface FolderPreset {
19
+ id: string;
20
+ label: string;
21
+ icon?: IconName;
22
+ description?: string;
23
+ structure: PresetNode[];
24
+ /** When true, this preset is auto-instantiated on every new record's drive for the owning object. */
25
+ autoInstantiate?: boolean;
26
+ }
27
+ interface PresetNode {
28
+ title: string;
29
+ description?: string;
30
+ children?: PresetNode[];
31
+ }
32
+ /** Max depth allowed for preset.structure to keep instantiation predictable. */
33
+ declare const MAX_PRESET_DEPTH = 5;
34
+
35
+ type BuiltInTransform = "toString" | "toNumber" | "toDate" | "toBoolean" | "toISOString";
36
+ type SchemaOperation = {
37
+ type: "add_attribute";
38
+ attribute: Attribute;
39
+ } | {
40
+ type: "remove_attribute";
41
+ name: string;
42
+ backup_config: Attribute;
43
+ } | {
44
+ type: "rename_attribute";
45
+ from: string;
46
+ to: string;
47
+ } | {
48
+ type: "change_type";
49
+ name: string;
50
+ from: AttributeType;
51
+ to: AttributeType;
52
+ transform?: BuiltInTransform;
53
+ } | {
54
+ type: "update_config";
55
+ name: string;
56
+ from: Partial<Record<string, unknown>>;
57
+ to: Partial<Record<string, unknown>>;
58
+ } | {
59
+ type: "remove_object";
60
+ backup: Record<string, unknown>;
61
+ } | {
62
+ type: "rename_object";
63
+ from: string;
64
+ to: string;
65
+ };
66
+ interface MigrationDefinition {
67
+ version: number;
68
+ operations: SchemaOperation[];
69
+ }
70
+
71
+ /**
72
+ * Timestamps for tracking creation and updates
73
+ */
74
+ interface Timestamps {
75
+ createdAt: Date;
76
+ updatedAt: Date;
77
+ }
78
+ /**
79
+ * Object definition - Represents a database table/entity
80
+ */
81
+ interface ObjectDefinition {
82
+ id?: Uuid;
83
+ name: string;
84
+ label: string;
85
+ pluralLabel?: string;
86
+ description?: string;
87
+ icon?: IconName;
88
+ /**
89
+ * Template expression used to compute the object's display label.
90
+ * Supports variable interpolation and pipes for formatting.
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * // Simple attribute reference
95
+ * labelExpression: "{{ name }}"
96
+ *
97
+ * // Multiple attributes
98
+ * labelExpression: "{{ firstName }} {{ lastName }}"
99
+ *
100
+ * // With pipes for formatting
101
+ * labelExpression: "{{ code | UPPER }} - {{ name | capitalize }}"
102
+ * ```
103
+ *
104
+ * Available pipes: UPPER, LOWER, capitalize, trim
105
+ */
106
+ labelExpression: string;
107
+ /**
108
+ * Optional template expression used to compute the semantic text sent to
109
+ * Meilisearch for vector generation. When absent, records opt out of semantic
110
+ * embedding generation.
111
+ */
112
+ embeddingExpression?: string;
113
+ attributes: Attribute[];
114
+ system?: boolean;
115
+ /**
116
+ * If true, no custom (user-created) attributes are allowed on this object.
117
+ * `standards diff` will report an error if any custom attribute is found.
118
+ * Use .sealed() on the ObjectBuilder to set this.
119
+ */
120
+ sealed?: boolean;
121
+ /**
122
+ * List of custom attribute names explicitly acknowledged by the developer.
123
+ * On a sealed object, these names will NOT trigger a CI failure.
124
+ * On an extensible object, this is purely documentary.
125
+ * Use .tolerate(["name"]) on the ObjectBuilder to set this.
126
+ */
127
+ toleratedAttributes?: string[];
128
+ metadata?: Record<string, unknown>;
129
+ /** Current schema version (incremented with each migration) */
130
+ schema_version: number;
131
+ /** Ordered list of migrations applied to this object's schema */
132
+ migrations: MigrationDefinition[];
133
+ /** Smart-folder layout convention for documents attached to records of this object. */
134
+ documentLayout?: DocumentLayout;
135
+ }
136
+ /**
137
+ * Links an attribute to an object
138
+ */
139
+ interface ObjectAttribute {
140
+ objectId: Uuid;
141
+ attributeId: Uuid;
142
+ order?: number;
143
+ required?: boolean;
144
+ }
145
+ /**
146
+ * Record - Instance of an Object (a row in the database)
147
+ */
148
+ interface ObjectRecord<TValues extends Record<string, unknown> = Record<string, unknown>> extends Timestamps {
149
+ id: Uuid;
150
+ objectId: Uuid;
151
+ /**
152
+ * Display label computed from the object's labelExpression.
153
+ * Computed dynamically based on record values.
154
+ *
155
+ * @example "John Doe" (from "{{ firstName }} {{ lastName }}")
156
+ */
157
+ label: string;
158
+ /**
159
+ * Semantic text computed from the object's embeddingExpression and persisted
160
+ * for Meilisearch documentTemplate-based vector generation.
161
+ */
162
+ embeddingText?: string;
163
+ values: TValues;
164
+ /** Per-computed-attribute state keyed by attribute name. */
165
+ computedStates?: Record<string, ComputedAttributeState>;
166
+ /**
167
+ * Custom metadata for the record.
168
+ * Use this for UI/UX state, feature flags, or any application-specific data.
169
+ * Unlike system fields (id, createdAt, updatedAt), metadata can be updated.
170
+ */
171
+ metadata?: Record<string, unknown>;
172
+ /**
173
+ * Soft delete timestamp.
174
+ * If set, the record is considered deleted but can be restored.
175
+ * Queries exclude soft-deleted records by default.
176
+ */
177
+ deletedAt?: Date | null;
178
+ /**
179
+ * Actor ID who soft-deleted this record.
180
+ * Set alongside deletedAt when a record is soft-deleted.
181
+ */
182
+ deletedBy?: string | null;
183
+ /**
184
+ * Actor ID who created this record.
185
+ * Automatically set by RecordService when actorId is configured.
186
+ * Optional for backward compatibility with existing records.
187
+ */
188
+ createdBy?: string;
189
+ /**
190
+ * Actor ID who last updated this record.
191
+ * Automatically set by RecordService when actorId is configured.
192
+ * Optional for backward compatibility with existing records.
193
+ */
194
+ lastUpdatedBy?: string;
195
+ /** Schema version at the time this record was last migrated */
196
+ schemaVersion: number;
197
+ }
198
+ /**
199
+ * System-managed field names on ObjectRecord.
200
+ * These are stored as SQL columns (not in JSONB `values`).
201
+ *
202
+ * Use this in adapters to determine if a filter/sort attribute is a table column
203
+ * vs. a JSONB value field.
204
+ *
205
+ * @example
206
+ * ```typescript
207
+ * if (SYSTEM_FIELD_NAMES.includes(filter.attribute)) {
208
+ * // Filter on SQL column (e.g., WHERE created_at > ...)
209
+ * } else {
210
+ * // Filter on JSONB field (e.g., WHERE values->>'name' = ...)
211
+ * }
212
+ * ```
213
+ */
214
+ declare const SYSTEM_FIELD_NAMES: readonly ["id", "createdAt", "updatedAt", "createdBy", "lastUpdatedBy"];
215
+ /**
216
+ * Type for system field names
217
+ */
218
+ type SystemFieldName = (typeof SYSTEM_FIELD_NAMES)[number];
219
+ /**
220
+ * Reserved attribute names that cannot be used for custom attributes.
221
+ * These names conflict with ObjectRecord properties.
222
+ *
223
+ * Includes:
224
+ * - System fields (id, createdAt, updatedAt, createdBy, lastUpdatedBy)
225
+ * - Other ObjectRecord properties (objectId, label, values, metadata, deletedAt)
226
+ *
227
+ * @example
228
+ * ```typescript
229
+ * if (RESERVED_ATTRIBUTE_NAMES.includes(attributeName)) {
230
+ * throw new Error(`"${attributeName}" is a reserved name`);
231
+ * }
232
+ * ```
233
+ */
234
+ declare const RESERVED_ATTRIBUTE_NAMES: readonly ["id", "createdAt", "updatedAt", "createdBy", "lastUpdatedBy", "objectId", "label", "embeddingText", "values", "metadata", "deletedAt", "deletedBy", "schemaVersion"];
235
+ /**
236
+ * Type for reserved attribute names
237
+ */
238
+ type ReservedAttributeName = (typeof RESERVED_ATTRIBUTE_NAMES)[number];
239
+ /**
240
+ * Reserved object names that cannot be used for user-created (runtime) objects.
241
+ * These are owned by the framework as sealed system objects.
242
+ */
243
+ declare const RESERVED_OBJECT_NAMES: readonly ["skill"];
244
+ type ReservedObjectName = (typeof RESERVED_OBJECT_NAMES)[number];
245
+
246
+ /**
247
+ * Create a Zod schema for any attribute type.
248
+ * Returns a strict validator that does NOT handle optional fields.
249
+ * Use createFormAttributeValidator for form validation with optional support.
250
+ *
251
+ * @param attr - The attribute to create a validator for
252
+ * @param messages - Custom validation messages for i18n support
253
+ */
254
+ declare function createAttributeValidator(attr: Attribute, messages?: ValidationMessages): z.ZodTypeAny;
255
+ /**
256
+ * Create a Zod schema for form validation.
257
+ * - Normalizes empty values (empty strings, empty objects) to null for optional fields
258
+ * - Accepts custom messages for i18n support
259
+ *
260
+ * Use this in UI forms where optional fields may have null/undefined values.
261
+ *
262
+ * @param attr - The attribute to create a validator for
263
+ * @param messages - Custom validation messages for i18n support
264
+ */
265
+ declare function createFormAttributeValidator(attr: Attribute, messages?: ValidationMessages): z.ZodTypeAny;
266
+
267
+ /**
268
+ * Validate data against an attribute schema
269
+ */
270
+ declare function validateAttribute(attr: Attribute, value: unknown): ValidationResult;
271
+ /**
272
+ * Validate data against an object schema
273
+ */
274
+ declare function validateObject(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
275
+ /**
276
+ * Validate and throw if invalid.
277
+ *
278
+ * Throws `ValidationError` (code `SCHEMA_VALIDATION_FAILED`) on failure so HTTP
279
+ * adapters can map it to 400. Generic `Error` would bubble up to a 500.
280
+ */
281
+ declare function validateObjectOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
282
+ /**
283
+ * Validate data in draft mode.
284
+ * - All attributes are treated as optional (no required validation)
285
+ * - Provided values are still validated for format/type correctness
286
+ */
287
+ declare function validateDraft(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
288
+ /**
289
+ * Validate draft data and throw if format validation fails.
290
+ *
291
+ * Same contract as `validateObjectOrThrow` but skips `required()` checks.
292
+ * Throws `ValidationError` so HTTP adapters map it to 400.
293
+ */
294
+ declare function validateDraftOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
295
+ /**
296
+ * Throw a `ValidationError` when `data` contains keys that do not correspond
297
+ * to any attribute declared on `objectDef`.
298
+ *
299
+ * Call this on **client-supplied input** before Zod validation so the error
300
+ * message clearly names every offending key. Do NOT call on merged data that
301
+ * includes existing record values — older records may legitimately carry stale
302
+ * keys that predate this guard (see issue #658).
303
+ *
304
+ * Maps to HTTP 400 via `SchemaExceptionFilter` (code SCHEMA_VALIDATION_FAILED).
305
+ */
306
+ declare function rejectUnknownAttributesOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): void;
307
+ /**
308
+ * Get the list of required attributes that are missing values.
309
+ */
310
+ declare function getMissingRequiredAttributes(objectDef: ObjectDefinition, data: Record<string, unknown>): Attribute[];
311
+ /**
312
+ * Check if a record is complete (all required attributes have valid values).
313
+ */
314
+ declare function isRecordComplete(objectDef: ObjectDefinition, data: Record<string, unknown>): boolean;
315
+
316
+ export { type BuiltInTransform as B, type DocumentLayout as D, type FolderPreset as F, type MigrationDefinition as M, type ObjectDefinition as O, type PresetNode as P, RESERVED_ATTRIBUTE_NAMES as R, type SchemaOperation as S, type Timestamps as T, validateDraftOrThrow as a, validateObject as b, createFormAttributeValidator as c, validateObjectOrThrow as d, createAttributeValidator as e, validateAttribute as f, getMissingRequiredAttributes as g, type DocumentLayoutVariant as h, isRecordComplete as i, MAX_PRESET_DEPTH as j, type ObjectAttribute as k, type ObjectRecord as l, RESERVED_OBJECT_NAMES as m, type ReservedAttributeName as n, type ReservedObjectName as o, SYSTEM_FIELD_NAMES as p, type SystemFieldName as q, rejectUnknownAttributesOrThrow as r, validateDraft as v };