@happyvertical/smrt-core 0.34.7 → 0.34.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/manifest/static-manifest.js +2 -2
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +2 -2
- package/dist/manifest/test-manifest-stub.d.ts.map +1 -1
- package/dist/manifest/test-manifest-stub.js +234 -2
- package/dist/manifest/test-manifest-stub.js.map +1 -1
- package/dist/manifest.json +2 -2
- package/dist/object.d.ts +25 -0
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +64 -7
- package/dist/object.js.map +1 -1
- package/dist/smrt-knowledge.json +4 -4
- package/package.json +4 -4
package/dist/object.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object.js","sources":["../src/object.ts"],"sourcesContent":["// import type { AIMessageOptions } from '@happyvertical/ai';\n\nimport type { AITool } from '@happyvertical/ai';\nimport { createLogger } from '@happyvertical/logger';\nimport type { SmrtClassOptions } from './class';\nimport { SmrtClass } from './class';\nimport {\n broadcastCacheInvalidation,\n hasCrossProcessCacheInterest,\n invalidateCollectionCache,\n resolveDbCacheKey,\n} from './collection-cache';\nimport { ContentHasher } from './embeddings/hash';\nimport { EmbeddingProvider } from './embeddings/provider';\nimport { EmbeddingStorage } from './embeddings/storage';\nimport type { GenerateEmbeddingsOptions } from './embeddings/types';\nimport {\n DatabaseError,\n ErrorUtils,\n RuntimeError,\n SmrtError,\n TenantIsolationError,\n ValidationError,\n} from './errors';\nimport { createInterceptorContext, GlobalInterceptors } from './interceptors';\nimport { ObjectRegistry } from './registry';\nimport { verifyPersistenceTable } from './schema/table-verifier';\nimport {\n executeToolCall as executeToolCallInternal,\n type ToolCall,\n type ToolCallResult,\n} from './tools/tool-executor';\nimport { fieldsFromClass, tableNameFromClass, toSnakeCase } from './utils';\n\n// DEBUG_STI raises the level to 'debug' so the env-gated STI hydration traces\n// below (logger.debug, inside `if (process.env.DEBUG_STI)` guards) actually emit;\n// otherwise they're filtered at the default 'info' level.\nconst logger = createLogger({\n level: process.env.DEBUG_STI ? 'debug' : 'info',\n});\n\n/**\n * Default maximum number of characters of serialized object data injected into\n * the AI prompts built by `is()`, `do()`, and `describe()`.\n *\n * Acts as a coarse token-budget guard so a very large instance (e.g. a long\n * document body) cannot blow past model context limits or inflate request\n * costs. At roughly four characters per token this is ~25k tokens of object\n * data — generous enough for typical records, while still capping pathological\n * cases. Override per call with the `maxDataLength` option.\n */\nconst AI_PROMPT_DATA_MAX_LENGTH = 100_000;\n\n/**\n * Validate that _meta_type matches the expected class (Issue #713)\n *\n * Accepts both simple class name (e.g., 'Product') and qualified name\n * (e.g., '@happyvertical/smrt-core:Product') for namespace isolation support.\n *\n * @param actualMetaType - The _meta_type value from the data\n * @param className - The class name to validate against\n * @returns true if the meta type is valid for this class\n */\nfunction isValidMetaType(actualMetaType: unknown, className: string): boolean {\n if (typeof actualMetaType !== 'string') {\n return false;\n }\n\n // Accept simple class name match\n if (actualMetaType === className) {\n return true;\n }\n\n // Accept qualified name match (namespace isolation)\n const registeredClass = ObjectRegistry.getClass(className);\n if (\n registeredClass?.qualifiedName &&\n actualMetaType === registeredClass.qualifiedName\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Get the expected qualified or simple name for a class (for error messages)\n */\nfunction getExpectedMetaType(className: string): string {\n const registeredClass = ObjectRegistry.getClass(className);\n return registeredClass?.qualifiedName || className;\n}\n\n/**\n * Get all STI hierarchy members (base + descendants) for a class.\n *\n * R5-canon (Copilot follow-up): callers should pass a QUALIFIED name\n * (e.g. via `this.getResolvedQualifiedName()`). Passing a bare simple\n * name still works in single-package scenarios, but when two packages\n * register classes sharing the same simple name, `ObjectRegistry.\n * getClass(simpleName)` resolves to whichever match the multi-strategy\n * lookup picks first — which can be the wrong package. Passing the\n * qualified form makes STI sibling discovery collision-safe.\n */\nfunction getSTIHierarchyMembers(qualifiedOrSimpleName: string): string[] {\n // Best-effort qualify in case a caller passed a simple name; the\n // collision risk for that case is documented in the docstring above.\n const registered = ObjectRegistry.getClass(qualifiedOrSimpleName);\n const lookupKey =\n registered?.qualifiedName ?? registered?.name ?? qualifiedOrSimpleName;\n const stiBase = ObjectRegistry.getSTIBase(lookupKey);\n if (!stiBase) {\n return [];\n }\n\n return Array.from(\n new Set([stiBase, ...ObjectRegistry.getDescendants(stiBase)]),\n );\n}\n\ntype PersistenceWritePlan =\n | { type: 'upsert'; conflictColumns: string[] }\n | { type: 'updateById'; qualifiedMetaType: string };\n\n/**\n * Warn once per process if a consumer has SMRT_SKIP_STI_REHYDRATE set.\n * The env variable is a no-op since Release C (#1134); without this\n * diagnostic anyone who followed the Release A changeset note would\n * silently lose the behavior they opted into.\n */\nlet didWarnSkipRehydrate = false;\nfunction warnIfSkipRehydrateSet(): void {\n if (didWarnSkipRehydrate) return;\n didWarnSkipRehydrate = true;\n if (process.env.SMRT_SKIP_STI_REHYDRATE !== undefined) {\n logger.warn(\n '[smrt] SMRT_SKIP_STI_REHYDRATE is set but has no effect since ' +\n 'Release C (#1134). The flag is retired; unconditional STI ' +\n 'descendant rehydration is the only behavior. Remove the env ' +\n 'variable from your configuration. See issue #1139 for the perf ' +\n 'follow-up.',\n );\n }\n}\n\n/**\n * Options for SmrtObject initialization\n */\nexport interface SmrtObjectOptions extends SmrtClassOptions {\n /**\n * Unique identifier for the object\n */\n id?: string;\n\n /**\n * URL-friendly identifier\n */\n slug?: string;\n\n /**\n * Optional context to scope the slug (could be a path, domain, etc.)\n */\n context?: string;\n\n /**\n * Creation timestamp\n */\n created_at?: Date;\n\n /**\n * Last update timestamp\n */\n updated_at?: Date;\n\n /**\n * Flag to skip automatic field extraction (internal use)\n */\n _extractingFields?: boolean;\n\n /**\n * Flag to skip database loading (internal use)\n */\n _skipLoad?: boolean;\n\n /**\n * Flag to skip save-time embedding auto-generation (internal use).\n *\n * This is used when framework code will generate embeddings explicitly after\n * saving and wants to avoid racing a duplicate background generation.\n */\n _skipAutoEmbeddings?: boolean;\n\n /**\n * Allow arbitrary field values to be passed\n */\n [key: string]: any;\n}\n\n/**\n * Options for the relationship loaders {@link SmrtObject.loadRelated},\n * {@link SmrtObject.loadRelatedMany}, and {@link SmrtObject.getRelated}.\n */\nexport interface LoadRelatedOptions {\n /**\n * Bypass the cross-tenant isolation guard.\n *\n * By default, resolving a relationship from a tenant-scoped object to an\n * object in a *different*, non-null tenant throws a `TenantIsolationError`.\n * Set this to `true` for deliberate cross-tenant flows (admin tooling,\n * migrations, super-admin bypass paths) where the access is intentional.\n *\n * @default false\n */\n allowCrossTenant?: boolean;\n}\n\n/**\n * Base class for all persistent SMRT domain objects.\n *\n * Provides a full ORM lifecycle: construct with options, call `initialize()`,\n * then use `save()` / `delete()` for persistence. Objects are identified by a\n * UUID `id` and an optional URL-friendly `slug` (auto-generated from `name`,\n * `title`, `label`, or `id` if not provided).\n *\n * Key capabilities:\n * - **Persistence**: `save()` (upsert with retry), `delete()` (with hooks)\n * - **Loading**: `loadFromId()`, `loadFromSlug()` (called automatically by `initialize()`)\n * - **AI operations**: `is()` (boolean criteria check), `do()` (freeform instruction)\n * - **Relationships**: `loadRelated()` (foreignKey), `loadRelatedMany()` (oneToMany)\n * - **Context memory**: `remember()` / `recall()` / `recallAll()` / `forget()` / `forgetScope()`\n * - **STI support**: `_meta_type` discriminator, `_meta_data` JSONB for child fields\n * - **Serialization**: `toJSON()` (framework-managed, handles STI), `transformJSON()` (override hook)\n *\n * @example\n * ```typescript\n * @smrt()\n * class Product extends SmrtObject {\n * name: string = '';\n * price: number = 0.0;\n * }\n *\n * const product = new Product({ db: myDb, name: 'Widget', price: 9.99 });\n * await product.initialize();\n * await product.save();\n * console.log(product.id); // auto-generated UUID\n * ```\n */\nexport class SmrtObject extends SmrtClass {\n /**\n * Database table name for this object\n */\n public _tableName!: string;\n\n /**\n * Cache for loaded relationships to avoid repeated database queries\n * Maps fieldName to loaded object(s)\n */\n private _loadedRelationships: Map<string, any> = new Map();\n\n /**\n * Whether this object is backed by an existing database row.\n *\n * Set when the object is hydrated from the database (collection\n * get/list/query, `loadFromId()`, `loadFromSlug()`) and after a successful\n * `save()`. `save()` uses it to target the primary key on upsert instead\n * of the natural-key conflict columns, so natural-key edits (e.g. renaming\n * a slug) update the existing row rather than colliding on `*_pkey`\n * (issue #1472).\n */\n private _persisted = false;\n\n /**\n * Override options with SmrtObjectOptions type for proper type narrowing.\n * Initialized by parent constructor via super() call.\n */\n public declare options: SmrtObjectOptions;\n\n /**\n * Unique identifier for the object\n */\n protected _id: string | null | undefined;\n\n /**\n * URL-friendly identifier\n */\n protected _slug: string | null | undefined;\n\n /**\n * Optional context to scope the slug\n */\n protected _context: string | null | undefined;\n\n /**\n * Creation timestamp\n */\n public created_at: Date | null | undefined = null;\n\n /**\n * Last update timestamp\n */\n public updated_at: Date | null | undefined = null;\n\n /**\n * Creates a new SmrtObject instance\n *\n * @param options - Configuration options including identifiers and metadata\n * @throws Error if options is null\n */\n constructor(options: SmrtObjectOptions = {}) {\n super(options);\n // Explicitly set child's options property after parent initialization\n // This is required because the override declaration creates a new property slot\n this.options = options;\n if (options === null) {\n throw new Error('options cant be null');\n }\n this._id = options.id || null;\n this._slug = options.slug || null;\n this._context = options.context || '';\n\n // Auto-register the class if it's not already registered\n // and it's not the base SmrtObject class itself\n // Skip registration during field extraction to avoid infinite recursion\n if (\n this.constructor !== SmrtObject &&\n !ObjectRegistry.getClassByConstructor(\n this.constructor as typeof SmrtObject,\n ) &&\n !(options as any)?._skipRegistration\n ) {\n ObjectRegistry.register(this.constructor as typeof SmrtObject, {});\n }\n }\n\n private getRegisteredClassInfo() {\n return ObjectRegistry.getClassByConstructor(\n this.constructor as typeof SmrtObject,\n );\n }\n\n protected getResolvedClassName(): string {\n return this.getRegisteredClassInfo()?.name || this.constructor.name;\n }\n\n protected getResolvedQualifiedName(): string {\n const registered = this.getRegisteredClassInfo();\n return (\n registered?.qualifiedName || registered?.name || this.constructor.name\n );\n }\n\n private getCurrentMetaType(): string | undefined {\n const metaType = (this as any)._meta_type;\n return typeof metaType === 'string' ? metaType : undefined;\n }\n\n private isLegacySTIDiscriminatorUpgrade(\n currentMetaType: string | undefined,\n nextMetaType: unknown,\n className: string,\n ): currentMetaType is string {\n return (\n typeof nextMetaType === 'string' &&\n typeof currentMetaType === 'string' &&\n currentMetaType !== nextMetaType &&\n !currentMetaType.includes(':') &&\n isValidMetaType(currentMetaType, className) &&\n isValidMetaType(nextMetaType, className)\n );\n }\n\n private async planPersistenceWrite(\n className: string,\n tableStrategy: string,\n data: Record<string, any>,\n conflictColumns: string[],\n ): Promise<PersistenceWritePlan> {\n const upsertPlan: PersistenceWritePlan = {\n type: 'upsert',\n conflictColumns,\n };\n\n if (tableStrategy !== 'sti' || !data.id) {\n return upsertPlan;\n }\n\n const currentMetaType = this.getCurrentMetaType();\n const nextMetaType = data._meta_type;\n if (\n !this.isLegacySTIDiscriminatorUpgrade(\n currentMetaType,\n nextMetaType,\n className,\n )\n ) {\n return upsertPlan;\n }\n const qualifiedMetaType = String(nextMetaType);\n const conflictIdentity: Record<string, any> = {};\n for (const column of conflictColumns.filter(\n (conflictColumn) => conflictColumn !== '_meta_type',\n )) {\n if (!Object.hasOwn(data, column)) {\n return upsertPlan;\n }\n conflictIdentity[column] = data[column];\n }\n\n const id = String(data.id);\n const existingById = await ErrorUtils.withRetry(\n async () => {\n try {\n return await this.db.get(this.tableName, { id });\n } catch (error) {\n throw DatabaseError.queryFailed(\n `get(${this.tableName}, legacy STI id)`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n },\n 3,\n 500,\n );\n\n if (!existingById || existingById._meta_type !== currentMetaType) {\n return upsertPlan;\n }\n\n const slug = String(data.slug ?? '');\n const context = String(data.context ?? '');\n const existingQualified = await ErrorUtils.withRetry(\n async () => {\n try {\n return await this.db.get(this.tableName, {\n ...conflictIdentity,\n _meta_type: qualifiedMetaType,\n });\n } catch (error) {\n throw DatabaseError.queryFailed(\n `get(${this.tableName}, qualified STI conflict identity)`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n },\n 3,\n 500,\n );\n\n if (existingQualified && existingQualified.id !== id) {\n throw DatabaseError.stiDiscriminatorConflict({\n className,\n tableName: this.tableName,\n id,\n slug,\n context,\n conflictIdentity,\n legacyMetaType: currentMetaType,\n qualifiedMetaType,\n duplicateId: String(existingQualified.id),\n });\n }\n\n // This mirrors save()'s current last-writer-wins behavior: the probe and\n // update are not transactional, so concurrent saves may both choose this.\n return { type: 'updateById', qualifiedMetaType };\n }\n\n /**\n * Protected setter for ID to maintain type safety\n * Used internally by collection.create() and other framework code\n * @internal\n */\n protected setId(id: string): void {\n this._id = id;\n }\n\n /**\n * Whether this object is backed by an existing database row.\n *\n * True after hydration from the database (collection get/list/query,\n * `loadFromId()`, `loadFromSlug()`) or after a successful `save()`.\n */\n public get isPersisted(): boolean {\n return this._persisted;\n }\n\n /**\n * Marks this object as backed by an existing database row, so `save()`\n * targets the primary key instead of the natural-key conflict columns.\n * Called by framework hydration paths (issue #1472).\n * @internal\n */\n public markAsPersisted(): void {\n this._persisted = true;\n }\n\n protected async verifyStorageReady(): Promise<void> {\n await verifyPersistenceTable(\n this.db,\n this.tableName,\n this.constructor.name,\n );\n }\n\n /**\n * Protected setter for STI discriminator to maintain type safety\n * Used internally for Single Table Inheritance support\n * @internal\n */\n protected setMetaType(metaType: string): void {\n (this as any)._meta_type = metaType;\n }\n\n /**\n * Smart clone helper to avoid array/object aliasing (Issue #22)\n *\n * Clones values to prevent shared references between options and instance properties:\n * - Primitives (string, number, boolean, null, undefined): No clone needed\n * - Dates: No clone needed (immutable)\n * - Field instances: No clone needed (framework objects)\n * - Arrays: Shallow clone\n * - Plain objects: Shallow clone\n * - Other objects: Pass through (class instances, etc.)\n *\n * @param value - Value to clone\n * @returns Cloned value or original if no cloning needed\n * @private\n */\n private cloneValue(value: any): any {\n // Primitives and null/undefined - no clone needed\n if (value === null || value === undefined) return value;\n if (typeof value !== 'object') return value;\n\n // Dates - immutable, no clone needed\n if (value instanceof Date) return value;\n\n // Arrays - shallow clone to avoid aliasing\n if (Array.isArray(value)) return [...value];\n\n // Plain objects - shallow clone to avoid aliasing\n // Check if it's a plain object (created via {} or Object.create(null))\n const proto = Object.getPrototypeOf(value);\n if (proto === null || proto === Object.prototype) {\n return { ...value };\n }\n\n // Other objects (class instances, etc.) - pass through\n return value;\n }\n\n /**\n * Initialize properties from options after field initializers have run\n * This ensures option values take precedence over default field initializer values\n * Uses smart cloning to prevent array/object aliasing (Issue #22)\n */\n private async initializePropertiesFromOptions(): Promise<void> {\n const options = this.options;\n\n // Set base properties that exist on SmrtObject\n if (options.created_at !== undefined) this.created_at = options.created_at;\n if (options.updated_at !== undefined) this.updated_at = options.updated_at;\n\n // Set STI discriminator if present\n if (options._meta_type !== undefined) {\n this.setMetaType(options._meta_type);\n }\n\n // Get all fields (both Field instances and plain properties)\n const fields = await fieldsFromClass(\n this.constructor as new (\n ...args: any[]\n ) => any,\n );\n\n // Apply option values to all fields\n for (const [key, field] of Object.entries(fields)) {\n if (options[key] !== undefined) {\n // Clone value to avoid aliasing (Issue #22)\n const clonedValue = this.cloneValue(options[key]);\n\n // Check if property is writable before setting (Issue #61)\n // Get descriptor from instance or entire prototype chain\n let descriptor = Object.getOwnPropertyDescriptor(this, key);\n if (!descriptor) {\n let proto = Object.getPrototypeOf(this);\n while (proto && !descriptor) {\n descriptor = Object.getOwnPropertyDescriptor(proto, key);\n proto = Object.getPrototypeOf(proto);\n }\n }\n\n // Only set if property has a setter or is writable\n // Skip readonly properties (e.g., tableName getter without setter)\n if (!descriptor || descriptor.set || descriptor.writable === true) {\n // Set the property value\n this[key as keyof this] = clonedValue;\n }\n }\n }\n }\n\n /**\n * Gets the unique identifier for this object\n */\n get id(): string | null | undefined {\n return this._id;\n }\n\n /**\n * Sets the unique identifier for this object\n *\n * @param value - The ID to set\n * @throws Error if the value is invalid\n */\n set id(value: string | null | undefined) {\n if (!value || value === 'undefined' || value === 'null') {\n throw new Error(`id is required, ${value} given`);\n }\n this._id = value;\n }\n\n /**\n * Gets the URL-friendly slug for this object\n */\n get slug(): string | null | undefined {\n return this._slug;\n }\n\n /**\n * Sets the URL-friendly slug for this object\n *\n * @param value - The slug to set\n * @throws Error if the value is invalid\n */\n set slug(value: string | null | undefined) {\n if (!value || value === 'undefined' || value === 'null') {\n throw new Error(`slug is invalid, ${value} given`);\n }\n\n this._slug = value;\n }\n\n /**\n * Gets the context that scopes this object's slug\n */\n get context(): string {\n return this._context || '';\n }\n\n /**\n * Sets the context that scopes this object's slug\n *\n * @param value - The context to set\n * @throws Error if the value is invalid\n */\n set context(value: string | null | undefined) {\n if (value !== '' && !value) {\n throw new Error(`context is invalid, ${value} given`);\n }\n this._context = value;\n }\n\n /**\n * Initializes this object and optionally loads its data from the database.\n *\n * Initialization order:\n * 1. Runs TypeScript field initializers (class property defaults)\n * 2. Applies `options` values on top of defaults (options win)\n * 3. If `options.id` is set, calls `loadFromId()` to hydrate from DB\n * 4. If `options.slug` is set (and no id), calls `loadFromSlug()` instead\n *\n * Runtime schema verification is deferred until the first actual DB\n * operation, which keeps initialization safe for SSR and prerendering\n * without mutating application schema.\n *\n * Called automatically by collection methods. Call manually only when\n * constructing objects outside of a collection.\n *\n * @returns This instance, ready to use (enables chaining)\n *\n * @example\n * ```typescript\n * const product = new Product({ db: myDb, id: 'existing-uuid' });\n * await product.initialize(); // loads product data from DB\n * console.log(product.name);\n * ```\n */\n public async initialize(): Promise<this> {\n await super.initialize();\n\n // Initialize properties from options AFTER all field initializers have run\n // This prevents TypeScript field initializers from overwriting option values\n // This must run for all classes (decorator-based or not) unless explicitly skipped\n if (!this.options._extractingFields) {\n await this.initializePropertiesFromOptions();\n }\n\n // Defer schema verification until an operation actually touches the\n // backing table. That keeps construction lightweight without hiding schema\n // mutation inside normal runtime flows.\n\n if (this._id && !(this.options as any)._skipLoad) {\n await this.loadFromId();\n } else if (this._slug && !(this.options as any)._skipLoad) {\n await this.loadFromSlug();\n }\n\n return this;\n }\n\n /**\n * Determines if this class needs automatic property initialization from options\n *\n * Decorator-based classes handle property assignment in their constructor,\n * so they don't need the automatic property initialization logic.\n * This optimization avoids redundant work and Field instance handling.\n *\n * @returns True if property initialization is needed, false otherwise\n * @private\n */\n private needsPropertyInitialization(): boolean {\n const className = this.getResolvedClassName();\n\n // Check if this class has decorator metadata in the registry\n // If it does, it's using decorators and handles its own initialization\n if (ObjectRegistry.hasClass(className)) {\n const hasDecorators = ObjectRegistry.hasFieldDecorators(className);\n if (hasDecorators) {\n // Class uses decorators - properties are set in constructor\n return false;\n }\n }\n\n // Default: assume it needs property initialization (field helpers pattern)\n return true;\n }\n\n /**\n * Loads data from a database row into this object's properties\n *\n * STI Support: If using Single Table Inheritance (tableStrategy: 'sti'):\n * - Merges _meta_data JSONB fields into the main data object\n * - Validates _meta_type discriminator matches class name\n *\n * @param data - Database row data (with snake_case column names)\n * @throws Error if STI validation fails\n */\n async loadDataFromDb(data: any) {\n const className = this.getResolvedClassName();\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] Loading', {\n class: className,\n dataKeys: Object.keys(data),\n metaType: data._meta_type,\n });\n }\n\n // Get field definitions to pass to formatDataJs\n const fields = await this.getFields();\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] Field definitions', {\n class: className,\n fieldKeys: Object.keys(fields),\n });\n }\n\n // Format data: Convert snake_case column names to camelCase property names\n // and convert date strings to Date objects (Issue #339)\n const { formatDataJs } = await import('./utils.js');\n const formattedData = formatDataJs(data, fields);\n\n // Check if this class uses STI (Single Table Inheritance).\n // R5-canon: pass the qualified name so a colliding simple name in\n // another package can't yield the wrong tableStrategy here.\n const tableStrategy = ObjectRegistry.getTableStrategy(\n this.getResolvedQualifiedName(),\n );\n const isSTI = tableStrategy === 'sti';\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] After formatDataJs', {\n class: className,\n isSTI,\n formattedDataKeys: Object.keys(formattedData),\n });\n }\n\n // STI: Fail-fast validation for _meta_type discriminator\n if (isSTI) {\n // Validation 1: _meta_type must be present in database row\n if (!formattedData._meta_type) {\n throw new Error(\n `STI validation failed: Missing _meta_type discriminator in database row for ${className}. ` +\n `Ensure the row was saved with STI support enabled.`,\n );\n }\n\n // Validation 2: _meta_type must match the class being instantiated\n // Accept both simple class name and qualified name (namespace isolation - Issue #713)\n if (!isValidMetaType(formattedData._meta_type, className)) {\n throw new Error(\n `STI validation failed: Type mismatch when loading ${className}. ` +\n `Database row has _meta_type='${formattedData._meta_type}' but expected '${getExpectedMetaType(className)}'. ` +\n `This usually means you're trying to load a row with the wrong class.`,\n );\n }\n\n // Set _meta_type on the object\n this.setMetaType(formattedData._meta_type);\n }\n\n // STI: Meta fields are already merged by formatDataJs\n // No additional processing needed\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] Starting field hydration', {\n class: className,\n fieldCount: Object.keys(fields).length,\n });\n }\n\n let hydratedCount = 0;\n let skippedCount = 0;\n\n for (const field in fields) {\n if (Object.hasOwn(fields, field)) {\n // Check if property is writable before setting (Issue #63)\n // Get descriptor from instance or entire prototype chain\n let descriptor = Object.getOwnPropertyDescriptor(this, field);\n if (!descriptor) {\n let proto = Object.getPrototypeOf(this);\n while (proto && !descriptor) {\n descriptor = Object.getOwnPropertyDescriptor(proto, field);\n proto = Object.getPrototypeOf(proto);\n }\n }\n\n // Only set if property has a setter or is writable\n // Skip readonly properties (e.g., tableName getter without setter)\n if (!descriptor || descriptor.set || descriptor.writable === true) {\n // Use formatted data (camelCase) instead of raw data (snake_case)\n // formatDataJs() already handles type conversions (dates, booleans, etc.)\n const value = formattedData[field];\n\n if (process.env.DEBUG_STI && value !== undefined) {\n logger.debug(`[loadDataFromDb] Setting field '${field}'`, {\n value,\n valueType: typeof value,\n });\n }\n\n this[field as keyof this] = value;\n hydratedCount++;\n } else {\n skippedCount++;\n if (process.env.DEBUG_STI) {\n logger.debug(`[loadDataFromDb] Skipping readonly field '${field}'`);\n }\n }\n }\n }\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] Hydration complete', {\n class: className,\n hydratedCount,\n skippedCount,\n totalFields: Object.keys(fields).length,\n });\n }\n\n // The data came from an existing row, so subsequent saves must update\n // that row by primary key even if natural-key fields change (issue #1472).\n this._persisted = true;\n }\n\n /**\n * Gets the database table name for this object\n */\n get tableName() {\n if (!this._tableName) {\n // For STI, use the base class's table name from schema (manifest-derived).\n // R5-canon: use the qualified name as the lookup key so a colliding\n // simple name in another package can't yield the wrong tableStrategy\n // / STI base and route every query through the wrong table.\n const className = this.getResolvedClassName();\n const qualifiedName = this.getResolvedQualifiedName();\n const tableStrategy = ObjectRegistry.getTableStrategy(qualifiedName);\n\n if (tableStrategy === 'sti') {\n const stiBase = ObjectRegistry.getSTIBase(qualifiedName);\n if (stiBase) {\n // Use base class's schema tableName (from manifest)\n const baseSchema = ObjectRegistry.getSchema(stiBase);\n if (baseSchema?.tableName) {\n this._tableName = baseSchema.tableName;\n } else {\n // Fallback to own schema tableName\n const ownSchema = ObjectRegistry.getSchema(className);\n this._tableName =\n ownSchema?.tableName || tableNameFromClass(this.constructor);\n }\n } else {\n // Fallback to own schema tableName\n const ownSchema = ObjectRegistry.getSchema(className);\n this._tableName =\n ownSchema?.tableName || tableNameFromClass(this.constructor);\n }\n } else {\n // CTI: Use own schema tableName\n const ownSchema = ObjectRegistry.getSchema(className);\n this._tableName =\n ownSchema?.tableName || tableNameFromClass(this.constructor);\n }\n }\n return this._tableName;\n }\n\n /**\n * Gets field definitions and current values for this object\n *\n * @returns Object containing field definitions with current values\n */\n async getFields() {\n const className = this.getResolvedClassName();\n const cachedFields = await ObjectRegistry.getAllFields(className);\n const fields: Record<string, any> = {};\n\n for (const [key, field] of cachedFields.entries()) {\n const meta = { ...(field._meta || {}) };\n delete meta.__smrtSystemField;\n\n fields[key] = {\n name: key,\n type: field.type || 'TEXT',\n _meta: meta,\n };\n }\n\n // Add current instance values to the fields\n // Use getPropertyValue to unwrap Field instances\n for (const key in fields) {\n fields[key].value = this.getPropertyValue(key);\n }\n\n return fields;\n }\n\n /**\n * Override hook for customizing JSON serialization output.\n *\n * This is the **only safe way** to customize serialization. Do **not** override\n * `toJSON()` directly — it manages STI discriminator assignment (`_meta_type`),\n * meta-field extraction into `_meta_data`, and manifest-driven field enumeration.\n * Overriding it will silently break STI persistence.\n *\n * The `data` argument already contains all persisted fields. Return a new object\n * (spread `data` and add/modify/remove keys) to change what is serialized.\n * Non-persisted computed properties added here are excluded from `save()` because\n * the DB write path uses `toJSON()` output, not this hook's additions — unless\n * those keys also correspond to real schema columns.\n *\n * @param data - Fully serialized object produced by the framework's `toJSON()` logic\n * @returns Transformed data to use as the final serialization result\n *\n * @example\n * ```typescript\n * class Article extends SmrtObject {\n * body: string = '';\n *\n * protected transformJSON(data: any): any {\n * return {\n * ...data,\n * wordCount: this.body.split(/\\s+/).length,\n * preview: this.body.substring(0, 100),\n * };\n * }\n * }\n * ```\n *\n * @see {@link toJSON} for the framework implementation (do not override)\n */\n protected transformJSON(data: any): any {\n return data; // Default: no transformation\n }\n\n /**\n * Custom JSON serialization\n * Returns a plain object with all field values for proper JSON.stringify() behavior\n * Field instances automatically call their toJSON() method during serialization\n *\n * Issue #205: Filters out undefined values to prevent database errors\n *\n * Note: This method cannot be async because JSON.stringify() expects synchronous toJSON()\n * It uses direct property access instead of getFields() to avoid async issues\n *\n * STI Support: If using Single Table Inheritance (tableStrategy: 'sti'):\n * - Sets _meta_type discriminator to class name\n * - Extracts meta fields to _meta_data JSONB column\n *\n * **Customization:** Override `transformJSON()` instead of this method.\n * See transformJSON() documentation for safe customization patterns.\n */\n toJSON() {\n const className = this.getResolvedClassName();\n const data: any = {\n id: this.id,\n slug: this.slug,\n context: this.context,\n created_at: this.created_at,\n updated_at: this.updated_at,\n };\n\n // Check if this class uses STI (Single Table Inheritance)\n // R5-canon: qualified-key lookup so a colliding simple name in\n // another package can't yield the wrong STI strategy here.\n const tableStrategy = ObjectRegistry.getTableStrategy(\n this.getResolvedQualifiedName(),\n );\n const isSTI = tableStrategy === 'sti';\n\n // If STI, add discriminator and prepare meta_data container\n if (isSTI) {\n // Use qualified name for STI discriminator (namespace isolation)\n // The qualified name uses the child class's own package, not the parent's\n // This supports multi-package inheritance hierarchies (Issue #713)\n data._meta_type = this.getResolvedQualifiedName();\n data._meta_data = {};\n }\n\n // Get registered field definitions (synchronous access to already-loaded metadata)\n // For inheritance hierarchies, use cached inherited fields if available (populated by getAllFields())\n // This ensures multi-level STI classes serialize all parent fields correctly (Issue #332)\n const registered = ObjectRegistry.getClass(className);\n let registeredFields =\n registered?.inheritedFields || ObjectRegistry.getFields(className);\n\n // In STI mode, we need to know about ALL sibling class fields to provide default values\n // for fields that exist in siblings but not in this class (Issue #391).\n // R5-canon (Copilot follow-up): pass the qualified name so STI\n // sibling discovery is collision-safe across packages.\n if (isSTI) {\n const descendants = getSTIHierarchyMembers(\n this.getResolvedQualifiedName(),\n );\n if (descendants.length > 0) {\n const allSTIFields = new Map(registeredFields);\n\n // Merge fields from all sibling classes\n for (const descendant of descendants) {\n const descendantFields =\n ObjectRegistry.getClass(descendant)?.inheritedFields ||\n ObjectRegistry.getFields(descendant);\n for (const [key, value] of descendantFields) {\n if (!allSTIFields.has(key)) {\n allSTIFields.set(key, value);\n }\n }\n }\n\n registeredFields = allSTIFields;\n }\n }\n\n // Use manifest fields exclusively (manifest-first architecture)\n // All schema fields are in the manifest from AST scanning\n // Dynamic properties added at runtime are intentionally excluded (not part of schema)\n for (const key of registeredFields.keys()) {\n // Skip private properties, methods, and already-handled core fields\n if (\n key.startsWith('_') ||\n key === 'id' ||\n key === 'slug' ||\n key === 'context' ||\n key === 'created_at' ||\n key === 'updated_at' ||\n key === 'options' || // Skip options object (not a database column)\n typeof (this as any)[key] === 'function'\n ) {\n continue;\n }\n\n // Get field definition (used for transient check and type checking)\n const fieldDef = registeredFields.get(key);\n\n // Skip transient fields (non-persisted fields like functions, computed properties)\n // NOTE: This filtering logic must match SchemaGenerator.generateColumns()\n // Changes to field filtering should be applied in BOTH places\n if (fieldDef && (fieldDef.transient || fieldDef._meta?.transient)) {\n continue;\n }\n\n // Skip relationship fields that don't create columns\n // oneToMany and manyToMany are relationship metadata, not actual database columns\n // NOTE: This must match the filtering in SchemaGenerator.generateColumns()\n if (\n fieldDef &&\n (fieldDef.type === 'oneToMany' || fieldDef.type === 'manyToMany')\n ) {\n continue;\n }\n\n const prop = (this as any)[key];\n const value = this.getPropertyValue(key);\n\n // Handle undefined values (Issue #205, #391)\n // In STI, a child class may not have a property defined on a sibling class.\n // This logic ensures undefined properties are serialized correctly based on their type.\n if (value === undefined) {\n // Get field type from either the property instance (field helper) or the manifest\n const fieldType =\n (prop && typeof prop === 'object' && 'type' in prop && prop.type) ||\n fieldDef?.type;\n\n if (fieldType === 'text') {\n // Don't convert tenant ID fields to empty string (Issue #841)\n // Tenant fields should remain null/undefined for interceptor to auto-populate.\n // Check both the property instance and field definition for __tenancy marker.\n // Note: __tenancy can be at fieldDef.__tenancy (from @tenantId decorator) or\n // fieldDef._meta.__tenancy (from @smrt({ tenantScoped: true }))\n const hasTenancyMarker =\n (prop &&\n typeof prop === 'object' &&\n '__tenancy' in prop &&\n (prop as any).__tenancy?.isTenantIdField) ||\n (fieldDef as any)?.__tenancy?.isTenantIdField ||\n (fieldDef as any)?._meta?.__tenancy?.isTenantIdField;\n\n if (hasTenancyMarker) {\n // Leave tenant field as null so interceptor can auto-populate\n if (isSTI && fieldDef?.type === 'meta') {\n data._meta_data[key] = null;\n } else {\n data[key] = null;\n }\n } else {\n // For regular TEXT fields, convert undefined to an empty string.\n if (isSTI && fieldDef?.type === 'meta') {\n data._meta_data[key] = '';\n } else {\n data[key] = '';\n }\n }\n } else if (fieldType === 'json') {\n // For JSON fields, use the default value from manifest to prevent:\n // 1. Invalid JSON casting errors in DuckDB (empty string \"\")\n // 2. Runtime errors when code expects arrays/objects (null)\n const defaultValue = fieldDef?.default ?? null;\n\n if (isSTI && fieldDef?.type === 'meta') {\n data._meta_data[key] = defaultValue;\n } else {\n data[key] = defaultValue;\n }\n }\n\n // For all cases of 'undefined' (handled or not), we continue to the next field.\n // This prevents the undefined value from being assigned to the data object below,\n // allowing the database to use its default value for unhandled types.\n continue;\n }\n\n // STI: Separate meta fields from regular fields\n if (isSTI && fieldDef && fieldDef.type === 'meta') {\n // Meta fields go into _meta_data JSONB column\n data._meta_data[key] = value;\n } else {\n // Regular fields become table columns\n data[key] = value;\n }\n }\n\n // Call transformation hook to allow safe customization\n // This enables subclasses to add/modify fields without overriding toJSON()\n return this.transformJSON(data);\n }\n\n /**\n * Converts this object to a plain JavaScript object (POJO)\n *\n * Unlike toJSON() which returns an object that can still be a class instance,\n * this method returns a true plain object suitable for:\n * - SvelteKit's load function returns (requires serializable data)\n * - Passing data through web workers\n * - Any context requiring non-class objects\n *\n * @returns Plain JavaScript object with all field values\n *\n * @example\n * ```typescript\n * // In a SvelteKit +page.server.ts load function:\n * const users = await userCollection.list();\n * return {\n * users: users.map(u => u.toPlainObject())\n * };\n * ```\n */\n toPlainObject(): Record<string, unknown> {\n return JSON.parse(JSON.stringify(this));\n }\n\n /**\n * Collects the property names of fields marked `@field({ sensitive: true })`\n * for this instance's class (and, under STI, every member of its hierarchy,\n * since `toJSON()` merges sibling fields into the serialized payload).\n *\n * Reads both the first-class `sensitive` flag and the `_meta.sensitive`\n * mirror so it works regardless of whether the field metadata came from the\n * AST manifest or a runtime `@field()` decorator registration.\n */\n private getSensitiveFieldNames(): Set<string> {\n const className = this.getResolvedClassName();\n const registered = ObjectRegistry.getClass(className);\n const fieldMaps: Map<string, any>[] = [\n registered?.inheritedFields || ObjectRegistry.getFields(className),\n ];\n\n const tableStrategy = ObjectRegistry.getTableStrategy(\n this.getResolvedQualifiedName(),\n );\n if (tableStrategy === 'sti') {\n const descendants = getSTIHierarchyMembers(\n this.getResolvedQualifiedName(),\n );\n for (const descendant of descendants) {\n fieldMaps.push(\n ObjectRegistry.getClass(descendant)?.inheritedFields ||\n ObjectRegistry.getFields(descendant),\n );\n }\n }\n\n const sensitive = new Set<string>();\n for (const fields of fieldMaps) {\n for (const [key, def] of fields) {\n if (def && (def.sensitive === true || def._meta?.sensitive === true)) {\n sensitive.add(key);\n }\n }\n }\n return sensitive;\n }\n\n /**\n * Public-safe serialization for network surfaces.\n *\n * Returns the same shape as `toJSON()` but with every `sensitive` field\n * removed (including STI meta fields nested under `_meta_data`). This is the\n * serializer used by the generated REST / MCP / SvelteKit routes so that\n * secret columns (API secrets, credentials, tax IDs) are never returned over\n * the wire, while `toJSON()` continues to carry them for database persistence.\n *\n * @returns A plain object safe to send to API consumers.\n */\n toPublicJSON(): Record<string, unknown> {\n const json = this.toJSON() as Record<string, unknown>;\n const sensitiveFields = this.getSensitiveFieldNames();\n if (sensitiveFields.size === 0) {\n return json;\n }\n\n const metaData =\n json._meta_data && typeof json._meta_data === 'object'\n ? (json._meta_data as Record<string, unknown>)\n : null;\n\n for (const name of sensitiveFields) {\n delete json[name];\n if (metaData) {\n delete metaData[name];\n }\n }\n return json;\n }\n\n /**\n * Gets or generates a unique ID for this object\n *\n * @returns Promise resolving to the object's ID\n */\n async getId() {\n if (this.slug) {\n await this.verifyStorageReady();\n\n // lookup by slug and context using adapter method\n const saved = await this.db.get(this.tableName, {\n slug: this.slug,\n context: this.context,\n });\n if (saved) {\n this.id = saved.id;\n }\n }\n\n if (!this.id) {\n this.id = crypto.randomUUID();\n }\n return this.id;\n }\n\n /**\n * Returns the slug for this object, generating one if not already set.\n *\n * Generation falls back through the following fields in order:\n * `name` → `title` → `label` → `id`\n *\n * The generated slug is lowercased, with non-alphanumeric characters\n * replaced by hyphens and leading/trailing hyphens stripped.\n *\n * Called automatically by `save()` when no slug is present.\n *\n * @returns The existing slug or a newly generated one (may be `null` if\n * none of the fallback fields and `id` are set)\n *\n * @example\n * ```typescript\n * const product = new Product({ name: 'My Widget' });\n * console.log(await product.getSlug()); // 'my-widget'\n * ```\n */\n async getSlug() {\n if (!this.slug) {\n // Try multiple fallback fields in order: name, title, label, id\n let sourceField = null;\n\n if ((this as any).name) {\n sourceField = String((this as any).name);\n } else if ((this as any).title) {\n sourceField = String((this as any).title);\n } else if ((this as any).label) {\n sourceField = String((this as any).label);\n } else if (this.id) {\n // Final fallback: use ID\n sourceField = String(this.id);\n }\n\n if (sourceField) {\n // Generate slug from source field\n this.slug = sourceField\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '');\n }\n }\n\n // check for existing slug and make unique?\n return this.slug;\n }\n\n /**\n * Gets the ID of this object if it's already saved in the database\n *\n * @returns Promise resolving to the saved ID or null if not saved\n */\n async getSavedId() {\n if (!this.id && !this.slug) {\n return null;\n }\n\n await this.verifyStorageReady();\n\n // Try to find by id first\n if (this.id) {\n const byId = await this.db.get(this.tableName, { id: this.id });\n if (byId) return byId.id;\n }\n\n // Fall back to finding by slug\n if (this.slug) {\n const bySlug = await this.db.get(this.tableName, { slug: this.slug });\n if (bySlug) return bySlug.id;\n }\n\n return null;\n }\n\n /**\n * Checks if this object is already saved in the database\n *\n * @returns Promise resolving to true if saved, false otherwise\n */\n async isSaved() {\n const saved = await this.getSavedId();\n return !!saved;\n }\n\n /**\n * Resolve the set of snake_case column names whose database type is `UUID`\n * for the table this object writes to.\n *\n * Declared foreign keys (`@foreignKey()`) and cross-package references\n * (`@crossPackageRef()`) generate native `UUID` columns (R11). Their default\n * declared value in TypeScript is the empty string (`''`), which is not a\n * valid UUID literal. Postgres rejects `''` on a `uuid` column with\n * `invalid input syntax for type uuid`, so any optional/unset declared FK\n * (a root entity's self-reference, an optional cross-package link, etc.)\n * would fail to insert. We coerce `''` → `NULL` for these columns before\n * binding (see {@link coerceEmptyUuidValuesToNull}); this method tells that\n * coercion which columns are UUID-typed.\n *\n * Resolution prefers the built schema (`getSchema().columns`), which already\n * reflects all reconciliation — e.g. a `@foreignKey()` whose target class\n * uses `idType: 'text'` is downgraded to `TEXT` and is therefore correctly\n * excluded here. For STI children, columns live on the STI base table, so we\n * union the base schema's columns. When no built schema is available (pure\n * runtime-registered classes without a manifest) we fall back to field\n * metadata, mirroring the schema-builder's field→SQL mapping.\n */\n private async resolveUuidColumnNames(\n className: string,\n ): Promise<Set<string>> {\n const uuidColumns = new Set<string>();\n\n const collectFromSchema = (schemaName: string | null | undefined): void => {\n if (!schemaName) return;\n const schema = ObjectRegistry.getSchema(schemaName);\n const columns = schema?.columns;\n if (!columns) return;\n for (const [columnName, columnDef] of Object.entries(columns)) {\n if ((columnDef as { type?: string })?.type === 'UUID') {\n uuidColumns.add(columnName);\n }\n }\n };\n\n // Own schema (covers non-STI and STI-base classes).\n collectFromSchema(className);\n\n // STI children: FK columns are declared on the base table.\n const qualifiedName = this.getResolvedQualifiedName();\n if (ObjectRegistry.getTableStrategy(qualifiedName) === 'sti') {\n collectFromSchema(ObjectRegistry.getSTIBase(qualifiedName));\n }\n\n if (uuidColumns.size > 0) {\n return uuidColumns;\n }\n\n // Fallback: derive UUID columns from field metadata when no built schema\n // is available. Mirrors schema-builder's field→SQL mapping so that a\n // text-id cross-package ref is not treated as UUID.\n try {\n const fields = await ObjectRegistry.getAllFields(className);\n for (const [fieldName, field] of fields.entries()) {\n if (!field) continue;\n const type = field.type;\n if (type !== 'foreignKey' && type !== 'crossPackageRef') {\n continue;\n }\n const metaSqlType = field._meta?.sqlType;\n if (metaSqlType) {\n if (metaSqlType === 'UUID') {\n uuidColumns.add(toSnakeCase(fieldName));\n }\n continue;\n }\n const isTextIdCrossRef =\n type === 'crossPackageRef' &&\n (field._meta?.idType === 'text' || field.idType === 'text');\n if (!isTextIdCrossRef) {\n uuidColumns.add(toSnakeCase(fieldName));\n }\n }\n } catch {\n // Best-effort fallback; never let UUID-column resolution block a save.\n }\n\n return uuidColumns;\n }\n\n /**\n * Coerce empty-string values to `NULL` for UUID-typed columns in the\n * snake_cased write payload.\n *\n * Framework-level fix for the whole class of bug where a declared FK field\n * defaults to `''` (the natural TypeScript default for `string`) and is left\n * unset on insert — e.g. creating a ROOT entity whose optional self-reference\n * (`previousFactId`, `parentPartnerId`, …) is empty. On Postgres `uuid`\n * columns, `''` raises `invalid input syntax for type uuid`. Coercing to\n * `NULL` here fixes every such field uniformly without per-field type churn\n * or consumer-facing type changes. Mutates `data` in place.\n */\n private async coerceEmptyUuidValuesToNull(\n className: string,\n data: Record<string, any>,\n ): Promise<void> {\n const uuidColumns = await this.resolveUuidColumnNames(className);\n if (uuidColumns.size === 0) return;\n for (const columnName of uuidColumns) {\n if (data[columnName] === '') {\n data[columnName] = null;\n }\n }\n }\n\n /**\n * Persists this object to the database using an upsert (insert or update).\n *\n * Steps performed on every save:\n * 1. Runs field-level validation (`validateBeforeSave()`)\n * 2. Executes `beforeSave` interceptors (e.g. tenant injection)\n * 3. Assigns a UUID `id` if not already set\n * 4. Generates a `slug` via `getSlug()` if not already set\n * 5. Updates `updated_at` (and sets `created_at` on first save)\n * 6. Upserts the row with automatic retry (3 attempts, 500 ms backoff)\n * 7. Executes `afterSave` interceptors\n * 8. Triggers embedding generation in the background if configured\n *\n * For STI classes, validates that `_meta_type` is present and correct\n * before writing to the database.\n *\n * @returns This instance after saving (enables chaining)\n * @throws {ValidationError} If a required field is missing or a unique constraint is violated\n * @throws {DatabaseError} If the table does not exist (`DB_SCHEMA_MISSING`) or the query fails\n * @throws {RuntimeError} For any other unexpected failure during save\n *\n * @example\n * ```typescript\n * const product = new Product({ db: myDb, name: 'Widget', price: 9.99 });\n * await product.initialize();\n * await product.save();\n * console.log(product.id); // UUID assigned during save\n *\n * // Update\n * product.price = 14.99;\n * await product.save();\n * ```\n */\n async save() {\n const className = this.getResolvedClassName();\n\n try {\n // Validate object state before saving\n await this.validateBeforeSave();\n\n // Validate cross-package references that opted into save-time validation\n await this.validateCrossPackageRefs();\n\n // Execute beforeSave interceptors (e.g., tenancy validation)\n const interceptorContext = createInterceptorContext(className, 'save');\n await GlobalInterceptors.executeBeforeSave(this, interceptorContext);\n\n if (!this.id) {\n this.id = crypto.randomUUID();\n }\n\n if (!this.slug) {\n this.slug = await this.getSlug();\n }\n\n // Update the updated_at timestamp\n this.updated_at = new Date();\n\n if (!this.created_at) {\n this.created_at = new Date();\n }\n\n await this.verifyStorageReady();\n\n // Execute save operation with retry logic for transient failures\n // Use per-adapter upsert method instead of generating SQL.\n // R5-canon: qualified-key lookup avoids cross-package collisions.\n\n const tableStrategy = ObjectRegistry.getTableStrategy(\n this.getResolvedQualifiedName(),\n );\n\n // Development-mode warning: Detect unsafe toJSON() overrides in STI classes\n if (process.env.NODE_ENV === 'development') {\n const hasOverride = this.toJSON !== SmrtObject.prototype.toJSON;\n const usesSTI = tableStrategy === 'sti';\n\n if (hasOverride && usesSTI) {\n logger.warn(\n `[SMRT STI Warning] ${this.constructor.name} overrides toJSON() but uses STI.\\n` +\n `Ensure super.toJSON() is called or _meta_type is set manually.\\n` +\n `This can cause \"Missing _meta_type discriminator\" errors.\\n` +\n `Prefer using the transformJSON() hook instead of overriding toJSON().\\n` +\n `See issue #377: https://github.com/happyvertical/smrt/issues/377`,\n );\n }\n }\n\n if (tableStrategy === 'sti') {\n // Release C (#1134) retired the SMRT_SKIP_STI_REHYDRATE env flag.\n // PR #1131's unconditional rehydration stays the single behavior:\n // it repairs stale-but-present `inheritedFields` caches that the\n // conservative hydration path would skip (see\n // external-runtime-hydration.test.ts:1071). Further optimizing\n // this loop away via eager invalidation at re-registration time\n // is tracked as a separate follow-up (#1139).\n warnIfSkipRehydrateSet();\n // R5-canon (Copilot follow-up): pass the qualified name to\n // `getSTIHierarchyMembers` so STI sibling discovery is\n // collision-safe across packages with same-simple-name classes.\n const qualifiedName = this.getResolvedQualifiedName();\n const classesNeedingFreshSTIFieldState = Array.from(\n new Set([qualifiedName, ...getSTIHierarchyMembers(qualifiedName)]),\n );\n for (const stiClassName of classesNeedingFreshSTIFieldState) {\n await ObjectRegistry.getAllFields(stiClassName);\n }\n }\n\n const jsonData = this.toJSON();\n\n // STI: Fail-fast validation for _meta_type discriminator\n if (tableStrategy === 'sti') {\n if (!jsonData._meta_type) {\n throw new Error(\n `STI validation failed: Missing _meta_type discriminator when saving ${className}. ` +\n `This should have been set automatically by toJSON(). Please report this bug.`,\n );\n }\n // Accept both simple class name and qualified name (namespace isolation - Issue #713)\n if (!isValidMetaType(jsonData._meta_type, className)) {\n throw new Error(\n `STI validation failed: _meta_type mismatch when saving ${className}. ` +\n `Expected '${getExpectedMetaType(className)}' but got '${jsonData._meta_type}'. ` +\n `This should not happen - please report this bug.`,\n );\n }\n }\n\n // Convert camelCase keys to snake_case for database columns\n // Preserve leading underscore for special fields like _meta_type, _meta_data\n const data: Record<string, any> = {};\n for (const [key, value] of Object.entries(jsonData)) {\n if (key.startsWith('_')) {\n // Preserve leading underscore for special fields\n data[key] = value;\n } else {\n data[toSnakeCase(key)] = value;\n }\n }\n\n // Coerce empty-string values to NULL for native UUID columns (declared\n // FKs / cross-package refs). The TypeScript default for an unset\n // `string`-typed FK is `''`, which Postgres rejects on a `uuid` column\n // (\"invalid input syntax for type uuid\"). This framework-level coercion\n // fixes every optional/unset declared-FK field uniformly.\n await this.coerceEmptyUuidValuesToNull(className, data);\n\n // Get conflict columns from registry (supports custom columns for junction tables)\n const conflictColumns = ObjectRegistry.getConflictColumns(className);\n const writePlan = await this.planPersistenceWrite(\n className,\n tableStrategy,\n data,\n conflictColumns,\n );\n\n // Issue #1472: objects backed by an existing row must conflict on the\n // primary key. With natural-key conflict columns, editing a natural-key\n // field (e.g. slug) makes the conflict target match no row, so the\n // upsert takes the INSERT path with the existing id and violates\n // `*_pkey`. New objects keep natural-key conflict so ingestion-style\n // dedup (create/getOrUpsert against a known slug) still updates in\n // place. planPersistenceWrite() intentionally still receives the\n // natural-key columns — its legacy-STI probe semantics are unchanged.\n const upsertConflictColumns =\n this._persisted && data.id ? ['id'] : conflictColumns;\n\n await ErrorUtils.withRetry(\n async () => {\n try {\n if (writePlan.type === 'updateById') {\n const { id: _id, ...updateData } = data;\n await this.db.update(this.tableName, { id: data.id }, updateData);\n this.setMetaType(writePlan.qualifiedMetaType);\n } else {\n await this.db.upsert(this.tableName, upsertConflictColumns, data);\n }\n } catch (error) {\n // Detect specific database error types. `@happyvertical/sql` does\n // not normalize driver errors, so match SQLite, PostgreSQL and\n // DuckDB constraint strings to preserve the advertised typed-error\n // parity (#1378) across adapters.\n if (error instanceof Error) {\n const kind = SmrtObject.classifyConstraintError(error.message);\n if (kind === 'unique') {\n const field = this.extractConstraintField(error.message);\n throw ValidationError.uniqueConstraint(\n field,\n this.getFieldValue(field),\n );\n }\n if (kind === 'not_null') {\n const field = this.extractConstraintField(error.message);\n throw ValidationError.requiredField(field, className);\n }\n const operation =\n writePlan.type === 'updateById'\n ? `UPDATE ${this.tableName} (id-targeted)`\n : `UPSERT INTO ${this.tableName}`;\n throw DatabaseError.queryFailed(operation, error);\n }\n throw error;\n }\n },\n 3,\n 500,\n );\n\n // The row now exists, so any further save() must update it by primary\n // key even if natural-key fields change afterwards (issue #1472).\n this._persisted = true;\n\n // Bust cached collection reads for this table (issue #1498). SMRT owns\n // every mutation path, so this is the write-invalidation guarantee the\n // opt-in read cache relies on.\n this.invalidateCollectionReadCache();\n\n // Execute afterSave interceptors (e.g., tenant audit logging)\n await GlobalInterceptors.executeAfterSave(this, interceptorContext);\n\n // Auto-generate embeddings only when an AI client is configured. Manual\n // generation can still use local embeddings, but save-time background\n // work should not unexpectedly load a local transformer model.\n const embeddingConfig = ObjectRegistry.resolveEmbeddingConfig(className);\n const skipAutoEmbeddings = this.options._skipAutoEmbeddings === true;\n if (\n embeddingConfig &&\n embeddingConfig.autoGenerate !== false &&\n !skipAutoEmbeddings\n ) {\n const aiClient = await this.getOptionalAiClient();\n\n // Check if any embedding field content has changed\n if (aiClient) {\n const isStale = await this.hasStaleEmbeddings();\n if (isStale) {\n // Generate embeddings in background to avoid blocking save\n this.generateEmbeddings().catch((error) => {\n logger.warn(\n `Failed to auto-generate embeddings for ${this.constructor.name}`,\n { error: error instanceof Error ? error.message : error },\n );\n });\n }\n }\n }\n if (skipAutoEmbeddings) {\n this.options._skipAutoEmbeddings = false;\n }\n\n return this;\n } catch (error) {\n // Re-throw SMRT errors as-is (ValidationError, DatabaseError,\n // TenantIsolationError, etc. all extend SmrtError) so their stable\n // `code`/`instanceof` contract survives the save() boundary.\n if (error instanceof SmrtError) {\n throw error;\n }\n\n // Preserve tenancy errors thrown by the `beforeSave` interceptor. The\n // `@happyvertical/smrt-tenancy` TenantIsolationError / TenantContextError\n // extend plain `Error` (core cannot depend on the tenancy package), so\n // they are NOT instanceof SmrtError. Re-throw them as-is by their stable\n // `code` (or class name fallback) so handlers can still match\n // `err.code === 'TENANT_ISOLATION_VIOLATION'` / 'TENANT_CONTEXT_REQUIRED'\n // on the write path, just like on the relationship-load path.\n if (this.isTenantContractError(error)) {\n throw error;\n }\n\n throw RuntimeError.operationFailed(\n 'save',\n `${className}#${this.id}`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n /**\n * Detects tenant-boundary errors that must propagate from `save()` unwrapped.\n *\n * Matches both core's {@link TenantIsolationError} and the duck-typed\n * tenancy-package errors (`TenantIsolationError` / `TenantContextError`) that\n * the `beforeSave` interceptor throws. Those tenancy classes extend plain\n * `Error` — core cannot import the tenancy package (the dependency runs the\n * other way) — so they are matched by their stable `code` constants, with a\n * class-name fallback for resilience.\n */\n private isTenantContractError(error: unknown): boolean {\n if (error instanceof TenantIsolationError) {\n return true;\n }\n const candidate = error as\n | { code?: unknown; name?: unknown }\n | null\n | undefined;\n const code = candidate?.code;\n if (\n code === 'TENANT_ISOLATION_VIOLATION' ||\n code === 'TENANT_CONTEXT_REQUIRED'\n ) {\n return true;\n }\n const name = candidate?.name;\n return name === 'TenantIsolationError' || name === 'TenantContextError';\n }\n\n /**\n * Validates object state before saving\n * Override in subclasses to add custom validation logic\n */\n protected async validateBeforeSave(): Promise<void> {\n const className = this.getResolvedClassName();\n\n // Priority 1: Use pre-computed validation rules from manifest (Issue #782)\n // This is the fastest path - rules are serializable and don't require closures\n const validationRules = ObjectRegistry.getValidationRules(className);\n\n if (validationRules && validationRules.length > 0) {\n const errors = await ObjectRegistry.validateWithRules(\n this,\n validationRules,\n className,\n );\n\n if (errors.length > 0) {\n throw errors[0];\n }\n return;\n }\n\n // Priority 2: Use compiled validators (backward compatibility)\n const validators = ObjectRegistry.getValidators(className);\n\n if (validators && validators.length > 0) {\n // Execute all cached validators\n const errors: ValidationError[] = [];\n\n for (const validator of validators) {\n const error = await validator(this);\n if (error) {\n errors.push(error);\n }\n }\n\n // If there are validation errors, throw the first one\n // (In the future, we could throw all errors as a ValidationReport)\n if (errors.length > 0) {\n throw errors[0];\n }\n return;\n }\n\n // Priority 3: Fallback to old validation logic if no cached validators\n // (for classes not registered with ObjectRegistry)\n const fields = await fieldsFromClass(this.constructor as any);\n\n for (const [fieldName, field] of Object.entries(fields)) {\n // With decorators, field definitions are plain objects with nested options\n if ((field as any).options?.required) {\n const value = this.getFieldValue(fieldName);\n if (value === null || value === undefined || value === '') {\n throw ValidationError.requiredField(fieldName, className);\n }\n }\n }\n }\n\n /**\n * Validates cross-package references that opted in via `validate: true`.\n *\n * Iterates registered fields of type `crossPackageRef`. For each one whose\n * field options include `validate: true` AND has a non-empty value, looks up\n * the referenced object via the target package's manifest and throws\n * `ValidationError` if the target row does not exist.\n *\n * Empty/null/undefined values are treated as \"no reference set\" and skipped.\n * Fields without `validate: true` are always skipped (the registered metadata\n * still powers eager loading and `loadRelated()`).\n */\n protected async validateCrossPackageRefs(): Promise<void> {\n const className = this.getResolvedClassName();\n const registered = ObjectRegistry.getClass(className);\n if (!registered) return;\n\n const fields = registered.inheritedFields || registered.fields;\n if (!fields || fields.size === 0) return;\n\n type CrossRefCheck = {\n fieldName: string;\n qualifiedTarget: string;\n value: string;\n };\n const checks: CrossRefCheck[] = [];\n\n for (const [fieldName, field] of fields) {\n if (field?.type !== 'crossPackageRef') continue;\n const opts = field._meta || field;\n if (!opts.validate) continue;\n if (!field.related) continue;\n\n const value = this.getFieldValue(fieldName);\n if (value === null || value === undefined || value === '') continue;\n\n checks.push({\n fieldName,\n qualifiedTarget: String(field.related),\n value: String(value),\n });\n }\n\n if (checks.length === 0) return;\n\n for (const check of checks) {\n await ObjectRegistry.ensureManifestLoaded(check.qualifiedTarget);\n\n const targetClass =\n ObjectRegistry.getClassByQualifiedName(check.qualifiedTarget) ??\n ObjectRegistry.getClass(check.qualifiedTarget);\n\n if (!targetClass) {\n throw new ValidationError(\n `crossPackageRef target ${check.qualifiedTarget} for ${className}.${check.fieldName} is not registered. ` +\n `Ensure the target package's manifest is discoverable at runtime.`,\n 'VALIDATION_CROSS_PACKAGE_REF_UNREGISTERED',\n { className, fieldName: check.fieldName, value: check.value },\n );\n }\n\n const probe = new targetClass.constructor(this.options) as SmrtObject;\n await probe.initialize();\n await probe.verifyStorageReady();\n const row = await probe.db.get(probe.tableName, { id: check.value });\n if (!row) {\n throw new ValidationError(\n `crossPackageRef validation failed: ${className}.${check.fieldName} references ` +\n `${check.qualifiedTarget} id=\"${check.value}\" but no such row exists.`,\n 'VALIDATION_CROSS_PACKAGE_REF_MISSING',\n { className, fieldName: check.fieldName, value: check.value },\n );\n }\n }\n }\n\n /**\n * Gets the value of a field on this object\n */\n protected getFieldValue(fieldName: string): any {\n return (this as any)[fieldName];\n }\n\n /**\n * Gets the value of a property.\n *\n * @param key - Property name to get value from\n * @returns The property value\n */\n protected getPropertyValue(key: string): any {\n return (this as any)[key];\n }\n\n /**\n * Classifies a raw database driver error message as a unique-constraint or\n * not-null-constraint violation, across SQLite, PostgreSQL and DuckDB.\n *\n * `@happyvertical/sql` does not normalize driver errors, so each dialect's\n * native wording is matched case-insensitively. Returns `null` when the\n * message is not a recognized unique/not-null violation (the caller then\n * falls back to a generic `DatabaseError`). Kept as a pure static so the\n * cross-dialect matching can be unit-tested directly without a live PG/DuckDB\n * connection (#1378).\n *\n * @param message - The raw driver error message.\n * @returns `'unique'`, `'not_null'`, or `null`.\n */\n static classifyConstraintError(\n message: string,\n ): 'unique' | 'not_null' | null {\n if (!message) {\n return null;\n }\n\n // NOT NULL — checked first because DuckDB's \"violates\" wording would\n // otherwise be misread as a unique violation below.\n // SQLite/DuckDB: \"NOT NULL constraint failed: t.col\"\n // PostgreSQL: 'null value in column \"col\" ... violates not-null constraint'\n if (\n /NOT NULL constraint failed/i.test(message) ||\n /null value in column .* violates not-null/i.test(message)\n ) {\n return 'not_null';\n }\n\n // UNIQUE — match unique/primary-key wording specifically. Do NOT match a\n // bare \"Constraint Error ... violates\", because DuckDB phrases foreign-key\n // failures the same way (\"Constraint Error: violates foreign key\n // constraint\"); a broad match would misreport an FK violation as a unique\n // one. Unmatched constraint kinds (FK, CHECK) fall through to a generic\n // DatabaseError, preserving the original error contract.\n // SQLite: \"UNIQUE constraint failed: t.col\"\n // PostgreSQL: \"duplicate key value violates unique constraint ...\"\n // DuckDB: \"Constraint Error: ... violates unique/primary key constraint\"\n if (\n /UNIQUE constraint failed/i.test(message) ||\n /violates unique constraint/i.test(message) ||\n /violates primary key constraint/i.test(message)\n ) {\n return 'unique';\n }\n\n return null;\n }\n\n /**\n * Extracts field name from database constraint error messages.\n *\n * Handles SQLite, PostgreSQL and DuckDB phrasings. Returns\n * `'unknown_field'` when no column name can be recovered.\n */\n protected extractConstraintField(errorMessage: string): string {\n // Try to extract field name from common constraint patterns across dialects.\n const patterns = [\n // SQLite / DuckDB: \"UNIQUE constraint failed: products.slug\"\n /UNIQUE constraint failed: \\w+\\.(\\w+)/i,\n // SQLite / DuckDB: \"NOT NULL constraint failed: products.name\"\n /NOT NULL constraint failed: \\w+\\.(\\w+)/i,\n // PostgreSQL not-null: 'null value in column \"name\" ...'\n /null value in column \"([^\"]+)\"/i,\n // PostgreSQL unique DETAIL line: 'Key (slug)=(foo) already exists.'\n /Key \\(([^)]+)\\)=/i,\n // SQLite / DuckDB generic fallback: \"constraint failed: slug\"\n /constraint failed: (\\w+)/i,\n ];\n\n for (const pattern of patterns) {\n const match = errorMessage.match(pattern);\n if (match?.[1]) {\n return match[1];\n }\n }\n\n return 'unknown_field';\n }\n\n /**\n * Hydrates this object from the database using its `id` property.\n *\n * Queries the database for a row matching `{ id: this._id }` and calls\n * `loadDataFromDb()` if found. Uses a 3-attempt retry with 250 ms initial\n * delay to handle transient failures.\n *\n * Called automatically by `initialize()` when `options.id` is provided.\n * Typically you do not need to call this directly.\n *\n * @returns Promise that resolves when loading is complete (no-op if not found)\n * @throws {ValidationError} If `this._id` is not set\n * @throws {DatabaseError} If the query fails after all retries\n *\n * @example\n * ```typescript\n * const product = new Product({ db: myDb });\n * await product.initialize();\n * product._id = 'some-uuid';\n * await product.loadFromId(); // hydrates from DB\n * ```\n */\n public async loadFromId() {\n try {\n if (!this._id) {\n throw ValidationError.requiredField('id', this.constructor.name);\n }\n\n await this.verifyStorageReady();\n\n await ErrorUtils.withRetry(\n async () => {\n try {\n const existing = await this.db.get(this.tableName, {\n id: this._id,\n });\n if (existing) {\n await this.loadDataFromDb(existing);\n }\n } catch (error) {\n throw DatabaseError.queryFailed(\n `get(${this.tableName}, { id: ${this._id} })`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n },\n 3,\n 250,\n );\n } catch (error) {\n if (error instanceof ValidationError || error instanceof DatabaseError) {\n throw error;\n }\n\n throw RuntimeError.operationFailed(\n 'loadFromId',\n `${this.constructor.name}#${this._id}`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n /**\n * Hydrates this object from the database using its `slug` (and `context`).\n *\n * Queries for a row matching `{ slug, context }`. The `context` defaults to\n * an empty string when not provided. Calls `loadDataFromDb()` if a matching\n * row is found.\n *\n * Called automatically by `initialize()` when `options.slug` is provided and\n * no `options.id` is set. Typically you do not need to call this directly.\n *\n * @returns Promise that resolves when loading is complete (no-op if not found)\n *\n * @example\n * ```typescript\n * const product = new Product({ db: myDb, slug: 'my-widget', context: 'shop' });\n * await product.initialize(); // calls loadFromSlug() automatically\n * console.log(product.name);\n * ```\n */\n public async loadFromSlug() {\n await this.verifyStorageReady();\n\n const existing = await this.db.get(this.tableName, {\n slug: this._slug,\n context: this._context || '',\n });\n if (existing) {\n await this.loadDataFromDb(existing);\n }\n }\n\n /**\n * Serializes this instance into the \"content body\" injected into the AI\n * prompts used by {@link is}, {@link do}, and {@link describe} so those\n * methods reason over the object's own field data, not just the caller's\n * instruction string.\n *\n * Uses {@link toPublicJSON} (never {@link toJSON}) so that\n * `@field({ sensitive: true })` values — API secrets, credentials, tax IDs —\n * are never sent to the model. The serialized payload is truncated to\n * `maxLength` characters as a coarse token-budget guard for large instances;\n * truncation appends a clear marker so the model knows the data was cut.\n *\n * @param maxLength - Maximum characters of object data to include\n * (defaults to {@link AI_PROMPT_DATA_MAX_LENGTH}). A non-positive value\n * disables truncation.\n * @returns A JSON string of the object's public (sensitive-stripped) fields\n */\n private serializeForAiPrompt(\n maxLength: number = AI_PROMPT_DATA_MAX_LENGTH,\n ): string {\n let serialized: string;\n try {\n serialized = JSON.stringify(this.toPublicJSON(), null, 2);\n } catch (error) {\n // Defensive: never let a serialization edge case break an AI call.\n // The instruction-only prompt still works; we just lose the data context.\n logger.warn(\n `Failed to serialize ${this.constructor.name} for AI prompt: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n serialized = '{}';\n }\n\n if (\n Number.isFinite(maxLength) &&\n maxLength > 0 &&\n serialized.length > maxLength\n ) {\n const marker = `\\n… [truncated: object data exceeded ${maxLength} characters]`;\n // Reserve room for the marker so the returned string never exceeds\n // maxLength — the budget is a hard ceiling, not \"data + marker\". For a\n // budget smaller than the marker itself, emit just the marker (an\n // unusably small budget still yields a clear truncation signal).\n const keep = Math.max(0, maxLength - marker.length);\n serialized = `${serialized.slice(0, keep)}${marker}`;\n }\n\n return serialized;\n }\n\n /**\n * Builds the optional \"content body\" section prepended to the AI prompts in\n * {@link is}, {@link do}, and {@link describe}.\n *\n * Returns an empty string when the caller opts out with `includeData: false`\n * — used by callers that already curate the object's relevant fields into\n * their own instruction/criteria string (so the data is not duplicated, and\n * the prompt stays exactly as the caller authored it). Otherwise it wraps\n * {@link serializeForAiPrompt} in `--- Beginning/End of content ---`\n * delimiters so the methods reason over the instance's own data by default.\n *\n * @param includeData - `false` to omit the section; any other value (incl.\n * `undefined`) injects it\n * @param maxLength - Forwarded to {@link serializeForAiPrompt} as the\n * truncation budget\n * @returns The content-body section (with a trailing newline) or `''`\n */\n private buildAiContentSection(\n includeData: boolean | undefined,\n maxLength?: number,\n ): string {\n if (includeData === false) {\n return '';\n }\n const contentBody = this.serializeForAiPrompt(maxLength);\n return `--- Beginning of content ---\\n${contentBody}\\n--- End of content ---\\n`;\n }\n\n /**\n * Evaluates whether this object satisfies the given natural-language criteria using AI.\n *\n * Injects the object's own public field data (via {@link toPublicJSON}, so\n * `@field({ sensitive: true })` values are excluded) into the prompt as the\n * \"content body\", then asks the AI whether that data meets the criteria and\n * to reply with a `{ result: boolean }` JSON response. Uses any AI-callable\n * tools registered on this class (via `@smrt({ ai })`) as part of the\n * function-calling context.\n *\n * @param criteria - Natural-language description of the condition to evaluate\n * @param options - AI message options passed to `ai.message()` (e.g. model\n * override). Two non-standard control keys are consumed here and not\n * forwarded to `ai.message()`:\n * - `includeData: false` — omit the injected object \"content body\" (for\n * callers that already curate the relevant fields into `criteria`).\n * - `maxDataLength` (number of characters) — override the injected\n * object-data truncation limit.\n * @returns `true` if the object meets the criteria, `false` otherwise\n * @throws Error if the AI returns a non-boolean or malformed JSON response\n *\n * @example\n * ```typescript\n * const article = await articles.get('article-uuid');\n * const isSuitable = await article.is('appropriate for a general audience');\n * if (isSuitable) await article.publish();\n * ```\n *\n * @see {@link do} for open-ended instructions instead of boolean checks\n */\n public async is(criteria: string, options: any = {}) {\n const ai = await this.getAiClient();\n const { maxDataLength, includeData, ...aiOptions } = options ?? {};\n const contentSection = this.buildAiContentSection(\n includeData,\n maxDataLength,\n );\n const prompt = `${contentSection}--- Beginning of criteria ---\\n${criteria}\\n--- End of criteria ---\\nDoes the content meet all the given criteria? Reply with a json object with a single boolean 'result' property`;\n\n // Get available tools for AI function calling\n const tools = this.getAvailableTools();\n\n const message = await ai.message(prompt, {\n ...(aiOptions as any),\n responseFormat: { type: 'json_object' },\n tools: tools.length > 0 ? tools : undefined,\n });\n\n try {\n const { result } = JSON.parse(message);\n if (result === true || result === false) {\n return result;\n }\n } catch (_e) {\n throw new Error(`Unexpected answer: ${message}`);\n }\n }\n\n /**\n * Performs a freeform operation on this object using AI instructions.\n *\n * Injects the object's own public field data (via {@link toPublicJSON}, so\n * `@field({ sensitive: true })` values are excluded) into the prompt as the\n * \"content body\" the instructions operate on, then returns the raw text\n * response. Unlike `is()`, this method does not constrain the response\n * format — use it for transformations, summaries, extractions, or any\n * open-ended AI task.\n *\n * Uses any AI-callable tools registered on this class (via `@smrt({ ai })`)\n * as part of the function-calling context.\n *\n * @param instructions - Natural-language instructions for the AI to follow\n * @param options - AI message options passed to `ai.message()` (e.g. model\n * override). Two non-standard control keys are consumed here and not\n * forwarded to `ai.message()`:\n * - `includeData: false` — omit the injected object \"content body\" (for\n * callers that already curate the relevant fields into `instructions`).\n * - `maxDataLength` (number of characters) — override the injected\n * object-data truncation limit.\n * @returns The raw AI response string\n *\n * @example\n * ```typescript\n * const article = await articles.get('article-uuid');\n * const summary = await article.do('summarize this article in 3 bullet points');\n * const translated = await article.do('translate the title and body to Spanish');\n * ```\n *\n * @see {@link is} for boolean criteria checks\n */\n public async do(instructions: string, options: any = {}) {\n const ai = await this.getAiClient();\n const { maxDataLength, includeData, ...aiOptions } = options ?? {};\n const contentSection = this.buildAiContentSection(\n includeData,\n maxDataLength,\n );\n const prompt = `${contentSection}--- Beginning of instructions ---\\n${instructions}\\n--- End of instructions ---\\nBased on the content body, please follow the instructions and provide a response. Never make use of codeblocks.`;\n\n // Get available tools for AI function calling\n const tools = this.getAvailableTools();\n\n const result = await ai.message(prompt, {\n ...aiOptions,\n tools: tools.length > 0 ? tools : undefined,\n });\n\n return result;\n }\n\n /**\n * Generates a description of this object using AI (Issue #52)\n *\n * Creates a concise, human-readable description based on the object's content\n * and properties. The object's own public field data (via\n * {@link toPublicJSON}, so `@field({ sensitive: true })` values are excluded)\n * is injected into the prompt as the \"content body\" the description is built\n * from. Useful for summaries, previews, and documentation.\n *\n * @param options - AI message options (can include style, length, focus,\n * etc.). Two non-standard control keys are consumed here and not forwarded\n * to `ai.message()`:\n * - `includeData: false` — omit the injected object \"content body\".\n * - `maxDataLength` (number of characters) — override the injected\n * object-data truncation limit.\n * @returns Promise resolving to the AI-generated description\n *\n * @example\n * ```typescript\n * const product = await products.get('product-123');\n * const description = await product.describe();\n * // \"A high-quality widget for home improvement...\"\n *\n * // With custom options\n * const shortDesc = await product.describe({ maxTokens: 50 });\n * // \"Premium widget, steel construction\"\n * ```\n */\n public async describe(options: any = {}) {\n const ai = await this.getAiClient();\n const { maxDataLength, includeData, ...aiOptions } = options ?? {};\n const contentSection = this.buildAiContentSection(\n includeData,\n maxDataLength,\n );\n const prompt = `${contentSection}Generate a concise, professional description of this object based on its content and properties. The description should be clear, informative, and suitable for display to end users. Focus on the most important and distinctive characteristics.`;\n\n // Get available tools for AI function calling\n const tools = this.getAvailableTools();\n\n const result = await ai.message(prompt, {\n ...aiOptions,\n tools: tools.length > 0 ? tools : undefined,\n });\n\n return result;\n }\n\n /**\n * Runs a lifecycle hook if it's defined in the object's configuration\n *\n * @param hookName - Name of the hook to run (e.g., 'beforeDelete', 'afterDelete')\n * @returns Promise that resolves when the hook completes\n */\n protected async runHook(hookName: string): Promise<void> {\n const config = ObjectRegistry.getConfig(this.constructor.name);\n const hook = config.hooks?.[hookName as keyof typeof config.hooks];\n\n if (!hook) {\n return; // No hook defined, nothing to do\n }\n\n if (typeof hook === 'string') {\n // Hook is a method name to call on this instance\n const method = (this as any)[hook];\n if (typeof method === 'function') {\n await method.call(this);\n } else {\n logger.warn(\n `Hook method '${hook}' not found on ${this.constructor.name}`,\n );\n }\n } else if (typeof hook === 'function') {\n // Hook is a function to call with this instance as parameter\n await hook(this);\n }\n }\n\n /**\n * Deletes this object from the database.\n *\n * Runs the full lifecycle in order:\n * 1. `beforeDelete` interceptors (e.g. tenant validation)\n * 2. `beforeDelete` lifecycle hook (defined in `@smrt({ hooks })`)\n * 3. Database row deletion\n * 4. `afterDelete` lifecycle hook\n * 5. `afterDelete` interceptors\n *\n * Prefer `collection.delete(id)` from application code — it loads the\n * object first (returning `false` when not found) before calling this method.\n *\n * @returns Promise that resolves when deletion is complete\n *\n * @example\n * ```typescript\n * const product = await products.get('product-uuid');\n * if (product) await product.delete();\n * ```\n */\n public async delete(): Promise<void> {\n // Execute beforeDelete interceptors (e.g., tenant validation)\n const interceptorContext = createInterceptorContext(\n this.constructor.name,\n 'delete',\n );\n await GlobalInterceptors.executeBeforeDelete(this, interceptorContext);\n\n await this.runHook('beforeDelete');\n\n await this.verifyStorageReady();\n await this.db.delete(this.tableName, { id: this.id });\n\n // The backing row is gone — a later save() should go through the\n // natural-key insert path again rather than targeting a deleted id.\n this._persisted = false;\n\n // Bust cached collection reads for this table (issue #1498).\n this.invalidateCollectionReadCache();\n\n await this.runHook('afterDelete');\n\n // Execute afterDelete interceptors (e.g., tenant audit logging)\n await GlobalInterceptors.executeAfterDelete(this, interceptorContext);\n }\n\n /**\n * Invalidate cached collection reads after a successful mutation\n * (issue #1498).\n *\n * Always drops this table's in-process entries — a no-op when nothing\n * opted into caching. When the table is cached cross-process (see\n * {@link shouldBroadcastCacheInvalidation}), the invalidation is also\n * broadcast to peer replicas over the database adapter's notification\n * capability, fire-and-forget. Cache maintenance must never fail the\n * write that triggered it.\n */\n private invalidateCollectionReadCache(): void {\n try {\n const dbKey = resolveDbCacheKey(this.db);\n invalidateCollectionCache(dbKey, this.tableName);\n\n if (this.shouldBroadcastCacheInvalidation(dbKey)) {\n void broadcastCacheInvalidation(this.db, this.tableName);\n }\n } catch (error) {\n logger.warn('Failed to invalidate collection read cache after write', {\n table: this.tableName,\n error: error instanceof Error ? error.message : error,\n });\n }\n }\n\n /**\n * Decide whether a mutation should broadcast a cross-process cache\n * invalidation. Invalidation is table-scoped, so the decision must be too:\n *\n * 1. A per-call `crossProcess` cached read in this process registered\n * interest in the table — broadcast even without model-level config.\n * 2. This class's resolved `@smrt({ cache })` config sets `crossProcess`.\n * 3. Any other STI hierarchy member sharing the table resolves to a\n * `crossProcess` config — a child that opted out with `cache: false`\n * still mutates the shared table its base/siblings are caching.\n */\n private shouldBroadcastCacheInvalidation(dbKey: string): boolean {\n if (hasCrossProcessCacheInterest(dbKey, this.tableName)) {\n return true;\n }\n\n const qualifiedName = this.getResolvedQualifiedName();\n if (\n ObjectRegistry.resolveCollectionCacheConfig(qualifiedName)?.crossProcess\n ) {\n return true;\n }\n\n for (const member of getSTIHierarchyMembers(qualifiedName)) {\n if (member === qualifiedName) continue;\n if (ObjectRegistry.resolveCollectionCacheConfig(member)?.crossProcess) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Check if a relationship has been loaded\n *\n * @param fieldName - Name of the relationship field\n * @returns True if the relationship is loaded, false otherwise\n * @example\n * ```typescript\n * if (order.isRelatedLoaded('customer')) {\n * console.log('Customer already loaded');\n * }\n * ```\n */\n public isRelatedLoaded(fieldName: string): boolean {\n return this._loadedRelationships.has(fieldName);\n }\n\n /**\n * Lazy-loads a `foreignKey` or `crossPackageRef` relationship and caches the\n * result.\n *\n * Looks up the relationship metadata in the ObjectRegistry, reads the\n * foreign key value on this object, and fetches the related object from\n * the database. Subsequent calls return the cached value without hitting\n * the database again.\n *\n * For STI relationships, the correct subclass is determined by reading\n * `_meta_type` from the database row before instantiation.\n *\n * Enforces tenant isolation: if this object and the loaded target both carry\n * a non-null `tenantId` that differ, a {@link TenantIsolationError} is thrown\n * (unless `opts.allowCrossTenant` is set). The check is a no-op for\n * global/null-tenant models and same-tenant loads, so it only catches genuine\n * cross-tenant leaks (Issue #1321).\n *\n * @param fieldName - Name of the `@foreignKey()` or `@crossPackageRef()`\n * decorated property\n * @param opts - Optional loader options; see {@link LoadRelatedOptions}\n * @returns The related object, or `null` if the foreign key is empty\n * @throws {RuntimeError} If `fieldName` is not a `foreignKey` or\n * `crossPackageRef` relationship, or the target class is not found in the\n * ObjectRegistry\n * @throws {TenantIsolationError} If the target belongs to a different,\n * non-null tenant and `opts.allowCrossTenant` is not set\n *\n * @example\n * ```typescript\n * // class Order { @foreignKey(Customer) customerId: string = ''; }\n * const customer = await order.loadRelated('customerId');\n * console.log(customer?.name);\n * ```\n *\n * @see {@link getRelated} for a convenience wrapper that auto-detects relationship type\n */\n public async loadRelated(\n fieldName: string,\n opts?: LoadRelatedOptions,\n ): Promise<any> {\n // Check if already loaded\n if (this._loadedRelationships.has(fieldName)) {\n const cached = this._loadedRelationships.get(fieldName);\n // Re-validate cached targets: a cache populated by an eager `include`\n // load (or a prior allowCrossTenant load) must not leak cross-tenant data\n // through a later guarded call (Issue #1321).\n this.assertRelatedTenant(cached, fieldName, opts?.allowCrossTenant);\n return cached;\n }\n\n // Ensure manifest is loaded for external packages before accessing relationships\n // This is critical for cross-package relationship resolution (Issue #746)\n await ObjectRegistry.ensureManifestLoaded(this.constructor.name);\n\n // Get relationship metadata from ObjectRegistry\n const relationships = ObjectRegistry.getRelationships(\n this.constructor.name,\n );\n const relationship = relationships.find(\n (r) =>\n r.fieldName === fieldName &&\n (r.type === 'foreignKey' || r.type === 'crossPackageRef'),\n );\n\n if (!relationship) {\n throw RuntimeError.invalidState(\n `Field ${fieldName} is not a foreignKey or crossPackageRef relationship on ${this.constructor.name}`,\n { fieldName, className: this.constructor.name },\n );\n }\n\n // Get the foreign key value\n const foreignKeyValue = this[fieldName as keyof this];\n if (!foreignKeyValue) {\n // No related object (foreign key is null)\n this._loadedRelationships.set(fieldName, null);\n return null;\n }\n\n // For crossPackageRef, the target is a qualified name and the target package's\n // manifest may not be loaded yet — ensure it's available before lookup.\n if (relationship.type === 'crossPackageRef') {\n await ObjectRegistry.ensureManifestLoaded(relationship.targetClass);\n }\n\n // Get the target class constructor (try qualified name first for crossPackageRef)\n const targetClassInfo =\n relationship.type === 'crossPackageRef'\n ? (ObjectRegistry.getClassByQualifiedName(relationship.targetClass) ??\n ObjectRegistry.getClass(relationship.targetClass))\n : ObjectRegistry.getClass(relationship.targetClass);\n if (!targetClassInfo) {\n throw RuntimeError.invalidState(\n `Target class ${relationship.targetClass} not found in ObjectRegistry`,\n { targetClass: relationship.targetClass, fieldName },\n );\n }\n\n // Check if target class uses STI (Single Table Inheritance)\n const tableStrategy = ObjectRegistry.getTableStrategy(\n relationship.targetClass,\n );\n const isSTI = tableStrategy === 'sti';\n\n // For STI classes, we need to determine the actual subclass from the database row\n let actualClassInfo = targetClassInfo;\n if (isSTI) {\n // First, fetch just the row to get the _meta_type discriminator\n const tempInstance = new targetClassInfo.constructor(this.options);\n await tempInstance.initialize();\n await tempInstance.verifyStorageReady();\n const row = await tempInstance.db.get(tempInstance.tableName, {\n id: foreignKeyValue as string,\n });\n\n if (row?._meta_type) {\n // Get the actual class from the registry based on _meta_type\n // Support both qualified names (new format: @pkg:Class) and simple names (legacy)\n let actualClass = ObjectRegistry.getClassByQualifiedName(\n row._meta_type,\n );\n if (!actualClass) {\n // Fall back to simple name lookup for legacy data\n actualClass = ObjectRegistry.getClass(row._meta_type);\n }\n if (actualClass) {\n actualClassInfo = actualClass;\n }\n }\n }\n\n // Create an instance of the correct class and load by ID\n const relatedInstance = new actualClassInfo.constructor(this.options);\n await relatedInstance.initialize();\n relatedInstance.id = foreignKeyValue as string;\n await relatedInstance.loadFromId();\n\n // Enforce tenant isolation before caching/returning so a blocked\n // cross-tenant target is never cached (Issue #1321).\n this.assertRelatedTenant(\n relatedInstance,\n fieldName,\n opts?.allowCrossTenant,\n );\n\n // Cache the loaded object\n this._loadedRelationships.set(fieldName, relatedInstance);\n return relatedInstance;\n }\n\n /**\n * Guards a loaded relationship target against cross-tenant access.\n *\n * Throws {@link TenantIsolationError} when this object and `loaded` both carry\n * a non-null `tenantId` that differ — the genuine cross-tenant leak. It is a\n * no-op when `allowCrossTenant === true`, when `loaded` is `null`, when either\n * side has a `null`/`undefined` tenant (global / non-tenant-scoped models),\n * and when both sides share the same tenant (Issue #1321).\n *\n * `loaded` may be a single related object or an array (oneToMany / manyToMany);\n * arrays are validated per item. This runs on both fresh loads and cache hits,\n * so a cache populated by an eager `include` load — or by a prior\n * `allowCrossTenant` load — cannot leak cross-tenant data through a later\n * guarded call.\n *\n * @param loaded - The loaded related object, or array of objects.\n * @param fieldName - The relationship field name (for error context).\n * @param allowCrossTenant - When exactly `true`, bypasses the guard entirely.\n */\n private assertRelatedTenant(\n loaded: unknown,\n fieldName: string,\n allowCrossTenant?: boolean,\n ): void {\n // Strict `=== true`: only the documented opt-in bypasses the guard, never an\n // incidental truthy value passed from untyped JS callers.\n if (allowCrossTenant === true || loaded == null) {\n return;\n }\n\n if (Array.isArray(loaded)) {\n for (const item of loaded) {\n this.assertRelatedTenant(item, fieldName, allowCrossTenant);\n }\n return;\n }\n\n const sourceTenantId = (this as { tenantId?: unknown }).tenantId;\n const targetTenantId = (loaded as { tenantId?: unknown }).tenantId;\n\n if (\n sourceTenantId != null &&\n targetTenantId != null &&\n sourceTenantId !== targetTenantId\n ) {\n throw TenantIsolationError.crossTenantReference({\n sourceClass: this.constructor.name,\n fieldName,\n sourceTenantId: String(sourceTenantId),\n targetClass: (loaded as { constructor?: { name?: string } })\n ?.constructor?.name,\n targetTenantId: String(targetTenantId),\n });\n }\n }\n\n /**\n * Load related objects for oneToMany or manyToMany fields (lazy loading)\n *\n * Loads all related objects from the database. For oneToMany, queries by\n * the inverse foreign key. For manyToMany, queries through the join table.\n *\n * Enforces tenant isolation per item: if this object and a loaded target both\n * carry a non-null `tenantId` that differ, a {@link TenantIsolationError} is\n * thrown (unless `opts.allowCrossTenant` is set). The check is a no-op for\n * global/null-tenant models and same-tenant loads, so it only catches genuine\n * cross-tenant leaks (Issue #1321).\n *\n * @param fieldName - Name of the oneToMany or manyToMany field\n * @param opts - Optional loader options; see {@link LoadRelatedOptions}\n * @returns Promise resolving to array of related objects\n * @throws {RuntimeError} If the field is not a relationship or not implemented\n * @throws {TenantIsolationError} If any loaded item belongs to a different,\n * non-null tenant and `opts.allowCrossTenant` is not set\n * @example\n * ```typescript\n * // Given: class Customer with orders = oneToMany(Order)\n * const orders = await customer.loadRelatedMany('orders');\n * console.log(`${orders.length} orders found`);\n * ```\n */\n public async loadRelatedMany(\n fieldName: string,\n opts?: LoadRelatedOptions,\n ): Promise<any[]> {\n // Check if already loaded\n if (this._loadedRelationships.has(fieldName)) {\n const cached = this._loadedRelationships.get(fieldName);\n // Re-validate cached targets: a cache populated by an eager `include`\n // load (or a prior allowCrossTenant load) must not leak cross-tenant data\n // through a later guarded call (Issue #1321).\n this.assertRelatedTenant(cached, fieldName, opts?.allowCrossTenant);\n return cached;\n }\n\n // Ensure manifest is loaded for external packages before accessing relationships\n // This is critical for cross-package relationship resolution (Issue #746)\n await ObjectRegistry.ensureManifestLoaded(this.constructor.name);\n\n // Get relationship metadata from ObjectRegistry\n const relationships = ObjectRegistry.getRelationships(\n this.constructor.name,\n );\n const relationship = relationships.find((r) => r.fieldName === fieldName);\n\n if (!relationship) {\n throw RuntimeError.invalidState(\n `Field ${fieldName} is not a relationship on ${this.constructor.name}`,\n { fieldName, className: this.constructor.name },\n );\n }\n\n if (relationship.type === 'oneToMany') {\n // Find the inverse foreignKey field on the target class. An instance can\n // satisfy an inverse FK that targets its own class OR any (STI) ancestor\n // it inherits the oneToMany from — the FK is declared against the base\n // class name, while `this.constructor.name` may be a subclass (e.g. a\n // Person inheriting Profile.relationshipsFrom).\n const inverseRelationships =\n ObjectRegistry.getInverseRelationshipsForSelf(this.constructor.name);\n const inverseCandidates = inverseRelationships.filter(\n (r) =>\n r.sourceClass === relationship.targetClass && r.type === 'foreignKey',\n );\n // When the target declares multiple foreign keys back to this class\n // (e.g. ProfileRelationship.fromProfileId / toProfileId), honor an\n // explicit `@oneToMany(Target, { foreignKey })` to pick the right side.\n // Otherwise fall back to the first match (legacy behavior).\n const explicitForeignKey = relationship.options?.foreignKey as\n | string\n | undefined;\n const matchedForeignKey = explicitForeignKey\n ? inverseCandidates.find((r) => r.fieldName === explicitForeignKey)\n : undefined;\n if (explicitForeignKey && !matchedForeignKey) {\n // A misspelled / stale `foreignKey` must fail loudly rather than\n // silently resolving the wrong inverse side.\n throw RuntimeError.invalidState(\n `oneToMany ${fieldName} on ${this.constructor.name} specifies foreignKey '${explicitForeignKey}', but ${relationship.targetClass} has no matching inverse foreignKey. Candidates: ${inverseCandidates.map((r) => r.fieldName).join(', ') || '(none)'}`,\n {\n fieldName,\n targetClass: relationship.targetClass,\n foreignKey: explicitForeignKey,\n },\n );\n }\n // Prefer an inverse FK that targets this exact class before falling back\n // to one inherited from an (STI) ancestor — preserves the pre-fallback\n // selection when a target declares FKs to multiple levels of the chain.\n const inverseForeignKey =\n matchedForeignKey ??\n inverseCandidates.find(\n (r) => r.targetClass === this.constructor.name,\n ) ??\n inverseCandidates[0];\n\n if (!inverseForeignKey) {\n throw RuntimeError.invalidState(\n `Could not find inverse foreignKey on ${relationship.targetClass} for oneToMany relationship ${fieldName}`,\n { fieldName, targetClass: relationship.targetClass },\n );\n }\n\n // Get or create cached collection instance\n const collection = await ObjectRegistry.getCollection(\n relationship.targetClass,\n this.options,\n );\n\n // Query using the inverse foreign key\n const relatedObjects = await collection.list({\n where: { [inverseForeignKey.fieldName]: this.id },\n });\n\n // Enforce tenant isolation per item before caching (Issue #1321).\n this.assertRelatedTenant(\n relatedObjects,\n fieldName,\n opts?.allowCrossTenant,\n );\n\n // Cache the loaded objects\n this._loadedRelationships.set(fieldName, relatedObjects);\n return relatedObjects;\n }\n\n if (relationship.type === 'manyToMany') {\n const { through, sourceColumn, targetColumn, targetClassName } =\n await this.resolveManyToManyJoin(fieldName, relationship);\n\n if (!this.id) {\n // No id yet — there can't be any join rows pointing at this instance.\n this._loadedRelationships.set(fieldName, []);\n return [];\n }\n\n await this.verifyStorageReady();\n\n const junctionRows = await this.db.query(\n `SELECT \"${targetColumn}\" FROM \"${through}\" WHERE \"${sourceColumn}\" = ?`,\n [this.id],\n );\n\n const targetIds = junctionRows.rows\n .map((row: any) => row[targetColumn])\n .filter(\n (id: any): id is string => typeof id === 'string' && id.length > 0,\n );\n\n if (targetIds.length === 0) {\n this._loadedRelationships.set(fieldName, []);\n return [];\n }\n\n const targetCollection = await ObjectRegistry.getCollection(\n targetClassName,\n this.options,\n );\n const targetObjects = await targetCollection.list({\n where: { 'id in': targetIds },\n });\n\n // Enforce tenant isolation per item before caching (Issue #1321).\n this.assertRelatedTenant(\n targetObjects,\n fieldName,\n opts?.allowCrossTenant,\n );\n\n this._loadedRelationships.set(fieldName, targetObjects);\n return targetObjects;\n }\n\n throw RuntimeError.invalidState(\n `Field ${fieldName} is not a oneToMany or manyToMany relationship`,\n { fieldName, type: relationship.type },\n );\n }\n\n /**\n * Resolves the junction-table coordinates for a manyToMany relationship.\n *\n * Discovers `through`, source-side column, and target-side column from the\n * registered field metadata. Falls back to convention (`<class>_id`) when\n * `sourceKey` / `targetKey` are not explicitly set.\n */\n protected async resolveManyToManyJoin(\n fieldName: string,\n relationship: {\n sourceClass: string;\n targetClass: string;\n options?: any;\n },\n ): Promise<{\n through: string;\n sourceColumn: string;\n targetColumn: string;\n targetClassName: string;\n }> {\n const decorator = ObjectRegistry.getFieldDecorator(\n relationship.sourceClass,\n fieldName,\n );\n const opts = relationship.options || {};\n\n const through = decorator?.through ?? opts.through ?? opts._meta?.through;\n if (!through) {\n throw RuntimeError.invalidState(\n `manyToMany field ${fieldName} on ${relationship.sourceClass} is missing the 'through' join table name`,\n { fieldName, type: 'manyToMany' },\n );\n }\n\n // For cross-package qualified targets, derive the simple name for column conventions\n const targetSimpleName = relationship.targetClass.includes(':')\n ? relationship.targetClass.split(':').pop()!\n : relationship.targetClass;\n const sourceSimpleName = relationship.sourceClass.includes(':')\n ? relationship.sourceClass.split(':').pop()!\n : relationship.sourceClass;\n\n const sourceColumn =\n decorator?.sourceKey ??\n opts.sourceKey ??\n opts._meta?.sourceKey ??\n `${toSnakeCase(sourceSimpleName)}_id`;\n const targetColumn =\n decorator?.targetKey ??\n opts.targetKey ??\n opts._meta?.targetKey ??\n `${toSnakeCase(targetSimpleName)}_id`;\n\n return {\n through: String(through),\n sourceColumn,\n targetColumn,\n targetClassName: relationship.targetClass,\n };\n }\n\n /**\n * Get a related object, loading it if not already loaded\n *\n * Convenience method that checks if the relationship is loaded and\n * loads it if necessary. Automatically detects foreignKey vs oneToMany/manyToMany.\n *\n * Tenant isolation is enforced by the underlying loaders; see\n * {@link loadRelated} and {@link loadRelatedMany}.\n *\n * @param fieldName - Name of the relationship field\n * @param opts - Optional loader options; see {@link LoadRelatedOptions}\n * @returns Promise resolving to the related object(s)\n * @throws {TenantIsolationError} If a loaded target belongs to a different,\n * non-null tenant and `opts.allowCrossTenant` is not set\n * @example\n * ```typescript\n * // Loads customer if not already loaded\n * const customer = await order.getRelated('customerId');\n *\n * // Loads orders if not already loaded\n * const orders = await customer.getRelated('orders');\n * ```\n */\n public async getRelated(\n fieldName: string,\n opts?: LoadRelatedOptions,\n ): Promise<any> {\n if (this._loadedRelationships.has(fieldName)) {\n const cached = this._loadedRelationships.get(fieldName);\n // Re-validate cached targets so an eager `include` load cannot leak\n // cross-tenant data through this convenience accessor (Issue #1321).\n this.assertRelatedTenant(cached, fieldName, opts?.allowCrossTenant);\n return cached;\n }\n\n // Ensure manifest is loaded for external packages before accessing relationships\n // This is critical for cross-package relationship resolution (Issue #746)\n await ObjectRegistry.ensureManifestLoaded(this.constructor.name);\n\n // Determine relationship type\n const relationships = ObjectRegistry.getRelationships(\n this.constructor.name,\n );\n const relationship = relationships.find((r) => r.fieldName === fieldName);\n\n if (!relationship) {\n throw RuntimeError.invalidState(\n `Field ${fieldName} is not a relationship on ${this.constructor.name}`,\n { fieldName, className: this.constructor.name },\n );\n }\n\n // Load based on relationship type\n if (\n relationship.type === 'foreignKey' ||\n relationship.type === 'crossPackageRef'\n ) {\n return this.loadRelated(fieldName, opts);\n }\n\n return this.loadRelatedMany(fieldName, opts);\n }\n\n /**\n * Get available AI-callable tools for this object\n *\n * Returns the pre-generated tool definitions from the manifest.\n * Tools are generated at build time based on the @smrt decorator's AI config.\n *\n * @returns Array of AITool definitions for LLM function calling\n * @example\n * ```typescript\n * const tools = document.getAvailableTools();\n * console.log(`${tools.length} AI-callable methods available`);\n * ```\n */\n public getAvailableTools(): AITool[] {\n const classInfo = ObjectRegistry.getClass(this.constructor.name);\n return classInfo?.tools || [];\n }\n\n /**\n * Execute a tool call from AI on this object instance\n *\n * Validates the tool call against allowed methods and executes it with\n * proper error handling and timing.\n *\n * @param toolCall - Tool call from AI response\n * @returns Promise resolving to the tool call result\n * @example\n * ```typescript\n * const toolCall = {\n * id: 'call_123',\n * type: 'function',\n * function: {\n * name: 'analyze',\n * arguments: '{\"type\": \"detailed\"}'\n * }\n * };\n *\n * const result = await document.executeToolCall(toolCall);\n * console.log(result.success ? result.result : result.error);\n * ```\n */\n public async executeToolCall(toolCall: ToolCall): Promise<ToolCallResult> {\n const tools = this.getAvailableTools();\n const allowedMethods = tools.map((tool) => tool.function.name);\n\n return executeToolCallInternal(this, toolCall, allowedMethods);\n }\n\n /**\n * Stores a named value in the `_smrt_contexts` system table, scoped to this object.\n *\n * Context entries are keyed by `(owner_class, owner_id, scope, key, version)` and\n * support an optional `confidence` score (0–1, default 1.0) for learned patterns.\n * Calling `remember()` with the same scope+key upserts the existing entry.\n *\n * Requires `initialize()` to have been called (needs `this.systemDb`).\n *\n * @param options.id - Optional explicit ID for the context entry (auto-generated if omitted)\n * @param options.scope - Hierarchical path scoping the context (e.g. `'parser/example.com'`)\n * @param options.key - Lookup key within the scope (e.g. a normalized URL)\n * @param options.value - Any JSON-serializable value to store\n * @param options.metadata - Optional additional JSON metadata\n * @param options.confidence - Confidence score (0–1, default 1.0)\n * @param options.version - Schema version for the stored value (default 1)\n * @param options.expiresAt - Optional expiry date after which `recall()` will ignore this entry\n * @returns Promise that resolves when the context is stored\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * await agent.remember({\n * scope: 'parser/example.com',\n * key: normalizedUrl,\n * value: { patterns: ['regex1', 'regex2'] },\n * confidence: 0.9,\n * });\n * ```\n *\n * @see {@link recall} to retrieve a single entry\n * @see {@link recallAll} to retrieve all entries in a scope\n * @see {@link forget} to delete a specific entry\n */\n public async remember(options: {\n id?: string;\n scope: string;\n key: string;\n value: any;\n metadata?: any;\n confidence?: number;\n version?: number;\n expiresAt?: Date;\n }): Promise<void> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n const id = options.id || crypto.randomUUID();\n const now = new Date();\n\n // Ensure the object has an ID - generate one if it doesn't exist\n if (!this.id) {\n this._id = crypto.randomUUID();\n }\n\n await this.systemDb.upsert(\n '_smrt_contexts',\n ['owner_class', 'owner_id', 'scope', 'key', 'version'],\n {\n id,\n owner_class: this._className,\n owner_id: this.id,\n scope: options.scope,\n key: options.key,\n value: JSON.stringify(options.value),\n metadata: options.metadata ? JSON.stringify(options.metadata) : null,\n version: options.version ?? 1,\n confidence: options.confidence ?? 1.0,\n created_at: now,\n updated_at: now,\n last_used_at: now,\n expires_at: options.expiresAt ?? null,\n },\n );\n }\n\n /**\n * Retrieves a single remembered context value for this object.\n *\n * Looks up the most recent (highest confidence, then highest version) entry\n * matching `(owner_class, owner_id, scope, key)`. Returns the JSON-parsed value\n * or `null` if no matching entry exists.\n *\n * When `includeAncestors: true`, walks up the scope hierarchy by progressively\n * removing the last path segment (e.g. `'a/b/c'` → `'a/b'` → `'a'` → `'global'`)\n * until a match is found.\n *\n * @param options.scope - Scope path to search (e.g. `'parser/example.com/article'`)\n * @param options.key - Lookup key within the scope\n * @param options.includeAncestors - If `true`, fall back to parent scopes (default `false`)\n * @param options.minConfidence - Only return entries at or above this confidence (0–1)\n * @returns The stored value (parsed from JSON), or `null` if not found\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * const strategy = await agent.recall({\n * scope: 'parser/example.com/article',\n * key: normalizedUrl,\n * includeAncestors: true,\n * minConfidence: 0.6,\n * });\n * ```\n *\n * @see {@link remember} to store a context entry\n * @see {@link recallAll} to retrieve all entries in a scope\n */\n public async recall(options: {\n scope: string;\n key: string;\n includeAncestors?: boolean;\n minConfidence?: number;\n }): Promise<any | null> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n // Use single() with template literals for custom SQL query\n let result: Record<string, any> | null;\n if (options.minConfidence !== undefined) {\n result = await this.systemDb.single`\n SELECT value, confidence\n FROM _smrt_contexts\n WHERE owner_class = ${this._className}\n AND owner_id = ${this.id}\n AND scope = ${options.scope}\n AND key = ${options.key}\n AND confidence >= ${options.minConfidence}\n ORDER BY confidence DESC, version DESC\n LIMIT 1\n `;\n } else {\n result = await this.systemDb.single`\n SELECT value, confidence\n FROM _smrt_contexts\n WHERE owner_class = ${this._className}\n AND owner_id = ${this.id}\n AND scope = ${options.scope}\n AND key = ${options.key}\n ORDER BY confidence DESC, version DESC\n LIMIT 1\n `;\n }\n\n if (result) {\n // Guard against a corrupted _smrt_contexts row: a single malformed value\n // must not throw an uncaught SyntaxError out of recall(). Treat it as a\n // miss and continue to the ancestor fallback (#1378).\n try {\n return JSON.parse(result.value);\n } catch (error) {\n logger.warn('Skipping corrupted _smrt_contexts value in recall()', {\n ownerClass: this._className,\n ownerId: this.id,\n scope: options.scope,\n key: options.key,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Hierarchical fallback to parent scopes\n if (options.includeAncestors) {\n const scopeParts = options.scope.split('/');\n while (scopeParts.length > 0) {\n scopeParts.pop();\n const parentScope = scopeParts.join('/') || 'global';\n\n const parentResult = await this.recall({\n ...options,\n scope: parentScope,\n includeAncestors: false,\n });\n\n if (parentResult) return parentResult;\n }\n }\n\n return null;\n }\n\n /**\n * Retrieves all remembered context entries for this object in a scope.\n *\n * Returns a `Map<key, value>` for every entry owned by this object that matches\n * the scope and optional filters. When `includeDescendants: true`, a LIKE query\n * (`scope%`) matches the scope itself and all child scopes.\n *\n * @param options.scope - Optional scope path filter; omit to retrieve all scopes\n * @param options.includeDescendants - If `true`, match `scope` and all child scopes (default `false`)\n * @param options.minConfidence - Only include entries at or above this confidence (0–1)\n * @returns `Map<string, any>` of key → JSON-parsed value pairs\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * const strategies = await agent.recallAll({\n * scope: 'parser/example.com',\n * minConfidence: 0.5,\n * });\n * for (const [url, pattern] of strategies) {\n * console.log(`Cached pattern for ${url}:`, pattern);\n * }\n * ```\n *\n * @see {@link recall} to retrieve a single entry by key\n * @see {@link forgetScope} to delete all entries in a scope\n */\n public async recallAll(\n options: {\n scope?: string;\n includeDescendants?: boolean;\n minConfidence?: number;\n } = {},\n ): Promise<Map<string, any>> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n const results = new Map<string, any>();\n\n // Build where clause for db.list()\n const where: Record<string, any> = {\n owner_class: this._className,\n owner_id: this.id,\n };\n\n if (options.scope) {\n if (options.includeDescendants) {\n // Use LIKE pattern to match scope and all descendants\n // Pattern 'scope%' matches both 'scope' and 'scope/child'\n where['scope like'] = `${options.scope}%`;\n } else {\n where.scope = options.scope;\n }\n }\n\n if (options.minConfidence !== undefined) {\n where['confidence >='] = options.minConfidence;\n }\n\n const rows = await this.systemDb.list('_smrt_contexts', where);\n\n for (const row of rows) {\n // Skip a corrupted row rather than aborting the whole recallAll() (#1378).\n try {\n results.set(row.key, JSON.parse(row.value));\n } catch (error) {\n logger.warn('Skipping corrupted _smrt_contexts value in recallAll()', {\n ownerClass: this._className,\n ownerId: this.id,\n scope: options.scope,\n key: row.key,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return results;\n }\n\n /**\n * Deletes a specific remembered context entry for this object.\n *\n * Removes the entry matching `(owner_class, owner_id, scope, key)`. A no-op\n * if the entry does not exist.\n *\n * @param options.scope - Scope path of the entry to delete\n * @param options.key - Key of the entry to delete\n * @returns Promise that resolves when the entry is deleted\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * await agent.forget({ scope: 'parser/example.com', key: normalizedUrl });\n * ```\n *\n * @see {@link forgetScope} to delete all entries in a scope at once\n * @see {@link remember} to store a context entry\n */\n public async forget(options: { scope: string; key: string }): Promise<void> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n await this.systemDb.delete('_smrt_contexts', {\n owner_class: this._className,\n owner_id: this.id,\n scope: options.scope,\n key: options.key,\n });\n }\n\n /**\n * Deletes all remembered context entries in a scope for this object.\n *\n * When `includeDescendants: true`, uses a LIKE query (`scope%`) that matches\n * the scope itself and all child scopes (e.g. `'parser/example.com'` also\n * deletes `'parser/example.com/article'`).\n *\n * @param options.scope - Scope path to clear\n * @param options.includeDescendants - If `true`, also delete all child scopes (default `false`)\n * @returns Number of context entries deleted\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * const count = await agent.forgetScope({\n * scope: 'parser/example.com',\n * includeDescendants: true,\n * });\n * console.log(`Cleared ${count} cached strategies`);\n * ```\n *\n * @see {@link forget} to delete a single entry by key\n * @see {@link recallAll} to bulk-retrieve before clearing\n */\n public async forgetScope(options: {\n scope: string;\n includeDescendants?: boolean;\n }): Promise<number> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n // Build where clause for db.delete()\n const where: Record<string, any> = {\n owner_class: this._className,\n owner_id: this.id,\n };\n\n if (options.includeDescendants) {\n // Use LIKE pattern to match scope and all descendants\n where['scope like'] = `${options.scope}%`;\n } else {\n where.scope = options.scope;\n }\n\n const result = await this.systemDb.delete('_smrt_contexts', where);\n return result.affected || 0;\n }\n\n // ============================================================================\n // Embedding Methods for Semantic Search\n // ============================================================================\n\n /**\n * Generate embeddings for configured fields\n *\n * Creates embedding vectors for fields configured in the @smrt decorator\n * and stores them in the _smrt_embeddings system table. Uses content hashing\n * to detect changes and avoid regenerating unchanged content.\n *\n * @param options - Generation options\n * @returns Promise that resolves when embeddings are generated\n * @throws Error if no embedding configuration or database not initialized\n *\n * @example\n * ```typescript\n * // Generate embeddings for all configured fields\n * await article.generateEmbeddings();\n *\n * // Generate only for specific fields\n * await article.generateEmbeddings({ fields: ['title'] });\n *\n * // Force regeneration (ignore content hash)\n * await article.generateEmbeddings({ force: true });\n * ```\n */\n public async generateEmbeddings(\n options: GenerateEmbeddingsOptions = {},\n ): Promise<void> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n if (!this.id) {\n throw new Error('Object must have an ID before generating embeddings.');\n }\n\n // Get embedding configuration for this class\n const config = ObjectRegistry.resolveEmbeddingConfig(this.constructor.name);\n if (!config) {\n throw new Error(\n `No embedding configuration found for ${this.constructor.name}. ` +\n `Add embeddings config to the @smrt() decorator.`,\n );\n }\n\n // Determine which fields to process\n const fieldsToProcess = options.fields || config.fields;\n const provider = options.provider || config.provider;\n const aiClient = await this.getOptionalAiClient();\n\n // Create embedding provider\n const embeddingProvider = new EmbeddingProvider(\n {\n dimensions: config.dimensions,\n provider,\n localModel: config.localModel,\n aiModel: config.aiModel,\n fallbackToAI: config.fallbackToAI,\n },\n aiClient,\n );\n\n // Resolve vector capabilities for native storage\n const projectConfig = ObjectRegistry.getProjectEmbeddingConfig();\n const vector =\n projectConfig?.storage === 'native' ? this.systemDb.vector : undefined;\n\n // Process each field\n for (const fieldName of fieldsToProcess) {\n const content = this.getPropertyValue(fieldName);\n if (!content || typeof content !== 'string') {\n continue; // Skip empty or non-string fields\n }\n\n // Check content hash to avoid regenerating unchanged content\n const contentHash = ContentHasher.hash(content);\n\n if (!options.force) {\n const existing = await EmbeddingStorage.get(\n this.systemDb,\n this.constructor.name,\n this.id,\n fieldName,\n embeddingProvider.getModelName(),\n );\n\n if (existing && existing.content_hash === contentHash) {\n continue; // Content unchanged, skip regeneration\n }\n }\n\n // Generate embedding\n const embeddings = await embeddingProvider.embed(content);\n const embedding = embeddings[0];\n\n // Store embedding (with optional native vector storage)\n await EmbeddingStorage.upsert(\n this.systemDb,\n {\n objectClass: this.constructor.name,\n objectId: this.id,\n fieldName,\n contentHash,\n embedding,\n model: embeddingProvider.getModelName(),\n dimensions: config.dimensions,\n provider,\n },\n vector,\n );\n }\n\n // Handle combined field if configured\n if (config.combinedField) {\n const { name, template } = config.combinedField;\n\n // Build combined content from template\n let combinedContent = template;\n for (const fieldName of config.fields) {\n const value = this.getPropertyValue(fieldName) || '';\n combinedContent = combinedContent.replace(\n new RegExp(`\\\\{${fieldName}\\\\}`, 'g'),\n String(value),\n );\n }\n\n if (combinedContent.trim()) {\n const contentHash = ContentHasher.hash(combinedContent);\n\n if (!options.force) {\n const existing = await EmbeddingStorage.get(\n this.systemDb,\n this.constructor.name,\n this.id,\n name,\n embeddingProvider.getModelName(),\n );\n\n if (existing && existing.content_hash === contentHash) {\n return; // Combined content unchanged\n }\n }\n\n const embeddings = await embeddingProvider.embed(combinedContent);\n const embedding = embeddings[0];\n\n await EmbeddingStorage.upsert(\n this.systemDb,\n {\n objectClass: this.constructor.name,\n objectId: this.id,\n fieldName: name,\n contentHash,\n embedding,\n model: embeddingProvider.getModelName(),\n dimensions: config.dimensions,\n provider,\n },\n vector,\n );\n }\n }\n }\n\n /**\n * Get stored embedding for a field\n *\n * Retrieves the embedding vector for a specific field from storage.\n * Returns null if no embedding exists for the field.\n *\n * @param fieldName - Name of the field to get embedding for\n * @param model - Optional model name (defaults to configured model)\n * @returns Promise resolving to embedding vector or null\n *\n * @example\n * ```typescript\n * const embedding = await article.getEmbedding('title');\n * if (embedding) {\n * console.log(`Embedding has ${embedding.length} dimensions`);\n * }\n * ```\n */\n public async getEmbedding(\n fieldName: string,\n model?: string,\n ): Promise<number[] | null> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n if (!this.id) {\n return null;\n }\n\n // Determine model name using EmbeddingProvider for consistency with generateEmbeddings()\n let modelName = model;\n if (!modelName) {\n const config = ObjectRegistry.resolveEmbeddingConfig(\n this.constructor.name,\n );\n if (config) {\n const aiClient = await this.getOptionalAiClient();\n // Create EmbeddingProvider to get consistent model name\n const provider = new EmbeddingProvider(\n {\n dimensions: config.dimensions,\n provider: config.provider,\n localModel: config.localModel,\n aiModel: config.aiModel,\n fallbackToAI: config.fallbackToAI,\n },\n aiClient,\n );\n modelName = provider.getModelName();\n } else {\n // Fallback to default\n modelName = 'Xenova/bge-base-en-v1.5';\n }\n }\n\n const stored = await EmbeddingStorage.get(\n this.systemDb,\n this.constructor.name,\n this.id,\n fieldName,\n modelName,\n );\n\n return stored?.embedding || null;\n }\n\n /**\n * Check if any embeddings are stale (content has changed)\n *\n * Compares content hashes of configured fields with stored embeddings\n * to determine if regeneration is needed.\n *\n * @returns Promise resolving to true if any embeddings are stale\n *\n * @example\n * ```typescript\n * if (await article.hasStaleEmbeddings()) {\n * await article.generateEmbeddings();\n * }\n * ```\n */\n public async hasStaleEmbeddings(): Promise<boolean> {\n if (!this.systemDb || !this.id) {\n return false;\n }\n\n const config = ObjectRegistry.resolveEmbeddingConfig(this.constructor.name);\n if (!config) {\n return false;\n }\n\n const aiClient = await this.getOptionalAiClient();\n const embeddingProvider = new EmbeddingProvider(\n {\n dimensions: config.dimensions,\n provider: config.provider,\n localModel: config.localModel,\n aiModel: config.aiModel,\n fallbackToAI: config.fallbackToAI,\n },\n aiClient,\n );\n const modelName = embeddingProvider.getModelName();\n\n // Get stored embeddings for this object\n const storedEmbeddings = await EmbeddingStorage.getForObject(\n this.systemDb,\n this.constructor.name,\n this.id,\n );\n\n // Check each configured field\n for (const fieldName of config.fields) {\n const content = this.getPropertyValue(fieldName);\n if (!content || typeof content !== 'string') {\n continue;\n }\n\n const currentHash = ContentHasher.hash(content);\n const stored = storedEmbeddings.find(\n (e) => e.field_name === fieldName && e.model === modelName,\n );\n\n if (!stored) {\n return true; // No embedding exists for the current provider/model\n }\n\n if (stored.content_hash !== currentHash) {\n return true; // Content has changed\n }\n }\n\n // Check combined field if configured\n if (config.combinedField) {\n let combinedContent = config.combinedField.template;\n for (const fieldName of config.fields) {\n const value = this.getPropertyValue(fieldName) || '';\n combinedContent = combinedContent.replace(\n new RegExp(`\\\\{${fieldName}\\\\}`, 'g'),\n String(value),\n );\n }\n\n const currentHash = ContentHasher.hash(combinedContent);\n const stored = storedEmbeddings.find(\n (e) =>\n e.field_name === config.combinedField?.name && e.model === modelName,\n );\n\n if (!stored || stored.content_hash !== currentHash) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Clear all embeddings for this object\n *\n * Removes all stored embeddings from the _smrt_embeddings table.\n * Useful when deleting objects or resetting embedding state.\n *\n * @returns Promise that resolves when embeddings are cleared\n *\n * @example\n * ```typescript\n * await article.clearEmbeddings();\n * ```\n */\n public async clearEmbeddings(): Promise<void> {\n if (!this.systemDb || !this.id) {\n return;\n }\n\n await EmbeddingStorage.deleteForObject(\n this.systemDb,\n this.constructor.name,\n this.id,\n );\n }\n}\n"],"names":["executeToolCallInternal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"object.js","sources":["../src/object.ts"],"sourcesContent":["// import type { AIMessageOptions } from '@happyvertical/ai';\n\nimport type { AITool } from '@happyvertical/ai';\nimport { createLogger } from '@happyvertical/logger';\nimport type { SmrtClassOptions } from './class';\nimport { SmrtClass } from './class';\nimport {\n broadcastCacheInvalidation,\n hasCrossProcessCacheInterest,\n invalidateCollectionCache,\n resolveDbCacheKey,\n} from './collection-cache';\nimport { ContentHasher } from './embeddings/hash';\nimport { EmbeddingProvider } from './embeddings/provider';\nimport { EmbeddingStorage } from './embeddings/storage';\nimport type { GenerateEmbeddingsOptions } from './embeddings/types';\nimport {\n DatabaseError,\n ErrorUtils,\n RuntimeError,\n SmrtError,\n TenantIsolationError,\n ValidationError,\n} from './errors';\nimport { createInterceptorContext, GlobalInterceptors } from './interceptors';\nimport { ObjectRegistry } from './registry';\nimport { verifyPersistenceTable } from './schema/table-verifier';\nimport {\n executeToolCall as executeToolCallInternal,\n type ToolCall,\n type ToolCallResult,\n} from './tools/tool-executor';\nimport { fieldsFromClass, tableNameFromClass, toSnakeCase } from './utils';\n\n// DEBUG_STI raises the level to 'debug' so the env-gated STI hydration traces\n// below (logger.debug, inside `if (process.env.DEBUG_STI)` guards) actually emit;\n// otherwise they're filtered at the default 'info' level.\nconst logger = createLogger({\n level: process.env.DEBUG_STI ? 'debug' : 'info',\n});\n\n/**\n * Default maximum number of characters of serialized object data injected into\n * the AI prompts built by `is()`, `do()`, and `describe()`.\n *\n * Acts as a coarse token-budget guard so a very large instance (e.g. a long\n * document body) cannot blow past model context limits or inflate request\n * costs. At roughly four characters per token this is ~25k tokens of object\n * data — generous enough for typical records, while still capping pathological\n * cases. Override per call with the `maxDataLength` option.\n */\nconst AI_PROMPT_DATA_MAX_LENGTH = 100_000;\n\n/**\n * Validate that _meta_type matches the expected class (Issue #713)\n *\n * Accepts both simple class name (e.g., 'Product') and qualified name\n * (e.g., '@happyvertical/smrt-core:Product') for namespace isolation support.\n *\n * @param actualMetaType - The _meta_type value from the data\n * @param className - The class name to validate against\n * @returns true if the meta type is valid for this class\n */\nfunction isValidMetaType(actualMetaType: unknown, className: string): boolean {\n if (typeof actualMetaType !== 'string') {\n return false;\n }\n\n // Accept simple class name match\n if (actualMetaType === className) {\n return true;\n }\n\n // Accept qualified name match (namespace isolation)\n const registeredClass = ObjectRegistry.getClass(className);\n if (\n registeredClass?.qualifiedName &&\n actualMetaType === registeredClass.qualifiedName\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Get the expected qualified or simple name for a class (for error messages)\n */\nfunction getExpectedMetaType(className: string): string {\n const registeredClass = ObjectRegistry.getClass(className);\n return registeredClass?.qualifiedName || className;\n}\n\n/**\n * Get all STI hierarchy members (base + descendants) for a class.\n *\n * R5-canon (Copilot follow-up): callers should pass a QUALIFIED name\n * (e.g. via `this.getResolvedQualifiedName()`). Passing a bare simple\n * name still works in single-package scenarios, but when two packages\n * register classes sharing the same simple name, `ObjectRegistry.\n * getClass(simpleName)` resolves to whichever match the multi-strategy\n * lookup picks first — which can be the wrong package. Passing the\n * qualified form makes STI sibling discovery collision-safe.\n */\nfunction getSTIHierarchyMembers(qualifiedOrSimpleName: string): string[] {\n // Best-effort qualify in case a caller passed a simple name; the\n // collision risk for that case is documented in the docstring above.\n const registered = ObjectRegistry.getClass(qualifiedOrSimpleName);\n const lookupKey =\n registered?.qualifiedName ?? registered?.name ?? qualifiedOrSimpleName;\n const stiBase = ObjectRegistry.getSTIBase(lookupKey);\n if (!stiBase) {\n return [];\n }\n\n return Array.from(\n new Set([stiBase, ...ObjectRegistry.getDescendants(stiBase)]),\n );\n}\n\ntype PersistenceWritePlan =\n | { type: 'upsert'; conflictColumns: string[] }\n | { type: 'updateById'; qualifiedMetaType: string };\n\n/**\n * Warn once per process if a consumer has SMRT_SKIP_STI_REHYDRATE set.\n * The env variable is a no-op since Release C (#1134); without this\n * diagnostic anyone who followed the Release A changeset note would\n * silently lose the behavior they opted into.\n */\nlet didWarnSkipRehydrate = false;\nfunction warnIfSkipRehydrateSet(): void {\n if (didWarnSkipRehydrate) return;\n didWarnSkipRehydrate = true;\n if (process.env.SMRT_SKIP_STI_REHYDRATE !== undefined) {\n logger.warn(\n '[smrt] SMRT_SKIP_STI_REHYDRATE is set but has no effect since ' +\n 'Release C (#1134). The flag is retired; unconditional STI ' +\n 'descendant rehydration is the only behavior. Remove the env ' +\n 'variable from your configuration. See issue #1139 for the perf ' +\n 'follow-up.',\n );\n }\n}\n\n/**\n * Options for SmrtObject initialization\n */\nexport interface SmrtObjectOptions extends SmrtClassOptions {\n /**\n * Unique identifier for the object\n */\n id?: string;\n\n /**\n * URL-friendly identifier\n */\n slug?: string;\n\n /**\n * Optional context to scope the slug (could be a path, domain, etc.)\n */\n context?: string;\n\n /**\n * Creation timestamp\n */\n created_at?: Date;\n\n /**\n * Last update timestamp\n */\n updated_at?: Date;\n\n /**\n * Flag to skip automatic field extraction (internal use)\n */\n _extractingFields?: boolean;\n\n /**\n * Flag to skip database loading (internal use)\n */\n _skipLoad?: boolean;\n\n /**\n * Flag to skip save-time embedding auto-generation (internal use).\n *\n * This is used when framework code will generate embeddings explicitly after\n * saving and wants to avoid racing a duplicate background generation.\n */\n _skipAutoEmbeddings?: boolean;\n\n /**\n * Allow arbitrary field values to be passed\n */\n [key: string]: any;\n}\n\n/**\n * Options for the relationship loaders {@link SmrtObject.loadRelated},\n * {@link SmrtObject.loadRelatedMany}, and {@link SmrtObject.getRelated}.\n */\nexport interface LoadRelatedOptions {\n /**\n * Bypass the cross-tenant isolation guard.\n *\n * By default, resolving a relationship from a tenant-scoped object to an\n * object in a *different*, non-null tenant throws a `TenantIsolationError`.\n * Set this to `true` for deliberate cross-tenant flows (admin tooling,\n * migrations, super-admin bypass paths) where the access is intentional.\n *\n * @default false\n */\n allowCrossTenant?: boolean;\n}\n\n/**\n * Base class for all persistent SMRT domain objects.\n *\n * Provides a full ORM lifecycle: construct with options, call `initialize()`,\n * then use `save()` / `delete()` for persistence. Objects are identified by a\n * UUID `id` and an optional URL-friendly `slug` (auto-generated from `name`,\n * `title`, `label`, or `id` if not provided).\n *\n * Key capabilities:\n * - **Persistence**: `save()` (upsert with retry), `delete()` (with hooks)\n * - **Loading**: `loadFromId()`, `loadFromSlug()` (called automatically by `initialize()`)\n * - **AI operations**: `is()` (boolean criteria check), `do()` (freeform instruction)\n * - **Relationships**: `loadRelated()` (foreignKey), `loadRelatedMany()` (oneToMany)\n * - **Context memory**: `remember()` / `recall()` / `recallAll()` / `forget()` / `forgetScope()`\n * - **STI support**: `_meta_type` discriminator, `_meta_data` JSONB for child fields\n * - **Serialization**: `toJSON()` (framework-managed, handles STI), `transformJSON()` (override hook)\n *\n * @example\n * ```typescript\n * @smrt()\n * class Product extends SmrtObject {\n * name: string = '';\n * price: number = 0.0;\n * }\n *\n * const product = new Product({ db: myDb, name: 'Widget', price: 9.99 });\n * await product.initialize();\n * await product.save();\n * console.log(product.id); // auto-generated UUID\n * ```\n */\nexport class SmrtObject extends SmrtClass {\n /**\n * Database table name for this object\n */\n public _tableName!: string;\n\n /**\n * Cache for loaded relationships to avoid repeated database queries\n * Maps fieldName to loaded object(s)\n */\n private _loadedRelationships: Map<string, any> = new Map();\n\n /**\n * Whether this object is backed by an existing database row.\n *\n * Set when the object is hydrated from the database (collection\n * get/list/query, `loadFromId()`, `loadFromSlug()`) and after a successful\n * `save()`. `save()` uses it to target the primary key on upsert instead\n * of the natural-key conflict columns, so natural-key edits (e.g. renaming\n * a slug) update the existing row rather than colliding on `*_pkey`\n * (issue #1472).\n */\n private _persisted = false;\n\n /**\n * Override options with SmrtObjectOptions type for proper type narrowing.\n * Initialized by parent constructor via super() call.\n */\n public declare options: SmrtObjectOptions;\n\n /**\n * Unique identifier for the object\n */\n protected _id: string | null | undefined;\n\n /**\n * URL-friendly identifier\n */\n protected _slug: string | null | undefined;\n\n /**\n * Optional context to scope the slug\n */\n protected _context: string | null | undefined;\n\n /**\n * Creation timestamp\n */\n public created_at: Date | null | undefined = null;\n\n /**\n * Last update timestamp\n */\n public updated_at: Date | null | undefined = null;\n\n /**\n * Creates a new SmrtObject instance\n *\n * @param options - Configuration options including identifiers and metadata\n * @throws Error if options is null\n */\n constructor(options: SmrtObjectOptions = {}) {\n super(options);\n // Explicitly set child's options property after parent initialization\n // This is required because the override declaration creates a new property slot\n this.options = options;\n if (options === null) {\n throw new Error('options cant be null');\n }\n this._id = options.id || null;\n this._slug = options.slug || null;\n this._context = options.context || '';\n\n // Auto-register the class if it's not already registered\n // and it's not the base SmrtObject class itself\n // Skip registration during field extraction to avoid infinite recursion\n if (\n this.constructor !== SmrtObject &&\n !ObjectRegistry.getClassByConstructor(\n this.constructor as typeof SmrtObject,\n ) &&\n !(options as any)?._skipRegistration\n ) {\n ObjectRegistry.register(this.constructor as typeof SmrtObject, {});\n }\n }\n\n private getRegisteredClassInfo() {\n return ObjectRegistry.getClassByConstructor(\n this.constructor as typeof SmrtObject,\n );\n }\n\n protected getResolvedClassName(): string {\n return this.getRegisteredClassInfo()?.name || this.constructor.name;\n }\n\n protected getResolvedQualifiedName(): string {\n const registered = this.getRegisteredClassInfo();\n return (\n registered?.qualifiedName || registered?.name || this.constructor.name\n );\n }\n\n private getCurrentMetaType(): string | undefined {\n const metaType = (this as any)._meta_type;\n return typeof metaType === 'string' ? metaType : undefined;\n }\n\n private isLegacySTIDiscriminatorUpgrade(\n currentMetaType: string | undefined,\n nextMetaType: unknown,\n className: string,\n ): currentMetaType is string {\n return (\n typeof nextMetaType === 'string' &&\n typeof currentMetaType === 'string' &&\n currentMetaType !== nextMetaType &&\n !currentMetaType.includes(':') &&\n isValidMetaType(currentMetaType, className) &&\n isValidMetaType(nextMetaType, className)\n );\n }\n\n private async planPersistenceWrite(\n className: string,\n tableStrategy: string,\n data: Record<string, any>,\n conflictColumns: string[],\n ): Promise<PersistenceWritePlan> {\n const upsertPlan: PersistenceWritePlan = {\n type: 'upsert',\n conflictColumns,\n };\n\n if (tableStrategy !== 'sti' || !data.id) {\n return upsertPlan;\n }\n\n const currentMetaType = this.getCurrentMetaType();\n const nextMetaType = data._meta_type;\n if (\n !this.isLegacySTIDiscriminatorUpgrade(\n currentMetaType,\n nextMetaType,\n className,\n )\n ) {\n return upsertPlan;\n }\n const qualifiedMetaType = String(nextMetaType);\n const conflictIdentity: Record<string, any> = {};\n for (const column of conflictColumns.filter(\n (conflictColumn) => conflictColumn !== '_meta_type',\n )) {\n if (!Object.hasOwn(data, column)) {\n return upsertPlan;\n }\n conflictIdentity[column] = data[column];\n }\n\n const id = String(data.id);\n const existingById = await ErrorUtils.withRetry(\n async () => {\n try {\n return await this.db.get(this.tableName, { id });\n } catch (error) {\n throw DatabaseError.queryFailed(\n `get(${this.tableName}, legacy STI id)`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n },\n 3,\n 500,\n );\n\n if (!existingById || existingById._meta_type !== currentMetaType) {\n return upsertPlan;\n }\n\n const slug = String(data.slug ?? '');\n const context = String(data.context ?? '');\n const existingQualified = await ErrorUtils.withRetry(\n async () => {\n try {\n return await this.db.get(this.tableName, {\n ...conflictIdentity,\n _meta_type: qualifiedMetaType,\n });\n } catch (error) {\n throw DatabaseError.queryFailed(\n `get(${this.tableName}, qualified STI conflict identity)`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n },\n 3,\n 500,\n );\n\n if (existingQualified && existingQualified.id !== id) {\n throw DatabaseError.stiDiscriminatorConflict({\n className,\n tableName: this.tableName,\n id,\n slug,\n context,\n conflictIdentity,\n legacyMetaType: currentMetaType,\n qualifiedMetaType,\n duplicateId: String(existingQualified.id),\n });\n }\n\n // This mirrors save()'s current last-writer-wins behavior: the probe and\n // update are not transactional, so concurrent saves may both choose this.\n return { type: 'updateById', qualifiedMetaType };\n }\n\n /**\n * Protected setter for ID to maintain type safety\n * Used internally by collection.create() and other framework code\n * @internal\n */\n protected setId(id: string): void {\n this._id = id;\n }\n\n /**\n * Whether this object is backed by an existing database row.\n *\n * True after hydration from the database (collection get/list/query,\n * `loadFromId()`, `loadFromSlug()`) or after a successful `save()`.\n */\n public get isPersisted(): boolean {\n return this._persisted;\n }\n\n /**\n * Marks this object as backed by an existing database row, so `save()`\n * targets the primary key instead of the natural-key conflict columns.\n * Called by framework hydration paths (issue #1472).\n * @internal\n */\n public markAsPersisted(): void {\n this._persisted = true;\n }\n\n protected async verifyStorageReady(): Promise<void> {\n await verifyPersistenceTable(\n this.db,\n this.tableName,\n this.constructor.name,\n );\n }\n\n /**\n * Protected setter for STI discriminator to maintain type safety\n * Used internally for Single Table Inheritance support\n * @internal\n */\n protected setMetaType(metaType: string): void {\n (this as any)._meta_type = metaType;\n }\n\n /**\n * Smart clone helper to avoid array/object aliasing (Issue #22)\n *\n * Clones values to prevent shared references between options and instance properties:\n * - Primitives (string, number, boolean, null, undefined): No clone needed\n * - Dates: No clone needed (immutable)\n * - Field instances: No clone needed (framework objects)\n * - Arrays: Shallow clone\n * - Plain objects: Shallow clone\n * - Other objects: Pass through (class instances, etc.)\n *\n * @param value - Value to clone\n * @returns Cloned value or original if no cloning needed\n * @private\n */\n private cloneValue(value: any): any {\n // Primitives and null/undefined - no clone needed\n if (value === null || value === undefined) return value;\n if (typeof value !== 'object') return value;\n\n // Dates - immutable, no clone needed\n if (value instanceof Date) return value;\n\n // Arrays - shallow clone to avoid aliasing\n if (Array.isArray(value)) return [...value];\n\n // Plain objects - shallow clone to avoid aliasing\n // Check if it's a plain object (created via {} or Object.create(null))\n const proto = Object.getPrototypeOf(value);\n if (proto === null || proto === Object.prototype) {\n return { ...value };\n }\n\n // Other objects (class instances, etc.) - pass through\n return value;\n }\n\n /**\n * Initialize properties from options after field initializers have run\n * This ensures option values take precedence over default field initializer values\n * Uses smart cloning to prevent array/object aliasing (Issue #22)\n */\n private async initializePropertiesFromOptions(): Promise<void> {\n const options = this.options;\n\n // Set base properties that exist on SmrtObject\n if (options.created_at !== undefined) this.created_at = options.created_at;\n if (options.updated_at !== undefined) this.updated_at = options.updated_at;\n\n // Set STI discriminator if present\n if (options._meta_type !== undefined) {\n this.setMetaType(options._meta_type);\n }\n\n // Get all fields (both Field instances and plain properties)\n const fields = await fieldsFromClass(\n this.constructor as new (\n ...args: any[]\n ) => any,\n );\n\n // Apply option values to all fields\n for (const [key, field] of Object.entries(fields)) {\n if (options[key] !== undefined) {\n // Clone value to avoid aliasing (Issue #22)\n const clonedValue = this.cloneValue(options[key]);\n\n // Check if property is writable before setting (Issue #61)\n // Get descriptor from instance or entire prototype chain\n let descriptor = Object.getOwnPropertyDescriptor(this, key);\n if (!descriptor) {\n let proto = Object.getPrototypeOf(this);\n while (proto && !descriptor) {\n descriptor = Object.getOwnPropertyDescriptor(proto, key);\n proto = Object.getPrototypeOf(proto);\n }\n }\n\n // Only set if property has a setter or is writable\n // Skip readonly properties (e.g., tableName getter without setter)\n if (!descriptor || descriptor.set || descriptor.writable === true) {\n // Set the property value\n this[key as keyof this] = clonedValue;\n }\n }\n }\n }\n\n /**\n * Gets the unique identifier for this object\n */\n get id(): string | null | undefined {\n return this._id;\n }\n\n /**\n * Sets the unique identifier for this object\n *\n * @param value - The ID to set\n * @throws Error if the value is invalid\n */\n set id(value: string | null | undefined) {\n if (!value || value === 'undefined' || value === 'null') {\n throw new Error(`id is required, ${value} given`);\n }\n this._id = value;\n }\n\n /**\n * Gets the URL-friendly slug for this object\n */\n get slug(): string | null | undefined {\n return this._slug;\n }\n\n /**\n * Sets the URL-friendly slug for this object\n *\n * @param value - The slug to set\n * @throws Error if the value is invalid\n */\n set slug(value: string | null | undefined) {\n if (!value || value === 'undefined' || value === 'null') {\n throw new Error(`slug is invalid, ${value} given`);\n }\n\n this._slug = value;\n }\n\n /**\n * Gets the context that scopes this object's slug\n */\n get context(): string {\n return this._context || '';\n }\n\n /**\n * Sets the context that scopes this object's slug\n *\n * @param value - The context to set\n * @throws Error if the value is invalid\n */\n set context(value: string | null | undefined) {\n if (value !== '' && !value) {\n throw new Error(`context is invalid, ${value} given`);\n }\n this._context = value;\n }\n\n /**\n * Initializes this object and optionally loads its data from the database.\n *\n * Initialization order:\n * 1. Runs TypeScript field initializers (class property defaults)\n * 2. Applies `options` values on top of defaults (options win)\n * 3. If `options.id` is set, calls `loadFromId()` to hydrate from DB\n * 4. If `options.slug` is set (and no id), calls `loadFromSlug()` instead\n *\n * Runtime schema verification is deferred until the first actual DB\n * operation, which keeps initialization safe for SSR and prerendering\n * without mutating application schema.\n *\n * Called automatically by collection methods. Call manually only when\n * constructing objects outside of a collection.\n *\n * @returns This instance, ready to use (enables chaining)\n *\n * @example\n * ```typescript\n * const product = new Product({ db: myDb, id: 'existing-uuid' });\n * await product.initialize(); // loads product data from DB\n * console.log(product.name);\n * ```\n */\n public async initialize(): Promise<this> {\n await super.initialize();\n\n // Initialize properties from options AFTER all field initializers have run\n // This prevents TypeScript field initializers from overwriting option values\n // This must run for all classes (decorator-based or not) unless explicitly skipped\n if (!this.options._extractingFields) {\n await this.initializePropertiesFromOptions();\n }\n\n // Defer schema verification until an operation actually touches the\n // backing table. That keeps construction lightweight without hiding schema\n // mutation inside normal runtime flows.\n\n if (this._id && !(this.options as any)._skipLoad) {\n await this.loadFromId();\n } else if (this._slug && !(this.options as any)._skipLoad) {\n await this.loadFromSlug();\n }\n\n return this;\n }\n\n /**\n * Determines if this class needs automatic property initialization from options\n *\n * Decorator-based classes handle property assignment in their constructor,\n * so they don't need the automatic property initialization logic.\n * This optimization avoids redundant work and Field instance handling.\n *\n * @returns True if property initialization is needed, false otherwise\n * @private\n */\n private needsPropertyInitialization(): boolean {\n const className = this.getResolvedClassName();\n\n // Check if this class has decorator metadata in the registry\n // If it does, it's using decorators and handles its own initialization\n if (ObjectRegistry.hasClass(className)) {\n const hasDecorators = ObjectRegistry.hasFieldDecorators(className);\n if (hasDecorators) {\n // Class uses decorators - properties are set in constructor\n return false;\n }\n }\n\n // Default: assume it needs property initialization (field helpers pattern)\n return true;\n }\n\n /**\n * Loads data from a database row into this object's properties\n *\n * STI Support: If using Single Table Inheritance (tableStrategy: 'sti'):\n * - Merges _meta_data JSONB fields into the main data object\n * - Validates _meta_type discriminator matches class name\n *\n * @param data - Database row data (with snake_case column names)\n * @throws Error if STI validation fails\n */\n async loadDataFromDb(data: any) {\n const className = this.getResolvedClassName();\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] Loading', {\n class: className,\n dataKeys: Object.keys(data),\n metaType: data._meta_type,\n });\n }\n\n // Get field definitions to pass to formatDataJs\n const fields = await this.getFields();\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] Field definitions', {\n class: className,\n fieldKeys: Object.keys(fields),\n });\n }\n\n // Format data: Convert snake_case column names to camelCase property names\n // and convert date strings to Date objects (Issue #339)\n const { formatDataJs } = await import('./utils.js');\n const formattedData = formatDataJs(data, fields);\n\n // Check if this class uses STI (Single Table Inheritance).\n // R5-canon: pass the qualified name so a colliding simple name in\n // another package can't yield the wrong tableStrategy here.\n const tableStrategy = ObjectRegistry.getTableStrategy(\n this.getResolvedQualifiedName(),\n );\n const isSTI = tableStrategy === 'sti';\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] After formatDataJs', {\n class: className,\n isSTI,\n formattedDataKeys: Object.keys(formattedData),\n });\n }\n\n // STI: Fail-fast validation for _meta_type discriminator\n if (isSTI) {\n // Validation 1: _meta_type must be present in database row\n if (!formattedData._meta_type) {\n throw new Error(\n `STI validation failed: Missing _meta_type discriminator in database row for ${className}. ` +\n `Ensure the row was saved with STI support enabled.`,\n );\n }\n\n // Validation 2: _meta_type must match the class being instantiated\n // Accept both simple class name and qualified name (namespace isolation - Issue #713)\n if (!isValidMetaType(formattedData._meta_type, className)) {\n throw new Error(\n `STI validation failed: Type mismatch when loading ${className}. ` +\n `Database row has _meta_type='${formattedData._meta_type}' but expected '${getExpectedMetaType(className)}'. ` +\n `This usually means you're trying to load a row with the wrong class.`,\n );\n }\n\n // Set _meta_type on the object\n this.setMetaType(formattedData._meta_type);\n }\n\n // STI: Meta fields are already merged by formatDataJs\n // No additional processing needed\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] Starting field hydration', {\n class: className,\n fieldCount: Object.keys(fields).length,\n });\n }\n\n let hydratedCount = 0;\n let skippedCount = 0;\n\n for (const field in fields) {\n if (Object.hasOwn(fields, field)) {\n // Check if property is writable before setting (Issue #63)\n // Get descriptor from instance or entire prototype chain\n let descriptor = Object.getOwnPropertyDescriptor(this, field);\n if (!descriptor) {\n let proto = Object.getPrototypeOf(this);\n while (proto && !descriptor) {\n descriptor = Object.getOwnPropertyDescriptor(proto, field);\n proto = Object.getPrototypeOf(proto);\n }\n }\n\n // Only set if property has a setter or is writable\n // Skip readonly properties (e.g., tableName getter without setter)\n if (!descriptor || descriptor.set || descriptor.writable === true) {\n // Use formatted data (camelCase) instead of raw data (snake_case)\n // formatDataJs() already handles type conversions (dates, booleans, etc.)\n const value = formattedData[field];\n\n if (process.env.DEBUG_STI && value !== undefined) {\n logger.debug(`[loadDataFromDb] Setting field '${field}'`, {\n value,\n valueType: typeof value,\n });\n }\n\n this[field as keyof this] = value;\n hydratedCount++;\n } else {\n skippedCount++;\n if (process.env.DEBUG_STI) {\n logger.debug(`[loadDataFromDb] Skipping readonly field '${field}'`);\n }\n }\n }\n }\n\n if (process.env.DEBUG_STI) {\n logger.debug('[loadDataFromDb] Hydration complete', {\n class: className,\n hydratedCount,\n skippedCount,\n totalFields: Object.keys(fields).length,\n });\n }\n\n // The data came from an existing row, so subsequent saves must update\n // that row by primary key even if natural-key fields change (issue #1472).\n this._persisted = true;\n }\n\n /**\n * Gets the database table name for this object\n */\n get tableName() {\n if (!this._tableName) {\n // For STI, use the base class's table name from schema (manifest-derived).\n // R5-canon: use the qualified name as the lookup key so a colliding\n // simple name in another package can't yield the wrong tableStrategy\n // / STI base and route every query through the wrong table.\n const className = this.getResolvedClassName();\n const qualifiedName = this.getResolvedQualifiedName();\n const tableStrategy = ObjectRegistry.getTableStrategy(qualifiedName);\n\n if (tableStrategy === 'sti') {\n const stiBase = ObjectRegistry.getSTIBase(qualifiedName);\n if (stiBase) {\n // Use base class's schema tableName (from manifest)\n const baseSchema = ObjectRegistry.getSchema(stiBase);\n if (baseSchema?.tableName) {\n this._tableName = baseSchema.tableName;\n } else {\n // Fallback to own schema tableName\n const ownSchema = ObjectRegistry.getSchema(className);\n this._tableName =\n ownSchema?.tableName || tableNameFromClass(this.constructor);\n }\n } else {\n // Fallback to own schema tableName\n const ownSchema = ObjectRegistry.getSchema(className);\n this._tableName =\n ownSchema?.tableName || tableNameFromClass(this.constructor);\n }\n } else {\n // CTI: Use own schema tableName\n const ownSchema = ObjectRegistry.getSchema(className);\n this._tableName =\n ownSchema?.tableName || tableNameFromClass(this.constructor);\n }\n }\n return this._tableName;\n }\n\n /**\n * Gets field definitions and current values for this object\n *\n * @returns Object containing field definitions with current values\n */\n async getFields() {\n const className = this.getResolvedClassName();\n const cachedFields = await ObjectRegistry.getAllFields(className);\n const fields: Record<string, any> = {};\n\n for (const [key, field] of cachedFields.entries()) {\n const meta = { ...(field._meta || {}) };\n delete meta.__smrtSystemField;\n\n fields[key] = {\n name: key,\n type: field.type || 'TEXT',\n _meta: meta,\n };\n }\n\n // Add current instance values to the fields\n // Use getPropertyValue to unwrap Field instances\n for (const key in fields) {\n fields[key].value = this.getPropertyValue(key);\n }\n\n return fields;\n }\n\n /**\n * Override hook for customizing JSON serialization output.\n *\n * This is the **only safe way** to customize serialization. Do **not** override\n * `toJSON()` directly — it manages STI discriminator assignment (`_meta_type`),\n * meta-field extraction into `_meta_data`, and manifest-driven field enumeration.\n * Overriding it will silently break STI persistence.\n *\n * The `data` argument already contains all persisted fields. Return a new object\n * (spread `data` and add/modify/remove keys) to change what is serialized.\n * Non-persisted computed properties added here are excluded from `save()` because\n * the DB write path uses `toJSON()` output, not this hook's additions — unless\n * those keys also correspond to real schema columns.\n *\n * @param data - Fully serialized object produced by the framework's `toJSON()` logic\n * @returns Transformed data to use as the final serialization result\n *\n * @example\n * ```typescript\n * class Article extends SmrtObject {\n * body: string = '';\n *\n * protected transformJSON(data: any): any {\n * return {\n * ...data,\n * wordCount: this.body.split(/\\s+/).length,\n * preview: this.body.substring(0, 100),\n * };\n * }\n * }\n * ```\n *\n * @see {@link toJSON} for the framework implementation (do not override)\n */\n protected transformJSON(data: any): any {\n return data; // Default: no transformation\n }\n\n /**\n * Custom JSON serialization\n * Returns a plain object with all field values for proper JSON.stringify() behavior\n * Field instances automatically call their toJSON() method during serialization\n *\n * Issue #205: Filters out undefined values to prevent database errors\n *\n * Note: This method cannot be async because JSON.stringify() expects synchronous toJSON()\n * It uses direct property access instead of getFields() to avoid async issues\n *\n * STI Support: If using Single Table Inheritance (tableStrategy: 'sti'):\n * - Sets _meta_type discriminator to class name\n * - Extracts meta fields to _meta_data JSONB column\n *\n * **Customization:** Override `transformJSON()` instead of this method.\n * See transformJSON() documentation for safe customization patterns.\n */\n toJSON() {\n const className = this.getResolvedClassName();\n const data: any = {\n id: this.id,\n slug: this.slug,\n context: this.context,\n created_at: this.created_at,\n updated_at: this.updated_at,\n };\n\n // Check if this class uses STI (Single Table Inheritance)\n // R5-canon: qualified-key lookup so a colliding simple name in\n // another package can't yield the wrong STI strategy here.\n const tableStrategy = ObjectRegistry.getTableStrategy(\n this.getResolvedQualifiedName(),\n );\n const isSTI = tableStrategy === 'sti';\n\n // If STI, add discriminator and prepare meta_data container\n if (isSTI) {\n // Use qualified name for STI discriminator (namespace isolation)\n // The qualified name uses the child class's own package, not the parent's\n // This supports multi-package inheritance hierarchies (Issue #713)\n data._meta_type = this.getResolvedQualifiedName();\n data._meta_data = {};\n }\n\n // Get registered field definitions (synchronous access to already-loaded metadata)\n // For inheritance hierarchies, use cached inherited fields if available (populated by getAllFields())\n // This ensures multi-level STI classes serialize all parent fields correctly (Issue #332)\n const registered = ObjectRegistry.getClass(className);\n let registeredFields =\n registered?.inheritedFields || ObjectRegistry.getFields(className);\n\n // In STI mode, we need to know about ALL sibling class fields to provide default values\n // for fields that exist in siblings but not in this class (Issue #391).\n // R5-canon (Copilot follow-up): pass the qualified name so STI\n // sibling discovery is collision-safe across packages.\n if (isSTI) {\n const descendants = getSTIHierarchyMembers(\n this.getResolvedQualifiedName(),\n );\n if (descendants.length > 0) {\n const allSTIFields = new Map(registeredFields);\n\n // Merge fields from all sibling classes\n for (const descendant of descendants) {\n const descendantFields =\n ObjectRegistry.getClass(descendant)?.inheritedFields ||\n ObjectRegistry.getFields(descendant);\n for (const [key, value] of descendantFields) {\n if (!allSTIFields.has(key)) {\n allSTIFields.set(key, value);\n }\n }\n }\n\n registeredFields = allSTIFields;\n }\n }\n\n // Use manifest fields exclusively (manifest-first architecture)\n // All schema fields are in the manifest from AST scanning\n // Dynamic properties added at runtime are intentionally excluded (not part of schema)\n for (const key of registeredFields.keys()) {\n // Skip private properties, methods, and already-handled core fields\n if (\n key.startsWith('_') ||\n key === 'id' ||\n key === 'slug' ||\n key === 'context' ||\n key === 'created_at' ||\n key === 'updated_at' ||\n key === 'options' || // Skip options object (not a database column)\n typeof (this as any)[key] === 'function'\n ) {\n continue;\n }\n\n // Get field definition (used for transient check and type checking)\n const fieldDef = registeredFields.get(key);\n\n // Skip transient fields (non-persisted fields like functions, computed properties)\n // NOTE: This filtering logic must match SchemaGenerator.generateColumns()\n // Changes to field filtering should be applied in BOTH places\n if (fieldDef && (fieldDef.transient || fieldDef._meta?.transient)) {\n continue;\n }\n\n // Skip relationship fields that don't create columns\n // oneToMany and manyToMany are relationship metadata, not actual database columns\n // NOTE: This must match the filtering in SchemaGenerator.generateColumns()\n if (\n fieldDef &&\n (fieldDef.type === 'oneToMany' || fieldDef.type === 'manyToMany')\n ) {\n continue;\n }\n\n const prop = (this as any)[key];\n const value = this.getPropertyValue(key);\n\n // Handle undefined values (Issue #205, #391)\n // In STI, a child class may not have a property defined on a sibling class.\n // This logic ensures undefined properties are serialized correctly based on their type.\n if (value === undefined) {\n // Get field type from either the property instance (field helper) or the manifest\n const fieldType =\n (prop && typeof prop === 'object' && 'type' in prop && prop.type) ||\n fieldDef?.type;\n\n if (fieldType === 'text') {\n // Don't convert tenant ID fields to empty string (Issue #841)\n // Tenant fields should remain null/undefined for interceptor to auto-populate.\n // Check both the property instance and field definition for __tenancy marker.\n // Note: __tenancy can be at fieldDef.__tenancy (from @tenantId decorator) or\n // fieldDef._meta.__tenancy (from @smrt({ tenantScoped: true }))\n const hasTenancyMarker =\n (prop &&\n typeof prop === 'object' &&\n '__tenancy' in prop &&\n (prop as any).__tenancy?.isTenantIdField) ||\n (fieldDef as any)?.__tenancy?.isTenantIdField ||\n (fieldDef as any)?._meta?.__tenancy?.isTenantIdField;\n\n if (hasTenancyMarker) {\n // Leave tenant field as null so interceptor can auto-populate\n if (isSTI && fieldDef?.type === 'meta') {\n data._meta_data[key] = null;\n } else {\n data[key] = null;\n }\n } else {\n // For regular TEXT fields, convert undefined to an empty string.\n if (isSTI && fieldDef?.type === 'meta') {\n data._meta_data[key] = '';\n } else {\n data[key] = '';\n }\n }\n } else if (fieldType === 'json') {\n // For JSON fields, use the default value from manifest to prevent:\n // 1. Invalid JSON casting errors in DuckDB (empty string \"\")\n // 2. Runtime errors when code expects arrays/objects (null)\n const defaultValue = fieldDef?.default ?? null;\n\n if (isSTI && fieldDef?.type === 'meta') {\n data._meta_data[key] = defaultValue;\n } else {\n data[key] = defaultValue;\n }\n }\n\n // For all cases of 'undefined' (handled or not), we continue to the next field.\n // This prevents the undefined value from being assigned to the data object below,\n // allowing the database to use its default value for unhandled types.\n continue;\n }\n\n // STI: Separate meta fields from regular fields\n if (isSTI && fieldDef && fieldDef.type === 'meta') {\n // Meta fields go into _meta_data JSONB column\n data._meta_data[key] = value;\n } else {\n // Regular fields become table columns\n data[key] = value;\n }\n }\n\n // Call transformation hook to allow safe customization\n // This enables subclasses to add/modify fields without overriding toJSON()\n return this.transformJSON(data);\n }\n\n /**\n * Converts this object to a plain JavaScript object (POJO)\n *\n * Unlike toJSON() which returns an object that can still be a class instance,\n * this method returns a true plain object suitable for:\n * - SvelteKit's load function returns (requires serializable data)\n * - Passing data through web workers\n * - Any context requiring non-class objects\n *\n * @returns Plain JavaScript object with all field values\n *\n * @example\n * ```typescript\n * // In a SvelteKit +page.server.ts load function:\n * const users = await userCollection.list();\n * return {\n * users: users.map(u => u.toPlainObject())\n * };\n * ```\n */\n toPlainObject(): Record<string, unknown> {\n return JSON.parse(JSON.stringify(this));\n }\n\n /**\n * Collects the property names of fields marked `@field({ sensitive: true })`\n * for this instance's class (and, under STI, every member of its hierarchy,\n * since `toJSON()` merges sibling fields into the serialized payload).\n *\n * Reads both the first-class `sensitive` flag and the `_meta.sensitive`\n * mirror so it works regardless of whether the field metadata came from the\n * AST manifest or a runtime `@field()` decorator registration.\n */\n private getSensitiveFieldNames(): Set<string> {\n const className = this.getResolvedClassName();\n const registered = ObjectRegistry.getClass(className);\n const fieldMaps: Map<string, any>[] = [\n registered?.inheritedFields || ObjectRegistry.getFields(className),\n ];\n\n const tableStrategy = ObjectRegistry.getTableStrategy(\n this.getResolvedQualifiedName(),\n );\n if (tableStrategy === 'sti') {\n const descendants = getSTIHierarchyMembers(\n this.getResolvedQualifiedName(),\n );\n for (const descendant of descendants) {\n fieldMaps.push(\n ObjectRegistry.getClass(descendant)?.inheritedFields ||\n ObjectRegistry.getFields(descendant),\n );\n }\n }\n\n const sensitive = new Set<string>();\n for (const fields of fieldMaps) {\n for (const [key, def] of fields) {\n if (def && (def.sensitive === true || def._meta?.sensitive === true)) {\n sensitive.add(key);\n }\n }\n }\n return sensitive;\n }\n\n /**\n * Public-safe serialization for network surfaces.\n *\n * Returns the same shape as `toJSON()` but with every `sensitive` field\n * removed (including STI meta fields nested under `_meta_data`). This is the\n * serializer used by the generated REST / MCP / SvelteKit routes so that\n * secret columns (API secrets, credentials, tax IDs) are never returned over\n * the wire, while `toJSON()` continues to carry them for database persistence.\n *\n * @returns A plain object safe to send to API consumers.\n */\n toPublicJSON(): Record<string, unknown> {\n return this.projectPublicJSON(new WeakSet<SmrtObject>());\n }\n\n /**\n * Recursive worker behind {@link toPublicJSON}.\n *\n * Strips this instance's sensitive fields (top-level + STI `_meta_data`),\n * then walks the serialized payload and reduces any nested `SmrtObject`\n * value to its OWN public projection. Without this, a nested instance held\n * in a field value (or surfaced by a `transformJSON()` override) would be\n * serialized via `JSON.stringify` -> its `toJSON()`, leaking that nested\n * object's `@field({ sensitive: true })` values to API/MCP/AI consumers\n * (#1580).\n *\n * @param seen - Ancestor path of `SmrtObject` instances on the current\n * branch, used purely to break reference cycles. An instance already on\n * the path is dropped rather than recursed into. It is a path set (entries\n * are removed on the way back up), not a global visited set, so an object\n * legitimately shared across sibling branches is still projected in each.\n */\n private projectPublicJSON(\n seen: WeakSet<SmrtObject>,\n ): Record<string, unknown> {\n const json = this.toJSON() as Record<string, unknown>;\n const sensitiveFields = this.getSensitiveFieldNames();\n\n if (sensitiveFields.size > 0) {\n const metaData =\n json._meta_data && typeof json._meta_data === 'object'\n ? (json._meta_data as Record<string, unknown>)\n : null;\n for (const name of sensitiveFields) {\n delete json[name];\n if (metaData) {\n delete metaData[name];\n }\n }\n }\n\n seen.add(this);\n try {\n for (const key of Object.keys(json)) {\n json[key] = SmrtObject.sanitizePublicValue(json[key], seen);\n }\n } finally {\n seen.delete(this);\n }\n return json;\n }\n\n /**\n * Reduce an arbitrary serialized value to its public-safe form: a nested\n * `SmrtObject` becomes its `toPublicJSON()` projection; plain objects and\n * arrays are walked; everything else passes through unchanged. Part of the\n * {@link toPublicJSON} recursive sensitive-field strip (#1580).\n */\n private static sanitizePublicValue(\n value: unknown,\n seen: WeakSet<SmrtObject>,\n ): unknown {\n if (value instanceof SmrtObject) {\n // Cycle: this instance is already on the current ancestor path.\n // Drop it (undefined serializes away) rather than recurse forever.\n if (seen.has(value)) {\n return undefined;\n }\n return value.projectPublicJSON(seen);\n }\n if (Array.isArray(value)) {\n return value.map((item) => SmrtObject.sanitizePublicValue(item, seen));\n }\n // Only descend into plain objects (e.g. `_meta_data`, parsed JSON fields).\n // Leave Date / Map / other class instances untouched so we never rewrite\n // their internals.\n if (value !== null && typeof value === 'object') {\n const proto = Object.getPrototypeOf(value);\n if (proto === Object.prototype || proto === null) {\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(\n value as Record<string, unknown>,\n )) {\n out[key] = SmrtObject.sanitizePublicValue(item, seen);\n }\n return out;\n }\n }\n return value;\n }\n\n /**\n * Gets or generates a unique ID for this object\n *\n * @returns Promise resolving to the object's ID\n */\n async getId() {\n if (this.slug) {\n await this.verifyStorageReady();\n\n // lookup by slug and context using adapter method\n const saved = await this.db.get(this.tableName, {\n slug: this.slug,\n context: this.context,\n });\n if (saved) {\n this.id = saved.id;\n }\n }\n\n if (!this.id) {\n this.id = crypto.randomUUID();\n }\n return this.id;\n }\n\n /**\n * Returns the slug for this object, generating one if not already set.\n *\n * Generation falls back through the following fields in order:\n * `name` → `title` → `label` → `id`\n *\n * The generated slug is lowercased, with non-alphanumeric characters\n * replaced by hyphens and leading/trailing hyphens stripped.\n *\n * Called automatically by `save()` when no slug is present.\n *\n * @returns The existing slug or a newly generated one (may be `null` if\n * none of the fallback fields and `id` are set)\n *\n * @example\n * ```typescript\n * const product = new Product({ name: 'My Widget' });\n * console.log(await product.getSlug()); // 'my-widget'\n * ```\n */\n async getSlug() {\n if (!this.slug) {\n // Try multiple fallback fields in order: name, title, label, id\n let sourceField = null;\n\n if ((this as any).name) {\n sourceField = String((this as any).name);\n } else if ((this as any).title) {\n sourceField = String((this as any).title);\n } else if ((this as any).label) {\n sourceField = String((this as any).label);\n } else if (this.id) {\n // Final fallback: use ID\n sourceField = String(this.id);\n }\n\n if (sourceField) {\n // Generate slug from source field\n this.slug = sourceField\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '');\n }\n }\n\n // check for existing slug and make unique?\n return this.slug;\n }\n\n /**\n * Gets the ID of this object if it's already saved in the database\n *\n * @returns Promise resolving to the saved ID or null if not saved\n */\n async getSavedId() {\n if (!this.id && !this.slug) {\n return null;\n }\n\n await this.verifyStorageReady();\n\n // Try to find by id first\n if (this.id) {\n const byId = await this.db.get(this.tableName, { id: this.id });\n if (byId) return byId.id;\n }\n\n // Fall back to finding by slug\n if (this.slug) {\n const bySlug = await this.db.get(this.tableName, { slug: this.slug });\n if (bySlug) return bySlug.id;\n }\n\n return null;\n }\n\n /**\n * Checks if this object is already saved in the database\n *\n * @returns Promise resolving to true if saved, false otherwise\n */\n async isSaved() {\n const saved = await this.getSavedId();\n return !!saved;\n }\n\n /**\n * Resolve the set of snake_case column names whose database type is `UUID`\n * for the table this object writes to.\n *\n * Declared foreign keys (`@foreignKey()`) and cross-package references\n * (`@crossPackageRef()`) generate native `UUID` columns (R11). Their default\n * declared value in TypeScript is the empty string (`''`), which is not a\n * valid UUID literal. Postgres rejects `''` on a `uuid` column with\n * `invalid input syntax for type uuid`, so any optional/unset declared FK\n * (a root entity's self-reference, an optional cross-package link, etc.)\n * would fail to insert. We coerce `''` → `NULL` for these columns before\n * binding (see {@link coerceEmptyUuidValuesToNull}); this method tells that\n * coercion which columns are UUID-typed.\n *\n * Resolution prefers the built schema (`getSchema().columns`), which already\n * reflects all reconciliation — e.g. a `@foreignKey()` whose target class\n * uses `idType: 'text'` is downgraded to `TEXT` and is therefore correctly\n * excluded here. For STI children, columns live on the STI base table, so we\n * union the base schema's columns. When no built schema is available (pure\n * runtime-registered classes without a manifest) we fall back to field\n * metadata, mirroring the schema-builder's field→SQL mapping.\n */\n private async resolveUuidColumnNames(\n className: string,\n ): Promise<Set<string>> {\n const uuidColumns = new Set<string>();\n\n const collectFromSchema = (schemaName: string | null | undefined): void => {\n if (!schemaName) return;\n const schema = ObjectRegistry.getSchema(schemaName);\n const columns = schema?.columns;\n if (!columns) return;\n for (const [columnName, columnDef] of Object.entries(columns)) {\n if ((columnDef as { type?: string })?.type === 'UUID') {\n uuidColumns.add(columnName);\n }\n }\n };\n\n // Own schema (covers non-STI and STI-base classes).\n collectFromSchema(className);\n\n // STI children: FK columns are declared on the base table.\n const qualifiedName = this.getResolvedQualifiedName();\n if (ObjectRegistry.getTableStrategy(qualifiedName) === 'sti') {\n collectFromSchema(ObjectRegistry.getSTIBase(qualifiedName));\n }\n\n if (uuidColumns.size > 0) {\n return uuidColumns;\n }\n\n // Fallback: derive UUID columns from field metadata when no built schema\n // is available. Mirrors schema-builder's field→SQL mapping so that a\n // text-id cross-package ref is not treated as UUID.\n try {\n const fields = await ObjectRegistry.getAllFields(className);\n for (const [fieldName, field] of fields.entries()) {\n if (!field) continue;\n const type = field.type;\n if (type !== 'foreignKey' && type !== 'crossPackageRef') {\n continue;\n }\n const metaSqlType = field._meta?.sqlType;\n if (metaSqlType) {\n if (metaSqlType === 'UUID') {\n uuidColumns.add(toSnakeCase(fieldName));\n }\n continue;\n }\n const isTextIdCrossRef =\n type === 'crossPackageRef' &&\n (field._meta?.idType === 'text' || field.idType === 'text');\n if (!isTextIdCrossRef) {\n uuidColumns.add(toSnakeCase(fieldName));\n }\n }\n } catch {\n // Best-effort fallback; never let UUID-column resolution block a save.\n }\n\n return uuidColumns;\n }\n\n /**\n * Coerce empty-string values to `NULL` for UUID-typed columns in the\n * snake_cased write payload.\n *\n * Framework-level fix for the whole class of bug where a declared FK field\n * defaults to `''` (the natural TypeScript default for `string`) and is left\n * unset on insert — e.g. creating a ROOT entity whose optional self-reference\n * (`previousFactId`, `parentPartnerId`, …) is empty. On Postgres `uuid`\n * columns, `''` raises `invalid input syntax for type uuid`. Coercing to\n * `NULL` here fixes every such field uniformly without per-field type churn\n * or consumer-facing type changes. Mutates `data` in place.\n */\n private async coerceEmptyUuidValuesToNull(\n className: string,\n data: Record<string, any>,\n ): Promise<void> {\n const uuidColumns = await this.resolveUuidColumnNames(className);\n if (uuidColumns.size === 0) return;\n for (const columnName of uuidColumns) {\n if (data[columnName] === '') {\n data[columnName] = null;\n }\n }\n }\n\n /**\n * Persists this object to the database using an upsert (insert or update).\n *\n * Steps performed on every save:\n * 1. Runs field-level validation (`validateBeforeSave()`)\n * 2. Executes `beforeSave` interceptors (e.g. tenant injection)\n * 3. Assigns a UUID `id` if not already set\n * 4. Generates a `slug` via `getSlug()` if not already set\n * 5. Updates `updated_at` (and sets `created_at` on first save)\n * 6. Upserts the row with automatic retry (3 attempts, 500 ms backoff)\n * 7. Executes `afterSave` interceptors\n * 8. Triggers embedding generation in the background if configured\n *\n * For STI classes, validates that `_meta_type` is present and correct\n * before writing to the database.\n *\n * @returns This instance after saving (enables chaining)\n * @throws {ValidationError} If a required field is missing or a unique constraint is violated\n * @throws {DatabaseError} If the table does not exist (`DB_SCHEMA_MISSING`) or the query fails\n * @throws {RuntimeError} For any other unexpected failure during save\n *\n * @example\n * ```typescript\n * const product = new Product({ db: myDb, name: 'Widget', price: 9.99 });\n * await product.initialize();\n * await product.save();\n * console.log(product.id); // UUID assigned during save\n *\n * // Update\n * product.price = 14.99;\n * await product.save();\n * ```\n */\n async save() {\n const className = this.getResolvedClassName();\n\n try {\n // Validate object state before saving\n await this.validateBeforeSave();\n\n // Validate cross-package references that opted into save-time validation\n await this.validateCrossPackageRefs();\n\n // Execute beforeSave interceptors (e.g., tenancy validation)\n const interceptorContext = createInterceptorContext(className, 'save');\n await GlobalInterceptors.executeBeforeSave(this, interceptorContext);\n\n if (!this.id) {\n this.id = crypto.randomUUID();\n }\n\n if (!this.slug) {\n this.slug = await this.getSlug();\n }\n\n // Update the updated_at timestamp\n this.updated_at = new Date();\n\n if (!this.created_at) {\n this.created_at = new Date();\n }\n\n await this.verifyStorageReady();\n\n // Execute save operation with retry logic for transient failures\n // Use per-adapter upsert method instead of generating SQL.\n // R5-canon: qualified-key lookup avoids cross-package collisions.\n\n const tableStrategy = ObjectRegistry.getTableStrategy(\n this.getResolvedQualifiedName(),\n );\n\n // Development-mode warning: Detect unsafe toJSON() overrides in STI classes\n if (process.env.NODE_ENV === 'development') {\n const hasOverride = this.toJSON !== SmrtObject.prototype.toJSON;\n const usesSTI = tableStrategy === 'sti';\n\n if (hasOverride && usesSTI) {\n logger.warn(\n `[SMRT STI Warning] ${this.constructor.name} overrides toJSON() but uses STI.\\n` +\n `Ensure super.toJSON() is called or _meta_type is set manually.\\n` +\n `This can cause \"Missing _meta_type discriminator\" errors.\\n` +\n `Prefer using the transformJSON() hook instead of overriding toJSON().\\n` +\n `See issue #377: https://github.com/happyvertical/smrt/issues/377`,\n );\n }\n }\n\n if (tableStrategy === 'sti') {\n // Release C (#1134) retired the SMRT_SKIP_STI_REHYDRATE env flag.\n // PR #1131's unconditional rehydration stays the single behavior:\n // it repairs stale-but-present `inheritedFields` caches that the\n // conservative hydration path would skip (see\n // external-runtime-hydration.test.ts:1071). Further optimizing\n // this loop away via eager invalidation at re-registration time\n // is tracked as a separate follow-up (#1139).\n warnIfSkipRehydrateSet();\n // R5-canon (Copilot follow-up): pass the qualified name to\n // `getSTIHierarchyMembers` so STI sibling discovery is\n // collision-safe across packages with same-simple-name classes.\n const qualifiedName = this.getResolvedQualifiedName();\n const classesNeedingFreshSTIFieldState = Array.from(\n new Set([qualifiedName, ...getSTIHierarchyMembers(qualifiedName)]),\n );\n for (const stiClassName of classesNeedingFreshSTIFieldState) {\n await ObjectRegistry.getAllFields(stiClassName);\n }\n }\n\n const jsonData = this.toJSON();\n\n // STI: Fail-fast validation for _meta_type discriminator\n if (tableStrategy === 'sti') {\n if (!jsonData._meta_type) {\n throw new Error(\n `STI validation failed: Missing _meta_type discriminator when saving ${className}. ` +\n `This should have been set automatically by toJSON(). Please report this bug.`,\n );\n }\n // Accept both simple class name and qualified name (namespace isolation - Issue #713)\n if (!isValidMetaType(jsonData._meta_type, className)) {\n throw new Error(\n `STI validation failed: _meta_type mismatch when saving ${className}. ` +\n `Expected '${getExpectedMetaType(className)}' but got '${jsonData._meta_type}'. ` +\n `This should not happen - please report this bug.`,\n );\n }\n }\n\n // Convert camelCase keys to snake_case for database columns\n // Preserve leading underscore for special fields like _meta_type, _meta_data\n const data: Record<string, any> = {};\n for (const [key, value] of Object.entries(jsonData)) {\n if (key.startsWith('_')) {\n // Preserve leading underscore for special fields\n data[key] = value;\n } else {\n data[toSnakeCase(key)] = value;\n }\n }\n\n // Coerce empty-string values to NULL for native UUID columns (declared\n // FKs / cross-package refs). The TypeScript default for an unset\n // `string`-typed FK is `''`, which Postgres rejects on a `uuid` column\n // (\"invalid input syntax for type uuid\"). This framework-level coercion\n // fixes every optional/unset declared-FK field uniformly.\n await this.coerceEmptyUuidValuesToNull(className, data);\n\n // Get conflict columns from registry (supports custom columns for junction tables)\n const conflictColumns = ObjectRegistry.getConflictColumns(className);\n const writePlan = await this.planPersistenceWrite(\n className,\n tableStrategy,\n data,\n conflictColumns,\n );\n\n // Issue #1472: objects backed by an existing row must conflict on the\n // primary key. With natural-key conflict columns, editing a natural-key\n // field (e.g. slug) makes the conflict target match no row, so the\n // upsert takes the INSERT path with the existing id and violates\n // `*_pkey`. New objects keep natural-key conflict so ingestion-style\n // dedup (create/getOrUpsert against a known slug) still updates in\n // place. planPersistenceWrite() intentionally still receives the\n // natural-key columns — its legacy-STI probe semantics are unchanged.\n const upsertConflictColumns =\n this._persisted && data.id ? ['id'] : conflictColumns;\n\n await ErrorUtils.withRetry(\n async () => {\n try {\n if (writePlan.type === 'updateById') {\n const { id: _id, ...updateData } = data;\n await this.db.update(this.tableName, { id: data.id }, updateData);\n this.setMetaType(writePlan.qualifiedMetaType);\n } else {\n await this.db.upsert(this.tableName, upsertConflictColumns, data);\n }\n } catch (error) {\n // Detect specific database error types. `@happyvertical/sql` does\n // not normalize driver errors, so match SQLite, PostgreSQL and\n // DuckDB constraint strings to preserve the advertised typed-error\n // parity (#1378) across adapters.\n if (error instanceof Error) {\n const kind = SmrtObject.classifyConstraintError(error.message);\n if (kind === 'unique') {\n const field = this.extractConstraintField(error.message);\n throw ValidationError.uniqueConstraint(\n field,\n this.getFieldValue(field),\n );\n }\n if (kind === 'not_null') {\n const field = this.extractConstraintField(error.message);\n throw ValidationError.requiredField(field, className);\n }\n const operation =\n writePlan.type === 'updateById'\n ? `UPDATE ${this.tableName} (id-targeted)`\n : `UPSERT INTO ${this.tableName}`;\n throw DatabaseError.queryFailed(operation, error);\n }\n throw error;\n }\n },\n 3,\n 500,\n );\n\n // The row now exists, so any further save() must update it by primary\n // key even if natural-key fields change afterwards (issue #1472).\n this._persisted = true;\n\n // Bust cached collection reads for this table (issue #1498). SMRT owns\n // every mutation path, so this is the write-invalidation guarantee the\n // opt-in read cache relies on.\n this.invalidateCollectionReadCache();\n\n // Execute afterSave interceptors (e.g., tenant audit logging)\n await GlobalInterceptors.executeAfterSave(this, interceptorContext);\n\n // Auto-generate embeddings only when an AI client is configured. Manual\n // generation can still use local embeddings, but save-time background\n // work should not unexpectedly load a local transformer model.\n const embeddingConfig = ObjectRegistry.resolveEmbeddingConfig(className);\n const skipAutoEmbeddings = this.options._skipAutoEmbeddings === true;\n if (\n embeddingConfig &&\n embeddingConfig.autoGenerate !== false &&\n !skipAutoEmbeddings\n ) {\n const aiClient = await this.getOptionalAiClient();\n\n // Check if any embedding field content has changed\n if (aiClient) {\n const isStale = await this.hasStaleEmbeddings();\n if (isStale) {\n // Generate embeddings in background to avoid blocking save\n this.generateEmbeddings().catch((error) => {\n logger.warn(\n `Failed to auto-generate embeddings for ${this.constructor.name}`,\n { error: error instanceof Error ? error.message : error },\n );\n });\n }\n }\n }\n if (skipAutoEmbeddings) {\n this.options._skipAutoEmbeddings = false;\n }\n\n return this;\n } catch (error) {\n // Re-throw SMRT errors as-is (ValidationError, DatabaseError,\n // TenantIsolationError, etc. all extend SmrtError) so their stable\n // `code`/`instanceof` contract survives the save() boundary.\n if (error instanceof SmrtError) {\n throw error;\n }\n\n // Preserve tenancy errors thrown by the `beforeSave` interceptor. The\n // `@happyvertical/smrt-tenancy` TenantIsolationError / TenantContextError\n // extend plain `Error` (core cannot depend on the tenancy package), so\n // they are NOT instanceof SmrtError. Re-throw them as-is by their stable\n // `code` (or class name fallback) so handlers can still match\n // `err.code === 'TENANT_ISOLATION_VIOLATION'` / 'TENANT_CONTEXT_REQUIRED'\n // on the write path, just like on the relationship-load path.\n if (this.isTenantContractError(error)) {\n throw error;\n }\n\n throw RuntimeError.operationFailed(\n 'save',\n `${className}#${this.id}`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n /**\n * Detects tenant-boundary errors that must propagate from `save()` unwrapped.\n *\n * Matches both core's {@link TenantIsolationError} and the duck-typed\n * tenancy-package errors (`TenantIsolationError` / `TenantContextError`) that\n * the `beforeSave` interceptor throws. Those tenancy classes extend plain\n * `Error` — core cannot import the tenancy package (the dependency runs the\n * other way) — so they are matched by their stable `code` constants, with a\n * class-name fallback for resilience.\n */\n private isTenantContractError(error: unknown): boolean {\n if (error instanceof TenantIsolationError) {\n return true;\n }\n const candidate = error as\n | { code?: unknown; name?: unknown }\n | null\n | undefined;\n const code = candidate?.code;\n if (\n code === 'TENANT_ISOLATION_VIOLATION' ||\n code === 'TENANT_CONTEXT_REQUIRED'\n ) {\n return true;\n }\n const name = candidate?.name;\n return name === 'TenantIsolationError' || name === 'TenantContextError';\n }\n\n /**\n * Validates object state before saving\n * Override in subclasses to add custom validation logic\n */\n protected async validateBeforeSave(): Promise<void> {\n const className = this.getResolvedClassName();\n\n // Priority 1: Use pre-computed validation rules from manifest (Issue #782)\n // This is the fastest path - rules are serializable and don't require closures\n const validationRules = ObjectRegistry.getValidationRules(className);\n\n if (validationRules && validationRules.length > 0) {\n const errors = await ObjectRegistry.validateWithRules(\n this,\n validationRules,\n className,\n );\n\n if (errors.length > 0) {\n throw errors[0];\n }\n return;\n }\n\n // Priority 2: Use compiled validators (backward compatibility)\n const validators = ObjectRegistry.getValidators(className);\n\n if (validators && validators.length > 0) {\n // Execute all cached validators\n const errors: ValidationError[] = [];\n\n for (const validator of validators) {\n const error = await validator(this);\n if (error) {\n errors.push(error);\n }\n }\n\n // If there are validation errors, throw the first one\n // (In the future, we could throw all errors as a ValidationReport)\n if (errors.length > 0) {\n throw errors[0];\n }\n return;\n }\n\n // Priority 3: Fallback to old validation logic if no cached validators\n // (for classes not registered with ObjectRegistry)\n const fields = await fieldsFromClass(this.constructor as any);\n\n for (const [fieldName, field] of Object.entries(fields)) {\n // With decorators, field definitions are plain objects with nested options\n if ((field as any).options?.required) {\n const value = this.getFieldValue(fieldName);\n if (value === null || value === undefined || value === '') {\n throw ValidationError.requiredField(fieldName, className);\n }\n }\n }\n }\n\n /**\n * Validates cross-package references that opted in via `validate: true`.\n *\n * Iterates registered fields of type `crossPackageRef`. For each one whose\n * field options include `validate: true` AND has a non-empty value, looks up\n * the referenced object via the target package's manifest and throws\n * `ValidationError` if the target row does not exist.\n *\n * Empty/null/undefined values are treated as \"no reference set\" and skipped.\n * Fields without `validate: true` are always skipped (the registered metadata\n * still powers eager loading and `loadRelated()`).\n */\n protected async validateCrossPackageRefs(): Promise<void> {\n const className = this.getResolvedClassName();\n const registered = ObjectRegistry.getClass(className);\n if (!registered) return;\n\n const fields = registered.inheritedFields || registered.fields;\n if (!fields || fields.size === 0) return;\n\n type CrossRefCheck = {\n fieldName: string;\n qualifiedTarget: string;\n value: string;\n };\n const checks: CrossRefCheck[] = [];\n\n for (const [fieldName, field] of fields) {\n if (field?.type !== 'crossPackageRef') continue;\n const opts = field._meta || field;\n if (!opts.validate) continue;\n if (!field.related) continue;\n\n const value = this.getFieldValue(fieldName);\n if (value === null || value === undefined || value === '') continue;\n\n checks.push({\n fieldName,\n qualifiedTarget: String(field.related),\n value: String(value),\n });\n }\n\n if (checks.length === 0) return;\n\n for (const check of checks) {\n await ObjectRegistry.ensureManifestLoaded(check.qualifiedTarget);\n\n const targetClass =\n ObjectRegistry.getClassByQualifiedName(check.qualifiedTarget) ??\n ObjectRegistry.getClass(check.qualifiedTarget);\n\n if (!targetClass) {\n throw new ValidationError(\n `crossPackageRef target ${check.qualifiedTarget} for ${className}.${check.fieldName} is not registered. ` +\n `Ensure the target package's manifest is discoverable at runtime.`,\n 'VALIDATION_CROSS_PACKAGE_REF_UNREGISTERED',\n { className, fieldName: check.fieldName, value: check.value },\n );\n }\n\n const probe = new targetClass.constructor(this.options) as SmrtObject;\n await probe.initialize();\n await probe.verifyStorageReady();\n const row = await probe.db.get(probe.tableName, { id: check.value });\n if (!row) {\n throw new ValidationError(\n `crossPackageRef validation failed: ${className}.${check.fieldName} references ` +\n `${check.qualifiedTarget} id=\"${check.value}\" but no such row exists.`,\n 'VALIDATION_CROSS_PACKAGE_REF_MISSING',\n { className, fieldName: check.fieldName, value: check.value },\n );\n }\n }\n }\n\n /**\n * Gets the value of a field on this object\n */\n protected getFieldValue(fieldName: string): any {\n return (this as any)[fieldName];\n }\n\n /**\n * Gets the value of a property.\n *\n * @param key - Property name to get value from\n * @returns The property value\n */\n protected getPropertyValue(key: string): any {\n return (this as any)[key];\n }\n\n /**\n * Classifies a raw database driver error message as a unique-constraint or\n * not-null-constraint violation, across SQLite, PostgreSQL and DuckDB.\n *\n * `@happyvertical/sql` does not normalize driver errors, so each dialect's\n * native wording is matched case-insensitively. Returns `null` when the\n * message is not a recognized unique/not-null violation (the caller then\n * falls back to a generic `DatabaseError`). Kept as a pure static so the\n * cross-dialect matching can be unit-tested directly without a live PG/DuckDB\n * connection (#1378).\n *\n * @param message - The raw driver error message.\n * @returns `'unique'`, `'not_null'`, or `null`.\n */\n static classifyConstraintError(\n message: string,\n ): 'unique' | 'not_null' | null {\n if (!message) {\n return null;\n }\n\n // NOT NULL — checked first because DuckDB's \"violates\" wording would\n // otherwise be misread as a unique violation below.\n // SQLite/DuckDB: \"NOT NULL constraint failed: t.col\"\n // PostgreSQL: 'null value in column \"col\" ... violates not-null constraint'\n if (\n /NOT NULL constraint failed/i.test(message) ||\n /null value in column .* violates not-null/i.test(message)\n ) {\n return 'not_null';\n }\n\n // UNIQUE — match unique/primary-key wording specifically. Do NOT match a\n // bare \"Constraint Error ... violates\", because DuckDB phrases foreign-key\n // failures the same way (\"Constraint Error: violates foreign key\n // constraint\"); a broad match would misreport an FK violation as a unique\n // one. Unmatched constraint kinds (FK, CHECK) fall through to a generic\n // DatabaseError, preserving the original error contract.\n // SQLite: \"UNIQUE constraint failed: t.col\"\n // PostgreSQL: \"duplicate key value violates unique constraint ...\"\n // DuckDB: \"Constraint Error: ... violates unique/primary key constraint\"\n if (\n /UNIQUE constraint failed/i.test(message) ||\n /violates unique constraint/i.test(message) ||\n /violates primary key constraint/i.test(message)\n ) {\n return 'unique';\n }\n\n return null;\n }\n\n /**\n * Extracts field name from database constraint error messages.\n *\n * Handles SQLite, PostgreSQL and DuckDB phrasings. Returns\n * `'unknown_field'` when no column name can be recovered.\n */\n protected extractConstraintField(errorMessage: string): string {\n // Try to extract field name from common constraint patterns across dialects.\n const patterns = [\n // SQLite / DuckDB: \"UNIQUE constraint failed: products.slug\"\n /UNIQUE constraint failed: \\w+\\.(\\w+)/i,\n // SQLite / DuckDB: \"NOT NULL constraint failed: products.name\"\n /NOT NULL constraint failed: \\w+\\.(\\w+)/i,\n // PostgreSQL not-null: 'null value in column \"name\" ...'\n /null value in column \"([^\"]+)\"/i,\n // PostgreSQL unique DETAIL line: 'Key (slug)=(foo) already exists.'\n /Key \\(([^)]+)\\)=/i,\n // SQLite / DuckDB generic fallback: \"constraint failed: slug\"\n /constraint failed: (\\w+)/i,\n ];\n\n for (const pattern of patterns) {\n const match = errorMessage.match(pattern);\n if (match?.[1]) {\n return match[1];\n }\n }\n\n return 'unknown_field';\n }\n\n /**\n * Hydrates this object from the database using its `id` property.\n *\n * Queries the database for a row matching `{ id: this._id }` and calls\n * `loadDataFromDb()` if found. Uses a 3-attempt retry with 250 ms initial\n * delay to handle transient failures.\n *\n * Called automatically by `initialize()` when `options.id` is provided.\n * Typically you do not need to call this directly.\n *\n * @returns Promise that resolves when loading is complete (no-op if not found)\n * @throws {ValidationError} If `this._id` is not set\n * @throws {DatabaseError} If the query fails after all retries\n *\n * @example\n * ```typescript\n * const product = new Product({ db: myDb });\n * await product.initialize();\n * product._id = 'some-uuid';\n * await product.loadFromId(); // hydrates from DB\n * ```\n */\n public async loadFromId() {\n try {\n if (!this._id) {\n throw ValidationError.requiredField('id', this.constructor.name);\n }\n\n await this.verifyStorageReady();\n\n await ErrorUtils.withRetry(\n async () => {\n try {\n const existing = await this.db.get(this.tableName, {\n id: this._id,\n });\n if (existing) {\n await this.loadDataFromDb(existing);\n }\n } catch (error) {\n throw DatabaseError.queryFailed(\n `get(${this.tableName}, { id: ${this._id} })`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n },\n 3,\n 250,\n );\n } catch (error) {\n if (error instanceof ValidationError || error instanceof DatabaseError) {\n throw error;\n }\n\n throw RuntimeError.operationFailed(\n 'loadFromId',\n `${this.constructor.name}#${this._id}`,\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n /**\n * Hydrates this object from the database using its `slug` (and `context`).\n *\n * Queries for a row matching `{ slug, context }`. The `context` defaults to\n * an empty string when not provided. Calls `loadDataFromDb()` if a matching\n * row is found.\n *\n * Called automatically by `initialize()` when `options.slug` is provided and\n * no `options.id` is set. Typically you do not need to call this directly.\n *\n * @returns Promise that resolves when loading is complete (no-op if not found)\n *\n * @example\n * ```typescript\n * const product = new Product({ db: myDb, slug: 'my-widget', context: 'shop' });\n * await product.initialize(); // calls loadFromSlug() automatically\n * console.log(product.name);\n * ```\n */\n public async loadFromSlug() {\n await this.verifyStorageReady();\n\n const existing = await this.db.get(this.tableName, {\n slug: this._slug,\n context: this._context || '',\n });\n if (existing) {\n await this.loadDataFromDb(existing);\n }\n }\n\n /**\n * Serializes this instance into the \"content body\" injected into the AI\n * prompts used by {@link is}, {@link do}, and {@link describe} so those\n * methods reason over the object's own field data, not just the caller's\n * instruction string.\n *\n * Uses {@link toPublicJSON} (never {@link toJSON}) so that\n * `@field({ sensitive: true })` values — API secrets, credentials, tax IDs —\n * are never sent to the model. The serialized payload is truncated to\n * `maxLength` characters as a coarse token-budget guard for large instances;\n * truncation appends a clear marker so the model knows the data was cut.\n *\n * @param maxLength - Maximum characters of object data to include\n * (defaults to {@link AI_PROMPT_DATA_MAX_LENGTH}). A non-positive value\n * disables truncation.\n * @returns A JSON string of the object's public (sensitive-stripped) fields\n */\n private serializeForAiPrompt(\n maxLength: number = AI_PROMPT_DATA_MAX_LENGTH,\n ): string {\n let serialized: string;\n try {\n serialized = JSON.stringify(this.toPublicJSON(), null, 2);\n } catch (error) {\n // Defensive: never let a serialization edge case break an AI call.\n // The instruction-only prompt still works; we just lose the data context.\n logger.warn(\n `Failed to serialize ${this.constructor.name} for AI prompt: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n serialized = '{}';\n }\n\n if (\n Number.isFinite(maxLength) &&\n maxLength > 0 &&\n serialized.length > maxLength\n ) {\n const marker = `\\n… [truncated: object data exceeded ${maxLength} characters]`;\n // Reserve room for the marker so the returned string never exceeds\n // maxLength — the budget is a hard ceiling, not \"data + marker\". For a\n // budget smaller than the marker itself, emit just the marker (an\n // unusably small budget still yields a clear truncation signal).\n const keep = Math.max(0, maxLength - marker.length);\n serialized = `${serialized.slice(0, keep)}${marker}`;\n }\n\n return serialized;\n }\n\n /**\n * Builds the optional \"content body\" section prepended to the AI prompts in\n * {@link is}, {@link do}, and {@link describe}.\n *\n * Returns an empty string when the caller opts out with `includeData: false`\n * — used by callers that already curate the object's relevant fields into\n * their own instruction/criteria string (so the data is not duplicated, and\n * the prompt stays exactly as the caller authored it). Otherwise it wraps\n * {@link serializeForAiPrompt} in `--- Beginning/End of content ---`\n * delimiters so the methods reason over the instance's own data by default.\n *\n * @param includeData - `false` to omit the section; any other value (incl.\n * `undefined`) injects it\n * @param maxLength - Forwarded to {@link serializeForAiPrompt} as the\n * truncation budget\n * @returns The content-body section (with a trailing newline) or `''`\n */\n private buildAiContentSection(\n includeData: boolean | undefined,\n maxLength?: number,\n ): string {\n if (includeData === false) {\n return '';\n }\n const contentBody = this.serializeForAiPrompt(maxLength);\n return `--- Beginning of content ---\\n${contentBody}\\n--- End of content ---\\n`;\n }\n\n /**\n * Evaluates whether this object satisfies the given natural-language criteria using AI.\n *\n * Injects the object's own public field data (via {@link toPublicJSON}, so\n * `@field({ sensitive: true })` values are excluded) into the prompt as the\n * \"content body\", then asks the AI whether that data meets the criteria and\n * to reply with a `{ result: boolean }` JSON response. Uses any AI-callable\n * tools registered on this class (via `@smrt({ ai })`) as part of the\n * function-calling context.\n *\n * @param criteria - Natural-language description of the condition to evaluate\n * @param options - AI message options passed to `ai.message()` (e.g. model\n * override). Two non-standard control keys are consumed here and not\n * forwarded to `ai.message()`:\n * - `includeData: false` — omit the injected object \"content body\" (for\n * callers that already curate the relevant fields into `criteria`).\n * - `maxDataLength` (number of characters) — override the injected\n * object-data truncation limit.\n * @returns `true` if the object meets the criteria, `false` otherwise\n * @throws Error if the AI returns a non-boolean or malformed JSON response\n *\n * @example\n * ```typescript\n * const article = await articles.get('article-uuid');\n * const isSuitable = await article.is('appropriate for a general audience');\n * if (isSuitable) await article.publish();\n * ```\n *\n * @see {@link do} for open-ended instructions instead of boolean checks\n */\n public async is(criteria: string, options: any = {}) {\n const ai = await this.getAiClient();\n const { maxDataLength, includeData, ...aiOptions } = options ?? {};\n const contentSection = this.buildAiContentSection(\n includeData,\n maxDataLength,\n );\n const prompt = `${contentSection}--- Beginning of criteria ---\\n${criteria}\\n--- End of criteria ---\\nDoes the content meet all the given criteria? Reply with a json object with a single boolean 'result' property`;\n\n // Get available tools for AI function calling\n const tools = this.getAvailableTools();\n\n const message = await ai.message(prompt, {\n ...(aiOptions as any),\n responseFormat: { type: 'json_object' },\n tools: tools.length > 0 ? tools : undefined,\n });\n\n try {\n const { result } = JSON.parse(message);\n if (result === true || result === false) {\n return result;\n }\n } catch (_e) {\n throw new Error(`Unexpected answer: ${message}`);\n }\n }\n\n /**\n * Performs a freeform operation on this object using AI instructions.\n *\n * Injects the object's own public field data (via {@link toPublicJSON}, so\n * `@field({ sensitive: true })` values are excluded) into the prompt as the\n * \"content body\" the instructions operate on, then returns the raw text\n * response. Unlike `is()`, this method does not constrain the response\n * format — use it for transformations, summaries, extractions, or any\n * open-ended AI task.\n *\n * Uses any AI-callable tools registered on this class (via `@smrt({ ai })`)\n * as part of the function-calling context.\n *\n * @param instructions - Natural-language instructions for the AI to follow\n * @param options - AI message options passed to `ai.message()` (e.g. model\n * override). Two non-standard control keys are consumed here and not\n * forwarded to `ai.message()`:\n * - `includeData: false` — omit the injected object \"content body\" (for\n * callers that already curate the relevant fields into `instructions`).\n * - `maxDataLength` (number of characters) — override the injected\n * object-data truncation limit.\n * @returns The raw AI response string\n *\n * @example\n * ```typescript\n * const article = await articles.get('article-uuid');\n * const summary = await article.do('summarize this article in 3 bullet points');\n * const translated = await article.do('translate the title and body to Spanish');\n * ```\n *\n * @see {@link is} for boolean criteria checks\n */\n public async do(instructions: string, options: any = {}) {\n const ai = await this.getAiClient();\n const { maxDataLength, includeData, ...aiOptions } = options ?? {};\n const contentSection = this.buildAiContentSection(\n includeData,\n maxDataLength,\n );\n const prompt = `${contentSection}--- Beginning of instructions ---\\n${instructions}\\n--- End of instructions ---\\nBased on the content body, please follow the instructions and provide a response. Never make use of codeblocks.`;\n\n // Get available tools for AI function calling\n const tools = this.getAvailableTools();\n\n const result = await ai.message(prompt, {\n ...aiOptions,\n tools: tools.length > 0 ? tools : undefined,\n });\n\n return result;\n }\n\n /**\n * Generates a description of this object using AI (Issue #52)\n *\n * Creates a concise, human-readable description based on the object's content\n * and properties. The object's own public field data (via\n * {@link toPublicJSON}, so `@field({ sensitive: true })` values are excluded)\n * is injected into the prompt as the \"content body\" the description is built\n * from. Useful for summaries, previews, and documentation.\n *\n * @param options - AI message options (can include style, length, focus,\n * etc.). Two non-standard control keys are consumed here and not forwarded\n * to `ai.message()`:\n * - `includeData: false` — omit the injected object \"content body\".\n * - `maxDataLength` (number of characters) — override the injected\n * object-data truncation limit.\n * @returns Promise resolving to the AI-generated description\n *\n * @example\n * ```typescript\n * const product = await products.get('product-123');\n * const description = await product.describe();\n * // \"A high-quality widget for home improvement...\"\n *\n * // With custom options\n * const shortDesc = await product.describe({ maxTokens: 50 });\n * // \"Premium widget, steel construction\"\n * ```\n */\n public async describe(options: any = {}) {\n const ai = await this.getAiClient();\n const { maxDataLength, includeData, ...aiOptions } = options ?? {};\n const contentSection = this.buildAiContentSection(\n includeData,\n maxDataLength,\n );\n const prompt = `${contentSection}Generate a concise, professional description of this object based on its content and properties. The description should be clear, informative, and suitable for display to end users. Focus on the most important and distinctive characteristics.`;\n\n // Get available tools for AI function calling\n const tools = this.getAvailableTools();\n\n const result = await ai.message(prompt, {\n ...aiOptions,\n tools: tools.length > 0 ? tools : undefined,\n });\n\n return result;\n }\n\n /**\n * Runs a lifecycle hook if it's defined in the object's configuration\n *\n * @param hookName - Name of the hook to run (e.g., 'beforeDelete', 'afterDelete')\n * @returns Promise that resolves when the hook completes\n */\n protected async runHook(hookName: string): Promise<void> {\n const config = ObjectRegistry.getConfig(this.constructor.name);\n const hook = config.hooks?.[hookName as keyof typeof config.hooks];\n\n if (!hook) {\n return; // No hook defined, nothing to do\n }\n\n if (typeof hook === 'string') {\n // Hook is a method name to call on this instance\n const method = (this as any)[hook];\n if (typeof method === 'function') {\n await method.call(this);\n } else {\n logger.warn(\n `Hook method '${hook}' not found on ${this.constructor.name}`,\n );\n }\n } else if (typeof hook === 'function') {\n // Hook is a function to call with this instance as parameter\n await hook(this);\n }\n }\n\n /**\n * Deletes this object from the database.\n *\n * Runs the full lifecycle in order:\n * 1. `beforeDelete` interceptors (e.g. tenant validation)\n * 2. `beforeDelete` lifecycle hook (defined in `@smrt({ hooks })`)\n * 3. Database row deletion\n * 4. `afterDelete` lifecycle hook\n * 5. `afterDelete` interceptors\n *\n * Prefer `collection.delete(id)` from application code — it loads the\n * object first (returning `false` when not found) before calling this method.\n *\n * @returns Promise that resolves when deletion is complete\n *\n * @example\n * ```typescript\n * const product = await products.get('product-uuid');\n * if (product) await product.delete();\n * ```\n */\n public async delete(): Promise<void> {\n // Execute beforeDelete interceptors (e.g., tenant validation)\n const interceptorContext = createInterceptorContext(\n this.constructor.name,\n 'delete',\n );\n await GlobalInterceptors.executeBeforeDelete(this, interceptorContext);\n\n await this.runHook('beforeDelete');\n\n await this.verifyStorageReady();\n await this.db.delete(this.tableName, { id: this.id });\n\n // The backing row is gone — a later save() should go through the\n // natural-key insert path again rather than targeting a deleted id.\n this._persisted = false;\n\n // Bust cached collection reads for this table (issue #1498).\n this.invalidateCollectionReadCache();\n\n await this.runHook('afterDelete');\n\n // Execute afterDelete interceptors (e.g., tenant audit logging)\n await GlobalInterceptors.executeAfterDelete(this, interceptorContext);\n }\n\n /**\n * Invalidate cached collection reads after a successful mutation\n * (issue #1498).\n *\n * Always drops this table's in-process entries — a no-op when nothing\n * opted into caching. When the table is cached cross-process (see\n * {@link shouldBroadcastCacheInvalidation}), the invalidation is also\n * broadcast to peer replicas over the database adapter's notification\n * capability, fire-and-forget. Cache maintenance must never fail the\n * write that triggered it.\n */\n private invalidateCollectionReadCache(): void {\n try {\n const dbKey = resolveDbCacheKey(this.db);\n invalidateCollectionCache(dbKey, this.tableName);\n\n if (this.shouldBroadcastCacheInvalidation(dbKey)) {\n void broadcastCacheInvalidation(this.db, this.tableName);\n }\n } catch (error) {\n logger.warn('Failed to invalidate collection read cache after write', {\n table: this.tableName,\n error: error instanceof Error ? error.message : error,\n });\n }\n }\n\n /**\n * Decide whether a mutation should broadcast a cross-process cache\n * invalidation. Invalidation is table-scoped, so the decision must be too:\n *\n * 1. A per-call `crossProcess` cached read in this process registered\n * interest in the table — broadcast even without model-level config.\n * 2. This class's resolved `@smrt({ cache })` config sets `crossProcess`.\n * 3. Any other STI hierarchy member sharing the table resolves to a\n * `crossProcess` config — a child that opted out with `cache: false`\n * still mutates the shared table its base/siblings are caching.\n */\n private shouldBroadcastCacheInvalidation(dbKey: string): boolean {\n if (hasCrossProcessCacheInterest(dbKey, this.tableName)) {\n return true;\n }\n\n const qualifiedName = this.getResolvedQualifiedName();\n if (\n ObjectRegistry.resolveCollectionCacheConfig(qualifiedName)?.crossProcess\n ) {\n return true;\n }\n\n for (const member of getSTIHierarchyMembers(qualifiedName)) {\n if (member === qualifiedName) continue;\n if (ObjectRegistry.resolveCollectionCacheConfig(member)?.crossProcess) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Check if a relationship has been loaded\n *\n * @param fieldName - Name of the relationship field\n * @returns True if the relationship is loaded, false otherwise\n * @example\n * ```typescript\n * if (order.isRelatedLoaded('customer')) {\n * console.log('Customer already loaded');\n * }\n * ```\n */\n public isRelatedLoaded(fieldName: string): boolean {\n return this._loadedRelationships.has(fieldName);\n }\n\n /**\n * Lazy-loads a `foreignKey` or `crossPackageRef` relationship and caches the\n * result.\n *\n * Looks up the relationship metadata in the ObjectRegistry, reads the\n * foreign key value on this object, and fetches the related object from\n * the database. Subsequent calls return the cached value without hitting\n * the database again.\n *\n * For STI relationships, the correct subclass is determined by reading\n * `_meta_type` from the database row before instantiation.\n *\n * Enforces tenant isolation: if this object and the loaded target both carry\n * a non-null `tenantId` that differ, a {@link TenantIsolationError} is thrown\n * (unless `opts.allowCrossTenant` is set). The check is a no-op for\n * global/null-tenant models and same-tenant loads, so it only catches genuine\n * cross-tenant leaks (Issue #1321).\n *\n * @param fieldName - Name of the `@foreignKey()` or `@crossPackageRef()`\n * decorated property\n * @param opts - Optional loader options; see {@link LoadRelatedOptions}\n * @returns The related object, or `null` if the foreign key is empty\n * @throws {RuntimeError} If `fieldName` is not a `foreignKey` or\n * `crossPackageRef` relationship, or the target class is not found in the\n * ObjectRegistry\n * @throws {TenantIsolationError} If the target belongs to a different,\n * non-null tenant and `opts.allowCrossTenant` is not set\n *\n * @example\n * ```typescript\n * // class Order { @foreignKey(Customer) customerId: string = ''; }\n * const customer = await order.loadRelated('customerId');\n * console.log(customer?.name);\n * ```\n *\n * @see {@link getRelated} for a convenience wrapper that auto-detects relationship type\n */\n public async loadRelated(\n fieldName: string,\n opts?: LoadRelatedOptions,\n ): Promise<any> {\n // Check if already loaded\n if (this._loadedRelationships.has(fieldName)) {\n const cached = this._loadedRelationships.get(fieldName);\n // Re-validate cached targets: a cache populated by an eager `include`\n // load (or a prior allowCrossTenant load) must not leak cross-tenant data\n // through a later guarded call (Issue #1321).\n this.assertRelatedTenant(cached, fieldName, opts?.allowCrossTenant);\n return cached;\n }\n\n // Ensure manifest is loaded for external packages before accessing relationships\n // This is critical for cross-package relationship resolution (Issue #746)\n await ObjectRegistry.ensureManifestLoaded(this.constructor.name);\n\n // Get relationship metadata from ObjectRegistry\n const relationships = ObjectRegistry.getRelationships(\n this.constructor.name,\n );\n const relationship = relationships.find(\n (r) =>\n r.fieldName === fieldName &&\n (r.type === 'foreignKey' || r.type === 'crossPackageRef'),\n );\n\n if (!relationship) {\n throw RuntimeError.invalidState(\n `Field ${fieldName} is not a foreignKey or crossPackageRef relationship on ${this.constructor.name}`,\n { fieldName, className: this.constructor.name },\n );\n }\n\n // Get the foreign key value\n const foreignKeyValue = this[fieldName as keyof this];\n if (!foreignKeyValue) {\n // No related object (foreign key is null)\n this._loadedRelationships.set(fieldName, null);\n return null;\n }\n\n // For crossPackageRef, the target is a qualified name and the target package's\n // manifest may not be loaded yet — ensure it's available before lookup.\n if (relationship.type === 'crossPackageRef') {\n await ObjectRegistry.ensureManifestLoaded(relationship.targetClass);\n }\n\n // Get the target class constructor (try qualified name first for crossPackageRef)\n const targetClassInfo =\n relationship.type === 'crossPackageRef'\n ? (ObjectRegistry.getClassByQualifiedName(relationship.targetClass) ??\n ObjectRegistry.getClass(relationship.targetClass))\n : ObjectRegistry.getClass(relationship.targetClass);\n if (!targetClassInfo) {\n throw RuntimeError.invalidState(\n `Target class ${relationship.targetClass} not found in ObjectRegistry`,\n { targetClass: relationship.targetClass, fieldName },\n );\n }\n\n // Check if target class uses STI (Single Table Inheritance)\n const tableStrategy = ObjectRegistry.getTableStrategy(\n relationship.targetClass,\n );\n const isSTI = tableStrategy === 'sti';\n\n // For STI classes, we need to determine the actual subclass from the database row\n let actualClassInfo = targetClassInfo;\n if (isSTI) {\n // First, fetch just the row to get the _meta_type discriminator\n const tempInstance = new targetClassInfo.constructor(this.options);\n await tempInstance.initialize();\n await tempInstance.verifyStorageReady();\n const row = await tempInstance.db.get(tempInstance.tableName, {\n id: foreignKeyValue as string,\n });\n\n if (row?._meta_type) {\n // Get the actual class from the registry based on _meta_type\n // Support both qualified names (new format: @pkg:Class) and simple names (legacy)\n let actualClass = ObjectRegistry.getClassByQualifiedName(\n row._meta_type,\n );\n if (!actualClass) {\n // Fall back to simple name lookup for legacy data\n actualClass = ObjectRegistry.getClass(row._meta_type);\n }\n if (actualClass) {\n actualClassInfo = actualClass;\n }\n }\n }\n\n // Create an instance of the correct class and load by ID\n const relatedInstance = new actualClassInfo.constructor(this.options);\n await relatedInstance.initialize();\n relatedInstance.id = foreignKeyValue as string;\n await relatedInstance.loadFromId();\n\n // Enforce tenant isolation before caching/returning so a blocked\n // cross-tenant target is never cached (Issue #1321).\n this.assertRelatedTenant(\n relatedInstance,\n fieldName,\n opts?.allowCrossTenant,\n );\n\n // Cache the loaded object\n this._loadedRelationships.set(fieldName, relatedInstance);\n return relatedInstance;\n }\n\n /**\n * Guards a loaded relationship target against cross-tenant access.\n *\n * Throws {@link TenantIsolationError} when this object and `loaded` both carry\n * a non-null `tenantId` that differ — the genuine cross-tenant leak. It is a\n * no-op when `allowCrossTenant === true`, when `loaded` is `null`, when either\n * side has a `null`/`undefined` tenant (global / non-tenant-scoped models),\n * and when both sides share the same tenant (Issue #1321).\n *\n * `loaded` may be a single related object or an array (oneToMany / manyToMany);\n * arrays are validated per item. This runs on both fresh loads and cache hits,\n * so a cache populated by an eager `include` load — or by a prior\n * `allowCrossTenant` load — cannot leak cross-tenant data through a later\n * guarded call.\n *\n * @param loaded - The loaded related object, or array of objects.\n * @param fieldName - The relationship field name (for error context).\n * @param allowCrossTenant - When exactly `true`, bypasses the guard entirely.\n */\n private assertRelatedTenant(\n loaded: unknown,\n fieldName: string,\n allowCrossTenant?: boolean,\n ): void {\n // Strict `=== true`: only the documented opt-in bypasses the guard, never an\n // incidental truthy value passed from untyped JS callers.\n if (allowCrossTenant === true || loaded == null) {\n return;\n }\n\n if (Array.isArray(loaded)) {\n for (const item of loaded) {\n this.assertRelatedTenant(item, fieldName, allowCrossTenant);\n }\n return;\n }\n\n const sourceTenantId = (this as { tenantId?: unknown }).tenantId;\n const targetTenantId = (loaded as { tenantId?: unknown }).tenantId;\n\n if (\n sourceTenantId != null &&\n targetTenantId != null &&\n sourceTenantId !== targetTenantId\n ) {\n throw TenantIsolationError.crossTenantReference({\n sourceClass: this.constructor.name,\n fieldName,\n sourceTenantId: String(sourceTenantId),\n targetClass: (loaded as { constructor?: { name?: string } })\n ?.constructor?.name,\n targetTenantId: String(targetTenantId),\n });\n }\n }\n\n /**\n * Load related objects for oneToMany or manyToMany fields (lazy loading)\n *\n * Loads all related objects from the database. For oneToMany, queries by\n * the inverse foreign key. For manyToMany, queries through the join table.\n *\n * Enforces tenant isolation per item: if this object and a loaded target both\n * carry a non-null `tenantId` that differ, a {@link TenantIsolationError} is\n * thrown (unless `opts.allowCrossTenant` is set). The check is a no-op for\n * global/null-tenant models and same-tenant loads, so it only catches genuine\n * cross-tenant leaks (Issue #1321).\n *\n * @param fieldName - Name of the oneToMany or manyToMany field\n * @param opts - Optional loader options; see {@link LoadRelatedOptions}\n * @returns Promise resolving to array of related objects\n * @throws {RuntimeError} If the field is not a relationship or not implemented\n * @throws {TenantIsolationError} If any loaded item belongs to a different,\n * non-null tenant and `opts.allowCrossTenant` is not set\n * @example\n * ```typescript\n * // Given: class Customer with orders = oneToMany(Order)\n * const orders = await customer.loadRelatedMany('orders');\n * console.log(`${orders.length} orders found`);\n * ```\n */\n public async loadRelatedMany(\n fieldName: string,\n opts?: LoadRelatedOptions,\n ): Promise<any[]> {\n // Check if already loaded\n if (this._loadedRelationships.has(fieldName)) {\n const cached = this._loadedRelationships.get(fieldName);\n // Re-validate cached targets: a cache populated by an eager `include`\n // load (or a prior allowCrossTenant load) must not leak cross-tenant data\n // through a later guarded call (Issue #1321).\n this.assertRelatedTenant(cached, fieldName, opts?.allowCrossTenant);\n return cached;\n }\n\n // Ensure manifest is loaded for external packages before accessing relationships\n // This is critical for cross-package relationship resolution (Issue #746)\n await ObjectRegistry.ensureManifestLoaded(this.constructor.name);\n\n // Get relationship metadata from ObjectRegistry\n const relationships = ObjectRegistry.getRelationships(\n this.constructor.name,\n );\n const relationship = relationships.find((r) => r.fieldName === fieldName);\n\n if (!relationship) {\n throw RuntimeError.invalidState(\n `Field ${fieldName} is not a relationship on ${this.constructor.name}`,\n { fieldName, className: this.constructor.name },\n );\n }\n\n if (relationship.type === 'oneToMany') {\n // Find the inverse foreignKey field on the target class. An instance can\n // satisfy an inverse FK that targets its own class OR any (STI) ancestor\n // it inherits the oneToMany from — the FK is declared against the base\n // class name, while `this.constructor.name` may be a subclass (e.g. a\n // Person inheriting Profile.relationshipsFrom).\n const inverseRelationships =\n ObjectRegistry.getInverseRelationshipsForSelf(this.constructor.name);\n const inverseCandidates = inverseRelationships.filter(\n (r) =>\n r.sourceClass === relationship.targetClass && r.type === 'foreignKey',\n );\n // When the target declares multiple foreign keys back to this class\n // (e.g. ProfileRelationship.fromProfileId / toProfileId), honor an\n // explicit `@oneToMany(Target, { foreignKey })` to pick the right side.\n // Otherwise fall back to the first match (legacy behavior).\n const explicitForeignKey = relationship.options?.foreignKey as\n | string\n | undefined;\n const matchedForeignKey = explicitForeignKey\n ? inverseCandidates.find((r) => r.fieldName === explicitForeignKey)\n : undefined;\n if (explicitForeignKey && !matchedForeignKey) {\n // A misspelled / stale `foreignKey` must fail loudly rather than\n // silently resolving the wrong inverse side.\n throw RuntimeError.invalidState(\n `oneToMany ${fieldName} on ${this.constructor.name} specifies foreignKey '${explicitForeignKey}', but ${relationship.targetClass} has no matching inverse foreignKey. Candidates: ${inverseCandidates.map((r) => r.fieldName).join(', ') || '(none)'}`,\n {\n fieldName,\n targetClass: relationship.targetClass,\n foreignKey: explicitForeignKey,\n },\n );\n }\n // Prefer an inverse FK that targets this exact class before falling back\n // to one inherited from an (STI) ancestor — preserves the pre-fallback\n // selection when a target declares FKs to multiple levels of the chain.\n const inverseForeignKey =\n matchedForeignKey ??\n inverseCandidates.find(\n (r) => r.targetClass === this.constructor.name,\n ) ??\n inverseCandidates[0];\n\n if (!inverseForeignKey) {\n throw RuntimeError.invalidState(\n `Could not find inverse foreignKey on ${relationship.targetClass} for oneToMany relationship ${fieldName}`,\n { fieldName, targetClass: relationship.targetClass },\n );\n }\n\n // Get or create cached collection instance\n const collection = await ObjectRegistry.getCollection(\n relationship.targetClass,\n this.options,\n );\n\n // Query using the inverse foreign key\n const relatedObjects = await collection.list({\n where: { [inverseForeignKey.fieldName]: this.id },\n });\n\n // Enforce tenant isolation per item before caching (Issue #1321).\n this.assertRelatedTenant(\n relatedObjects,\n fieldName,\n opts?.allowCrossTenant,\n );\n\n // Cache the loaded objects\n this._loadedRelationships.set(fieldName, relatedObjects);\n return relatedObjects;\n }\n\n if (relationship.type === 'manyToMany') {\n const { through, sourceColumn, targetColumn, targetClassName } =\n await this.resolveManyToManyJoin(fieldName, relationship);\n\n if (!this.id) {\n // No id yet — there can't be any join rows pointing at this instance.\n this._loadedRelationships.set(fieldName, []);\n return [];\n }\n\n await this.verifyStorageReady();\n\n const junctionRows = await this.db.query(\n `SELECT \"${targetColumn}\" FROM \"${through}\" WHERE \"${sourceColumn}\" = ?`,\n [this.id],\n );\n\n const targetIds = junctionRows.rows\n .map((row: any) => row[targetColumn])\n .filter(\n (id: any): id is string => typeof id === 'string' && id.length > 0,\n );\n\n if (targetIds.length === 0) {\n this._loadedRelationships.set(fieldName, []);\n return [];\n }\n\n const targetCollection = await ObjectRegistry.getCollection(\n targetClassName,\n this.options,\n );\n const targetObjects = await targetCollection.list({\n where: { 'id in': targetIds },\n });\n\n // Enforce tenant isolation per item before caching (Issue #1321).\n this.assertRelatedTenant(\n targetObjects,\n fieldName,\n opts?.allowCrossTenant,\n );\n\n this._loadedRelationships.set(fieldName, targetObjects);\n return targetObjects;\n }\n\n throw RuntimeError.invalidState(\n `Field ${fieldName} is not a oneToMany or manyToMany relationship`,\n { fieldName, type: relationship.type },\n );\n }\n\n /**\n * Resolves the junction-table coordinates for a manyToMany relationship.\n *\n * Discovers `through`, source-side column, and target-side column from the\n * registered field metadata. Falls back to convention (`<class>_id`) when\n * `sourceKey` / `targetKey` are not explicitly set.\n */\n protected async resolveManyToManyJoin(\n fieldName: string,\n relationship: {\n sourceClass: string;\n targetClass: string;\n options?: any;\n },\n ): Promise<{\n through: string;\n sourceColumn: string;\n targetColumn: string;\n targetClassName: string;\n }> {\n const decorator = ObjectRegistry.getFieldDecorator(\n relationship.sourceClass,\n fieldName,\n );\n const opts = relationship.options || {};\n\n const through = decorator?.through ?? opts.through ?? opts._meta?.through;\n if (!through) {\n throw RuntimeError.invalidState(\n `manyToMany field ${fieldName} on ${relationship.sourceClass} is missing the 'through' join table name`,\n { fieldName, type: 'manyToMany' },\n );\n }\n\n // For cross-package qualified targets, derive the simple name for column conventions\n const targetSimpleName = relationship.targetClass.includes(':')\n ? relationship.targetClass.split(':').pop()!\n : relationship.targetClass;\n const sourceSimpleName = relationship.sourceClass.includes(':')\n ? relationship.sourceClass.split(':').pop()!\n : relationship.sourceClass;\n\n const sourceColumn =\n decorator?.sourceKey ??\n opts.sourceKey ??\n opts._meta?.sourceKey ??\n `${toSnakeCase(sourceSimpleName)}_id`;\n const targetColumn =\n decorator?.targetKey ??\n opts.targetKey ??\n opts._meta?.targetKey ??\n `${toSnakeCase(targetSimpleName)}_id`;\n\n return {\n through: String(through),\n sourceColumn,\n targetColumn,\n targetClassName: relationship.targetClass,\n };\n }\n\n /**\n * Get a related object, loading it if not already loaded\n *\n * Convenience method that checks if the relationship is loaded and\n * loads it if necessary. Automatically detects foreignKey vs oneToMany/manyToMany.\n *\n * Tenant isolation is enforced by the underlying loaders; see\n * {@link loadRelated} and {@link loadRelatedMany}.\n *\n * @param fieldName - Name of the relationship field\n * @param opts - Optional loader options; see {@link LoadRelatedOptions}\n * @returns Promise resolving to the related object(s)\n * @throws {TenantIsolationError} If a loaded target belongs to a different,\n * non-null tenant and `opts.allowCrossTenant` is not set\n * @example\n * ```typescript\n * // Loads customer if not already loaded\n * const customer = await order.getRelated('customerId');\n *\n * // Loads orders if not already loaded\n * const orders = await customer.getRelated('orders');\n * ```\n */\n public async getRelated(\n fieldName: string,\n opts?: LoadRelatedOptions,\n ): Promise<any> {\n if (this._loadedRelationships.has(fieldName)) {\n const cached = this._loadedRelationships.get(fieldName);\n // Re-validate cached targets so an eager `include` load cannot leak\n // cross-tenant data through this convenience accessor (Issue #1321).\n this.assertRelatedTenant(cached, fieldName, opts?.allowCrossTenant);\n return cached;\n }\n\n // Ensure manifest is loaded for external packages before accessing relationships\n // This is critical for cross-package relationship resolution (Issue #746)\n await ObjectRegistry.ensureManifestLoaded(this.constructor.name);\n\n // Determine relationship type\n const relationships = ObjectRegistry.getRelationships(\n this.constructor.name,\n );\n const relationship = relationships.find((r) => r.fieldName === fieldName);\n\n if (!relationship) {\n throw RuntimeError.invalidState(\n `Field ${fieldName} is not a relationship on ${this.constructor.name}`,\n { fieldName, className: this.constructor.name },\n );\n }\n\n // Load based on relationship type\n if (\n relationship.type === 'foreignKey' ||\n relationship.type === 'crossPackageRef'\n ) {\n return this.loadRelated(fieldName, opts);\n }\n\n return this.loadRelatedMany(fieldName, opts);\n }\n\n /**\n * Get available AI-callable tools for this object\n *\n * Returns the pre-generated tool definitions from the manifest.\n * Tools are generated at build time based on the @smrt decorator's AI config.\n *\n * @returns Array of AITool definitions for LLM function calling\n * @example\n * ```typescript\n * const tools = document.getAvailableTools();\n * console.log(`${tools.length} AI-callable methods available`);\n * ```\n */\n public getAvailableTools(): AITool[] {\n const classInfo = ObjectRegistry.getClass(this.constructor.name);\n return classInfo?.tools || [];\n }\n\n /**\n * Execute a tool call from AI on this object instance\n *\n * Validates the tool call against allowed methods and executes it with\n * proper error handling and timing.\n *\n * @param toolCall - Tool call from AI response\n * @returns Promise resolving to the tool call result\n * @example\n * ```typescript\n * const toolCall = {\n * id: 'call_123',\n * type: 'function',\n * function: {\n * name: 'analyze',\n * arguments: '{\"type\": \"detailed\"}'\n * }\n * };\n *\n * const result = await document.executeToolCall(toolCall);\n * console.log(result.success ? result.result : result.error);\n * ```\n */\n public async executeToolCall(toolCall: ToolCall): Promise<ToolCallResult> {\n const tools = this.getAvailableTools();\n const allowedMethods = tools.map((tool) => tool.function.name);\n\n return executeToolCallInternal(this, toolCall, allowedMethods);\n }\n\n /**\n * Stores a named value in the `_smrt_contexts` system table, scoped to this object.\n *\n * Context entries are keyed by `(owner_class, owner_id, scope, key, version)` and\n * support an optional `confidence` score (0–1, default 1.0) for learned patterns.\n * Calling `remember()` with the same scope+key upserts the existing entry.\n *\n * Requires `initialize()` to have been called (needs `this.systemDb`).\n *\n * @param options.id - Optional explicit ID for the context entry (auto-generated if omitted)\n * @param options.scope - Hierarchical path scoping the context (e.g. `'parser/example.com'`)\n * @param options.key - Lookup key within the scope (e.g. a normalized URL)\n * @param options.value - Any JSON-serializable value to store\n * @param options.metadata - Optional additional JSON metadata\n * @param options.confidence - Confidence score (0–1, default 1.0)\n * @param options.version - Schema version for the stored value (default 1)\n * @param options.expiresAt - Optional expiry date after which `recall()` will ignore this entry\n * @returns Promise that resolves when the context is stored\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * await agent.remember({\n * scope: 'parser/example.com',\n * key: normalizedUrl,\n * value: { patterns: ['regex1', 'regex2'] },\n * confidence: 0.9,\n * });\n * ```\n *\n * @see {@link recall} to retrieve a single entry\n * @see {@link recallAll} to retrieve all entries in a scope\n * @see {@link forget} to delete a specific entry\n */\n public async remember(options: {\n id?: string;\n scope: string;\n key: string;\n value: any;\n metadata?: any;\n confidence?: number;\n version?: number;\n expiresAt?: Date;\n }): Promise<void> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n const id = options.id || crypto.randomUUID();\n const now = new Date();\n\n // Ensure the object has an ID - generate one if it doesn't exist\n if (!this.id) {\n this._id = crypto.randomUUID();\n }\n\n await this.systemDb.upsert(\n '_smrt_contexts',\n ['owner_class', 'owner_id', 'scope', 'key', 'version'],\n {\n id,\n owner_class: this._className,\n owner_id: this.id,\n scope: options.scope,\n key: options.key,\n value: JSON.stringify(options.value),\n metadata: options.metadata ? JSON.stringify(options.metadata) : null,\n version: options.version ?? 1,\n confidence: options.confidence ?? 1.0,\n created_at: now,\n updated_at: now,\n last_used_at: now,\n expires_at: options.expiresAt ?? null,\n },\n );\n }\n\n /**\n * Retrieves a single remembered context value for this object.\n *\n * Looks up the most recent (highest confidence, then highest version) entry\n * matching `(owner_class, owner_id, scope, key)`. Returns the JSON-parsed value\n * or `null` if no matching entry exists.\n *\n * When `includeAncestors: true`, walks up the scope hierarchy by progressively\n * removing the last path segment (e.g. `'a/b/c'` → `'a/b'` → `'a'` → `'global'`)\n * until a match is found.\n *\n * @param options.scope - Scope path to search (e.g. `'parser/example.com/article'`)\n * @param options.key - Lookup key within the scope\n * @param options.includeAncestors - If `true`, fall back to parent scopes (default `false`)\n * @param options.minConfidence - Only return entries at or above this confidence (0–1)\n * @returns The stored value (parsed from JSON), or `null` if not found\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * const strategy = await agent.recall({\n * scope: 'parser/example.com/article',\n * key: normalizedUrl,\n * includeAncestors: true,\n * minConfidence: 0.6,\n * });\n * ```\n *\n * @see {@link remember} to store a context entry\n * @see {@link recallAll} to retrieve all entries in a scope\n */\n public async recall(options: {\n scope: string;\n key: string;\n includeAncestors?: boolean;\n minConfidence?: number;\n }): Promise<any | null> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n // Use single() with template literals for custom SQL query\n let result: Record<string, any> | null;\n if (options.minConfidence !== undefined) {\n result = await this.systemDb.single`\n SELECT value, confidence\n FROM _smrt_contexts\n WHERE owner_class = ${this._className}\n AND owner_id = ${this.id}\n AND scope = ${options.scope}\n AND key = ${options.key}\n AND confidence >= ${options.minConfidence}\n ORDER BY confidence DESC, version DESC\n LIMIT 1\n `;\n } else {\n result = await this.systemDb.single`\n SELECT value, confidence\n FROM _smrt_contexts\n WHERE owner_class = ${this._className}\n AND owner_id = ${this.id}\n AND scope = ${options.scope}\n AND key = ${options.key}\n ORDER BY confidence DESC, version DESC\n LIMIT 1\n `;\n }\n\n if (result) {\n // Guard against a corrupted _smrt_contexts row: a single malformed value\n // must not throw an uncaught SyntaxError out of recall(). Treat it as a\n // miss and continue to the ancestor fallback (#1378).\n try {\n return JSON.parse(result.value);\n } catch (error) {\n logger.warn('Skipping corrupted _smrt_contexts value in recall()', {\n ownerClass: this._className,\n ownerId: this.id,\n scope: options.scope,\n key: options.key,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Hierarchical fallback to parent scopes\n if (options.includeAncestors) {\n const scopeParts = options.scope.split('/');\n while (scopeParts.length > 0) {\n scopeParts.pop();\n const parentScope = scopeParts.join('/') || 'global';\n\n const parentResult = await this.recall({\n ...options,\n scope: parentScope,\n includeAncestors: false,\n });\n\n if (parentResult) return parentResult;\n }\n }\n\n return null;\n }\n\n /**\n * Retrieves all remembered context entries for this object in a scope.\n *\n * Returns a `Map<key, value>` for every entry owned by this object that matches\n * the scope and optional filters. When `includeDescendants: true`, a LIKE query\n * (`scope%`) matches the scope itself and all child scopes.\n *\n * @param options.scope - Optional scope path filter; omit to retrieve all scopes\n * @param options.includeDescendants - If `true`, match `scope` and all child scopes (default `false`)\n * @param options.minConfidence - Only include entries at or above this confidence (0–1)\n * @returns `Map<string, any>` of key → JSON-parsed value pairs\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * const strategies = await agent.recallAll({\n * scope: 'parser/example.com',\n * minConfidence: 0.5,\n * });\n * for (const [url, pattern] of strategies) {\n * console.log(`Cached pattern for ${url}:`, pattern);\n * }\n * ```\n *\n * @see {@link recall} to retrieve a single entry by key\n * @see {@link forgetScope} to delete all entries in a scope\n */\n public async recallAll(\n options: {\n scope?: string;\n includeDescendants?: boolean;\n minConfidence?: number;\n } = {},\n ): Promise<Map<string, any>> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n const results = new Map<string, any>();\n\n // Build where clause for db.list()\n const where: Record<string, any> = {\n owner_class: this._className,\n owner_id: this.id,\n };\n\n if (options.scope) {\n if (options.includeDescendants) {\n // Use LIKE pattern to match scope and all descendants\n // Pattern 'scope%' matches both 'scope' and 'scope/child'\n where['scope like'] = `${options.scope}%`;\n } else {\n where.scope = options.scope;\n }\n }\n\n if (options.minConfidence !== undefined) {\n where['confidence >='] = options.minConfidence;\n }\n\n const rows = await this.systemDb.list('_smrt_contexts', where);\n\n for (const row of rows) {\n // Skip a corrupted row rather than aborting the whole recallAll() (#1378).\n try {\n results.set(row.key, JSON.parse(row.value));\n } catch (error) {\n logger.warn('Skipping corrupted _smrt_contexts value in recallAll()', {\n ownerClass: this._className,\n ownerId: this.id,\n scope: options.scope,\n key: row.key,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return results;\n }\n\n /**\n * Deletes a specific remembered context entry for this object.\n *\n * Removes the entry matching `(owner_class, owner_id, scope, key)`. A no-op\n * if the entry does not exist.\n *\n * @param options.scope - Scope path of the entry to delete\n * @param options.key - Key of the entry to delete\n * @returns Promise that resolves when the entry is deleted\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * await agent.forget({ scope: 'parser/example.com', key: normalizedUrl });\n * ```\n *\n * @see {@link forgetScope} to delete all entries in a scope at once\n * @see {@link remember} to store a context entry\n */\n public async forget(options: { scope: string; key: string }): Promise<void> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n await this.systemDb.delete('_smrt_contexts', {\n owner_class: this._className,\n owner_id: this.id,\n scope: options.scope,\n key: options.key,\n });\n }\n\n /**\n * Deletes all remembered context entries in a scope for this object.\n *\n * When `includeDescendants: true`, uses a LIKE query (`scope%`) that matches\n * the scope itself and all child scopes (e.g. `'parser/example.com'` also\n * deletes `'parser/example.com/article'`).\n *\n * @param options.scope - Scope path to clear\n * @param options.includeDescendants - If `true`, also delete all child scopes (default `false`)\n * @returns Number of context entries deleted\n * @throws Error if `initialize()` has not been called\n *\n * @example\n * ```typescript\n * const count = await agent.forgetScope({\n * scope: 'parser/example.com',\n * includeDescendants: true,\n * });\n * console.log(`Cleared ${count} cached strategies`);\n * ```\n *\n * @see {@link forget} to delete a single entry by key\n * @see {@link recallAll} to bulk-retrieve before clearing\n */\n public async forgetScope(options: {\n scope: string;\n includeDescendants?: boolean;\n }): Promise<number> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n // Build where clause for db.delete()\n const where: Record<string, any> = {\n owner_class: this._className,\n owner_id: this.id,\n };\n\n if (options.includeDescendants) {\n // Use LIKE pattern to match scope and all descendants\n where['scope like'] = `${options.scope}%`;\n } else {\n where.scope = options.scope;\n }\n\n const result = await this.systemDb.delete('_smrt_contexts', where);\n return result.affected || 0;\n }\n\n // ============================================================================\n // Embedding Methods for Semantic Search\n // ============================================================================\n\n /**\n * Generate embeddings for configured fields\n *\n * Creates embedding vectors for fields configured in the @smrt decorator\n * and stores them in the _smrt_embeddings system table. Uses content hashing\n * to detect changes and avoid regenerating unchanged content.\n *\n * @param options - Generation options\n * @returns Promise that resolves when embeddings are generated\n * @throws Error if no embedding configuration or database not initialized\n *\n * @example\n * ```typescript\n * // Generate embeddings for all configured fields\n * await article.generateEmbeddings();\n *\n * // Generate only for specific fields\n * await article.generateEmbeddings({ fields: ['title'] });\n *\n * // Force regeneration (ignore content hash)\n * await article.generateEmbeddings({ force: true });\n * ```\n */\n public async generateEmbeddings(\n options: GenerateEmbeddingsOptions = {},\n ): Promise<void> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n if (!this.id) {\n throw new Error('Object must have an ID before generating embeddings.');\n }\n\n // Get embedding configuration for this class\n const config = ObjectRegistry.resolveEmbeddingConfig(this.constructor.name);\n if (!config) {\n throw new Error(\n `No embedding configuration found for ${this.constructor.name}. ` +\n `Add embeddings config to the @smrt() decorator.`,\n );\n }\n\n // Determine which fields to process\n const fieldsToProcess = options.fields || config.fields;\n const provider = options.provider || config.provider;\n const aiClient = await this.getOptionalAiClient();\n\n // Create embedding provider\n const embeddingProvider = new EmbeddingProvider(\n {\n dimensions: config.dimensions,\n provider,\n localModel: config.localModel,\n aiModel: config.aiModel,\n fallbackToAI: config.fallbackToAI,\n },\n aiClient,\n );\n\n // Resolve vector capabilities for native storage\n const projectConfig = ObjectRegistry.getProjectEmbeddingConfig();\n const vector =\n projectConfig?.storage === 'native' ? this.systemDb.vector : undefined;\n\n // Process each field\n for (const fieldName of fieldsToProcess) {\n const content = this.getPropertyValue(fieldName);\n if (!content || typeof content !== 'string') {\n continue; // Skip empty or non-string fields\n }\n\n // Check content hash to avoid regenerating unchanged content\n const contentHash = ContentHasher.hash(content);\n\n if (!options.force) {\n const existing = await EmbeddingStorage.get(\n this.systemDb,\n this.constructor.name,\n this.id,\n fieldName,\n embeddingProvider.getModelName(),\n );\n\n if (existing && existing.content_hash === contentHash) {\n continue; // Content unchanged, skip regeneration\n }\n }\n\n // Generate embedding\n const embeddings = await embeddingProvider.embed(content);\n const embedding = embeddings[0];\n\n // Store embedding (with optional native vector storage)\n await EmbeddingStorage.upsert(\n this.systemDb,\n {\n objectClass: this.constructor.name,\n objectId: this.id,\n fieldName,\n contentHash,\n embedding,\n model: embeddingProvider.getModelName(),\n dimensions: config.dimensions,\n provider,\n },\n vector,\n );\n }\n\n // Handle combined field if configured\n if (config.combinedField) {\n const { name, template } = config.combinedField;\n\n // Build combined content from template\n let combinedContent = template;\n for (const fieldName of config.fields) {\n const value = this.getPropertyValue(fieldName) || '';\n combinedContent = combinedContent.replace(\n new RegExp(`\\\\{${fieldName}\\\\}`, 'g'),\n String(value),\n );\n }\n\n if (combinedContent.trim()) {\n const contentHash = ContentHasher.hash(combinedContent);\n\n if (!options.force) {\n const existing = await EmbeddingStorage.get(\n this.systemDb,\n this.constructor.name,\n this.id,\n name,\n embeddingProvider.getModelName(),\n );\n\n if (existing && existing.content_hash === contentHash) {\n return; // Combined content unchanged\n }\n }\n\n const embeddings = await embeddingProvider.embed(combinedContent);\n const embedding = embeddings[0];\n\n await EmbeddingStorage.upsert(\n this.systemDb,\n {\n objectClass: this.constructor.name,\n objectId: this.id,\n fieldName: name,\n contentHash,\n embedding,\n model: embeddingProvider.getModelName(),\n dimensions: config.dimensions,\n provider,\n },\n vector,\n );\n }\n }\n }\n\n /**\n * Get stored embedding for a field\n *\n * Retrieves the embedding vector for a specific field from storage.\n * Returns null if no embedding exists for the field.\n *\n * @param fieldName - Name of the field to get embedding for\n * @param model - Optional model name (defaults to configured model)\n * @returns Promise resolving to embedding vector or null\n *\n * @example\n * ```typescript\n * const embedding = await article.getEmbedding('title');\n * if (embedding) {\n * console.log(`Embedding has ${embedding.length} dimensions`);\n * }\n * ```\n */\n public async getEmbedding(\n fieldName: string,\n model?: string,\n ): Promise<number[] | null> {\n if (!this.systemDb) {\n throw new Error('Database not initialized. Call initialize() first.');\n }\n\n if (!this.id) {\n return null;\n }\n\n // Determine model name using EmbeddingProvider for consistency with generateEmbeddings()\n let modelName = model;\n if (!modelName) {\n const config = ObjectRegistry.resolveEmbeddingConfig(\n this.constructor.name,\n );\n if (config) {\n const aiClient = await this.getOptionalAiClient();\n // Create EmbeddingProvider to get consistent model name\n const provider = new EmbeddingProvider(\n {\n dimensions: config.dimensions,\n provider: config.provider,\n localModel: config.localModel,\n aiModel: config.aiModel,\n fallbackToAI: config.fallbackToAI,\n },\n aiClient,\n );\n modelName = provider.getModelName();\n } else {\n // Fallback to default\n modelName = 'Xenova/bge-base-en-v1.5';\n }\n }\n\n const stored = await EmbeddingStorage.get(\n this.systemDb,\n this.constructor.name,\n this.id,\n fieldName,\n modelName,\n );\n\n return stored?.embedding || null;\n }\n\n /**\n * Check if any embeddings are stale (content has changed)\n *\n * Compares content hashes of configured fields with stored embeddings\n * to determine if regeneration is needed.\n *\n * @returns Promise resolving to true if any embeddings are stale\n *\n * @example\n * ```typescript\n * if (await article.hasStaleEmbeddings()) {\n * await article.generateEmbeddings();\n * }\n * ```\n */\n public async hasStaleEmbeddings(): Promise<boolean> {\n if (!this.systemDb || !this.id) {\n return false;\n }\n\n const config = ObjectRegistry.resolveEmbeddingConfig(this.constructor.name);\n if (!config) {\n return false;\n }\n\n const aiClient = await this.getOptionalAiClient();\n const embeddingProvider = new EmbeddingProvider(\n {\n dimensions: config.dimensions,\n provider: config.provider,\n localModel: config.localModel,\n aiModel: config.aiModel,\n fallbackToAI: config.fallbackToAI,\n },\n aiClient,\n );\n const modelName = embeddingProvider.getModelName();\n\n // Get stored embeddings for this object\n const storedEmbeddings = await EmbeddingStorage.getForObject(\n this.systemDb,\n this.constructor.name,\n this.id,\n );\n\n // Check each configured field\n for (const fieldName of config.fields) {\n const content = this.getPropertyValue(fieldName);\n if (!content || typeof content !== 'string') {\n continue;\n }\n\n const currentHash = ContentHasher.hash(content);\n const stored = storedEmbeddings.find(\n (e) => e.field_name === fieldName && e.model === modelName,\n );\n\n if (!stored) {\n return true; // No embedding exists for the current provider/model\n }\n\n if (stored.content_hash !== currentHash) {\n return true; // Content has changed\n }\n }\n\n // Check combined field if configured\n if (config.combinedField) {\n let combinedContent = config.combinedField.template;\n for (const fieldName of config.fields) {\n const value = this.getPropertyValue(fieldName) || '';\n combinedContent = combinedContent.replace(\n new RegExp(`\\\\{${fieldName}\\\\}`, 'g'),\n String(value),\n );\n }\n\n const currentHash = ContentHasher.hash(combinedContent);\n const stored = storedEmbeddings.find(\n (e) =>\n e.field_name === config.combinedField?.name && e.model === modelName,\n );\n\n if (!stored || stored.content_hash !== currentHash) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Clear all embeddings for this object\n *\n * Removes all stored embeddings from the _smrt_embeddings table.\n * Useful when deleting objects or resetting embedding state.\n *\n * @returns Promise that resolves when embeddings are cleared\n *\n * @example\n * ```typescript\n * await article.clearEmbeddings();\n * ```\n */\n public async clearEmbeddings(): Promise<void> {\n if (!this.systemDb || !this.id) {\n return;\n }\n\n await EmbeddingStorage.deleteForObject(\n this.systemDb,\n this.constructor.name,\n this.id,\n );\n }\n}\n"],"names":["executeToolCallInternal"],"mappings":"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"}
|