From 24be696488d577149ce3648897952bdf0b311885 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 15:37:53 +0000 Subject: [PATCH 1/7] Initial plan From 8c60f1900d931a5e5e883ec28a0d192889a91f53 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 15:48:38 +0000 Subject: [PATCH 2/7] feat: Integrate @objectstack/spec as Protocol Constitution in @objectql/types Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/foundation/types/package.json | 5 +- packages/foundation/types/src/action.ts | 24 ++++ packages/foundation/types/src/field.ts | 167 +++++++++--------------- packages/foundation/types/src/index.ts | 7 + packages/foundation/types/src/object.ts | 101 +++++++++++++- pnpm-lock.yaml | 4 + 6 files changed, 198 insertions(+), 110 deletions(-) diff --git a/packages/foundation/types/package.json b/packages/foundation/types/package.json index 43073492..1ff6f460 100644 --- a/packages/foundation/types/package.json +++ b/packages/foundation/types/package.json @@ -22,10 +22,13 @@ "schemas" ], "scripts": { - "build": "tsc && npm run generate:schemas", + "build": "tsc", "generate:schemas": "node scripts/generate-schemas.js", "test": "jest --passWithNoTests" }, + "dependencies": { + "@objectstack/spec": "^0.1.1" + }, "devDependencies": { "ts-json-schema-generator": "^2.4.0" } diff --git a/packages/foundation/types/src/action.ts b/packages/foundation/types/src/action.ts index efa908fd..aead8890 100644 --- a/packages/foundation/types/src/action.ts +++ b/packages/foundation/types/src/action.ts @@ -6,9 +6,21 @@ * LICENSE file in the root directory of this source tree. */ +// Import and re-export types from the Protocol Constitution (@objectstack/spec) +import type { Action } from '@objectstack/spec'; import { FieldConfig } from "./field"; import { HookAPI } from "./hook"; // Reuse the restricted API interface +/** + * Re-export Protocol Types from the Constitution + */ +export type { Action as SpecAction }; + +/** + * RUNTIME-SPECIFIC TYPES + * The following types extend the Protocol Action definition with runtime execution capabilities + */ + /** * Defines the scope of the action. * - `record`: Acts on a specific record instance (e.g. "Approve Order"). @@ -24,6 +36,8 @@ export type ActionInputDefinition = Record; /** * Context passed to the action handler execution. + * + * RUNTIME TYPE: Used during action execution. */ export interface ActionContext { /** The object this action belongs to. */ @@ -58,11 +72,19 @@ export interface ActionContext { } /** + * Runtime Action Configuration + * * The configuration of an Action visible to the Metadata engine (YAML/JSON side). + * Compatible with Protocol Action but adds runtime-specific options. */ export interface ActionConfig { + /** Display label */ label?: string; + + /** Description */ description?: string; + + /** Icon name */ icon?: string; /** @@ -93,6 +115,8 @@ export interface ActionConfig { /** * The full implementation definition (Code side). + * + * RUNTIME TYPE: Includes the handler function for execution. */ export interface ActionDefinition extends ActionConfig { /** diff --git a/packages/foundation/types/src/field.ts b/packages/foundation/types/src/field.ts index ee3f5d80..da341d6e 100644 --- a/packages/foundation/types/src/field.ts +++ b/packages/foundation/types/src/field.ts @@ -6,11 +6,26 @@ * LICENSE file in the root directory of this source tree. */ -import { FieldValidation, ValidationAiContext } from './validation'; +// Import types from the Protocol Constitution (@objectstack/spec) +import type { FieldType as ProtocolFieldType, Field, SelectOption as SpecSelectOption } from '@objectstack/spec'; + +/** + * Re-export Protocol Types from the Constitution + * These are the wire-protocol standard types defined in @objectstack/spec + */ +export type { Field as SpecField, SpecSelectOption, ProtocolFieldType }; + +/** + * RUNTIME-SPECIFIC TYPES + * The following types extend or complement the Protocol Constitution + * with runtime-specific properties that don't belong in the wire protocol. + */ /** * Attachment field data structure for file and image types. * Stores metadata about uploaded files, with actual file content stored separately. + * + * This is a RUNTIME type - not part of the wire protocol. */ export interface AttachmentData { /** Unique identifier for this file */ @@ -41,6 +56,8 @@ export interface AttachmentData { /** * Image-specific attachment data with additional metadata. * Extends AttachmentData with image-specific properties. + * + * This is a RUNTIME type - not part of the wire protocol. */ export interface ImageAttachmentData extends AttachmentData { /** Image width in pixels */ @@ -61,111 +78,60 @@ export interface ImageAttachmentData extends AttachmentData { } /** - * Represents the supported field data types in the ObjectQL schema. - * These types determine how data is stored, validated, and rendered. + * Runtime Field Type * - * - `text`: Simple string. - * - `textarea`: Long string. - * - `select`: Choice from a list. - * - `lookup`: Relationship to another object. - * - `file`: File attachment. Value stored as AttachmentData (single) or AttachmentData[] (multiple). - * - `image`: Image attachment. Value stored as ImageAttachmentData (single) or ImageAttachmentData[] (multiple). + * Extends the Protocol FieldType with runtime-specific types. + * The Protocol Constitution defines the core field types. + * We add runtime-specific types like 'vector', 'grid', 'location', 'object' here. */ export type FieldType = - | 'text' - | 'textarea' - | 'markdown' - | 'html' - | 'select' - | 'date' - | 'datetime' - | 'time' - | 'number' - | 'currency' - | 'percent' - | 'boolean' - | 'email' - | 'phone' - | 'url' - | 'image' - | 'file' - | 'location' - | 'lookup' - | 'master_detail' - | 'password' - | 'formula' - | 'summary' - | 'auto_number' - | 'object' - | 'vector' - | 'grid'; + | ProtocolFieldType + | 'location' // Runtime: Geographic location + | 'object' // Runtime: Nested object/JSON + | 'vector' // Runtime: Vector embeddings for AI + | 'grid'; // Runtime: Inline grid/table /** - * Defines a single option for select/multiselect fields. + * Runtime Field Option + * + * Extends the Protocol SelectOption to allow number values (for backwards compatibility). */ export interface FieldOption { /** The display label for the option. */ label: string; /** The actual value stored in the database. */ value: string | number; + /** Optional color for visual representation */ + color?: string; + /** Whether this is the default option */ + default?: boolean; } /** - * Configuration for a single field on an object. - * This defines the schema, validation rules, and UI hints for the attribute. + * Runtime Field Configuration + * + * Extends the Protocol Field definition with runtime-specific properties. + * The Protocol Constitution (SpecField) defines the core field schema. + * This adds runtime conveniences and extensions. */ -export interface FieldConfig { - /** - * The unique API name of the field. - * If defined within an object map, this is often automatically populated from the key. - */ - name?: string; - - /** The human-readable label used in UIs. */ - label?: string; - - /** Description of the field for documentation or tooltip. */ - description?: string; - - /** The data type of the field. */ +export interface FieldConfig extends Omit { + /** The data type of the field (extended with runtime types) */ type: FieldType; - /** Whether the field is mandatory. Defaults to false. */ - required?: boolean; - - /** Whether the field is unique in the table. */ - unique?: boolean; - - /** Whether to create a database index for this field. */ - index?: boolean; - - /** Whether the field is read-only in UI. */ - readonly?: boolean; - - /** Whether the field is hidden from default UI/API response. */ - hidden?: boolean; - - /** The default value if not provided during creation. */ - defaultValue?: any; - - /** Tooltip or help text for the user. */ - help_text?: string; + /** Options for select fields (extended to allow number values) */ + options?: FieldOption[]; - /** - * Whether the field allows multiple values. - * Supported by 'select', 'lookup', 'file', 'image'. + /** + * RUNTIME EXTENSIONS BELOW + * These properties are NOT in the wire protocol but are useful for the runtime. */ - multiple?: boolean; - /** - * Options for select fields. - * List of available choices for select/multiselect fields. - */ - options?: FieldOption[]; + /** Tooltip or help text for the user. */ + help_text?: string; /** * Reference to another object for lookup/master_detail fields. - * Specifies the target object name for relationship fields. + * @deprecated Use 'reference' from SpecField instead */ reference_to?: string; @@ -206,37 +172,27 @@ export interface FieldConfig { */ min_height?: number; - // Validation properties - /** Minimum for number/currency/percent. */ - min?: number; - /** Maximum for number/currency/percent. */ - max?: number; - /** Minimum length for text based fields. */ - min_length?: number; - /** Maximum length for text based fields. */ - max_length?: number; - /** Regular expression pattern for validation. */ - regex?: string; - - /** - * Field validation configuration. - * Defines validation rules applied at the field level. + /** + * Regular expression pattern for validation. + * @deprecated Use SpecField validation pattern instead */ - validation?: FieldValidation; + regex?: string; /** * AI context for the field. * Provides semantic information for AI tools. */ - ai_context?: ValidationAiContext; + ai_context?: { + intent?: string; + validation_strategy?: string; + [key: string]: unknown; + }; - // Vector properties + // Vector properties (runtime-specific) /** Dimension of the vector for 'vector' type fields. */ dimension?: number; - // Formula properties - /** Formula expression (for 'formula' type fields). */ - formula?: string; + // Formula properties (extended from protocol) /** Expected return data type for formula fields. */ data_type?: 'number' | 'text' | 'date' | 'datetime' | 'boolean' | 'currency' | 'percent'; /** Display format for formula results (e.g., "0.00", "YYYY-MM-DD"). */ @@ -248,12 +204,13 @@ export interface FieldConfig { /** Default value for null/undefined referenced fields in formulas. */ treat_blank_as?: string | number | boolean | Date | null; - // Summary properties + // Summary properties (extended from protocol) /** Object to summarize. */ summary_object?: string; /** Field on the summary object. */ summary_field?: string; /** Type of summary (count, sum, min, max, avg). */ summary_type?: string; + /** Filters for summary */ filters?: unknown[]; } diff --git a/packages/foundation/types/src/index.ts b/packages/foundation/types/src/index.ts index 7cb938a2..e2c1712b 100644 --- a/packages/foundation/types/src/index.ts +++ b/packages/foundation/types/src/index.ts @@ -6,6 +6,13 @@ * LICENSE file in the root directory of this source tree. */ +/** + * Export our runtime types. + * + * These modules import and extend types from @objectstack/spec where needed. + * Users of @objectql/types should import from here to get both protocol types + * and runtime extensions. + */ export * from './field'; export * from './object'; export * from './driver'; diff --git a/packages/foundation/types/src/object.ts b/packages/foundation/types/src/object.ts index 7756be42..c53d99e9 100644 --- a/packages/foundation/types/src/object.ts +++ b/packages/foundation/types/src/object.ts @@ -6,17 +6,42 @@ * LICENSE file in the root directory of this source tree. */ +// Import and re-export types from the Protocol Constitution (@objectstack/spec) +import type { ServiceObject, IndexSchema } from '@objectstack/spec'; import { FieldConfig } from './field'; import { ActionConfig } from './action'; import { AnyValidationRule } from './validation'; +/** + * Re-export Protocol Types from the Constitution + */ +export type { ServiceObject as SpecObject, IndexSchema }; + +/** + * RUNTIME-SPECIFIC TYPES + * The following types extend or complement the Protocol Constitution + */ + +/** + * Index Configuration (compatible with Protocol) + * + * The Protocol defines IndexSchema. We provide a simpler alias for runtime convenience. + */ export interface IndexConfig { + /** Index name (optional, auto-generated if not provided) */ + name?: string; /** List of fields involved in the index */ fields: string[]; /** Whether the index enforces uniqueness */ unique?: boolean; } +/** + * AI Search Configuration + * + * RUNTIME EXTENSION: Not part of the wire protocol. + * Defines semantic search capabilities for the runtime engine. + */ export interface AiSearchConfig { /** Enable semantic search for this object */ enabled: boolean; @@ -28,24 +53,90 @@ export interface AiSearchConfig { target_field?: string; } +/** + * Object AI Configuration + * + * RUNTIME EXTENSION: Not part of the wire protocol. + */ export interface ObjectAiConfig { /** Configuration for semantic search / RAG */ search?: AiSearchConfig; } +/** + * Runtime Object Configuration + * + * Extends the Protocol ServiceObject with runtime-specific properties. + * The Protocol Constitution (SpecObject) defines the core object schema. + * This adds runtime conveniences like actions, AI config, and validation rules. + */ export interface ObjectConfig { + /** Object name (required by Protocol) */ name: string; - datasource?: string; // The name of the datasource to use + + /** Display label */ label?: string; - icon?: string; + + /** Plural label */ + pluralLabel?: string; + + /** Description */ description?: string; + /** Icon identifier */ + icon?: string; + + /** Datasource name (defaults to 'default') */ + datasource?: string; + + /** Custom table name (defaults to object name) */ + tableName?: string; + + /** Whether this is a system object */ + isSystem?: boolean; + + /** + * Field definitions + * Maps field names to their configurations + */ fields: Record; + + /** + * Index definitions + * Maps index names to their configurations + */ indexes?: Record; - /** AI capabilities configuration */ + + /** Primary display field */ + nameField?: string; + + /** Object capabilities (from Protocol) */ + enable?: { + /** Enable history tracking (Audit Trail) */ + trackHistory?: boolean; + /** Enable global search indexing */ + searchable?: boolean; + /** Enable REST/GraphQL API access */ + apiEnabled?: boolean; + /** Enable attachments/files */ + files?: boolean; + /** Enable discussions/chatter */ + feedEnabled?: boolean; + /** Enable Recycle Bin mechanics */ + trash?: boolean; + }; + + /** + * RUNTIME EXTENSIONS BELOW + */ + + /** AI capabilities configuration (RUNTIME ONLY) */ ai?: ObjectAiConfig; + + /** Custom actions (RUNTIME ONLY) */ actions?: Record; - /** Validation rules for this object */ + + /** Validation rules for this object (RUNTIME ONLY) */ validation?: { /** Validation rules */ rules?: AnyValidationRule[]; @@ -59,6 +150,8 @@ export interface ObjectConfig { /** * Base interface for all ObjectQL documents. + * + * RUNTIME TYPE: Represents a document instance in the database. */ export interface ObjectDoc { _id?: string | number; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5eb67951..62b9b99e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -428,6 +428,10 @@ importers: version: 5.9.3 packages/foundation/types: + dependencies: + '@objectstack/spec': + specifier: ^0.1.1 + version: 0.1.1 devDependencies: ts-json-schema-generator: specifier: ^2.4.0 From 07b8bce135f5e60239ad5c7911d0ee5787968c4a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 15:53:15 +0000 Subject: [PATCH 3/7] fix: Align field naming with @objectstack/spec protocol (autonumber, minLength, maxLength) Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/foundation/core/src/util.ts | 4 +- packages/foundation/types/src/field.ts | 58 ++++++++++++++++++- .../runtime/server/src/adapters/graphql.ts | 2 +- packages/runtime/server/src/metadata.ts | 4 +- packages/tools/cli/src/commands/generate.ts | 2 +- packages/tools/cli/src/commands/sync.ts | 4 +- 6 files changed, 65 insertions(+), 9 deletions(-) diff --git a/packages/foundation/core/src/util.ts b/packages/foundation/core/src/util.ts index 2060a74c..9617f535 100644 --- a/packages/foundation/core/src/util.ts +++ b/packages/foundation/core/src/util.ts @@ -111,6 +111,7 @@ export function convertIntrospectedSchemaToObjects( if (foreignKey) { // This is a lookup field fieldConfig = { + name: column.name, type: 'lookup', reference_to: foreignKey.referencedTable, label: toTitleCase(column.name), @@ -121,6 +122,7 @@ export function convertIntrospectedSchemaToObjects( const fieldType = mapDatabaseTypeToFieldType(column.type); fieldConfig = { + name: column.name, type: fieldType, label: toTitleCase(column.name), required: !column.nullable @@ -133,7 +135,7 @@ export function convertIntrospectedSchemaToObjects( // Add max length for text fields if (column.maxLength && (fieldType === 'text' || fieldType === 'textarea')) { - fieldConfig.max_length = column.maxLength; + fieldConfig.maxLength = column.maxLength; } // Add default value diff --git a/packages/foundation/types/src/field.ts b/packages/foundation/types/src/field.ts index da341d6e..67be55e4 100644 --- a/packages/foundation/types/src/field.ts +++ b/packages/foundation/types/src/field.ts @@ -113,14 +113,43 @@ export interface FieldOption { * Extends the Protocol Field definition with runtime-specific properties. * The Protocol Constitution (SpecField) defines the core field schema. * This adds runtime conveniences and extensions. + * + * We make certain spec fields optional since Zod applies defaults at parse time. */ -export interface FieldConfig extends Omit { +export interface FieldConfig extends Omit { /** The data type of the field (extended with runtime types) */ type: FieldType; /** Options for select fields (extended to allow number values) */ options?: FieldOption[]; + /** Whether the field is mandatory. Defaults to false. */ + required?: boolean; + + /** Whether the field allows multiple values. */ + multiple?: boolean; + + /** Whether the field is unique in the table. */ + unique?: boolean; + + /** Delete behavior for relationships */ + deleteBehavior?: 'set_null' | 'cascade' | 'restrict'; + + /** Whether the field is hidden from default UI/API response. */ + hidden?: boolean; + + /** Whether the field is read-only in UI. */ + readonly?: boolean; + + /** Whether the field is encrypted */ + encryption?: boolean; + + /** Whether to create a database index for this field. */ + index?: boolean; + + /** Whether this is an external ID field */ + externalId?: boolean; + /** * RUNTIME EXTENSIONS BELOW * These properties are NOT in the wire protocol but are useful for the runtime. @@ -174,10 +203,35 @@ export interface FieldConfig extends Omit { /** * Regular expression pattern for validation. - * @deprecated Use SpecField validation pattern instead + * @deprecated Use validation.pattern instead */ regex?: string; + /** + * Field validation configuration. + * Defines validation rules applied at the field level. + */ + validation?: { + /** Format validation (email, url, etc.) */ + format?: 'email' | 'url' | 'phone' | 'date' | 'datetime'; + /** Allowed protocols for URL validation */ + protocols?: string[]; + /** Minimum value for numbers */ + min?: number; + /** Maximum value for numbers */ + max?: number; + /** Minimum length for strings */ + min_length?: number; + /** Maximum length for strings */ + max_length?: number; + /** Regular expression pattern for validation */ + pattern?: string; + /** Regex pattern (alias for pattern) */ + regex?: string; + /** Custom validation message */ + message?: string; + }; + /** * AI context for the field. * Provides semantic information for AI tools. diff --git a/packages/runtime/server/src/adapters/graphql.ts b/packages/runtime/server/src/adapters/graphql.ts index d79521be..160c2b41 100644 --- a/packages/runtime/server/src/adapters/graphql.ts +++ b/packages/runtime/server/src/adapters/graphql.ts @@ -76,7 +76,7 @@ function mapFieldTypeToGraphQL(field: FieldConfig, isInput: boolean = false): Gr case 'currency': case 'percent': return GraphQLFloat; - case 'auto_number': + case 'autonumber': return GraphQLInt; case 'boolean': return GraphQLBoolean; diff --git a/packages/runtime/server/src/metadata.ts b/packages/runtime/server/src/metadata.ts index 66e07834..d91c8222 100644 --- a/packages/runtime/server/src/metadata.ts +++ b/packages/runtime/server/src/metadata.ts @@ -197,8 +197,8 @@ export function createMetadataHandler(app: IObjectQL, options?: MetadataHandlerO options: field.options, min: field.min, max: field.max, - min_length: field.min_length, - max_length: field.max_length, + minLength: field.minLength, + maxLength: field.maxLength, regex: field.regex }); } diff --git a/packages/tools/cli/src/commands/generate.ts b/packages/tools/cli/src/commands/generate.ts index e40d7787..6d1975e9 100644 --- a/packages/tools/cli/src/commands/generate.ts +++ b/packages/tools/cli/src/commands/generate.ts @@ -107,7 +107,7 @@ function mapFieldTypeToTs(field: FieldConfig): string { case 'number': case 'currency': case 'percent': - case 'auto_number': + case 'autonumber': return 'number'; case 'boolean': diff --git a/packages/tools/cli/src/commands/sync.ts b/packages/tools/cli/src/commands/sync.ts index 0bf0de1e..fa17e9f9 100644 --- a/packages/tools/cli/src/commands/sync.ts +++ b/packages/tools/cli/src/commands/sync.ts @@ -189,9 +189,9 @@ function generateObjectDefinition(table: IntrospectedTable, schema: Introspected field.unique = true; } - // Add max_length for text-based fields + // Add maxLength for text-based fields if (column.maxLength && (fieldType === 'text' || fieldType === 'textarea')) { - field.max_length = column.maxLength; + field.maxLength = column.maxLength; } if (column.defaultValue !== undefined && column.defaultValue !== null) { From 9ff88f2cffefed618827ff4d29ed075581f51a7b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 15:54:37 +0000 Subject: [PATCH 4/7] test: Fix test to use maxLength instead of max_length Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/foundation/core/test/util.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/foundation/core/test/util.test.ts b/packages/foundation/core/test/util.test.ts index 85677ec7..d3aba3a5 100644 --- a/packages/foundation/core/test/util.test.ts +++ b/packages/foundation/core/test/util.test.ts @@ -327,7 +327,7 @@ describe('Utility Functions', () => { const objects = convertIntrospectedSchemaToObjects(schema); const fields = objects[0].fields!; - expect(fields.short_text.max_length).toBe(100); + expect(fields.short_text.maxLength).toBe(100); }); it('should add default value when present', () => { From 5b07fd79ab0d4722474e6458ea7f53445d93af88 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 16:40:21 +0000 Subject: [PATCH 5/7] Initial plan From f9ddcf0fe3364dffc5b19ef1b5ab7c090b5dba3d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 16:47:19 +0000 Subject: [PATCH 6/7] Fix: Make name and label optional in FieldConfig to fix TypeScript compilation errors The @objectstack/spec package requires name and label fields on the Field type, but when fields are defined in ObjectConfig.fields as a Record, the name is inferred from the record key. This change makes name and label optional in FieldConfig to match this usage pattern. Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- packages/foundation/types/src/field.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/foundation/types/src/field.ts b/packages/foundation/types/src/field.ts index 67be55e4..e8339dc2 100644 --- a/packages/foundation/types/src/field.ts +++ b/packages/foundation/types/src/field.ts @@ -116,7 +116,13 @@ export interface FieldOption { * * We make certain spec fields optional since Zod applies defaults at parse time. */ -export interface FieldConfig extends Omit { +export interface FieldConfig extends Omit { + /** Field name (inferred from Record key when used in ObjectConfig.fields) */ + name?: string; + + /** Display label (derived from name if not provided) */ + label?: string; + /** The data type of the field (extended with runtime types) */ type: FieldType; From 9f1b180826d87f739da1ecc274cdd0f0d13fd755 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 08:26:20 +0000 Subject: [PATCH 7/7] refactor: Address PR review feedback - improve documentation and remove ambiguous deprecated properties Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- packages/foundation/core/src/util.ts | 4 ++ packages/foundation/core/src/validator.ts | 9 ++-- packages/foundation/types/src/field.ts | 51 ++++++++++++++++++----- packages/runtime/server/src/metadata.ts | 2 +- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/packages/foundation/core/src/util.ts b/packages/foundation/core/src/util.ts index 9617f535..0fd33e8a 100644 --- a/packages/foundation/core/src/util.ts +++ b/packages/foundation/core/src/util.ts @@ -110,6 +110,8 @@ export function convertIntrospectedSchemaToObjects( if (foreignKey) { // This is a lookup field + // Note: name must be set explicitly here since we're creating the config programmatically. + // When defined in YAML (ObjectConfig.fields Record), the name is auto-populated from the key. fieldConfig = { name: column.name, type: 'lookup', @@ -121,6 +123,8 @@ export function convertIntrospectedSchemaToObjects( // Regular field const fieldType = mapDatabaseTypeToFieldType(column.type); + // Note: name must be set explicitly here since we're creating the config programmatically. + // When defined in YAML (ObjectConfig.fields Record), the name is auto-populated from the key. fieldConfig = { name: column.name, type: fieldType, diff --git a/packages/foundation/core/src/validator.ts b/packages/foundation/core/src/validator.ts index 0a70b858..bd66a351 100644 --- a/packages/foundation/core/src/validator.ts +++ b/packages/foundation/core/src/validator.ts @@ -190,11 +190,10 @@ export class Validator { } } - // Pattern validation (supports both pattern and deprecated regex) - const patternValue = validation.pattern ?? validation.regex; - if (patternValue) { + // Pattern validation + if (validation.pattern) { try { - const pattern = new RegExp(patternValue); + const pattern = new RegExp(validation.pattern); if (!pattern.test(String(value))) { results.push({ rule: `${fieldName}_pattern`, @@ -208,7 +207,7 @@ export class Validator { results.push({ rule: `${fieldName}_pattern`, valid: false, - message: `Invalid regex pattern: ${patternValue}`, + message: `Invalid regex pattern: ${validation.pattern}`, severity: 'error', fields: [fieldName], }); diff --git a/packages/foundation/types/src/field.ts b/packages/foundation/types/src/field.ts index e8339dc2..1ed0b8be 100644 --- a/packages/foundation/types/src/field.ts +++ b/packages/foundation/types/src/field.ts @@ -114,7 +114,16 @@ export interface FieldOption { * The Protocol Constitution (SpecField) defines the core field schema. * This adds runtime conveniences and extensions. * - * We make certain spec fields optional since Zod applies defaults at parse time. + * Properties from the protocol Field interface that are re-declared here: + * - `name`, `label`: Made optional for runtime convenience (auto-populated from Record key) + * - `type`: Extended union type to include runtime-specific types (vector, grid, location, object) + * - `options`: Extended to allow numeric values for backwards compatibility + * - Boolean flags (`required`, `multiple`, `unique`, `hidden`, `readonly`, `encryption`, `index`, `externalId`): + * Made optional since Zod applies defaults at parse time, but runtime usage typically specifies these explicitly + * - `deleteBehavior`: Made optional with protocol-compatible enum values + * + * All other protocol properties (description, defaultValue, maxLength, minLength, precision, scale, min, max, + * reference, referenceFilters, writeRequiresMasterRead, expression, formula, summaryOperations) are inherited as-is. */ export interface FieldConfig extends Omit { /** Field name (inferred from Record key when used in ObjectConfig.fields) */ @@ -166,7 +175,32 @@ export interface FieldConfig extends Omit