@objectstack/objectql 5.0.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/registry.ts","../src/sys-metadata-repository.ts","../src/protocol.ts","../src/engine.ts","../src/hook-wrappers.ts","../src/hook-metrics.ts","../src/hook-binder.ts","../src/validation/record-validator.ts","../src/in-memory-aggregation.ts","../src/metadata-facade.ts","../src/plugin.ts","../src/kernel-factory.ts","../src/util.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ServiceObject, ObjectSchema, ObjectOwnership } from '@objectstack/spec/data';\nimport { ObjectStackManifest, ManifestSchema, InstalledPackage, InstalledPackageSchema } from '@objectstack/spec/kernel';\nimport { AppSchema } from '@objectstack/spec/ui';\n\n/**\n * Reserved namespaces that do not get FQN prefix applied.\n * Objects in these namespaces keep their short names (e.g., \"user\" — short name IS the canonical key).\n */\nexport const RESERVED_NAMESPACES = new Set(['base', 'system']);\n\n/**\n * Default priorities for ownership types.\n */\nexport const DEFAULT_OWNER_PRIORITY = 100;\nexport const DEFAULT_EXTENDER_PRIORITY = 200;\n\n/**\n * Contributor Record\n * Tracks how a package contributes to an object (own or extend).\n */\nexport interface ObjectContributor {\n packageId: string;\n namespace: string;\n ownership: ObjectOwnership;\n priority: number;\n definition: ServiceObject;\n}\n\n/**\n * Compute canonical registry key for an object.\n *\n * Under the current naming convention, object names are canonical identifiers\n * and are used as-is (no namespace__ prefix). The namespace parameter is\n * retained for backward compatibility but no longer affects the returned key.\n *\n * @param namespace - The package namespace (unused, kept for API compatibility)\n * @param shortName - The object's name (already the canonical identifier)\n * @returns The object name unchanged\n *\n * @example\n * computeFQN('crm', 'account') // => 'account'\n * computeFQN(undefined, 'task') // => 'task'\n */\nexport function computeFQN(_namespace: string | undefined, shortName: string): string {\n return shortName;\n}\n\n/**\n * Parse FQN back to namespace and short name.\n * \n * @param fqn - Object name (e.g., \"account\" or legacy \"crm__account\" for backward compat)\n * @returns { namespace, shortName } - namespace is undefined for unprefixed names\n */\nexport function parseFQN(fqn: string): { namespace: string | undefined; shortName: string } {\n const idx = fqn.indexOf('__');\n if (idx === -1) {\n return { namespace: undefined, shortName: fqn };\n }\n return {\n namespace: fqn.slice(0, idx),\n shortName: fqn.slice(idx + 2),\n };\n}\n\n/**\n * Deep merge two ServiceObject definitions.\n * Fields are merged additively. Other props: later value wins.\n */\nfunction mergeObjectDefinitions(base: ServiceObject, extension: Partial<ServiceObject>): ServiceObject {\n const merged = { ...base };\n\n // Merge fields additively\n if (extension.fields) {\n merged.fields = { ...base.fields, ...extension.fields };\n }\n\n // Merge validations additively\n if (extension.validations) {\n merged.validations = [...(base.validations || []), ...extension.validations];\n }\n\n // Merge indexes additively\n if (extension.indexes) {\n merged.indexes = [...(base.indexes || []), ...extension.indexes];\n }\n\n // Override scalar props (last writer wins)\n if (extension.label !== undefined) merged.label = extension.label;\n if (extension.pluralLabel !== undefined) merged.pluralLabel = extension.pluralLabel;\n if (extension.description !== undefined) merged.description = extension.description;\n\n return merged;\n}\n\n/**\n * Global Schema Registry\n * Unified storage for all metadata types (Objects, Apps, Flows, Layouts, etc.)\n * \n * ## Namespace & Ownership Model\n * \n * Objects use a namespace-based FQN system:\n * - `namespace`: Short identifier from package manifest (e.g., \"crm\", \"todo\")\n * - `name`: canonical object name (e.g., \"account\", \"sys_user\")\n * - Reserved namespaces (`base`, `system`) don't get prefixed\n * \n * Ownership modes:\n * - `own`: One package owns the object (creates the table, defines base schema)\n * - `extend`: Multiple packages can extend an object (add fields, merge by priority)\n * \n * ## Package vs App Distinction\n * - **Package**: The unit of installation, stored under type 'package'.\n * Each InstalledPackage wraps a ManifestSchema with lifecycle state.\n * - **App**: A UI navigation shell (AppSchema), registered under type 'apps'.\n * Apps are extracted from packages during registration.\n * - A package may contain 0, 1, or many apps.\n */\nexport type RegistryLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\n/**\n * Construction options for {@link SchemaRegistry}.\n */\nexport interface SchemaRegistryOptions {\n /**\n * Whether the host kernel runs in multi-tenant mode. When `true` (default),\n * the registry auto-injects `organization_id` (lookup → sys_organization)\n * into every registered user object that doesn't already declare it and\n * isn't `managedBy` an external subsystem or explicitly opted-out via\n * `systemFields: false`.\n *\n * Sourced from the `OS_MULTI_TENANT` env var when not explicitly set —\n * matches how the SecurityPlugin and CLI startup banner pick the mode.\n * Pass an explicit boolean to override (useful in tests).\n */\n multiTenant?: boolean;\n}\n\n/**\n * Augment a registered object with implicit system fields.\n *\n * Returns a *new* schema object when fields are added; returns the input\n * unchanged when nothing applies (the cheap path for system tables).\n *\n * Author-declared fields always win — we splice the system fields at the\n * front of the field map, so any same-named author field overwrites them\n * via the natural `{ ...sys, ...authored }` merge.\n *\n * Currently injects:\n * - `organization_id` — multi-tenant deployments. Required-false (the\n * SecurityPlugin populates it on insert; nullable rows are still\n * filtered out by the `tenant_isolation` RLS USING clause).\n * - `created_at` / `created_by` / `updated_at` / `updated_by` — audit\n * fields. Marked `system: true, readonly: true` so detail views can\n * surface them in a dedicated \"System Information\" section while\n * edit forms / drawers filter them out. The driver populates the\n * timestamps; the `*_by` lookups are filled by the runtime when an\n * authenticated session is present (NULL otherwise — e.g. seeded\n * rows).\n */\nexport function applySystemFields(\n schema: ServiceObject,\n opts: { multiTenant: boolean }\n): ServiceObject {\n // 1. Hard opt-out at object level (e.g. seed/migration tables).\n if ((schema as any).systemFields === false) return schema;\n\n // 2. Skip only `better-auth` managed tables. Their column layout is\n // driven by better-auth's own migrations (sys_user, sys_session,\n // sys_organization, …) and injecting extra columns here would\n // collide with what better-auth expects. Other `managedBy` buckets\n // (`platform`, `config`, `system`, `append-only`) all need the\n // tenant + audit columns for multi-tenant isolation and time-travel\n // history — withholding them silently broke RLS reads on\n // sys_audit_log / sys_activity (the SecurityPlugin's\n // field-existence safety net dropped `organization_id =\n // current_user.organization_id` as \"field missing\", producing\n // RLS_DENY_FILTER → 0 rows for every non-admin caller).\n if (schema.managedBy === 'better-auth') return schema;\n\n const sf =\n typeof (schema as any).systemFields === 'object' && (schema as any).systemFields !== null\n ? ((schema as any).systemFields as { tenant?: boolean; audit?: boolean })\n : undefined;\n\n // Honor explicit opt-out via either `systemFields.tenant === false`\n // OR `tenancy.enabled === false`. The latter is the schema-level\n // declaration that the table is a shared/global catalog (e.g.\n // sys_package — the Marketplace registry). Without this, the\n // registry would still inject `organization_id`, and the\n // SecurityPlugin's RLS layer would filter every cross-org read down\n // to 0 rows even though the schema explicitly disabled multi-tenancy.\n const tenancyDisabled = (schema as any).tenancy?.enabled === false;\n const wantTenant = opts.multiTenant && sf?.tenant !== false && !tenancyDisabled;\n const wantAudit = sf?.audit !== false;\n\n const additions: Record<string, any> = {};\n\n if (wantTenant && !schema.fields?.organization_id) {\n additions.organization_id = {\n type: 'lookup',\n reference: 'sys_organization',\n label: 'Organization',\n required: false,\n indexed: true,\n hidden: true,\n readonly: true,\n system: true,\n description: 'Tenant scope (auto-populated by SecurityPlugin on insert).',\n };\n }\n\n if (wantAudit) {\n if (!schema.fields?.created_at) {\n additions.created_at = {\n type: 'datetime',\n label: 'Created At',\n required: false,\n readonly: true,\n system: true,\n description: 'Timestamp when the record was created (auto-populated by the driver).',\n };\n }\n if (!schema.fields?.created_by) {\n additions.created_by = {\n type: 'lookup',\n reference: 'sys_user',\n label: 'Created By',\n required: false,\n readonly: true,\n system: true,\n description: 'User who created the record (populated when an authenticated session is present).',\n };\n }\n if (!schema.fields?.updated_at) {\n additions.updated_at = {\n type: 'datetime',\n label: 'Last Modified At',\n required: false,\n readonly: true,\n system: true,\n description: 'Timestamp of the most recent modification (auto-populated by the driver).',\n };\n }\n if (!schema.fields?.updated_by) {\n additions.updated_by = {\n type: 'lookup',\n reference: 'sys_user',\n label: 'Last Modified By',\n required: false,\n readonly: true,\n system: true,\n description: 'User who last modified the record (populated when an authenticated session is present).',\n };\n }\n }\n\n if (Object.keys(additions).length === 0) return schema;\n\n return {\n ...schema,\n fields: { ...additions, ...(schema.fields ?? {}) },\n };\n}\n\nexport class SchemaRegistry {\n // ==========================================\n // Logging control\n // ==========================================\n\n /** Controls verbosity of registry console messages. Default: 'info'. */\n private _logLevel: RegistryLogLevel = 'info';\n\n /** Whether to auto-inject multi-tenant system fields. */\n private readonly multiTenant: boolean;\n\n constructor(options: SchemaRegistryOptions = {}) {\n if (options.multiTenant !== undefined) {\n this.multiTenant = options.multiTenant;\n } else {\n // Mirror the SecurityPlugin / CLI banner default (env-driven, on by default).\n this.multiTenant =\n String(process.env.OS_MULTI_TENANT ?? 'true').toLowerCase() !== 'false';\n }\n }\n\n get logLevel(): RegistryLogLevel { return this._logLevel; }\n set logLevel(level: RegistryLogLevel) { this._logLevel = level; }\n\n private log(msg: string): void {\n if (this._logLevel === 'silent' || this._logLevel === 'error' || this._logLevel === 'warn') return;\n console.log(msg);\n }\n\n // ==========================================\n // Object-specific storage (Ownership Model)\n // ==========================================\n\n /** FQN → Contributor[] (all packages that own/extend this object) */\n private objectContributors = new Map<string, ObjectContributor[]>();\n\n /** FQN → Merged ServiceObject (cached, invalidated on changes) */\n private mergedObjectCache = new Map<string, ServiceObject>();\n\n /** Namespace → Set<PackageId> (multiple packages can share a namespace) */\n private namespaceRegistry = new Map<string, Set<string>>();\n\n // ==========================================\n // Generic metadata storage (non-object types)\n // ==========================================\n\n /** Type → Name/ID → MetadataItem */\n private metadata = new Map<string, Map<string, any>>();\n\n // ==========================================\n // Namespace Management\n // ==========================================\n\n /**\n * Register a namespace for a package.\n * Multiple packages can share the same namespace (e.g. 'sys').\n */\n registerNamespace(namespace: string, packageId: string): void {\n if (!namespace) return;\n\n let owners = this.namespaceRegistry.get(namespace);\n if (!owners) {\n owners = new Set();\n this.namespaceRegistry.set(namespace, owners);\n }\n owners.add(packageId);\n this.log(`[Registry] Registered namespace: ${namespace} → ${packageId}`);\n }\n\n /**\n * Unregister a namespace when a package is uninstalled.\n */\n unregisterNamespace(namespace: string, packageId: string): void {\n const owners = this.namespaceRegistry.get(namespace);\n if (owners) {\n owners.delete(packageId);\n if (owners.size === 0) {\n this.namespaceRegistry.delete(namespace);\n }\n this.log(`[Registry] Unregistered namespace: ${namespace} ← ${packageId}`);\n }\n }\n\n /**\n * Get the packages that use a namespace.\n */\n getNamespaceOwner(namespace: string): string | undefined {\n const owners = this.namespaceRegistry.get(namespace);\n if (!owners || owners.size === 0) return undefined;\n // Return the first registered package for backwards compatibility\n return owners.values().next().value;\n }\n\n /**\n * Get all packages that share a namespace.\n */\n getNamespaceOwners(namespace: string): string[] {\n const owners = this.namespaceRegistry.get(namespace);\n return owners ? Array.from(owners) : [];\n }\n\n // ==========================================\n // Object Registration (Ownership Model)\n // ==========================================\n\n /**\n * Register an object with ownership semantics.\n * \n * @param schema - The object definition\n * @param packageId - The owning package ID\n * @param namespace - The package namespace (for FQN computation)\n * @param ownership - 'own' (single owner) or 'extend' (additive merge)\n * @param priority - Merge priority (lower applied first, higher wins on conflict)\n * \n * @throws Error if trying to 'own' an object that already has an owner\n */\n registerObject(\n schema: ServiceObject,\n packageId: string,\n namespace?: string,\n ownership: ObjectOwnership = 'own',\n priority: number = ownership === 'own' ? DEFAULT_OWNER_PRIORITY : DEFAULT_EXTENDER_PRIORITY\n ): string {\n // Apply system-field injection (multi-tenant org_id, future owner/audit)\n // BEFORE FQN computation and contributor storage so every consumer of\n // the registered schema (driver syncSchema, REST projector, hooks)\n // sees the same canonical shape. Author-declared fields win — see\n // applySystemFields().\n schema = applySystemFields(schema, { multiTenant: this.multiTenant });\n\n const shortName = schema.name;\n const fqn = computeFQN(namespace, shortName);\n\n // Ensure namespace is registered\n if (namespace) {\n this.registerNamespace(namespace, packageId);\n }\n\n // Get or create contributor list\n let contributors = this.objectContributors.get(fqn);\n if (!contributors) {\n contributors = [];\n this.objectContributors.set(fqn, contributors);\n }\n\n // Validate ownership rules\n if (ownership === 'own') {\n const existingOwner = contributors.find(c => c.ownership === 'own');\n if (existingOwner && existingOwner.packageId !== packageId) {\n throw new Error(\n `Object \"${fqn}\" is already owned by package \"${existingOwner.packageId}\". ` +\n `Package \"${packageId}\" cannot claim ownership. Use 'extend' to add fields.`\n );\n }\n // Remove existing owner contribution from same package (re-registration)\n const idx = contributors.findIndex(c => c.packageId === packageId && c.ownership === 'own');\n if (idx !== -1) {\n contributors.splice(idx, 1);\n console.warn(`[Registry] Re-registering owned object: ${fqn} from ${packageId}`);\n }\n } else {\n // extend mode: remove existing extension from same package\n const idx = contributors.findIndex(c => c.packageId === packageId && c.ownership === 'extend');\n if (idx !== -1) {\n contributors.splice(idx, 1);\n }\n }\n\n // Add new contributor\n const contributor: ObjectContributor = {\n packageId,\n namespace: namespace || '',\n ownership,\n priority,\n definition: { ...schema, name: fqn }, // Store with FQN as name\n };\n contributors.push(contributor);\n\n // Sort by priority (ascending: lower priority applied first)\n contributors.sort((a, b) => a.priority - b.priority);\n\n // Invalidate merge cache\n this.mergedObjectCache.delete(fqn);\n\n this.log(`[Registry] Registered object: ${fqn} (${ownership}, priority=${priority}) from ${packageId}`);\n return fqn;\n }\n\n /**\n * Resolve an object by FQN, merging all contributions.\n * Returns the merged object or undefined if not found.\n */\n resolveObject(fqn: string): ServiceObject | undefined {\n // Check cache first\n const cached = this.mergedObjectCache.get(fqn);\n if (cached) return cached;\n\n const contributors = this.objectContributors.get(fqn);\n if (!contributors || contributors.length === 0) {\n return undefined;\n }\n\n // Find owner (must exist for a valid object)\n const ownerContrib = contributors.find(c => c.ownership === 'own');\n if (!ownerContrib) {\n console.warn(`[Registry] Object \"${fqn}\" has extenders but no owner. Skipping.`);\n return undefined;\n }\n\n // Start with owner's definition\n let merged = { ...ownerContrib.definition };\n\n // Apply extensions in priority order (already sorted)\n for (const contrib of contributors) {\n if (contrib.ownership === 'extend') {\n merged = mergeObjectDefinitions(merged, contrib.definition);\n }\n }\n\n // Cache the result\n this.mergedObjectCache.set(fqn, merged);\n return merged;\n }\n\n /**\n * Get object by name (short name canonical, FQN supported for disambiguation).\n *\n * Short names are canonical for user code, AI generation, and most lookups.\n * FQN is accepted as an explicit fallback for cross-package disambiguation\n * when two packages contribute objects with the same short name.\n *\n * Resolution order:\n * 1. Exact name match — the name IS the canonical key.\n * If multiple packages contribute the same short name, a warning is logged\n * and the first match wins — disambiguate by passing the FQN explicitly.\n * 2. Legacy FQN match (e.g., 'crm__account') — backward compat.\n */\n getObject(name: string): ServiceObject | undefined {\n // Canonical: short name lookup\n const matches: string[] = [];\n for (const fqn of this.objectContributors.keys()) {\n const { shortName } = parseFQN(fqn);\n if (shortName === name) {\n matches.push(fqn);\n }\n }\n if (matches.length > 0) {\n if (matches.length > 1) {\n console.warn(\n `[SchemaRegistry] Ambiguous short name \"${name}\" matches: ${matches.join(', ')}. ` +\n `Returning first match. Use FQN to disambiguate.`\n );\n }\n return this.resolveObject(matches[0]);\n }\n\n // Fallback: explicit FQN\n return this.resolveObject(name);\n }\n\n /**\n * Get all registered objects (merged).\n * \n * @param packageId - Optional filter: only objects contributed by this package\n */\n getAllObjects(packageId?: string): ServiceObject[] {\n const results: ServiceObject[] = [];\n\n for (const fqn of this.objectContributors.keys()) {\n // If filtering by package, check if this package contributes\n if (packageId) {\n const contributors = this.objectContributors.get(fqn);\n const hasContribution = contributors?.some(c => c.packageId === packageId);\n if (!hasContribution) continue;\n }\n\n const merged = this.resolveObject(fqn);\n if (merged) {\n // Tag with contributor info for UI\n (merged as any)._packageId = this.getObjectOwner(fqn)?.packageId;\n results.push(merged);\n }\n }\n\n return results;\n }\n\n /**\n * Get all contributors for an object.\n */\n getObjectContributors(fqn: string): ObjectContributor[] {\n return this.objectContributors.get(fqn) || [];\n }\n\n /**\n * Get the owner contributor for an object.\n */\n getObjectOwner(fqn: string): ObjectContributor | undefined {\n const contributors = this.objectContributors.get(fqn);\n return contributors?.find(c => c.ownership === 'own');\n }\n\n /**\n * Unregister all objects contributed by a package.\n * \n * @throws Error if trying to uninstall an owner that has extenders\n */\n unregisterObjectsByPackage(packageId: string, force: boolean = false): void {\n for (const [fqn, contributors] of this.objectContributors.entries()) {\n // Find this package's contributions\n const packageContribs = contributors.filter(c => c.packageId === packageId);\n \n for (const contrib of packageContribs) {\n if (contrib.ownership === 'own' && !force) {\n // Check if there are extenders from other packages\n const otherExtenders = contributors.filter(\n c => c.packageId !== packageId && c.ownership === 'extend'\n );\n if (otherExtenders.length > 0) {\n throw new Error(\n `Cannot uninstall package \"${packageId}\": object \"${fqn}\" is extended by ` +\n `${otherExtenders.map(c => c.packageId).join(', ')}. Uninstall extenders first.`\n );\n }\n }\n\n // Remove contribution\n const idx = contributors.indexOf(contrib);\n if (idx !== -1) {\n contributors.splice(idx, 1);\n this.log(`[Registry] Removed ${contrib.ownership} contribution to ${fqn} from ${packageId}`);\n }\n }\n\n // Clean up empty contributor lists\n if (contributors.length === 0) {\n this.objectContributors.delete(fqn);\n }\n\n // Invalidate cache\n this.mergedObjectCache.delete(fqn);\n }\n }\n\n // ==========================================\n // Generic Metadata (Non-Object Types)\n // ==========================================\n\n /**\n * Universal Register Method for non-object metadata.\n */\n registerItem<T>(type: string, item: T, keyField: keyof T = 'name' as keyof T, packageId?: string) {\n if (!this.metadata.has(type)) {\n this.metadata.set(type, new Map());\n }\n const collection = this.metadata.get(type)!;\n const baseName = String(item[keyField]);\n \n // Tag item with owning package for scoped queries\n if (packageId) {\n (item as any)._packageId = packageId;\n }\n\n // Validation Hook\n try {\n this.validate(type, item);\n } catch (e: any) {\n console.error(`[Registry] Validation failed for ${type} ${baseName}: ${e.message}`);\n }\n\n // Use composite key (packageId:name) when packageId is provided\n const storageKey = packageId ? `${packageId}:${baseName}` : baseName;\n\n if (collection.has(storageKey)) {\n this.log(`[Registry] Overwriting ${type}: ${storageKey}`);\n }\n collection.set(storageKey, item);\n this.log(`[Registry] Registered ${type}: ${storageKey}`);\n }\n\n /**\n * Validate Metadata against Spec Zod Schemas\n */\n validate(type: string, item: any): unknown {\n if (type === 'object') {\n return ObjectSchema.parse(item);\n }\n if (type === 'app') {\n return AppSchema.parse(item);\n }\n if (type === 'package') {\n return InstalledPackageSchema.parse(item);\n }\n if (type === 'plugin') {\n return ManifestSchema.parse(item);\n }\n return true;\n }\n\n /**\n * Universal Unregister Method\n */\n unregisterItem(type: string, name: string) {\n const collection = this.metadata.get(type);\n if (!collection) {\n console.warn(`[Registry] Attempted to unregister non-existent ${type}: ${name}`);\n return;\n }\n if (collection.has(name)) {\n collection.delete(name);\n this.log(`[Registry] Unregistered ${type}: ${name}`);\n return;\n }\n // Scan composite keys\n for (const key of collection.keys()) {\n if (key.endsWith(`:${name}`)) {\n collection.delete(key);\n this.log(`[Registry] Unregistered ${type}: ${key}`);\n return;\n }\n }\n console.warn(`[Registry] Attempted to unregister non-existent ${type}: ${name}`);\n }\n\n /**\n * Universal Get Method\n */\n getItem<T>(type: string, name: string): T | undefined {\n // Special handling for 'object' and 'objects' types - use objectContributors\n if (type === 'object' || type === 'objects') {\n return this.getObject(name) as unknown as T | undefined;\n }\n \n const collection = this.metadata.get(type);\n if (!collection) return undefined;\n const direct = collection.get(name);\n if (direct) return direct as T;\n // Scan for composite keys\n for (const [key, item] of collection) {\n if (key.endsWith(`:${name}`)) return item as T;\n }\n return undefined;\n }\n\n /**\n * Universal List Method\n */\n listItems<T>(type: string, packageId?: string): T[] {\n // Special handling for 'object' and 'objects' types - use objectContributors\n if (type === 'object' || type === 'objects') {\n return this.getAllObjects(packageId) as unknown as T[];\n }\n\n const items = Array.from(this.metadata.get(type)?.values() || []) as T[];\n if (packageId) {\n return items.filter((item: any) => item._packageId === packageId);\n }\n return items;\n }\n\n /**\n * Get all registered metadata types (Kinds)\n */\n getRegisteredTypes(): string[] {\n const types = Array.from(this.metadata.keys());\n // Always include 'object' even if stored separately\n if (!types.includes('object') && this.objectContributors.size > 0) {\n types.push('object');\n }\n return types;\n }\n\n // ==========================================\n // Package Management\n // ==========================================\n\n installPackage(manifest: ObjectStackManifest, settings?: Record<string, any>): InstalledPackage {\n const now = new Date().toISOString();\n const pkg: InstalledPackage = {\n manifest,\n status: 'installed',\n enabled: true,\n installedAt: now,\n updatedAt: now,\n settings,\n };\n \n // Register namespace if present\n if (manifest.namespace) {\n this.registerNamespace(manifest.namespace, manifest.id);\n }\n \n if (!this.metadata.has('package')) {\n this.metadata.set('package', new Map());\n }\n const collection = this.metadata.get('package')!;\n if (collection.has(manifest.id)) {\n console.warn(`[Registry] Overwriting package: ${manifest.id}`);\n }\n collection.set(manifest.id, pkg);\n this.log(`[Registry] Installed package: ${manifest.id} (${manifest.name})`);\n return pkg;\n }\n\n uninstallPackage(id: string): boolean {\n const pkg = this.getPackage(id);\n if (!pkg) {\n console.warn(`[Registry] Package not found for uninstall: ${id}`);\n return false;\n }\n\n // Unregister namespace\n if (pkg.manifest.namespace) {\n this.unregisterNamespace(pkg.manifest.namespace, id);\n }\n\n // Unregister objects (will throw if extenders exist)\n this.unregisterObjectsByPackage(id);\n\n // Remove package record\n const collection = this.metadata.get('package');\n if (collection) {\n collection.delete(id);\n this.log(`[Registry] Uninstalled package: ${id}`);\n return true;\n }\n return false;\n }\n\n getPackage(id: string): InstalledPackage | undefined {\n return this.metadata.get('package')?.get(id) as InstalledPackage | undefined;\n }\n\n getAllPackages(): InstalledPackage[] {\n return this.listItems<InstalledPackage>('package');\n }\n\n enablePackage(id: string): InstalledPackage | undefined {\n const pkg = this.getPackage(id);\n if (pkg) {\n pkg.enabled = true;\n pkg.status = 'installed';\n pkg.statusChangedAt = new Date().toISOString();\n pkg.updatedAt = new Date().toISOString();\n this.log(`[Registry] Enabled package: ${id}`);\n }\n return pkg;\n }\n\n disablePackage(id: string): InstalledPackage | undefined {\n const pkg = this.getPackage(id);\n if (pkg) {\n pkg.enabled = false;\n pkg.status = 'disabled';\n pkg.statusChangedAt = new Date().toISOString();\n pkg.updatedAt = new Date().toISOString();\n this.log(`[Registry] Disabled package: ${id}`);\n }\n return pkg;\n }\n\n // ==========================================\n // App Helpers\n // ==========================================\n\n registerApp(app: any, packageId?: string) {\n this.registerItem('app', app, 'name', packageId);\n }\n\n getApp(name: string): any {\n return this.getItem('app', name);\n }\n\n getAllApps(): any[] {\n return this.listItems('app');\n }\n\n // ==========================================\n // Plugin Helpers\n // ==========================================\n\n registerPlugin(manifest: ObjectStackManifest) {\n this.registerItem('plugin', manifest, 'id');\n }\n\n getAllPlugins(): ObjectStackManifest[] {\n return this.listItems<ObjectStackManifest>('plugin');\n }\n\n // ==========================================\n // Kind Helpers\n // ==========================================\n\n registerKind(kind: { id: string, globs: string[] }) {\n this.registerItem('kind', kind, 'id');\n }\n \n getAllKinds(): { id: string, globs: string[] }[] {\n return this.listItems('kind');\n }\n\n // ==========================================\n // Reset (for testing)\n // ==========================================\n\n /**\n * Invalidate the merged-schema cache for a single FQN (or short name).\n *\n * Call this from event-driven consumers (ADR-0008 M0 PR-7) when an\n * upstream metadata change makes the cached merged definition stale.\n * The contributor list is preserved — only the cached merge result is\n * dropped, so the next `resolveObject(fqn)` recomputes from scratch.\n *\n * Accepts either an FQN (`acme__contact`) or a bare short name\n * (`contact`); for the latter, all entries whose suffix matches the\n * name are invalidated.\n */\n invalidate(fqnOrName: string): void {\n if (this.mergedObjectCache.has(fqnOrName)) {\n this.mergedObjectCache.delete(fqnOrName);\n return;\n }\n // Short-name path: drop any cached merge whose FQN ends with `__<name>` or equals `<name>`.\n const suffix = `__${fqnOrName}`;\n for (const fqn of Array.from(this.mergedObjectCache.keys())) {\n if (fqn === fqnOrName || fqn.endsWith(suffix)) {\n this.mergedObjectCache.delete(fqn);\n }\n }\n }\n\n /** Drop every entry from the merged-schema cache. */\n invalidateAll(): void {\n this.mergedObjectCache.clear();\n }\n\n /**\n * Clear all registry state. Use only for testing.\n */\n reset(): void {\n this.objectContributors.clear();\n this.mergedObjectCache.clear();\n this.namespaceRegistry.clear();\n this.metadata.clear();\n this.log('[Registry] Reset complete');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * ADR-0008 PR-10b — `SysMetadataRepository`.\n *\n * Wraps the existing `sys_metadata` table behind the canonical\n * `MetadataRepository` interface. Implements the *single-row update*\n * semantics that ADR-0005 already ships — append-only event-log\n * persistence is M1 work.\n *\n * What this layer DOES (M0 + M1):\n * - get / put / delete / list against `sys_metadata`\n * - tenancy scope = `organization_id` (per-org overlays only;\n * project/branch concepts removed — see ADR-0008 §0 amendment)\n * - hash stamping with `hashSpec` (PR-10a guarantees stability)\n * - watch() implemented via an in-memory event broadcaster fed by\n * every successful put/delete on THIS instance\n * - whitelist enforcement: refuses to persist types whose registry\n * entry has `allowOrgOverride: false` (Prime Directive #8)\n * - **M1**: every successful put/delete appends a durable row to\n * `sys_metadata_history` inside the same engine.transaction() as the\n * parent `sys_metadata` write. No-op puts (identical hash) skip the\n * history write. Failed optimistic-lock checks abort before any\n * write reaches the database.\n * - **M1**: history() yields events from the durable log, ordered by\n * per-(org,type,name) `version` ASC.\n *\n * What this layer does NOT do (and will not, by design):\n * - cross-replica push notifications (LISTEN/NOTIFY, pub/sub, etc.).\n * The watch() contract is scoped to the local repository instance.\n * Multi-replica deployments are not a supported topology for the\n * metadata overlay — see ADR-0008 §11.\n * - hashSpec backfill for legacy rows missing `checksum`\n *\n * Schema mapping (ADR-0008 PR-10d.2):\n * Repository concept sys_metadata column\n * ─────────────────────── ───────────────────\n * body → metadata (JSON string)\n * hash (sha256) → checksum (text(64))\n * monotonic version int → version (number)\n * org isolation → organization_id (lookup)\n * actor → updated_by (lookup, optional)\n *\n * Composition: PR-10c will compose\n * `LayeredRepository([FileSystemRepository, SysMetadataRepository])`\n * and the manager bridge will route reads through that. Until then this\n * file is intentionally NOT wired into any production path — it has its\n * own test surface so we can build confidence before flipping the\n * switch.\n */\n\nimport { hashSpec, ConflictError } from '@objectstack/metadata-core';\nimport type {\n MetadataRepository,\n MetaRef,\n MetadataItem,\n MetadataItemHeader,\n MetadataEvent,\n PutOptions,\n PutResult,\n DeleteOptions,\n DeleteResult,\n ListFilter,\n WatchFilter,\n HistoryOptions,\n} from '@objectstack/metadata-core';\nimport { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel';\n\n/**\n * Sub-set of the ObjectQL engine shape we depend on. Kept narrow so\n * tests can stub it with a plain mock. Mirrors the real engine's\n * `options.context` pattern so transactions can thread through.\n */\nexport interface SysMetadataEngine {\n find(\n table: string,\n options: { where: Record<string, unknown>; limit?: number; orderBy?: any; context?: any },\n ): Promise<any[]>;\n findOne(\n table: string,\n options: { where: Record<string, unknown>; context?: any },\n ): Promise<any | null>;\n insert(\n table: string,\n data: Record<string, unknown>,\n options?: { context?: any },\n ): Promise<{ id: string }>;\n update(\n table: string,\n data: Record<string, unknown>,\n options: { where: Record<string, unknown>; context?: any },\n ): Promise<{ id: string }>;\n delete(\n table: string,\n options: { where: Record<string, unknown>; context?: any },\n ): Promise<{ deleted: number }>;\n /**\n * Optional. Falls through to direct callback invocation if the\n * underlying driver lacks ACID support (matches the real\n * `ObjectQL.transaction` semantics). Repository code must not rely on\n * rollback for correctness against in-memory drivers.\n */\n transaction?<T>(callback: (trxCtx: any) => Promise<T>, baseContext?: any): Promise<T>;\n}\n\nexport interface SysMetadataRepositoryOptions {\n engine: SysMetadataEngine;\n /**\n * Tenancy scope. `null` writes to env-wide overlay rows; a string\n * scopes to one organization (the supported shared-DB tenant model\n * — see ADR-0005 amendment).\n */\n organizationId?: string | null;\n /** Org label embedded in returned MetaRefs. Defaults to organizationId or `\"system\"`. */\n orgLabel?: string;\n}\n\n/** Derived from registry — single source of truth (Prime Directive #8). */\nconst OVERLAY_ALLOWED_TYPES: ReadonlySet<string> = new Set(\n DEFAULT_METADATA_TYPE_REGISTRY\n .filter((e) => e.allowOrgOverride)\n .map((e) => e.type),\n);\n\nexport class SysMetadataRepository implements MetadataRepository {\n private readonly engine: SysMetadataEngine;\n private readonly organizationId: string | null;\n private readonly orgLabel: string;\n\n /**\n * Local seq counter for in-memory watch() event broadcasts. Mirrors\n * the durable `event_seq` we write into `sys_metadata_history` on\n * each successful put/delete — assigned AFTER the transaction commits\n * so we never broadcast events that got rolled back.\n */\n private seqCounter = 0;\n private readonly watchers = new Set<(evt: MetadataEvent) => void>();\n private closed = false;\n\n /** Table name for the durable event log. */\n private readonly historyTable = 'sys_metadata_history';\n\n constructor(opts: SysMetadataRepositoryOptions) {\n this.engine = opts.engine;\n this.organizationId = opts.organizationId ?? null;\n this.orgLabel = opts.orgLabel ?? (opts.organizationId ?? 'system');\n }\n\n /**\n * Run `cb` inside `engine.transaction(...)` if the engine supports it,\n * otherwise fall through to a direct call. Matches the real\n * `ObjectQL.transaction` semantics — in-memory drivers (and our test\n * fakes) get no rollback, which is acceptable because production\n * always runs on a SQL driver with real ACID.\n */\n private async withTxn<T>(cb: (ctx: any) => Promise<T>): Promise<T> {\n if (typeof this.engine.transaction === 'function') {\n return this.engine.transaction(cb);\n }\n return cb(undefined);\n }\n\n /**\n * Read the current overlay row. Returns null if no row exists —\n * callers (e.g. LayeredRepository) fall through to lower layers.\n */\n async get(ref: MetaRef): Promise<MetadataItem | null> {\n this.assertOpen();\n const row = await this.engine.findOne('sys_metadata', {\n where: this.whereFor(ref),\n });\n if (!row) return null;\n return this.rowToItem(ref, row);\n }\n\n async put(ref: MetaRef, spec: unknown, opts: PutOptions): Promise<PutResult> {\n this.assertOpen();\n this.assertAllowed(ref.type);\n\n const body = (spec ?? {}) as Record<string, unknown>;\n const hash = hashSpec(body);\n\n // Run all reads + writes inside one transaction so the optimistic\n // lock, the parent-row mutation, and the history append are atomic.\n const result = await this.withTxn(async (ctx) => {\n const existing = await this.engine.findOne('sys_metadata', {\n where: this.whereFor(ref),\n context: ctx,\n });\n const existingHash: string | null = existing?.checksum ?? null;\n if (opts.parentVersion !== existingHash) {\n throw new ConflictError(this.fullRef(ref), opts.parentVersion, existingHash);\n }\n\n // No-op short-circuit: identical body → no write, no history row,\n // no event. We re-yield the existing item so callers see the\n // canonical hash but the seqCounter is unchanged.\n if (existing && existingHash === hash) {\n const item = this.rowToItem(ref, existing);\n return { skipped: true as const, version: hash, seq: item.seq, item };\n }\n\n const now = new Date().toISOString();\n const op: 'create' | 'update' = existing ? 'update' : 'create';\n\n // Per-(org,type,name) lineage counter. Use MAX from history so\n // delete+recreate continues incrementing instead of restarting\n // at 1 (which the prior `sys_metadata.version` semantics did).\n const version = await this.nextItemVersion(ref, ctx);\n // Per-org monotonic event log cursor.\n const eventSeq = await this.nextEventSeq(ctx);\n\n const parentRowData: Record<string, unknown> = {\n type: ref.type,\n name: ref.name,\n organization_id: this.organizationId,\n metadata: JSON.stringify(body),\n checksum: hash,\n state: 'active',\n version,\n updated_at: now,\n };\n let parentId: string;\n if (existing) {\n const existingId = (existing as { id?: string }).id;\n if (existingId === undefined) {\n throw new Error(\n `SysMetadataRepository.put: existing row for ${ref.type}/${ref.name} has no id column`,\n );\n }\n parentId = existingId;\n await this.engine.update('sys_metadata', parentRowData, {\n where: { id: existingId },\n context: ctx,\n });\n } else {\n parentRowData.created_at = now;\n const inserted = await this.engine.insert('sys_metadata', parentRowData, { context: ctx });\n parentId = inserted.id;\n }\n\n // Durable history append — same transaction, so the parent write\n // and the audit row commit together or roll back together.\n await this.engine.insert(\n this.historyTable,\n {\n id: this.uuid(),\n event_seq: eventSeq,\n metadata_id: parentId,\n type: ref.type,\n name: ref.name,\n version,\n operation_type: op,\n metadata: JSON.stringify(body),\n checksum: hash,\n previous_checksum: existingHash,\n change_note: opts.message,\n source: opts.source ?? 'sys-metadata-repo',\n organization_id: this.organizationId,\n recorded_by: opts.actor,\n recorded_at: now,\n },\n { context: ctx },\n );\n\n const item: MetadataItem = {\n ref: this.fullRef(ref),\n body,\n hash,\n parentHash: existingHash,\n authoredBy: opts.actor,\n authoredAt: now,\n message: opts.message,\n seq: eventSeq,\n };\n\n return {\n skipped: false as const,\n version: hash,\n seq: eventSeq,\n item,\n op,\n existingHash,\n now,\n source: opts.source ?? 'sys-metadata-repo',\n message: opts.message,\n actor: opts.actor,\n };\n });\n\n if (result.skipped) {\n return { version: result.version, seq: result.seq, item: result.item };\n }\n\n // Broadcast AFTER commit. seqCounter tracks the durable event_seq\n // so watch() consumers and history() consumers see the same cursor.\n this.seqCounter = result.seq;\n this.broadcast({\n seq: result.seq,\n op: result.op,\n ref: this.fullRef(ref),\n hash: result.version,\n parentHash: result.existingHash,\n actor: result.actor,\n message: result.message,\n ts: result.now,\n source: result.source,\n });\n\n return { version: result.version, seq: result.seq, item: result.item };\n }\n\n async delete(ref: MetaRef, opts: DeleteOptions): Promise<DeleteResult> {\n this.assertOpen();\n this.assertAllowed(ref.type);\n\n const result = await this.withTxn(async (ctx) => {\n const existing = await this.engine.findOne('sys_metadata', {\n where: this.whereFor(ref),\n context: ctx,\n });\n if (!existing) {\n throw new ConflictError(this.fullRef(ref), opts.parentVersion, null);\n }\n const existingHash: string | null = existing.checksum ?? null;\n if (opts.parentVersion !== existingHash) {\n throw new ConflictError(this.fullRef(ref), opts.parentVersion, existingHash);\n }\n\n const existingId = (existing as { id?: string }).id;\n if (existingId === undefined) {\n throw new Error(\n `SysMetadataRepository.delete: existing row for ${ref.type}/${ref.name} has no id column`,\n );\n }\n\n const now = new Date().toISOString();\n const version = await this.nextItemVersion(ref, ctx);\n const eventSeq = await this.nextEventSeq(ctx);\n\n await this.engine.delete('sys_metadata', {\n where: { id: existingId },\n context: ctx,\n });\n\n // Tombstone row — metadata/checksum are intentionally null. The\n // metadata_id column is plain text (no FK) so this orphaned ref\n // survives the parent's hard delete for forensic auditing.\n await this.engine.insert(\n this.historyTable,\n {\n id: this.uuid(),\n event_seq: eventSeq,\n metadata_id: existingId,\n type: ref.type,\n name: ref.name,\n version,\n operation_type: 'delete',\n metadata: null,\n checksum: null,\n previous_checksum: existingHash,\n change_note: opts.message,\n source: opts.source ?? 'sys-metadata-repo',\n organization_id: this.organizationId,\n recorded_by: opts.actor,\n recorded_at: now,\n },\n { context: ctx },\n );\n\n return {\n eventSeq,\n existingHash,\n now,\n source: opts.source ?? 'sys-metadata-repo',\n message: opts.message,\n actor: opts.actor,\n };\n });\n\n this.seqCounter = result.eventSeq;\n this.broadcast({\n seq: result.eventSeq,\n op: 'delete',\n ref: this.fullRef(ref),\n hash: null,\n parentHash: result.existingHash,\n actor: result.actor,\n message: result.message,\n ts: result.now,\n source: result.source,\n });\n\n return { seq: result.eventSeq };\n }\n\n async *list(filter: ListFilter): AsyncIterable<MetadataItemHeader> {\n this.assertOpen();\n const where: Record<string, unknown> = {\n organization_id: this.organizationId,\n state: 'active',\n };\n if (filter.type) where.type = filter.type;\n const rows = await this.engine.find('sys_metadata', {\n where,\n limit: filter.limit,\n });\n for (const row of rows) {\n if (filter.nameContains && !String(row.name).includes(filter.nameContains)) continue;\n const item = this.rowToItem(\n { ...this.fullRef({ type: row.type, name: row.name } as MetaRef) },\n row,\n );\n // Strip body for the header projection.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { body, ...header } = item;\n yield header;\n }\n }\n\n /**\n * Yield every history event for `(org, type?, name?)` from the\n * durable log, ordered by per-(type,name) `version` ascending. When\n * `filter.type`/`filter.name` are unset the consumer gets the full\n * org-scoped event stream — still ordered by version within each\n * (type,name) bucket, then by `recorded_at` across buckets (we sort\n * client-side because the test engine doesn't honor `orderBy`).\n */\n async *history(ref: MetaRef, opts?: HistoryOptions): AsyncIterable<MetadataEvent> {\n this.assertOpen();\n const full = this.fullRef(ref);\n const where: Record<string, unknown> = {\n organization_id: this.organizationId,\n type: full.type,\n name: full.name,\n };\n const rows = await this.engine.find(this.historyTable, { where });\n rows.sort((a: any, b: any) => {\n const va = typeof a.event_seq === 'number' ? a.event_seq : 0;\n const vb = typeof b.event_seq === 'number' ? b.event_seq : 0;\n return va - vb;\n });\n let yielded = 0;\n for (const row of rows) {\n if (opts?.sinceSeq !== undefined && (row.event_seq ?? 0) <= opts.sinceSeq) continue;\n if (opts?.limit !== undefined && yielded >= opts.limit) break;\n yielded++;\n yield {\n seq: (row.event_seq as number) ?? 0,\n op: (row.operation_type as MetadataEvent['op']) ?? 'update',\n ref: full,\n hash: (row.checksum as string | null) ?? null,\n parentHash: (row.previous_checksum as string | null) ?? null,\n actor: (row.recorded_by as string | undefined) ?? 'unknown',\n message: (row.change_note as string | undefined) ?? undefined,\n ts: (row.recorded_at as string) ?? new Date(0).toISOString(),\n source: (row.source as string | undefined) ?? 'sys-metadata-repo',\n };\n }\n }\n\n /**\n * Live event stream. Fires for every successful put/delete on THIS\n * instance — cross-replica fan-out is M1. Manual AsyncIterator (not\n * an async generator) so we can deterministically tear down via\n * `iter.return()`, matching the pattern used by InMemoryRepository.\n */\n watch(filter: WatchFilter, since?: number): AsyncIterable<MetadataEvent> {\n const self = this;\n return {\n [Symbol.asyncIterator]: () => {\n const queue: MetadataEvent[] = [];\n let pendingResolve: ((r: IteratorResult<MetadataEvent>) => void) | null = null;\n let stopped = false;\n\n const dispatch = (evt: MetadataEvent) => {\n if (stopped) return;\n if (!self.matchesFilter(evt, filter)) return;\n if (since !== undefined && evt.seq <= since) return;\n if (pendingResolve) {\n const r = pendingResolve;\n pendingResolve = null;\n r({ value: evt, done: false });\n } else {\n queue.push(evt);\n }\n };\n self.watchers.add(dispatch);\n\n return {\n next(): Promise<IteratorResult<MetadataEvent>> {\n if (stopped) return Promise.resolve({ value: undefined as any, done: true });\n const buffered = queue.shift();\n if (buffered) return Promise.resolve({ value: buffered, done: false });\n return new Promise((resolve) => {\n pendingResolve = resolve;\n });\n },\n return(): Promise<IteratorResult<MetadataEvent>> {\n stopped = true;\n self.watchers.delete(dispatch);\n if (pendingResolve) {\n const r = pendingResolve;\n pendingResolve = null;\n r({ value: undefined as any, done: true });\n }\n return Promise.resolve({ value: undefined as any, done: true });\n },\n };\n },\n };\n }\n\n /** Shut down all watch iterators. */\n close(): void {\n this.closed = true;\n // Drain watchers — each one's `return()` removes itself.\n const snapshot = Array.from(this.watchers);\n for (const w of snapshot) {\n try {\n w({\n seq: -1,\n op: 'delete',\n ref: { org: '', type: 'view', name: '_close' } as MetaRef,\n hash: null,\n parentHash: null,\n actor: 'system',\n ts: new Date().toISOString(),\n source: 'sys-metadata-repo-close',\n });\n } catch { /* noop */ }\n }\n this.watchers.clear();\n }\n\n // ── helpers ─────────────────────────────────────────────────────────\n\n private assertOpen(): void {\n if (this.closed) throw new Error('SysMetadataRepository is closed');\n }\n\n private assertAllowed(type: string): void {\n if (!OVERLAY_ALLOWED_TYPES.has(type)) {\n const err: any = new Error(\n `[not_overridable] '${type}' is not allowOrgOverride in the registry. ` +\n `Allowed: ${Array.from(OVERLAY_ALLOWED_TYPES).join(', ')}.`,\n );\n err.code = 'not_overridable';\n err.status = 403;\n throw err;\n }\n }\n\n private whereFor(ref: Pick<MetaRef, 'type' | 'name'>): Record<string, unknown> {\n return {\n type: ref.type,\n name: ref.name,\n organization_id: this.organizationId,\n state: 'active',\n };\n }\n\n private fullRef(ref: Pick<MetaRef, 'type' | 'name'>): MetaRef {\n return {\n org: this.orgLabel,\n type: ref.type,\n name: ref.name,\n };\n }\n\n private rowToItem(ref: Pick<MetaRef, 'type' | 'name'>, row: any): MetadataItem {\n const body: Record<string, unknown> =\n typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata ?? {});\n const hash: string = row.checksum ?? hashSpec(body);\n return {\n ref: this.fullRef(ref),\n body,\n hash,\n parentHash: null,\n authoredBy: row.updated_by ?? row.created_by ?? 'unknown',\n authoredAt: row.updated_at ?? row.created_at ?? new Date().toISOString(),\n message: undefined,\n seq: this.seqCounter,\n };\n }\n\n private broadcast(evt: MetadataEvent): void {\n for (const w of Array.from(this.watchers)) {\n try { w(evt); } catch { /* listener errors don't break the repo */ }\n }\n }\n\n private matchesFilter(evt: MetadataEvent, filter: WatchFilter): boolean {\n if (filter.type && evt.ref.type !== filter.type) return false;\n if (filter.name && evt.ref.name !== filter.name) return false;\n if (filter.org && evt.ref.org !== filter.org) return false;\n return true;\n }\n\n /**\n * Per-org monotonic event sequence. Reads `MAX(event_seq) + 1` from\n * `sys_metadata_history` scoped by `organization_id`. MUST be called\n * inside a transaction (the only caller is the put/delete txn body) —\n * concurrent writers in the same org race otherwise.\n */\n private async nextEventSeq(ctx: any): Promise<number> {\n try {\n const rows = await this.engine.find(this.historyTable, {\n where: { organization_id: this.organizationId },\n context: ctx,\n });\n let max = 0;\n for (const row of rows as Array<{ event_seq?: number | null }>) {\n const v = typeof row.event_seq === 'number' ? row.event_seq : 0;\n if (v > max) max = v;\n }\n return max + 1;\n } catch {\n // Table not provisioned yet (fresh DB) — start at 1.\n return 1;\n }\n }\n\n /**\n * Per-(org,type,name) lineage counter. Reads from history (not from\n * `sys_metadata.version`) so delete + recreate continues incrementing\n * instead of restarting at 1.\n */\n private async nextItemVersion(\n ref: Pick<MetaRef, 'type' | 'name'>,\n ctx: any,\n ): Promise<number> {\n try {\n const rows = await this.engine.find(this.historyTable, {\n where: {\n organization_id: this.organizationId,\n type: ref.type,\n name: ref.name,\n },\n context: ctx,\n });\n let max = 0;\n for (const row of rows as Array<{ version?: number | null }>) {\n const v = typeof row.version === 'number' ? row.version : 0;\n if (v > max) max = v;\n }\n return max + 1;\n } catch {\n return 1;\n }\n }\n\n /** Lightweight UUID-ish id for history rows; sufficient for an audit log. */\n private uuid(): string {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return globalThis.crypto.randomUUID();\n }\n return `evt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectStackProtocol } from '@objectstack/spec/api';\nimport { IDataEngine } from '@objectstack/core';\nimport type { ObjectQL } from './engine.js';\nimport { SysMetadataRepository, type SysMetadataEngine } from './sys-metadata-repository.js';\nimport { ConflictError } from '@objectstack/metadata-core';\nimport type {\n BatchUpdateRequest,\n BatchUpdateResponse,\n UpdateManyDataRequest,\n DeleteManyDataRequest\n} from '@objectstack/spec/api';\nimport type { MetadataCacheRequest, MetadataCacheResponse, ServiceInfo, ApiRoutes, WellKnownCapabilities } from '@objectstack/spec/api';\nimport type { IFeedService } from '@objectstack/spec/contracts';\nimport { parseFilterAST, isFilterAST } from '@objectstack/spec/data';\nimport { PLURAL_TO_SINGULAR, SINGULAR_TO_PLURAL } from '@objectstack/spec/shared';\nimport { ListViewSchema, FormViewSchema, DashboardSchema } from '@objectstack/spec/ui';\nimport { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel';\nimport { z } from 'zod';\n\n/**\n * Zod schemas used to validate overlay items before they are persisted into\n * `sys_metadata` by {@link ObjectStackProtocolImplementation.saveMetaItem}.\n *\n * Some types (notably `view`) are *not* a single schema but a discriminated\n * family — a grid/kanban/calendar list view vs. a simple/tabbed/wizard form\n * view. We dispatch to the right schema based on the `type` discriminant\n * rather than using `z.union([...])`, which would collapse all branch errors\n * into an opaque \"Invalid input\" union error.\n *\n * Validation policy:\n * - `safeParse` is used so we can craft a 422 with structured `issues`.\n * - We do NOT replace the persisted document with `parsed.data`; the\n * original payload is stored verbatim so Studio-only auxiliary fields\n * (e.g. `isPinned`, `isDefault`, `sortOrder`) survive the round-trip.\n * - Schemas are referenced lazily through the Spec's `lazySchema` Proxy,\n * so importing this module does not trigger eager Zod construction.\n * - Types without a registered schema (e.g. `app`, `package`) fall through\n * unvalidated for backwards compatibility — they were never enforced\n * historically and existing control-plane writes rely on the lenient\n * behaviour.\n */\nconst FORM_VIEW_TYPES = new Set(['simple', 'tabbed', 'wizard', 'split', 'drawer', 'modal']);\n\nfunction resolveOverlaySchema(type: string, item: unknown): z.ZodTypeAny | null {\n const singular = PLURAL_TO_SINGULAR[type] ?? type;\n switch (singular) {\n case 'view': {\n // Form views and list views share the `view` overlay type. Pick\n // the right Zod schema by inspecting the discriminant. Defaults\n // to ListViewSchema (matches the ListViewSchema `type.default('grid')`).\n const t = (item && typeof item === 'object' && 'type' in item)\n ? String((item as any).type)\n : undefined;\n return t && FORM_VIEW_TYPES.has(t) ? FormViewSchema : ListViewSchema;\n }\n case 'dashboard':\n return DashboardSchema;\n default:\n return null;\n }\n}\n\n/**\n * Simple hash function for ETag generation (browser-compatible)\n * Uses a basic hash algorithm instead of crypto.createHash\n */\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(16);\n}\n\n/**\n * Thrown by `updateData` / `deleteData` when the caller supplies an\n * `expectedVersion` that does not match the current record's `updated_at`.\n *\n * The HTTP layer maps this to `409 Conflict` with code `CONCURRENT_UPDATE`,\n * and includes both the current server-side version and the current record\n * payload so the client can render an informed conflict-resolution UI\n * (\"Reload latest\" vs. \"Overwrite anyway\").\n *\n * NOTE: This is an *application-level* compare-and-set — not an atomic\n * storage-layer CAS. There is a small TOCTOU window between the version\n * check and the subsequent write. For the conflict frequency this targets\n * (different users seconds-to-minutes apart in B2B record editing) this\n * is more than adequate; a future revision can push the check into the\n * driver's UPDATE statement (`WHERE id=? AND updated_at=?`) for true\n * atomicity.\n */\nexport class ConcurrentUpdateError extends Error {\n readonly code = 'CONCURRENT_UPDATE';\n readonly status = 409;\n readonly currentVersion: string | null;\n readonly currentRecord: unknown;\n constructor(opts: { currentVersion: string | null; currentRecord: unknown; message?: string }) {\n super(opts.message ?? 'Record was modified by another user');\n this.name = 'ConcurrentUpdateError';\n this.currentVersion = opts.currentVersion;\n this.currentRecord = opts.currentRecord;\n }\n}\n\n/**\n * Normalises a version token for comparison. Strips RFC-7232-style quotes\n * (`\"…\"`) that an HTTP `If-Match` header may carry, trims whitespace, and\n * returns null for empty / nullish input.\n */\nfunction normaliseVersionToken(v: unknown): string | null {\n if (v === null || v === undefined) return null;\n const s = String(v).trim();\n if (!s) return null;\n if (s.length >= 2 && s.startsWith('\"') && s.endsWith('\"')) {\n return s.slice(1, -1);\n }\n return s;\n}\n\n/**\n * Service Configuration for Discovery\n * Maps service names to their routes and plugin providers\n */\nconst SERVICE_CONFIG: Record<string, { route: string; plugin: string }> = {\n auth: { route: '/api/v1/auth', plugin: 'plugin-auth' },\n automation: { route: '/api/v1/automation', plugin: 'plugin-automation' },\n cache: { route: '/api/v1/cache', plugin: 'plugin-redis' },\n queue: { route: '/api/v1/queue', plugin: 'plugin-bullmq' },\n job: { route: '/api/v1/jobs', plugin: 'job-scheduler' },\n ui: { route: '/api/v1/ui', plugin: 'ui-plugin' },\n workflow: { route: '/api/v1/workflow', plugin: 'plugin-workflow' },\n realtime: { route: '/api/v1/realtime', plugin: 'plugin-realtime' },\n notification: { route: '/api/v1/notifications', plugin: 'plugin-notifications' },\n ai: { route: '/api/v1/ai', plugin: 'plugin-ai' },\n i18n: { route: '/api/v1/i18n', plugin: 'service-i18n' },\n graphql: { route: '/graphql', plugin: 'plugin-graphql' }, // GraphQL uses /graphql by convention (not versioned REST)\n 'file-storage': { route: '/api/v1/storage', plugin: 'plugin-storage' },\n search: { route: '/api/v1/search', plugin: 'plugin-search' },\n};\n\nexport class ObjectStackProtocolImplementation implements ObjectStackProtocol {\n private engine: ObjectQL;\n private getServicesRegistry?: () => Map<string, any>;\n private getFeedService?: () => IFeedService | undefined;\n /**\n * Project scope applied to sys_metadata reads/writes. When undefined\n * (single-kernel deployments), rows land in / come from the\n * platform-global bucket (`project_id IS NULL`). When set, every\n * saveMetaItem insert/update and loadMetaFromDb query is filtered by\n * `project_id = projectId`, so per-project kernels see only their own\n * metadata even if several projects share the same physical database.\n */\n private projectId?: string;\n\n /**\n * Lazily-instantiated SysMetadataRepository per organization. Keyed by\n * `${organizationId ?? '__env__'}`. Repositories are stateful — they\n * carry the per-org `seqCounter` and watch subscribers — so we cache\n * them rather than constructing one per call.\n */\n private overlayRepos = new Map<string, SysMetadataRepository>();\n\n constructor(\n engine: IDataEngine,\n getServicesRegistry?: () => Map<string, any>,\n getFeedService?: () => IFeedService | undefined,\n projectId?: string,\n ) {\n this.engine = engine as ObjectQL;\n this.getServicesRegistry = getServicesRegistry;\n this.getFeedService = getFeedService;\n this.projectId = projectId;\n }\n\n /**\n * Lazily obtain a SysMetadataRepository for the given organization.\n * Env-wide overlays (organizationId == null) share a singleton under\n * the `__env__` key.\n */\n private getOverlayRepo(organizationId: string | null): SysMetadataRepository {\n const key = organizationId ?? '__env__';\n let repo = this.overlayRepos.get(key);\n if (!repo) {\n repo = new SysMetadataRepository({\n engine: this.engine as unknown as SysMetadataEngine,\n organizationId,\n orgLabel: organizationId ?? 'env',\n });\n this.overlayRepos.set(key, repo);\n }\n return repo;\n }\n\n /**\n * One-time guard for ensuring the overlay-uniqueness UNIQUE INDEX exists\n * on `sys_metadata`. ADR-0005: scopes overlays by\n * `(type, name, organization_id, project_id, scope)` for active rows only.\n * Idempotent SQL — safe to attempt on every protocol instance.\n *\n * Inlined here (rather than importing from @objectstack/metadata/migrations)\n * to avoid a circular dependency: metadata already depends on objectql.\n */\n private overlayIndexEnsured = false;\n private async ensureOverlayIndex(): Promise<void> {\n if (this.overlayIndexEnsured) return;\n this.overlayIndexEnsured = true;\n try {\n const engineAny = this.engine as any;\n let driver: any = engineAny?.driver ?? engineAny?.getDriver?.();\n if (!driver && engineAny?.drivers instanceof Map) {\n for (const candidate of engineAny.drivers.values()) {\n if (\n candidate &&\n (typeof (candidate as any).raw === 'function' ||\n typeof (candidate as any).execute === 'function')\n ) {\n driver = candidate;\n break;\n }\n }\n }\n if (!driver) return;\n const exec = async (sql: string): Promise<void> => {\n if (typeof (driver as any).raw === 'function') {\n await (driver as any).raw(sql);\n } else if (typeof (driver as any).execute === 'function') {\n await (driver as any).execute(sql);\n } else {\n throw new Error('driver has neither raw nor execute');\n }\n };\n // ADR-0005 (revised 2026-05): per-env DBs replace the old\n // \"per-project\" isolation, so `project_id` is no longer a\n // discriminator. Overlay uniqueness is `(type, name,\n // organization_id)` filtered to active rows. Drop the legacy\n // composite index first so the new partial UNIQUE can claim\n // the same name — DROP INDEX IF EXISTS is idempotent.\n try { await exec(\"DROP INDEX IF EXISTS idx_sys_metadata_overlay_active\"); } catch { /* best-effort */ }\n const partialSql =\n \"CREATE UNIQUE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active \" +\n \"ON sys_metadata (type, name, organization_id) \" +\n \"WHERE state = 'active'\";\n const fallbackSql =\n \"CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active \" +\n \"ON sys_metadata (type, name, organization_id)\";\n try {\n await exec(partialSql);\n } catch (err: any) {\n const msg = err instanceof Error ? err.message : String(err);\n if (/partial|where clause|syntax/i.test(msg)) {\n try {\n await exec(fallbackSql);\n } catch {\n // ignore — non-essential optimization\n }\n }\n // \"already exists\" or anything else: best-effort\n }\n } catch {\n // ignore — index is an optimization, not a correctness invariant\n }\n }\n\n /**\n * Exposes the project scope the protocol is bound to. Consumers like\n * the HTTP dispatcher use this to decide whether to trust the process-\n * wide SchemaRegistry or whether they must route a read through the\n * protocol's project_id-filtered lookup.\n */\n getProjectId(): string | undefined {\n return this.projectId;\n }\n\n private requireFeedService(): IFeedService {\n const svc = this.getFeedService?.();\n if (!svc) {\n throw new Error('Feed service not available. Install and register service-feed to enable feed operations.');\n }\n return svc;\n }\n\n async getDiscovery() {\n // Get registered services from kernel if available\n const registeredServices = this.getServicesRegistry ? this.getServicesRegistry() : new Map();\n \n // Build dynamic service info with proper typing\n const services: Record<string, ServiceInfo> = {\n // --- Kernel-provided (objectql is an example kernel implementation) ---\n metadata: { enabled: true, status: 'available' as const, route: '/api/v1/meta', provider: 'objectql' },\n data: { enabled: true, status: 'available' as const, route: '/api/v1/data', provider: 'objectql' },\n analytics: { enabled: true, status: 'available' as const, route: '/api/v1/analytics', provider: 'objectql' },\n };\n\n // Check which services are actually registered\n for (const [serviceName, config] of Object.entries(SERVICE_CONFIG)) {\n if (registeredServices.has(serviceName)) {\n // Service is registered and available\n services[serviceName] = {\n enabled: true,\n status: 'available' as const,\n route: config.route,\n provider: config.plugin,\n };\n } else {\n // Service is not registered\n services[serviceName] = {\n enabled: false,\n status: 'unavailable' as const,\n message: `Install ${config.plugin} to enable`,\n };\n }\n }\n\n // Build routes from services — a flat convenience map for client routing\n const serviceToRouteKey: Record<string, keyof ApiRoutes> = {\n auth: 'auth',\n automation: 'automation',\n ui: 'ui',\n workflow: 'workflow',\n realtime: 'realtime',\n notification: 'notifications',\n ai: 'ai',\n i18n: 'i18n',\n graphql: 'graphql',\n 'file-storage': 'storage',\n };\n\n const optionalRoutes: Partial<ApiRoutes> = {\n analytics: '/api/v1/analytics',\n };\n\n // Add routes for available plugin services\n for (const [serviceName, config] of Object.entries(SERVICE_CONFIG)) {\n if (registeredServices.has(serviceName)) {\n const routeKey = serviceToRouteKey[serviceName];\n if (routeKey) {\n optionalRoutes[routeKey] = config.route;\n }\n }\n }\n\n // Add feed service status\n if (registeredServices.has('feed')) {\n services['feed'] = {\n enabled: true,\n status: 'available' as const,\n route: '/api/v1/data',\n provider: 'service-feed',\n };\n } else {\n services['feed'] = {\n enabled: false,\n status: 'unavailable' as const,\n message: 'Install service-feed to enable',\n };\n }\n\n const routes: ApiRoutes = {\n data: '/api/v1/data',\n metadata: '/api/v1/meta',\n ...optionalRoutes,\n };\n\n // Build well-known capabilities from registered services.\n // DiscoverySchema defines capabilities as Record<string, { enabled, features?, description? }>\n // (hierarchical format). We also keep a flat WellKnownCapabilities for backward compat.\n const wellKnown: WellKnownCapabilities = {\n feed: registeredServices.has('feed'),\n comments: registeredServices.has('feed'),\n automation: registeredServices.has('automation'),\n cron: registeredServices.has('job'),\n search: registeredServices.has('search'),\n export: registeredServices.has('automation') || registeredServices.has('queue'),\n chunkedUpload: registeredServices.has('file-storage'),\n };\n\n // Convert flat booleans → hierarchical capability objects\n const capabilities: Record<string, { enabled: boolean; description?: string }> = {};\n for (const [key, enabled] of Object.entries(wellKnown)) {\n capabilities[key] = { enabled };\n }\n\n return {\n version: '1.0',\n apiName: 'ObjectStack API',\n routes,\n services,\n capabilities,\n };\n }\n\n async getMetaTypes() {\n const schemaTypes = this.engine.registry.getRegisteredTypes();\n\n // Also include types from MetadataService (runtime-registered: agent, tool, etc.)\n let runtimeTypes: string[] = [];\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.getRegisteredTypes === 'function') {\n runtimeTypes = await metadataService.getRegisteredTypes();\n }\n } catch {\n // MetadataService not available\n }\n\n const allTypes = Array.from(new Set([...schemaTypes, ...runtimeTypes]));\n return { types: allTypes };\n }\n\n async getMetaItems(request: { type: string; packageId?: string; organizationId?: string }) {\n const { packageId } = request;\n let items: unknown[] = [];\n\n // Unscoped kernels (control plane): read everything from SchemaRegistry.\n // Scoped (project) kernels: skip user-project entries in SchemaRegistry to\n // prevent cross-project leakage, but DO include scope:'system' packages\n // (plugin-auth, plugin-security, plugin-audit, …) — those are globally\n // shared and must be visible at every project's meta endpoint.\n if (this.projectId === undefined) {\n items = [...this.engine.registry.listItems(request.type, packageId)];\n // Normalize singular/plural using explicit mapping\n if (items.length === 0) {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) items = [...this.engine.registry.listItems(alt, packageId)];\n }\n } else {\n // For project kernels: the SchemaRegistry is owned by THIS\n // kernel's ObjectQL instance (not shared across projects in the\n // process), so we can safely include every package — system\n // plugins (auth/security/audit) and the project's own app\n // package alike. The `_packageId` tag added by `listItems`\n // (registry.ts) is preserved for the sidebar to compute the\n // correct navigation URL.\n items = [...this.engine.registry.listItems(request.type, packageId)];\n if (items.length === 0) {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) items = [...this.engine.registry.listItems(alt, packageId)];\n }\n }\n\n // Always consult the DB so metadata persisted by the seeder /\n // bulkRegister shows up even when the registry already has unrelated\n // entries (the previous fallback-only logic meant per-env metadata\n // was never surfaced whenever system-bridged items populated the\n // registry). Deduplicate against whatever the registry returned.\n //\n // ADR-0005 (revised 2026-05): isolation is now per-organization, since\n // each env has its own physical DB. We surface both org-scoped overlays\n // (when an active org is provided) and env-wide (organization_id IS NULL)\n // overlays; org-scoped rows win on name collision.\n try {\n const orgId = (request as any).organizationId as string | undefined;\n const queryByOrg = async (oid: string | null): Promise<any[]> => {\n const whereClause: Record<string, unknown> = {\n type: request.type,\n state: 'active',\n organization_id: oid,\n };\n if (packageId) whereClause._packageId = packageId;\n let rs = await this.engine.find('sys_metadata', { where: whereClause });\n if ((!rs || rs.length === 0)) {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) {\n const altWhere: Record<string, unknown> = { type: alt, state: 'active', organization_id: oid };\n if (packageId) altWhere._packageId = packageId;\n rs = await this.engine.find('sys_metadata', { where: altWhere });\n }\n }\n return rs ?? [];\n };\n const envWideRecords = await queryByOrg(null);\n const orgRecords = orgId ? await queryByOrg(orgId) : [];\n // org-specific rows override env-wide rows on name collision\n const mergedMap = new Map<string, any>();\n for (const r of envWideRecords) mergedMap.set(r.name, r);\n for (const r of orgRecords) mergedMap.set(r.name, r);\n const records = Array.from(mergedMap.values());\n if (records && records.length > 0) {\n const byName = new Map<string, any>();\n for (const existing of items) {\n const entry = existing as any;\n if (entry && typeof entry === 'object' && 'name' in entry) {\n byName.set(entry.name, entry);\n }\n }\n for (const record of records) {\n const data = typeof record.metadata === 'string'\n ? JSON.parse(record.metadata)\n : record.metadata;\n if (data && typeof data === 'object' && 'name' in data) {\n byName.set(data.name, data);\n }\n // Only hydrate the global registry for unscoped calls —\n // scoped project entries must not leak process-wide.\n if (this.projectId === undefined) {\n this.engine.registry.registerItem(request.type, data, 'name' as any);\n }\n }\n items = Array.from(byName.values());\n }\n } catch {\n // DB not available — fall through with whatever we already have.\n }\n\n // Merge with MetadataService (runtime-registered items: agents, tools, etc.)\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.list === 'function') {\n let runtimeItems = await metadataService.list(request.type);\n // When filtering by packageId, only include runtime items that\n // belong to the requested package. MetadataService.list() returns\n // items from ALL packages, so we must filter here to respect the\n // package scope requested by the caller (e.g., Studio sidebar).\n if (packageId && runtimeItems && runtimeItems.length > 0) {\n runtimeItems = runtimeItems.filter((item: any) => item?._packageId === packageId);\n }\n if (runtimeItems && runtimeItems.length > 0) {\n // Merge, avoiding duplicates by name\n const itemMap = new Map<string, any>();\n for (const item of items) {\n const entry = item as any;\n if (entry && typeof entry === 'object' && 'name' in entry) {\n itemMap.set(entry.name, entry);\n }\n }\n for (const item of runtimeItems) {\n const entry = item as any;\n if (entry && typeof entry === 'object' && 'name' in entry) {\n // Do not overwrite entries already present in the\n // map: those came from sys_metadata (customization\n // overlays) or the SchemaRegistry and must win\n // over the MetadataService's artifact baseline.\n // Without this guard, saved per-org dashboard /\n // view overlays disappear from list endpoints on\n // refresh (detail endpoint kept showing the\n // overlay because it uses a different code path).\n if (!itemMap.has(entry.name)) {\n itemMap.set(entry.name, entry);\n }\n }\n }\n items = Array.from(itemMap.values());\n }\n }\n } catch {\n // MetadataService not available or doesn't support this type\n }\n\n return {\n type: request.type,\n items\n };\n }\n\n async getMetaItem(request: { type: string, name: string, packageId?: string, organizationId?: string }) {\n let item: unknown;\n const orgId = request.organizationId;\n\n // 1. Customization overlay lookup (sys_metadata).\n // Per ADR-0005 (revised), org-scoped row wins; env-wide\n // (organization_id IS NULL) row is the fallback before falling\n // through to the in-memory registry / MetadataService.\n try {\n const findOverlay = async (oid: string | null): Promise<any | undefined> => {\n const where: Record<string, unknown> = {\n type: request.type,\n name: request.name,\n state: 'active',\n organization_id: oid,\n };\n const rec = await this.engine.findOne('sys_metadata', { where });\n if (rec) return rec;\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) {\n const altWhere: Record<string, unknown> = {\n type: alt,\n name: request.name,\n state: 'active',\n organization_id: oid,\n };\n return await this.engine.findOne('sys_metadata', { where: altWhere });\n }\n return undefined;\n };\n const record = (orgId ? await findOverlay(orgId) : undefined)\n ?? await findOverlay(null);\n if (record) {\n item = typeof record.metadata === 'string'\n ? JSON.parse(record.metadata)\n : record.metadata;\n }\n } catch {\n // DB not available — fall through to registry / MetadataService\n }\n\n // 2. MetadataService (runtime-registered items: HMR-updated view/page/\n // dashboard/agent/tool, plus FilesystemLoader-sourced items). This\n // is consulted BEFORE the in-memory SchemaRegistry because the\n // registry is a boot-time cache populated by `loadMetadataFromService`\n // and is NOT invalidated on `MetadataManager.register()` (which is\n // how the CLI dev watcher pushes recompiled metadata into the\n // running server). Without this ordering, edits to `*.view.ts`\n // source files appear to take effect (MetadataManager learns the\n // new value) but reads continue to return the stale registry copy.\n if (item === undefined) {\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.get === 'function') {\n const fromService = await metadataService.get(request.type, request.name);\n if (fromService !== undefined && fromService !== null) {\n item = fromService;\n } else {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) {\n const altFromService = await metadataService.get(alt, request.name);\n if (altFromService !== undefined && altFromService !== null) {\n item = altFromService;\n }\n }\n }\n }\n } catch {\n // MetadataService not available — fall through\n }\n }\n\n // 3. In-memory SchemaRegistry (artifact-loaded out-of-box values, and\n // items that bypass MetadataService — e.g. some object-schema\n // extension chains registered by AppPlugin directly).\n // Both control-plane (unscoped) and project kernels consult the\n // registry. The previous guard that skipped the registry for\n // project kernels was meant to prevent cross-project leakage at\n // the LIST level — but for a single-item lookup the kernel's own\n // `engine.registry` is project-local (each ObjectQL instance has\n // its own SchemaRegistry), so reading from it is safe and\n // necessary. Without this, project-kernel callers of\n // `GET /api/v1/meta/object/<name>` 404 even though the object is\n // registered and visible via the list endpoint.\n if (item === undefined) {\n item = this.engine.registry.getItem(request.type, request.name);\n if (item === undefined) {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) item = this.engine.registry.getItem(alt, request.name);\n }\n }\n\n return {\n type: request.type,\n name: request.name,\n item\n };\n }\n\n async getUiView(request: { object: string, type: 'list' | 'form' }) {\n const schema = this.engine.registry.getObject(request.object);\n if (!schema) throw new Error(`Object ${request.object} not found`);\n\n const fields = schema.fields || {};\n const fieldKeys = Object.keys(fields);\n\n if (request.type === 'list') {\n // Intelligent Column Selection\n // 1. Always include 'name' or name-like fields\n // 2. Limit to 6 columns by default\n const priorityFields = ['name', 'title', 'label', 'subject', 'email', 'status', 'type', 'category', 'created_at'];\n \n let columns = fieldKeys.filter(k => priorityFields.includes(k));\n \n // If few priority fields, add others until 5\n if (columns.length < 5) {\n const remaining = fieldKeys.filter(k => !columns.includes(k) && k !== 'id' && !fields[k].hidden);\n columns = [...columns, ...remaining.slice(0, 5 - columns.length)];\n }\n \n // Sort columns by priority then alphabet or schema order\n // For now, just keep them roughly in order they appear in schema or priority list\n \n return {\n list: {\n type: 'grid' as const,\n object: request.object,\n label: schema.label || schema.name,\n columns: columns.map(f => ({\n field: f,\n label: fields[f]?.label || f,\n sortable: true\n })),\n sort: fields['created_at'] ? ([{ field: 'created_at', order: 'desc' }] as any) : undefined,\n searchableFields: columns.slice(0, 3) // Make first few textual columns searchable\n }\n };\n } else {\n // Form View Generation\n // Simple single-section layout for now\n const formFields = fieldKeys\n .filter(k => k !== 'id' && k !== 'created_at' && k !== 'updated_at' && !fields[k].hidden)\n .map(f => ({\n field: f,\n label: fields[f]?.label,\n required: fields[f]?.required,\n readonly: fields[f]?.readonly,\n type: fields[f]?.type,\n // Default to 2 columns for most, 1 for textareas\n colSpan: (fields[f]?.type === 'textarea' || fields[f]?.type === 'html') ? 2 : 1\n }));\n\n return {\n form: {\n type: 'simple' as const,\n object: request.object,\n label: `Edit ${schema.label || schema.name}`,\n sections: [\n {\n label: 'General Information',\n columns: 2 as const,\n collapsible: false,\n collapsed: false,\n fields: formFields\n }\n ]\n }\n };\n }\n }\n\n async findData(request: { object: string, query?: any, context?: any }) {\n const options: any = { ...request.query };\n // Forward the dispatcher's ExecutionContext so RBAC/RLS middleware\n // can apply per-request enforcement. The protocol layer is purely\n // a normalizer — it must never strip security context.\n if (request.context !== undefined) {\n options.context = request.context;\n }\n\n // ====================================================================\n // Normalize legacy params → QueryAST standard (where/fields/orderBy/offset/expand)\n // ====================================================================\n\n // OData-style `$`-prefixed params → bare aliases that the rest of\n // this function knows how to normalize. Without this step, params\n // like `?$top=2&$orderby=...` survive into the catch-all\n // implicit-filter pass below and get merged into `where` as\n // bogus field-equality predicates (e.g. `where.$top = \"2\"`),\n // which silently returns zero rows for every list endpoint.\n for (const [dollar, bare] of [\n ['$top', 'top'],\n ['$skip', 'skip'],\n ['$orderby', 'orderBy'],\n ['$select', 'select'],\n ['$count', 'count'],\n ] as const) {\n if (options[dollar] != null && options[bare] == null) {\n options[bare] = options[dollar];\n }\n delete options[dollar];\n }\n\n // Numeric fields — normalize top → limit, skip → offset\n if (options.top != null) {\n options.limit = Number(options.top);\n delete options.top;\n }\n if (options.skip != null) {\n options.offset = Number(options.skip);\n delete options.skip;\n }\n if (options.limit != null) options.limit = Number(options.limit);\n if (options.offset != null) options.offset = Number(options.offset);\n\n // Select → fields: comma-separated string → array\n if (typeof options.select === 'string') {\n options.fields = options.select.split(',').map((s: string) => s.trim()).filter(Boolean);\n } else if (Array.isArray(options.select)) {\n options.fields = options.select;\n }\n if (options.select !== undefined) delete options.select;\n\n // Sort/orderBy → orderBy: string → SortNode[] array\n const sortValue = options.orderBy ?? options.sort;\n if (typeof sortValue === 'string') {\n const parsed = sortValue.split(',').map((part: string) => {\n const trimmed = part.trim();\n if (trimmed.startsWith('-')) {\n return { field: trimmed.slice(1), order: 'desc' as const };\n }\n const [field, order] = trimmed.split(/\\s+/);\n return { field, order: (order?.toLowerCase() === 'desc' ? 'desc' : 'asc') as 'asc' | 'desc' };\n }).filter((s: any) => s.field);\n options.orderBy = parsed;\n } else if (Array.isArray(sortValue)) {\n options.orderBy = sortValue;\n }\n delete options.sort;\n\n // Filter/filters/$filter → where: normalize all filter aliases\n const filterValue = options.filter ?? options.filters ?? options.$filter ?? options.where;\n delete options.filter;\n delete options.filters;\n delete options.$filter;\n\n if (filterValue !== undefined) {\n let parsedFilter = filterValue;\n // JSON string → object\n if (typeof parsedFilter === 'string') {\n try { parsedFilter = JSON.parse(parsedFilter); } catch { /* keep as-is */ }\n }\n // Filter AST array → FilterCondition object\n if (isFilterAST(parsedFilter)) {\n parsedFilter = parseFilterAST(parsedFilter);\n }\n options.where = parsedFilter;\n }\n\n // Populate/expand/$expand → expand (Record<string, QueryAST>)\n const populateValue = options.populate;\n const expandValue = options.$expand ?? options.expand;\n const expandNames: string[] = [];\n if (typeof populateValue === 'string') {\n expandNames.push(...populateValue.split(',').map((s: string) => s.trim()).filter(Boolean));\n } else if (Array.isArray(populateValue)) {\n expandNames.push(...populateValue);\n }\n if (!expandNames.length && expandValue) {\n if (typeof expandValue === 'string') {\n expandNames.push(...expandValue.split(',').map((s: string) => s.trim()).filter(Boolean));\n } else if (Array.isArray(expandValue)) {\n expandNames.push(...expandValue);\n }\n }\n delete options.populate;\n delete options.$expand;\n // Clean up non-object expand (e.g. string) BEFORE the Record conversion\n // below, so that populate-derived names can create the expand Record even\n // when a legacy string expand was also present.\n if (typeof options.expand !== 'object' || options.expand === null) {\n delete options.expand;\n }\n // Only set expand if not already an object (advanced usage)\n if (expandNames.length > 0 && !options.expand) {\n options.expand = {} as Record<string, any>;\n for (const rel of expandNames) {\n options.expand[rel] = { object: rel };\n }\n }\n\n // Boolean fields\n for (const key of ['distinct', 'count']) {\n if (options[key] === 'true') options[key] = true;\n else if (options[key] === 'false') options[key] = false;\n }\n \n // Flat field filters: REST-style query params like ?id=abc&status=open\n // After extracting all known query parameters, any remaining keys are\n // treated as implicit field-level equality filters merged into `where`.\n const knownParams = new Set([\n 'top', 'limit', 'offset',\n 'orderBy',\n 'fields',\n 'where',\n 'expand',\n 'distinct', 'count',\n 'aggregations', 'groupBy',\n 'search', 'context', 'cursor',\n ]);\n if (!options.where) {\n const implicitFilters: Record<string, unknown> = {};\n for (const key of Object.keys(options)) {\n if (!knownParams.has(key)) {\n implicitFilters[key] = options[key];\n delete options[key];\n }\n }\n if (Object.keys(implicitFilters).length > 0) {\n options.where = implicitFilters;\n }\n }\n \n // Route to engine.aggregate() when the query has GROUP BY / aggregations.\n // engine.find() does not do in-memory aggregation fallback, so without\n // this branch a spec-shape aggregate request would silently return\n // ungrouped raw rows on drivers (e.g. SqlDriver) that don't natively\n // honor groupBy/aggregations in find().\n const hasGroupBy = Array.isArray(options.groupBy) && options.groupBy.length > 0;\n const hasAggregations = Array.isArray(options.aggregations) && options.aggregations.length > 0;\n if (hasGroupBy || hasAggregations) {\n const records = await this.engine.aggregate(request.object, {\n where: options.where,\n groupBy: options.groupBy,\n aggregations: options.aggregations,\n context: options.context,\n } as any);\n // Apply limit client-side (EngineAggregateOptions doesn't carry limit)\n const limited = typeof options.limit === 'number' && options.limit > 0\n ? records.slice(0, options.limit)\n : records;\n return {\n object: request.object,\n records: limited,\n total: limited.length,\n hasMore: false,\n };\n }\n\n const records = await this.engine.find(request.object, options);\n // Spec: FindDataResponseSchema — only `records` is returned.\n // OData `value` adaptation (if needed) is handled in the HTTP dispatch layer.\n return {\n object: request.object,\n records,\n total: records.length,\n hasMore: false\n };\n }\n\n async getData(request: { object: string, id: string, expand?: string | string[], select?: string | string[], context?: any }) {\n const queryOptions: any = {\n where: { id: request.id }\n };\n if (request.context !== undefined) {\n queryOptions.context = request.context;\n }\n\n // Support fields for single-record retrieval\n if (request.select) {\n queryOptions.fields = typeof request.select === 'string'\n ? request.select.split(',').map((s: string) => s.trim()).filter(Boolean)\n : request.select;\n }\n\n // Support expand for single-record retrieval\n if (request.expand) {\n const expandNames = typeof request.expand === 'string'\n ? request.expand.split(',').map((s: string) => s.trim()).filter(Boolean)\n : request.expand;\n queryOptions.expand = {} as Record<string, any>;\n for (const rel of expandNames) {\n queryOptions.expand[rel] = { object: rel };\n }\n }\n\n const result = await this.engine.findOne(request.object, queryOptions);\n if (result) {\n return {\n object: request.object,\n id: request.id,\n record: result\n };\n }\n const err = new Error(`Record ${request.id} not found in ${request.object}`) as Error & {\n code?: string;\n status?: number;\n object?: string;\n };\n err.code = 'RECORD_NOT_FOUND';\n err.status = 404;\n err.object = request.object;\n throw err;\n }\n\n async createData(request: { object: string, data: any, context?: any }) {\n const result = await this.engine.insert(\n request.object,\n request.data,\n request.context !== undefined ? { context: request.context } as any : undefined,\n );\n return {\n object: request.object,\n id: result.id,\n record: result\n };\n }\n\n async updateData(request: { object: string, id: string, data: any, expectedVersion?: string, context?: any }) {\n await this.assertVersionMatch(request.object, request.id, request.expectedVersion, request.context);\n const opts: any = { where: { id: request.id } };\n if (request.context !== undefined) opts.context = request.context;\n const result = await this.engine.update(request.object, request.data, opts);\n return {\n object: request.object,\n id: request.id,\n record: result\n };\n }\n\n async deleteData(request: { object: string, id: string, expectedVersion?: string, context?: any }) {\n await this.assertVersionMatch(request.object, request.id, request.expectedVersion, request.context);\n const opts: any = { where: { id: request.id } };\n if (request.context !== undefined) opts.context = request.context;\n await this.engine.delete(request.object, opts);\n return {\n object: request.object,\n id: request.id,\n success: true\n };\n }\n\n /**\n * Optimistic Concurrency Control gate shared by updateData/deleteData.\n *\n * When the caller passes a non-empty `expectedVersion` token (typically\n * the `updated_at` value they read), this fetches the current record\n * and compares its `updated_at` against the token. Mismatch → throw\n * `ConcurrentUpdateError` which the REST layer maps to 409.\n *\n * Behaviour:\n * - Empty/missing token → no check (opt-in semantics; existing callers\n * that haven't yet adopted OCC are unaffected).\n * - Record not found → no check; downstream `engine.update` will\n * surface the usual `RECORD_NOT_FOUND` 404. We intentionally do not\n * treat \"missing record\" as a concurrency conflict.\n * - Record has no `updated_at` field (timestamps disabled) → no check.\n * Logging would be noisy here; OCC is opt-in and the absence of a\n * version column is an explicit \"this object doesn't support OCC\"\n * signal.\n */\n private async assertVersionMatch(\n object: string,\n id: string,\n expectedVersion: string | undefined,\n context: any\n ): Promise<void> {\n const expected = normaliseVersionToken(expectedVersion);\n if (!expected) return;\n const findOpts: any = { where: { id } };\n if (context !== undefined) findOpts.context = context;\n const current = await this.engine.findOne(object, findOpts);\n if (!current) return;\n const currentVersion = normaliseVersionToken((current as any).updated_at);\n if (!currentVersion) return;\n if (currentVersion !== expected) {\n throw new ConcurrentUpdateError({\n currentVersion,\n currentRecord: current,\n message: `Record ${object}/${id} was modified by another user (current version ${currentVersion}, expected ${expected})`,\n });\n }\n }\n\n // ==========================================\n // Global Search (M10.5)\n // ==========================================\n /**\n * Cross-object substring search across all registered objects that opt in\n * via `enable.searchable !== false` and `enable.apiEnabled !== false`.\n * Searches text-like fields (text/textarea/email/url/phone/markdown/html/string)\n * whose `searchable: true` flag is set, falling back to the object's\n * `displayNameField` (or `name`) when no fields are explicitly searchable.\n *\n * The query is split into whitespace-separated terms; each term must match\n * (case-insensitive LIKE) at least one searchable field. RBAC/RLS is\n * enforced by forwarding the caller's `context` to `engine.find` so users\n * only see records they are entitled to read.\n */\n async searchAll(request: {\n q: string;\n objects?: string[];\n limit?: number;\n perObject?: number;\n context?: any;\n }): Promise<{\n query: string;\n hits: Array<{\n object: string;\n id: string;\n title: string;\n snippet?: string;\n record: any;\n }>;\n totalObjects: number;\n totalHits: number;\n truncated: boolean;\n }> {\n const q = (request.q ?? '').trim();\n if (!q) {\n return { query: '', hits: [], totalObjects: 0, totalHits: 0, truncated: false };\n }\n\n const overallLimit = Math.max(1, Math.min(100, Number(request.limit ?? 20)));\n const perObject = Math.max(1, Math.min(25, Number(request.perObject ?? 5)));\n const objectsFilter = request.objects && request.objects.length\n ? new Set(request.objects)\n : null;\n\n // Tokenise: each token must match (LIKE %term%) at least one searchable field\n const terms = q.split(/\\s+/).filter(Boolean).slice(0, 8);\n\n const allObjects = (this.engine as any).registry?.getAllObjects?.() ?? [];\n const hits: Array<{ object: string; id: string; title: string; snippet?: string; record: any }> = [];\n let objectsScanned = 0;\n\n for (const obj of allObjects) {\n if (hits.length >= overallLimit) break;\n if (!obj?.name) continue;\n if (objectsFilter && !objectsFilter.has(obj.name)) continue;\n\n // Skip platform/system tables and opt-outs\n const enable = obj.enable ?? {};\n if (enable.searchable === false) continue;\n if (enable.apiEnabled === false) continue;\n // Skip noisy system tables by name prefix\n if (obj.name.startsWith('sys_audit_log')\n || obj.name.startsWith('sys_activity')\n || obj.name.startsWith('sys_session')\n || obj.name.startsWith('sys_presence')\n || obj.name.startsWith('sys_metadata')\n || obj.name.startsWith('sys_account')) {\n continue;\n }\n\n const fieldsRaw = obj.fields;\n const fields: Array<{ name: string; type: string; searchable?: boolean }> =\n Array.isArray(fieldsRaw)\n ? fieldsRaw\n : (fieldsRaw && typeof fieldsRaw === 'object'\n ? Object.entries(fieldsRaw).map(([name, f]: [string, any]) => ({ name, ...(f || {}) }))\n : []);\n const TEXT_TYPES = new Set(['text', 'textarea', 'string', 'email', 'url', 'phone', 'markdown', 'html']);\n const fieldByName = new Map(fields.map(f => [f.name, f]));\n const hasField = (n: string) => fieldByName.has(n);\n // Resolve title for a record using titleFormat → displayNameField →\n // common conventional fields → id. titleFormat supports simple\n // `{field}` placeholders (the `template` dialect); unresolved\n // placeholders fall through to the next strategy.\n const titleFormatSource = (obj.titleFormat && (obj.titleFormat.source || obj.titleFormat))\n || undefined;\n const renderTitle = (row: any): string => {\n if (typeof titleFormatSource === 'string') {\n let allResolved = true;\n const rendered = titleFormatSource.replace(/\\{\\{?\\s*([a-zA-Z0-9_.]+)\\s*\\}?\\}/g, (_m, key) => {\n const v = row[key];\n if (v == null || v === '') { allResolved = false; return ''; }\n return String(v);\n }).trim();\n if (rendered && allResolved) return rendered;\n if (rendered) return rendered.replace(/\\s+-\\s+$/, '').replace(/^\\s+-\\s+/, '').trim() || row.id;\n }\n const candidates = [\n obj.displayNameField,\n 'name', 'full_name', 'title', 'subject', 'label', 'company',\n ].filter((c): c is string => typeof c === 'string' && hasField(c));\n for (const c of candidates) {\n const v = row[c];\n if (v != null && String(v).trim()) return String(v);\n }\n const fn = row.first_name, ln = row.last_name;\n if (fn || ln) return `${fn ?? ''} ${ln ?? ''}`.trim();\n return String(row.id);\n };\n\n const titleFieldName = obj.displayNameField\n || (hasField('name') ? 'name' : undefined)\n || (hasField('title') ? 'title' : undefined)\n || fields.find(f => TEXT_TYPES.has(f.type))?.name;\n\n let searchableFields = fields\n .filter(f => f && TEXT_TYPES.has(f.type) && f.searchable === true)\n .map(f => f.name as string);\n\n // Fallback: if no field is explicitly searchable, scan the title field\n if (searchableFields.length === 0 && titleFieldName) {\n searchableFields = [titleFieldName];\n }\n if (searchableFields.length === 0) continue;\n\n objectsScanned++;\n\n // Build AND-of-OR filter: every term must hit at least one field.\n // ObjectQL exposes case-insensitive substring matching via `$contains`.\n const andClauses = terms.map(term => ({\n $or: searchableFields.map(f => ({ [f]: { $contains: term } })),\n }));\n const where = andClauses.length === 1 ? andClauses[0] : { $and: andClauses };\n\n try {\n const opts: any = {\n where,\n limit: perObject,\n orderBy: [{ field: 'updated_at', direction: 'desc' }],\n };\n if (request.context !== undefined) opts.context = request.context;\n\n const rows = await this.engine.find(obj.name, opts);\n for (const row of rows || []) {\n if (hits.length >= overallLimit) break;\n const title = renderTitle(row);\n // Build snippet from first searchable field that contains a term\n let snippet: string | undefined;\n for (const f of searchableFields) {\n const v = row[f];\n if (typeof v === 'string' && v) {\n const lc = v.toLowerCase();\n const idx = terms.map(t => lc.indexOf(t.toLowerCase())).find(i => i >= 0);\n if (idx != null && idx >= 0) {\n const start = Math.max(0, idx - 30);\n const end = Math.min(v.length, idx + 90);\n snippet = (start > 0 ? '…' : '') + v.slice(start, end) + (end < v.length ? '…' : '');\n break;\n }\n }\n }\n hits.push({\n object: obj.name,\n id: row.id,\n title,\n snippet,\n record: row,\n });\n }\n } catch {\n // RBAC denial or driver hiccup — skip silently per object\n continue;\n }\n }\n\n return {\n query: q,\n hits,\n totalObjects: objectsScanned,\n totalHits: hits.length,\n truncated: hits.length >= overallLimit,\n };\n }\n\n // ==========================================\n // Lead Convert (M10.6)\n // ==========================================\n /**\n * Convert a qualified Lead into an Account + Contact (+ optional\n * Opportunity) and mark the Lead as converted. Mirrors the Salesforce\n * lead-conversion model:\n *\n * - If `accountId` is provided, the lead's company info is NOT used\n * to create a new account; the new contact and opportunity link to\n * the existing account instead.\n * - If `contactId` is provided, no new contact is created either —\n * useful when the lead is a new contact at an existing account.\n * - `createOpportunity` defaults to true; pass `false` to convert\n * without producing an opportunity (some teams convert \"logos\n * only\" first).\n * - Lead is updated atomically: `is_converted=true`,\n * `converted_account`/`converted_contact`/`converted_opportunity`\n * pointers, `converted_date`, and `status='converted'`.\n *\n * Atomicity is enforced via the default driver's transaction support\n * when available; otherwise a best-effort compensation (delete\n * already-created child records on failure) is attempted. Permission\n * checks on each child object are inherited from the caller's\n * execution context so SecurityPlugin still gates account/contact/\n * opportunity creates.\n */\n async convertLead(request: {\n leadId: string;\n accountId?: string;\n contactId?: string;\n createOpportunity?: boolean;\n opportunity?: {\n name?: string;\n amount?: number;\n close_date?: string;\n stage?: string;\n };\n convertedStatus?: string;\n context?: any;\n }): Promise<{\n lead: any;\n account: any;\n contact: any;\n opportunity: any | null;\n }> {\n const leadId = String(request.leadId || '').trim();\n if (!leadId) {\n const err: any = new Error('leadId is required');\n err.status = 400;\n err.code = 'INVALID_REQUEST';\n throw err;\n }\n const ctx = request.context;\n const ctxOpt = ctx !== undefined ? { context: ctx } : undefined;\n\n // Load lead\n const lead = await this.engine.findOne('lead', { where: { id: leadId }, ...(ctxOpt as any) } as any);\n if (!lead) {\n const err: any = new Error(`Lead '${leadId}' not found`);\n err.status = 404;\n err.code = 'LEAD_NOT_FOUND';\n throw err;\n }\n if (lead.is_converted) {\n const err: any = new Error(`Lead '${leadId}' is already converted`);\n err.status = 409;\n err.code = 'LEAD_ALREADY_CONVERTED';\n throw err;\n }\n\n // Wrap the whole conversion in a single DB transaction so that a\n // partial failure (e.g. opportunity insert fails after we've\n // already created the account/contact) rolls back atomically\n // instead of leaving orphan rows. Falls back to direct execution\n // on drivers without transaction support — in that case the\n // operations are still ordered so callers see the same partial\n // state we'd get from any non-atomic sequence.\n const runConversion = async (trxCtx: any) => {\n const opCtx = trxCtx ?? ctx;\n const trxCtxOpt = opCtx !== undefined ? { context: opCtx } : undefined;\n\n // 1) Account\n let account: any;\n if (request.accountId) {\n account = await this.engine.findOne('account', { where: { id: request.accountId }, ...(trxCtxOpt as any) } as any);\n if (!account) {\n const err: any = new Error(`Account '${request.accountId}' not found`);\n err.status = 404;\n err.code = 'ACCOUNT_NOT_FOUND';\n throw err;\n }\n } else {\n const accountPayload: Record<string, any> = {\n name: lead.company || `${lead.first_name ?? ''} ${lead.last_name ?? ''}`.trim() || 'Untitled Account',\n };\n if (lead.industry) accountPayload.industry = lead.industry;\n if (lead.annual_revenue) accountPayload.annual_revenue = lead.annual_revenue;\n if (lead.number_of_employees) accountPayload.employees = lead.number_of_employees;\n if (lead.website) accountPayload.website = lead.website;\n if (lead.phone) accountPayload.phone = lead.phone;\n if (lead.address) accountPayload.billing_address = lead.address;\n if (lead.owner) accountPayload.owner = lead.owner;\n account = await this.engine.insert('account', accountPayload, trxCtxOpt as any);\n }\n\n // 2) Contact\n let contact: any;\n if (request.contactId) {\n contact = await this.engine.findOne('contact', { where: { id: request.contactId }, ...(trxCtxOpt as any) } as any);\n if (!contact) {\n const err: any = new Error(`Contact '${request.contactId}' not found`);\n err.status = 404;\n err.code = 'CONTACT_NOT_FOUND';\n throw err;\n }\n } else {\n const contactPayload: Record<string, any> = {\n first_name: lead.first_name ?? '',\n last_name: lead.last_name ?? lead.company ?? 'Unknown',\n };\n if (lead.salutation) contactPayload.salutation = lead.salutation;\n if (lead.email) contactPayload.email = lead.email;\n if (lead.phone) contactPayload.phone = lead.phone;\n if (lead.mobile) contactPayload.mobile = lead.mobile;\n if (lead.title) contactPayload.title = lead.title;\n if (lead.address) contactPayload.mailing_address = lead.address;\n if (lead.owner) contactPayload.owner = lead.owner;\n if (account?.id) contactPayload.account = account.id;\n contact = await this.engine.insert('contact', contactPayload, trxCtxOpt as any);\n }\n\n // 3) Opportunity (optional)\n let opportunity: any | null = null;\n const shouldCreateOpp = request.createOpportunity !== false;\n if (shouldCreateOpp) {\n const oppOverrides = request.opportunity ?? {};\n const defaultName = oppOverrides.name\n || `${account?.name ?? lead.company ?? 'Lead'} - New Opportunity`;\n const defaultClose = oppOverrides.close_date\n || new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);\n const oppPayload: Record<string, any> = {\n name: defaultName,\n stage: oppOverrides.stage ?? 'qualification',\n close_date: defaultClose,\n };\n if (oppOverrides.amount !== undefined) oppPayload.amount = oppOverrides.amount;\n else if (lead.annual_revenue) oppPayload.amount = lead.annual_revenue;\n if (account?.id) oppPayload.account = account.id;\n if (contact?.id) oppPayload.primary_contact = contact.id;\n if (lead.owner) oppPayload.owner = lead.owner;\n if (lead.lead_source) oppPayload.lead_source = lead.lead_source;\n opportunity = await this.engine.insert('opportunity', oppPayload, trxCtxOpt as any);\n }\n\n // 4) Mark lead converted\n const leadUpdate: Record<string, any> = {\n is_converted: true,\n status: request.convertedStatus ?? 'converted',\n converted_account: account?.id ?? null,\n converted_contact: contact?.id ?? null,\n converted_opportunity: opportunity?.id ?? null,\n converted_date: new Date().toISOString(),\n };\n const updatedLead = await this.engine.update('lead', leadUpdate, {\n where: { id: leadId },\n ...(trxCtxOpt as any),\n } as any);\n\n return {\n lead: updatedLead ?? { ...lead, ...leadUpdate },\n account,\n contact,\n opportunity,\n };\n };\n\n return (this.engine as any).transaction(runConversion, ctx);\n }\n\n // ==========================================\n // Metadata Caching\n // ==========================================\n\n async getMetaItemCached(request: { type: string, name: string, cacheRequest?: MetadataCacheRequest }): Promise<MetadataCacheResponse> {\n try {\n // Delegate to getMetaItem so the customization-overlay read order\n // (sys_metadata → registry → MetadataService) is honoured here too\n // (ADR-0005). Without this, cached reads silently bypass overlays.\n const result = await this.getMetaItem({ type: request.type, name: request.name });\n const item = (result as any)?.item;\n\n if (!item) {\n throw new Error(`Metadata item ${request.type}/${request.name} not found`);\n }\n\n // Calculate ETag (simple hash of the stringified metadata)\n const content = JSON.stringify(item);\n const hash = simpleHash(content);\n const etag = { value: hash, weak: false };\n\n // Check If-None-Match header\n if (request.cacheRequest?.ifNoneMatch) {\n const clientEtag = request.cacheRequest.ifNoneMatch.replace(/^\"(.*)\"$/, '$1').replace(/^W\\/\"(.*)\"$/, '$1');\n if (clientEtag === hash) {\n // Return 304 Not Modified\n return {\n notModified: true,\n etag,\n };\n }\n }\n\n // Return full metadata with cache headers\n return {\n data: item,\n etag,\n lastModified: new Date().toISOString(),\n cacheControl: {\n directives: ['public', 'max-age'],\n maxAge: 3600, // 1 hour\n },\n notModified: false,\n };\n } catch (error: any) {\n throw error;\n }\n }\n\n // ==========================================\n // Batch Operations\n // ==========================================\n\n async batchData(request: { object: string, request: BatchUpdateRequest }): Promise<BatchUpdateResponse> {\n const { object, request: batchReq } = request;\n const { operation, records, options } = batchReq;\n const results: Array<{ id?: string; success: boolean; error?: string; record?: any }> = [];\n let succeeded = 0;\n let failed = 0;\n\n for (const record of records) {\n try {\n switch (operation) {\n case 'create': {\n const created = await this.engine.insert(object, record.data || record);\n results.push({ id: created.id, success: true, record: created });\n succeeded++;\n break;\n }\n case 'update': {\n if (!record.id) throw new Error('Record id is required for update');\n const updated = await this.engine.update(object, record.data || {}, { where: { id: record.id } });\n results.push({ id: record.id, success: true, record: updated });\n succeeded++;\n break;\n }\n case 'upsert': {\n // Try update first, then create if not found\n if (record.id) {\n try {\n const existing = await this.engine.findOne(object, { where: { id: record.id } });\n if (existing) {\n const updated = await this.engine.update(object, record.data || {}, { where: { id: record.id } });\n results.push({ id: record.id, success: true, record: updated });\n } else {\n const created = await this.engine.insert(object, { id: record.id, ...(record.data || {}) });\n results.push({ id: created.id, success: true, record: created });\n }\n } catch {\n const created = await this.engine.insert(object, { id: record.id, ...(record.data || {}) });\n results.push({ id: created.id, success: true, record: created });\n }\n } else {\n const created = await this.engine.insert(object, record.data || record);\n results.push({ id: created.id, success: true, record: created });\n }\n succeeded++;\n break;\n }\n case 'delete': {\n if (!record.id) throw new Error('Record id is required for delete');\n await this.engine.delete(object, { where: { id: record.id } });\n results.push({ id: record.id, success: true });\n succeeded++;\n break;\n }\n default:\n results.push({ id: record.id, success: false, error: `Unknown operation: ${operation}` });\n failed++;\n }\n } catch (err: any) {\n results.push({ id: record.id, success: false, error: err.message });\n failed++;\n if (options?.atomic) {\n // Abort remaining operations on first failure in atomic mode\n break;\n }\n if (!options?.continueOnError) {\n break;\n }\n }\n }\n\n return {\n success: failed === 0,\n operation,\n total: records.length,\n succeeded,\n failed,\n results: options?.returnRecords !== false ? results : results.map(r => ({ id: r.id, success: r.success, error: r.error })),\n } as BatchUpdateResponse;\n }\n \n async createManyData(request: { object: string, records: any[] }): Promise<any> {\n const records = await this.engine.insert(request.object, request.records);\n return {\n object: request.object,\n records,\n count: records.length\n };\n }\n \n async updateManyData(request: UpdateManyDataRequest): Promise<BatchUpdateResponse> {\n const { object, records, options } = request;\n const results: Array<{ id?: string; success: boolean; error?: string; record?: any }> = [];\n let succeeded = 0;\n let failed = 0;\n\n for (const record of records) {\n try {\n const updated = await this.engine.update(object, record.data, { where: { id: record.id } });\n results.push({ id: record.id, success: true, record: updated });\n succeeded++;\n } catch (err: any) {\n results.push({ id: record.id, success: false, error: err.message });\n failed++;\n if (!options?.continueOnError) {\n break;\n }\n }\n }\n\n return {\n success: failed === 0,\n operation: 'update',\n total: records.length,\n succeeded,\n failed,\n results,\n } as BatchUpdateResponse;\n }\n\n async analyticsQuery(request: any): Promise<any> {\n // Map AnalyticsQuery (cube-style) to engine aggregation.\n // cube name maps to object name; measures → aggregations; dimensions → groupBy.\n const { query, cube } = request;\n const object = cube;\n\n // Build groupBy from dimensions\n const groupBy = query.dimensions || [];\n\n // Build aggregations from measures\n // Measures can be simple field names like \"count\" or \"field_name.sum\"\n // Or cube-defined measure names. We support: field.function or just function(field).\n const aggregations: Array<{ field: string; method: string; alias: string }> = [];\n if (query.measures) {\n for (const measure of query.measures) {\n // Support formats: \"count\", \"amount.sum\", \"revenue.avg\"\n if (measure === 'count' || measure === 'count_all') {\n aggregations.push({ field: '*', method: 'count', alias: 'count' });\n } else if (measure.includes('.')) {\n const [field, method] = measure.split('.');\n aggregations.push({ field, method, alias: `${field}_${method}` });\n } else {\n // Treat as count of the field\n aggregations.push({ field: measure, method: 'sum', alias: measure });\n }\n }\n }\n\n // Build filter from analytics filters\n let filter: any = undefined;\n if (query.filters && query.filters.length > 0) {\n const conditions: any[] = query.filters.map((f: any) => {\n const op = this.mapAnalyticsOperator(f.operator);\n if (f.values && f.values.length === 1) {\n return { [f.member]: { [op]: f.values[0] } };\n } else if (f.values && f.values.length > 1) {\n return { [f.member]: { $in: f.values } };\n }\n return { [f.member]: { [op]: true } };\n });\n filter = conditions.length === 1 ? conditions[0] : { $and: conditions };\n }\n\n // Execute via engine.aggregate (which delegates to driver.find with groupBy/aggregations)\n const rows = await this.engine.aggregate(object, {\n where: filter,\n groupBy: groupBy.length > 0 ? groupBy : undefined,\n aggregations: aggregations.length > 0\n ? aggregations.map(a => ({ function: a.method as any, field: a.field, alias: a.alias }))\n : [{ function: 'count' as any, alias: 'count' }],\n });\n\n // Build field metadata\n const fields = [\n ...groupBy.map((d: string) => ({ name: d, type: 'string' })),\n ...aggregations.map(a => ({ name: a.alias, type: 'number' })),\n ];\n\n return {\n success: true,\n data: {\n rows,\n fields,\n },\n };\n }\n\n async getAnalyticsMeta(request: any): Promise<any> {\n // Auto-generate cube metadata from registered objects in SchemaRegistry.\n // Each object becomes a cube; number fields → measures; other fields → dimensions.\n const objects = this.engine.registry.listItems('object');\n const cubeFilter = request?.cube;\n\n const cubes: any[] = [];\n for (const obj of objects) {\n const schema = obj as any;\n if (cubeFilter && schema.name !== cubeFilter) continue;\n\n const measures: Record<string, any> = {};\n const dimensions: Record<string, any> = {};\n const fields = schema.fields || {};\n\n // Always add a count measure\n measures['count'] = {\n name: 'count',\n label: 'Count',\n type: 'count',\n sql: '*',\n };\n\n for (const [fieldName, fieldDef] of Object.entries(fields)) {\n const fd = fieldDef as any;\n const fieldType = fd.type || 'text';\n\n if (['number', 'currency', 'percent'].includes(fieldType)) {\n // Numeric fields become both measures and dimensions\n measures[`${fieldName}_sum`] = {\n name: `${fieldName}_sum`,\n label: `${fd.label || fieldName} (Sum)`,\n type: 'sum',\n sql: fieldName,\n };\n measures[`${fieldName}_avg`] = {\n name: `${fieldName}_avg`,\n label: `${fd.label || fieldName} (Avg)`,\n type: 'avg',\n sql: fieldName,\n };\n dimensions[fieldName] = {\n name: fieldName,\n label: fd.label || fieldName,\n type: 'number',\n sql: fieldName,\n };\n } else if (['date', 'datetime'].includes(fieldType)) {\n dimensions[fieldName] = {\n name: fieldName,\n label: fd.label || fieldName,\n type: 'time',\n sql: fieldName,\n granularities: ['day', 'week', 'month', 'quarter', 'year'],\n };\n } else if (['boolean'].includes(fieldType)) {\n dimensions[fieldName] = {\n name: fieldName,\n label: fd.label || fieldName,\n type: 'boolean',\n sql: fieldName,\n };\n } else {\n // text, select, lookup, etc. → dimension\n dimensions[fieldName] = {\n name: fieldName,\n label: fd.label || fieldName,\n type: 'string',\n sql: fieldName,\n };\n }\n }\n\n cubes.push({\n name: schema.name,\n title: schema.label || schema.name,\n description: schema.description,\n sql: schema.name,\n measures,\n dimensions,\n public: true,\n });\n }\n\n return {\n success: true,\n data: { cubes },\n };\n }\n\n private mapAnalyticsOperator(op: string): string {\n const map: Record<string, string> = {\n equals: '$eq',\n notEquals: '$ne',\n contains: '$contains',\n notContains: '$notContains',\n gt: '$gt',\n gte: '$gte',\n lt: '$lt',\n lte: '$lte',\n set: '$ne',\n notSet: '$eq',\n };\n return map[op] || '$eq';\n }\n\n async triggerAutomation(_request: any): Promise<any> {\n throw new Error('triggerAutomation requires plugin-automation service. Install and register a plugin that provides the \"automation\" service.');\n }\n\n async deleteManyData(request: DeleteManyDataRequest): Promise<any> {\n // This expects deleting by IDs.\n return this.engine.delete(request.object, {\n where: { id: { $in: request.ids } },\n ...request.options\n });\n }\n\n /**\n * Metadata types that are customer-overridable via {@link saveMetaItem}/\n * {@link deleteMetaItem} in project-kernel mode. Derived from the canonical\n * registry in {@link DEFAULT_METADATA_TYPE_REGISTRY}: a type opts in by\n * setting `allowOrgOverride: true` on its registry entry. The set is\n * augmented with the plural form of every singular so callers using REST\n * conventions (`/api/v1/meta/views/...`) get the same gate. See ADR-0005\n * §\"Whitelist enforcement\" for the rationale and the per-type rollout\n * checklist.\n */\n private static readonly OVERLAY_ALLOWED_TYPES: ReadonlySet<string> = (() => {\n const out = new Set<string>();\n for (const entry of DEFAULT_METADATA_TYPE_REGISTRY) {\n if (!entry.allowOrgOverride) continue;\n out.add(entry.type);\n const plural = SINGULAR_TO_PLURAL[entry.type];\n if (plural) out.add(plural);\n }\n return out;\n })();\n\n /** Normalize plural→singular before consulting the allow-list. */\n private static isOverlayAllowed(type: string): boolean {\n const singular = PLURAL_TO_SINGULAR[type] ?? type;\n return ObjectStackProtocolImplementation.OVERLAY_ALLOWED_TYPES.has(singular)\n || ObjectStackProtocolImplementation.OVERLAY_ALLOWED_TYPES.has(type);\n }\n\n /**\n * Mirror an object-type overlay write into the in-memory engine\n * registry so subsequent CRUD finds the new schema. Idempotent and\n * safe to call after a successful persistence call. For the legacy\n * write path this is invoked BEFORE persistence (historical behavior\n * preserved); for the PR-10d.3 repository path it is invoked only\n * AFTER `put()` resolves successfully, so a failed write — DB error,\n * optimistic-lock conflict, validation failure — never leaks a\n * stale schema into the registry.\n */\n private applyObjectRegistryMutation(request: { type: string; name: string; item?: any }): void {\n if (request.type !== 'object' && request.type !== 'objects') return;\n this.engine.registry.registerItem(request.type, request.item, 'name');\n try {\n this.engine.registry.registerObject(request.item as any, 'sys_metadata');\n } catch (err: any) {\n console.warn(\n `[Protocol] registerObject failed for ${request.name}: ${err?.message ?? err}`,\n );\n }\n }\n\n async saveMetaItem(request: { type: string, name: string, item?: any, organizationId?: string, parentVersion?: string | null, actor?: string }) {\n if (!request.item) {\n throw new Error('Item data is required');\n }\n\n // ADR-0005 opt-in gate: project-kernel customization is only allowed\n // for types whose registry entry sets `allowOrgOverride: true`.\n // Returns 403 `not_overridable` so the caller can distinguish from a\n // generic 400 (validation) or 422 (spec mismatch).\n if (this.projectId !== undefined\n && !ObjectStackProtocolImplementation.isOverlayAllowed(request.type)) {\n const allowed = Array.from(ObjectStackProtocolImplementation.OVERLAY_ALLOWED_TYPES).join(', ');\n const err = new Error(\n `[not_overridable] Metadata type '${request.type}' has not opted into per-org overlay writes. `\n + `Set allowOrgOverride: true on its DEFAULT_METADATA_TYPE_REGISTRY entry to enable. `\n + `Currently allowed: ${allowed}. See docs/adr/0005-metadata-customization-overlay.md.`\n );\n (err as any).code = 'not_overridable';\n (err as any).status = 403;\n throw err;\n }\n\n // Spec-conformance check: if a Zod schema is registered for this\n // overlay type (see OVERLAY_VALIDATION_SCHEMAS), validate the payload\n // before persisting. We surface invalid payloads as `422\n // invalid_metadata` with structured Zod issues so the Studio form can\n // highlight the offending field. The original `item` is kept verbatim\n // — `parsed.data` would strip Studio-only auxiliary fields (e.g.\n // isPinned, isDefault, sortOrder) that intentionally ride along with\n // the overlay document. ADR-0005 §\"Validation\".\n {\n const schema = resolveOverlaySchema(request.type, request.item);\n if (schema) {\n const parsed = schema.safeParse(request.item);\n if (!parsed.success) {\n const issues = parsed.error.issues.map((i: z.ZodIssue) => ({\n path: i.path.join('.'),\n message: i.message,\n code: i.code,\n }));\n const summary = issues.slice(0, 3)\n .map((i: { path: string; message: string }) => `${i.path || '<root>'}: ${i.message}`)\n .join('; ');\n const err = new Error(\n `[invalid_metadata] ${request.type}/${request.name} failed spec validation: ${summary}`\n + (issues.length > 3 ? ` (+${issues.length - 3} more)` : '')\n );\n (err as any).code = 'invalid_metadata';\n (err as any).status = 422;\n (err as any).issues = issues;\n throw err;\n }\n }\n }\n\n // 1. Update the in-memory registry (runtime cache) ONLY for the\n // `object` type — schema definitions feed engine.syncSchema and\n // must be reflected immediately for CRUD to work. For all other\n // metadata types (view, dashboard, ...) we deliberately do NOT\n // mutate the artifact-loaded registry — sys_metadata is the\n // authoritative overlay store and `getMetaItem` consults it\n // first (ADR-0005). Mutating the registry here would create a\n // \"stale overlay\" hazard: `deleteMetaItem` cannot restore the\n // original artifact value because it was overwritten in-place.\n // 1. (deferred) — Object-type runtime-registry mutation used to happen\n // here unconditionally. Moved to AFTER successful persistence\n // (PR-10d.3 rubber-duck #3): a failed put() — DB error, optimistic\n // conflict, validation — must not leave a stale object schema in\n // the in-memory registry. See `applyObjectRegistryMutation` below.\n\n // 2. Persist to sys_metadata as a customization overlay row.\n // ADR-0005 (revised 2026-05): isolation key is `organization_id`\n // (each env = its own DB, so project_id is redundant). Org-scoped\n // rows belong to the active organization in the request; env-wide\n // overlays are written with organization_id = NULL.\n await this.ensureOverlayIndex();\n\n // ADR-0008 — overlay-allowed metadata types ALWAYS route through the\n // repository write path: every mutation appends to the change log\n // and emits a watch event with a monotonic `seq` (which Studio /\n // browser clients consume for HMR). Non-overlay-allowed types\n // (`object`, `flow`, `agent`, ...) take the legacy raw-engine path\n // below — this preserves the control-plane bootstrap semantic where\n // `saveMetaItem` is permitted by the outer protocol gate to write\n // any metadata type when `projectId` is undefined (the repository's\n // `assertAllowed()` would 403 those writes).\n //\n // PR-10d.6 (this PR) removed the `useRepositoryWritePath` flag.\n // For overlay-allowed types the repo path is no longer opt-out-able.\n //\n // Callers that omit `parentVersion` get backward-compatible\n // \"last-write-wins\" semantics: we read the current row's checksum\n // and use it as the parent, so the conflict check tautologically\n // passes (best-effort — racy under concurrent writes; explicit\n // optimistic-lock is opt-in via `parentVersion`).\n // Callers that pass an explicit `parentVersion` (e.g. Studio after\n // reading an item) get true optimistic-lock conflict detection\n // surfaced as a 409.\n const singularTypeForRepo = PLURAL_TO_SINGULAR[request.type] ?? request.type;\n if (ObjectStackProtocolImplementation.isOverlayAllowed(singularTypeForRepo)) {\n const orgId = request.organizationId ?? null;\n const repo = this.getOverlayRepo(orgId);\n const ref = {\n type: singularTypeForRepo,\n name: request.name,\n org: orgId ?? 'env',\n } as Parameters<typeof repo.put>[0];\n let parentVersion: string | null;\n if (request.parentVersion !== undefined) {\n parentVersion = request.parentVersion;\n } else {\n const current = await repo.get(ref);\n parentVersion = current?.hash ?? null;\n }\n try {\n const result = await repo.put(ref, request.item, {\n parentVersion,\n actor: request.actor ?? 'system',\n source: 'protocol.saveMetaItem',\n });\n // Persistence succeeded — NOW it's safe to mutate the\n // in-memory object registry. If put() had thrown, the\n // registry would still reflect the prior state.\n this.applyObjectRegistryMutation(request);\n return {\n success: true,\n version: result.version,\n seq: result.seq,\n message: orgId\n ? `Saved customization overlay (org=${orgId}) — type=${request.type}, name=${request.name} [seq=${result.seq}]`\n : `Saved customization overlay (env-wide) — type=${request.type}, name=${request.name} [seq=${result.seq}]`,\n };\n } catch (err: any) {\n if (err instanceof ConflictError) {\n const conflict = new Error(\n `[metadata_conflict] ${request.type}/${request.name} has been modified since you loaded it. `\n + `Expected parent ${err.expectedParent ?? 'null'} but current is ${err.actualHead ?? 'null'}.`,\n );\n (conflict as any).code = 'metadata_conflict';\n (conflict as any).status = 409;\n (conflict as any).expectedParent = err.expectedParent;\n (conflict as any).actualHead = err.actualHead;\n throw conflict;\n }\n throw err;\n }\n }\n\n // Legacy raw-engine path — taken when the type is NOT overlay-allowed\n // (control-plane bootstrap of `object`/`flow`/etc. when `projectId` is\n // undefined). This branch is intentionally retained: the repository\n // write path's `assertAllowed()` would 403 these types. There is no\n // change-log / HMR machinery for non-overlay metadata because\n // control-plane mutations are bootstrap-only and not subject to\n // per-org overlay semantics.\n //\n // Note: the registry mutation for the legacy path happens BEFORE\n // persistence (preserved historical behaviour). The overlay-allowed\n // path moved it to AFTER persistence in PR-10d.3 (rubber-duck #3).\n this.applyObjectRegistryMutation(request);\n\n try {\n const now = new Date().toISOString();\n const orgId = request.organizationId ?? null;\n const scopedWhere: Record<string, unknown> = {\n type: request.type,\n name: request.name,\n organization_id: orgId,\n state: 'active',\n };\n const existing = await this.engine.findOne('sys_metadata', {\n where: scopedWhere,\n });\n\n if (existing) {\n await this.engine.update('sys_metadata', {\n metadata: JSON.stringify(request.item),\n updated_at: now,\n version: (existing.version || 0) + 1,\n state: 'active',\n }, {\n where: { id: existing.id }\n });\n } else {\n // Use crypto.randomUUID() when available (modern browsers and Node ≥ 14.17);\n // fall back to a time+random ID for older or restricted environments.\n const id = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `meta_${Date.now()}_${Math.random().toString(36).slice(2)}`;\n const row: Record<string, unknown> = {\n id,\n name: request.name,\n type: request.type,\n // `scope` enum is ['system','platform','user']; per-org\n // overlays use 'platform' as the informational tag. The\n // authoritative isolation key is `organization_id`.\n scope: 'platform',\n metadata: JSON.stringify(request.item),\n state: 'active',\n version: 1,\n created_at: now,\n updated_at: now,\n organization_id: orgId,\n };\n await this.engine.insert('sys_metadata', row);\n }\n\n return {\n success: true,\n message: orgId\n ? `Saved customization overlay (org=${orgId}) — type=${request.type}, name=${request.name}`\n : `Saved customization overlay (env-wide) — type=${request.type}, name=${request.name}`,\n };\n } catch (dbError: any) {\n // DB write failed — surface as an error rather than silently\n // succeeding (regression from the pre-ADR-0005 \"silent loss\" bug).\n console.error(\n `[Protocol] sys_metadata persistence failed for ${request.type}/${request.name}: ${dbError.message}`,\n );\n const err = new Error(\n `Failed to persist customization overlay to sys_metadata: ${dbError.message}. `\n + `In-memory registry was updated but will be lost on restart.`,\n );\n (err as any).code = 'overlay_persistence_failed';\n (err as any).status = 500;\n throw err;\n }\n }\n\n /**\n * Yield the durable change-log for a single metadata item — every\n * put/delete recorded in `sys_metadata_history` for `(org, type, name)`,\n * in event_seq order. Powers the Studio \"History\" tab and any\n * client-side audit timeline.\n *\n * Returns `[]` for non-overlay-allowed types (the legacy raw-engine\n * path doesn't record history) instead of throwing — callers can treat\n * \"no history\" uniformly.\n */\n async historyMetaItem(request: {\n type: string;\n name: string;\n organizationId?: string;\n sinceSeq?: number;\n limit?: number;\n }): Promise<{ events: import('@objectstack/metadata-core').MetadataEvent[] }> {\n const singularType = PLURAL_TO_SINGULAR[request.type] ?? request.type;\n if (!ObjectStackProtocolImplementation.isOverlayAllowed(singularType)) {\n return { events: [] };\n }\n const orgId = request.organizationId ?? null;\n const repo = this.getOverlayRepo(orgId);\n const ref = {\n type: singularType,\n name: request.name,\n org: orgId ?? 'env',\n } as Parameters<typeof repo.history>[0];\n\n const events: import('@objectstack/metadata-core').MetadataEvent[] = [];\n const opts: { sinceSeq?: number; limit?: number } = {};\n if (request.sinceSeq !== undefined) opts.sinceSeq = request.sinceSeq;\n if (request.limit !== undefined) opts.limit = request.limit;\n for await (const ev of repo.history(ref, opts)) events.push(ev);\n return { events };\n }\n\n /**\n * Remove a customization overlay row for the given metadata item, so the\n * next read falls through to the artifact-loaded default. Implements the\n * \"Reset to factory default\" semantic from ADR-0005. Whitelist is shared\n * with {@link saveMetaItem}.\n */\n async deleteMetaItem(request: {\n type: string;\n name: string;\n organizationId?: string;\n parentVersion?: string | null;\n actor?: string;\n }): Promise<{\n success: boolean;\n message?: string;\n reset?: boolean;\n seq?: number;\n }> {\n if (this.projectId !== undefined\n && !ObjectStackProtocolImplementation.isOverlayAllowed(request.type)) {\n const err = new Error(\n `[not_overridable] Metadata type '${request.type}' has not opted into per-org overlay writes. `\n + `See docs/adr/0005-metadata-customization-overlay.md.`\n );\n (err as any).code = 'not_overridable';\n (err as any).status = 403;\n throw err;\n }\n\n const singularTypeForRepo = PLURAL_TO_SINGULAR[request.type] ?? request.type;\n const useRepoPath = ObjectStackProtocolImplementation.isOverlayAllowed(singularTypeForRepo);\n\n // ADR-0008 — overlay-allowed types route through SysMetadataRepository\n // so the delete (a) is wrapped in engine.transaction(), (b) appends a\n // tombstone row to sys_metadata_history, and (c) emits a watch event\n // with a monotonic `seq` for HMR. Non-overlay-allowed types (only\n // reachable in control-plane bootstrap mode where projectId is\n // undefined) take the legacy raw-engine path below — the repository's\n // `assertAllowed()` whitelist would 403 those deletes.\n if (useRepoPath) {\n const orgId = request.organizationId ?? null;\n const repo = this.getOverlayRepo(orgId);\n const ref = {\n type: singularTypeForRepo,\n name: request.name,\n org: orgId ?? 'env',\n } as Parameters<typeof repo.delete>[0];\n\n try {\n // Probe first — \"no overlay exists\" is a success/no-op, not\n // a conflict. The repo would otherwise throw ConflictError.\n const current = await repo.get(ref);\n if (!current) {\n return {\n success: true,\n reset: false,\n message: `No customization overlay found for ${request.type}/${request.name} — already at artifact default.`,\n };\n }\n\n // Last-write-wins parent resolution unless the caller pinned\n // an explicit version (Studio's \"Reset\" button is unpinned;\n // a future \"delete vN\" flow can pass parentVersion).\n const parentVersion: string = request.parentVersion !== undefined\n ? (request.parentVersion ?? current.hash)\n : current.hash;\n\n const result = await repo.delete(ref, {\n parentVersion,\n actor: request.actor ?? 'system',\n source: 'protocol.deleteMetaItem',\n });\n\n // Refresh the in-memory artifact-side state on control-plane\n // kernels (same logic as the legacy branch — see comments\n // there for why this only runs when projectId === undefined).\n if (this.projectId === undefined) {\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.get === 'function') {\n const artifactItem = await metadataService.get(request.type, request.name);\n if (artifactItem !== undefined) {\n this.engine.registry.registerItem(request.type, artifactItem, 'name');\n }\n }\n } catch {\n // Best-effort registry refresh; next read fixes it anyway\n }\n }\n\n return {\n success: true,\n reset: true,\n seq: result.seq,\n message: `Customization overlay deleted — ${request.type}/${request.name} reset to artifact default. [seq=${result.seq}]`,\n };\n } catch (err: any) {\n if (err instanceof ConflictError) {\n const conflict = new Error(\n `[metadata_conflict] ${request.type}/${request.name} has been modified since you loaded it. `\n + `Expected parent ${err.expectedParent ?? 'null'} but current is ${err.actualHead ?? 'null'}.`,\n );\n (conflict as any).code = 'metadata_conflict';\n (conflict as any).status = 409;\n (conflict as any).expectedParent = err.expectedParent;\n (conflict as any).actualHead = err.actualHead;\n throw conflict;\n }\n const e = new Error(`Failed to delete customization overlay: ${err.message ?? err}`);\n (e as any).status = err?.status ?? 500;\n throw e;\n }\n }\n\n // ── Legacy raw-engine path: only reachable in control-plane bootstrap\n // (projectId === undefined) for non-overlay-allowed types like\n // `object`, `flow`, `agent`. No history row, no watch event — these\n // types don't participate in the change-log model.\n const scopedWhere: Record<string, unknown> = {\n type: request.type,\n name: request.name,\n organization_id: request.organizationId ?? null,\n };\n\n try {\n const existing = await this.engine.findOne('sys_metadata', { where: scopedWhere });\n if (!existing) {\n return {\n success: true,\n reset: false,\n message: `No customization overlay found for ${request.type}/${request.name} — already at artifact default.`,\n };\n }\n await this.engine.delete('sys_metadata', { where: { id: existing.id } });\n\n if (this.projectId === undefined) {\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.get === 'function') {\n const artifactItem = await metadataService.get(request.type, request.name);\n if (artifactItem !== undefined) {\n this.engine.registry.registerItem(request.type, artifactItem, 'name');\n }\n }\n } catch {\n // Best-effort registry refresh; next read fixes it anyway\n }\n }\n\n return {\n success: true,\n reset: true,\n message: `Customization overlay deleted — ${request.type}/${request.name} reset to artifact default.`,\n };\n } catch (err: any) {\n const e = new Error(`Failed to delete customization overlay: ${err.message}`);\n (e as any).status = 500;\n throw e;\n }\n }\n\n /**\n * Hydrate SchemaRegistry from the database on startup.\n * Loads all active metadata records and registers them in the in-memory registry.\n * Safe to call repeatedly — idempotent (latest DB record wins).\n *\n * Per ADR-0005, project-kernel mode ALSO hydrates from sys_metadata —\n * customization overlay rows must survive restart. Scope filter\n * (`project_id = this.projectId ?? null`) keeps tenants isolated.\n */\n async loadMetaFromDb(): Promise<{ loaded: number; errors: number }> {\n let loaded = 0;\n let errors = 0;\n try {\n // ADR-0005 (revised 2026-05): hydrate only env-wide rows\n // (organization_id IS NULL). Per-org overlays are loaded on\n // demand by getMetaItem to avoid cross-org leakage into the\n // process-wide SchemaRegistry.\n const where: Record<string, unknown> = {\n state: 'active',\n organization_id: null,\n };\n const records = await this.engine.find('sys_metadata', { where });\n for (const record of records) {\n try {\n const data = typeof record.metadata === 'string'\n ? JSON.parse(record.metadata)\n : record.metadata;\n // Normalize DB type to singular (DB may store legacy plural forms)\n const normalizedType = PLURAL_TO_SINGULAR[record.type] ?? record.type;\n if (normalizedType === 'object') {\n this.engine.registry.registerObject(data as any, record.packageId || 'sys_metadata');\n } else {\n this.engine.registry.registerItem(normalizedType, data, 'name' as any);\n }\n loaded++;\n } catch (e) {\n errors++;\n console.warn(`[Protocol] Failed to hydrate ${record.type}/${record.name}: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n } catch (e: any) {\n // \"no such table\" is expected on first run before migrations execute — not an error.\n if (!/no such table/i.test(e.message ?? '')) {\n console.warn(`[Protocol] DB hydration skipped: ${e.message}`);\n }\n }\n return { loaded, errors };\n }\n\n // ==========================================\n // Feed Operations\n // ==========================================\n\n async listFeed(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const result = await svc.listFeed({\n object: request.object,\n recordId: request.recordId,\n filter: request.type,\n limit: request.limit,\n cursor: request.cursor,\n });\n return { success: true, data: result };\n }\n\n async createFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.createFeedItem({\n object: request.object,\n recordId: request.recordId,\n type: request.type,\n actor: { type: 'user', id: 'current_user' },\n body: request.body,\n mentions: request.mentions,\n parentId: request.parentId,\n visibility: request.visibility,\n });\n return { success: true, data: item };\n }\n\n async updateFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.updateFeedItem(request.feedId, {\n body: request.body,\n mentions: request.mentions,\n visibility: request.visibility,\n });\n return { success: true, data: item };\n }\n\n async deleteFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n await svc.deleteFeedItem(request.feedId);\n return { success: true, data: { feedId: request.feedId } };\n }\n\n async addReaction(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const reactions = await svc.addReaction(request.feedId, request.emoji, 'current_user');\n return { success: true, data: { reactions } };\n }\n\n async removeReaction(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const reactions = await svc.removeReaction(request.feedId, request.emoji, 'current_user');\n return { success: true, data: { reactions } };\n }\n\n async pinFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.getFeedItem(request.feedId);\n if (!item) throw new Error(`Feed item ${request.feedId} not found`);\n // IFeedService doesn't have dedicated pin/unpin — use updateFeedItem to persist pin state\n await svc.updateFeedItem(request.feedId, { visibility: item.visibility });\n return { success: true, data: { feedId: request.feedId, pinned: true, pinnedAt: new Date().toISOString() } };\n }\n\n async unpinFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.getFeedItem(request.feedId);\n if (!item) throw new Error(`Feed item ${request.feedId} not found`);\n await svc.updateFeedItem(request.feedId, { visibility: item.visibility });\n return { success: true, data: { feedId: request.feedId, pinned: false } };\n }\n\n async starFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.getFeedItem(request.feedId);\n if (!item) throw new Error(`Feed item ${request.feedId} not found`);\n // IFeedService doesn't have dedicated star/unstar — verify item exists then return state\n await svc.updateFeedItem(request.feedId, { visibility: item.visibility });\n return { success: true, data: { feedId: request.feedId, starred: true, starredAt: new Date().toISOString() } };\n }\n\n async unstarFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.getFeedItem(request.feedId);\n if (!item) throw new Error(`Feed item ${request.feedId} not found`);\n await svc.updateFeedItem(request.feedId, { visibility: item.visibility });\n return { success: true, data: { feedId: request.feedId, starred: false } };\n }\n\n async searchFeed(request: any): Promise<any> {\n const svc = this.requireFeedService();\n // Search delegates to listFeed with filter since IFeedService doesn't have a dedicated search\n const result = await svc.listFeed({\n object: request.object,\n recordId: request.recordId,\n filter: request.type,\n limit: request.limit,\n cursor: request.cursor,\n });\n // Filter by query text in body\n const queryLower = (request.query || '').toLowerCase();\n const filtered = result.items.filter((item: any) =>\n item.body?.toLowerCase().includes(queryLower)\n );\n return { success: true, data: { items: filtered, total: filtered.length, hasMore: false } };\n }\n\n async getChangelog(request: any): Promise<any> {\n const svc = this.requireFeedService();\n // Changelog retrieves field_change type feed items\n const result = await svc.listFeed({\n object: request.object,\n recordId: request.recordId,\n filter: 'changes_only',\n limit: request.limit,\n cursor: request.cursor,\n });\n const entries = result.items.map((item: any) => ({\n id: item.id,\n object: item.object,\n recordId: item.recordId,\n actor: item.actor,\n changes: item.changes || [],\n timestamp: item.createdAt,\n source: item.source,\n }));\n return { success: true, data: { entries, total: result.total, nextCursor: result.nextCursor, hasMore: result.hasMore } };\n }\n\n async feedSubscribe(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const subscription = await svc.subscribe({\n object: request.object,\n recordId: request.recordId,\n userId: 'current_user',\n events: request.events,\n channels: request.channels,\n });\n return { success: true, data: subscription };\n }\n\n async feedUnsubscribe(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const unsubscribed = await svc.unsubscribe(request.object, request.recordId, 'current_user');\n return { success: true, data: { object: request.object, recordId: request.recordId, unsubscribed } };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { QueryAST, HookContext, ServiceObject } from '@objectstack/spec/data';\nimport {\n EngineQueryOptions,\n DataEngineInsertOptions,\n EngineUpdateOptions,\n EngineDeleteOptions,\n EngineAggregateOptions,\n EngineCountOptions\n} from '@objectstack/spec/data';\nimport { ExecutionContext, ExecutionContextSchema } from '@objectstack/spec/kernel';\nimport { DriverInterface, IDataEngine, Logger, createLogger } from '@objectstack/core';\nimport { CoreServiceName, StorageNameMapping } from '@objectstack/spec/system';\nimport { IRealtimeService, RealtimeEventPayload } from '@objectstack/spec/contracts';\nimport { pluralToSingular } from '@objectstack/spec/shared';\nimport { SchemaRegistry, computeFQN } from './registry.js';\nimport { ExpressionEngine } from '@objectstack/formula';\nimport type { Expression } from '@objectstack/spec';\nimport { bindHooksToEngine } from './hook-binder.js';\nimport { validateRecord } from './validation/record-validator.js';\nimport { applyInMemoryAggregation } from './in-memory-aggregation.js';\n\ninterface FormulaPlanEntry { name: string; expression: Expression; }\n\nfunction planFormulaProjection(\n schema: any,\n requestedFields: string[] | undefined\n): { plan: FormulaPlanEntry[]; projected?: string[] } {\n if (!schema?.fields) return { plan: [] };\n const allFieldNames = Object.keys(schema.fields);\n // When no explicit projection, evaluate every formula field on the schema —\n // matches REST default of \"return everything\". Explicit projection still\n // honours the caller's selection.\n const targets = (Array.isArray(requestedFields) && requestedFields.length > 0)\n ? requestedFields\n : allFieldNames;\n const plan: FormulaPlanEntry[] = [];\n const projected = new Set<string>();\n for (const f of targets) {\n const def = (schema.fields as any)[f];\n if (def?.type === 'formula' && def.expression) {\n // Normalize string-shorthand → Expression envelope (M9 transition).\n const expr: Expression = typeof def.expression === 'string'\n ? { dialect: 'cel', source: def.expression }\n : def.expression;\n plan.push({ name: f, expression: expr });\n // Pre-compile to surface syntax errors at planning stage rather than\n // per-row eval. Dependency discovery (which fields the formula reads)\n // is no longer used — CEL uses dynamic projection via `record.<field>`.\n ExpressionEngine.compile(expr);\n } else if (Array.isArray(requestedFields) && requestedFields.length > 0) {\n projected.add(f);\n }\n }\n if (plan.length === 0) return { plan: [] };\n // For formulas: project all schema fields so CEL `record.<field>` lookups\n // see complete data. Static dependency analysis on AST is M9.7 work.\n if (Array.isArray(requestedFields) && requestedFields.length > 0) {\n if (!projected.has('id')) projected.add('id');\n for (const fname of allFieldNames) {\n // Skip formula fields themselves — they are virtual and not\n // projectable by the underlying driver. Without this guard the\n // SQL driver emits `SELECT response_rate ...` which fails as\n // \"no such column\" and the driver returns [] (silently).\n const fdef = (schema.fields as any)[fname];\n if (fdef?.type === 'formula') continue;\n projected.add(fname);\n }\n return { plan, projected: Array.from(projected) };\n }\n // Implicit/full projection — leave projected undefined so the driver\n // returns its default columns (typically *).\n return { plan };\n}\n\nfunction applyFormulaPlan(plan: FormulaPlanEntry[], records: any[]): void {\n if (!plan.length) return;\n for (const rec of records) {\n if (rec == null) continue;\n for (const fp of plan) {\n const r = ExpressionEngine.evaluate(fp.expression, { record: rec });\n rec[fp.name] = r.ok ? r.value : null;\n }\n }\n}\n\nexport type HookHandler = (context: HookContext) => Promise<void> | void;\n\n/**\n * Per-object hook entry with priority support\n */\nexport interface HookEntry {\n handler: HookHandler;\n object?: string | string[]; // undefined = global hook\n priority: number;\n packageId?: string;\n /**\n * Original metadata-form `Hook` definition this entry was bound from\n * (when registered via `bindHooksToEngine`). Pure code-paths that call\n * `engine.registerHook` directly leave this undefined.\n */\n meta?: any;\n /** Hook `name` from metadata; used for diagnostics & deduplication. */\n hookName?: string;\n}\n\n/** Function registry entry — see `registerFunction`. */\ninterface FunctionEntry {\n handler: HookHandler;\n packageId?: string;\n}\n\n/**\n * Operation Context for Middleware Chain\n */\nexport interface OperationContext {\n object: string;\n operation: 'find' | 'findOne' | 'insert' | 'update' | 'delete' | 'count' | 'aggregate';\n ast?: QueryAST;\n data?: any;\n options?: any;\n context?: ExecutionContext;\n result?: any;\n}\n\n/**\n * Engine Middleware (Onion model)\n */\nexport type EngineMiddleware = (\n ctx: OperationContext,\n next: () => Promise<void>\n) => Promise<void>;\n\n/**\n * Host Context provided to plugins (Internal ObjectQL Plugin System)\n */\nexport interface ObjectQLHostContext {\n ql: ObjectQL;\n logger: Logger;\n // Extensible map for host-specific globals (like HTTP Router, etc.)\n [key: string]: any;\n}\n\n/**\n * Derive the registry key for a metadata item.\n *\n * Most metadata items expose a top-level `name` (or `id`). The `View`\n * container defined by `@objectstack/spec/ui` is special: it aggregates\n * `list / form / listViews / formViews` for a single object and is\n * keyed implicitly by its target object name (see `data.object`).\n *\n * Per spec, `ViewSchema` does NOT have a top-level `name` field\n * (view.zod.ts), so we resolve it from the inner data source. This\n * matches the server-side metadata API contract (`/api/v1/meta/views/:object`).\n */\nfunction resolveMetadataItemName(key: string, item: any): string | undefined {\n if (!item) return undefined;\n if (item.name) return item.name;\n if (item.id) return item.id;\n if (key === 'views') {\n return (\n item?.list?.data?.object ||\n item?.form?.data?.object ||\n undefined\n );\n }\n return undefined;\n}\n\n/**\n * ObjectQL Engine\n * \n * Implements the IDataEngine interface for data persistence.\n * Acts as the reference implementation for:\n * - CoreServiceName.data (CRUD)\n * - CoreServiceName.metadata (Schema Registry)\n */\nexport class ObjectQL implements IDataEngine {\n private drivers = new Map<string, DriverInterface>();\n private defaultDriver: string | null = null;\n private logger: Logger;\n\n // Datasource mapping rules (imported from defineStack)\n private datasourceMapping: Array<{\n namespace?: string;\n package?: string;\n objectPattern?: string;\n default?: boolean;\n datasource: string;\n priority?: number;\n }> = [];\n\n // Package manifests registry (for defaultDatasource lookup)\n private manifests = new Map<string, any>();\n\n // Per-object hooks with priority support\n private hooks: Map<string, HookEntry[]> = new Map([\n ['beforeFind', []], ['afterFind', []],\n ['beforeInsert', []], ['afterInsert', []],\n ['beforeUpdate', []], ['afterUpdate', []],\n ['beforeDelete', []], ['afterDelete', []],\n ]);\n\n // Middleware chain (onion model)\n private middlewares: Array<{\n fn: EngineMiddleware;\n object?: string;\n }> = [];\n\n // Action registry: key = \"objectName:actionName\"\n private actions = new Map<string, { handler: (ctx: any) => Promise<any> | any; package?: string }>();\n\n // Function registry: name → handler. Used by `bindHooksToEngine` to\n // resolve string-named hook handlers (the JSON-safe form). Populated by\n // `defineStack({ functions })` via `AppPlugin`, or directly via\n // `engine.registerFunction(...)`.\n private functions = new Map<string, FunctionEntry>();\n\n // Host provided context additions (e.g. Server router)\n private hostContext: Record<string, any> = {};\n\n // Realtime service for event publishing\n private realtimeService?: IRealtimeService;\n\n // Per-engine SchemaRegistry instance.\n //\n // Historically SchemaRegistry was a process-wide singleton of static state,\n // which broke multi-project servers: a project kernel would inherit every\n // object registered by the control plane (e.g. sys_metadata), and\n // getDriver()'s owner lookup would route CRUD to the wrong database. Each\n // engine now owns its registry so kernels are fully isolated.\n private _registry: SchemaRegistry = new SchemaRegistry();\n\n constructor(hostContext: Record<string, any> = {}) {\n this.hostContext = hostContext;\n // Use provided logger or create a new one\n this.logger = hostContext.logger || createLogger({ level: 'info', format: 'pretty' });\n // Pick up production hardening switches from env so deployers can\n // enforce strict-body without code changes:\n // OBJECTQL_STRICT_HOOKS=1 → unresolved hooks throw at bind time\n // OBJECTQL_WARN_LEGACY_HANDLER=1 → log a deprecation per legacy bind\n if (process?.env?.OBJECTQL_STRICT_HOOKS === '1') {\n (this as any)._strictHookBinding = true;\n }\n if (process?.env?.OBJECTQL_WARN_LEGACY_HANDLER === '1') {\n (this as any)._warnLegacyHandler = true;\n }\n this.logger.info('ObjectQL Engine Instance Created');\n }\n\n /**\n * Service Status Report\n * Used by Kernel to verify health and capabilities.\n */\n getStatus() {\n return {\n name: CoreServiceName.enum.data,\n status: 'running',\n version: '0.9.0',\n features: ['crud', 'query', 'aggregate', 'transactions', 'metadata']\n };\n }\n\n /**\n * Expose the SchemaRegistry for plugins to register metadata.\n *\n * Returns the per-engine instance, NOT the class. Each ObjectQL engine\n * owns its registry so multi-project kernels remain isolated.\n */\n get registry(): SchemaRegistry {\n return this._registry;\n }\n\n /**\n * Load and Register a Plugin\n */\n async use(manifestPart: any, runtimePart?: any) {\n this.logger.debug('Loading plugin', { \n hasManifest: !!manifestPart, \n hasRuntime: !!runtimePart \n });\n\n // 1. Validate / Register Manifest\n if (manifestPart) {\n this.registerApp(manifestPart);\n }\n\n // 2. Execute Runtime\n if (runtimePart) {\n const pluginDef = (runtimePart as any).default || runtimePart;\n if (pluginDef.onEnable) {\n this.logger.debug('Executing plugin runtime onEnable');\n \n const context: ObjectQLHostContext = {\n ql: this,\n logger: this.logger,\n // Expose the driver registry helper explicitly if needed\n drivers: {\n register: (driver: DriverInterface) => this.registerDriver(driver)\n },\n ...this.hostContext\n };\n \n await pluginDef.onEnable(context);\n this.logger.debug('Plugin runtime onEnable completed');\n }\n }\n }\n\n /**\n * Register a hook\n * @param event The event name (e.g. 'beforeFind', 'afterInsert')\n * @param handler The handler function\n * @param options Optional: target object(s) and priority\n */\n registerHook(event: string, handler: HookHandler, options?: {\n object?: string | string[];\n priority?: number;\n packageId?: string;\n /** Original metadata Hook definition (set by `bindHooksToEngine`). */\n meta?: any;\n /** Stable name from metadata (set by `bindHooksToEngine`). */\n hookName?: string;\n }) {\n if (!this.hooks.has(event)) {\n this.hooks.set(event, []);\n }\n const entries = this.hooks.get(event)!;\n entries.push({\n handler,\n object: options?.object,\n priority: options?.priority ?? 100,\n packageId: options?.packageId,\n meta: options?.meta,\n hookName: options?.hookName,\n });\n // Sort by priority (lower runs first)\n entries.sort((a, b) => a.priority - b.priority);\n this.logger.debug('Registered hook', { event, object: options?.object, priority: options?.priority ?? 100, totalHandlers: entries.length });\n }\n\n /**\n * Remove all hooks registered under a given `packageId`. Used by\n * `bindHooksToEngine` to make re-binding (hot reload, app reinstall)\n * idempotent, and by app uninstall flows.\n */\n unregisterHooksByPackage(packageId: string): number {\n if (!packageId) return 0;\n let removed = 0;\n for (const [event, entries] of this.hooks.entries()) {\n const before = entries.length;\n const kept = entries.filter((e) => e.packageId !== packageId);\n if (kept.length !== before) {\n this.hooks.set(event, kept);\n removed += before - kept.length;\n }\n }\n if (removed > 0) {\n this.logger.debug('Unregistered hooks by package', { packageId, removed });\n }\n return removed;\n }\n\n /**\n * Register a named function handler that can later be referenced by\n * string from a `Hook.handler` field. This is the JSON-safe form of\n * handler binding — declarative metadata persisted to disk or shipped\n * over the wire only carries the name.\n */\n registerFunction(name: string, handler: HookHandler, packageId?: string): void {\n if (!name || typeof handler !== 'function') return;\n this.functions.set(name, { handler, packageId });\n this.logger.debug('Registered function', { name, packageId });\n }\n\n /** Look up a registered function by name. */\n resolveFunction(name: string): HookHandler | undefined {\n return this.functions.get(name)?.handler;\n }\n\n /** Remove all functions registered under a given `packageId`. */\n unregisterFunctionsByPackage(packageId: string): number {\n if (!packageId) return 0;\n let removed = 0;\n for (const [name, entry] of this.functions.entries()) {\n if (entry.packageId === packageId) {\n this.functions.delete(name);\n removed += 1;\n }\n }\n if (removed > 0) {\n this.logger.debug('Unregistered functions by package', { packageId, removed });\n }\n return removed;\n }\n\n /**\n * Bind a list of declarative `Hook` metadata definitions to this engine.\n *\n * Convenience proxy to the canonical `bindHooksToEngine` so callers do\n * not need a separate import. Use `import { bindHooksToEngine } from\n * '@objectstack/objectql'` directly when you want the result object.\n */\n bindHooks(hooks: any[] | undefined, opts?: {\n packageId?: string;\n functions?: Record<string, HookHandler>;\n bodyRunner?: any;\n strict?: boolean;\n warnLegacyHandler?: boolean;\n metrics?: any;\n }): void {\n const merged = { ...(opts ?? {}), logger: this.logger } as any;\n if (!merged.bodyRunner && (this as any)._defaultBodyRunner) {\n merged.bodyRunner = (this as any)._defaultBodyRunner;\n }\n if (merged.strict === undefined && (this as any)._strictHookBinding) {\n merged.strict = true;\n }\n if (merged.warnLegacyHandler === undefined && (this as any)._warnLegacyHandler) {\n merged.warnLegacyHandler = true;\n }\n if (!merged.metrics && (this as any)._hookMetricsRecorder) {\n merged.metrics = (this as any)._hookMetricsRecorder;\n }\n bindHooksToEngine(this, hooks, merged);\n }\n\n /**\n * Install a default body-runner used when `bindHooks` is called without\n * an explicit one. The runtime layer sets this once on each per-project\n * engine so every binding path (template seed, metadata sync, AppPlugin)\n * can execute hook `body.source` consistently.\n */\n setDefaultBodyRunner(runner: any): void {\n (this as any)._defaultBodyRunner = runner;\n }\n\n /**\n * Toggle strict hook-binding mode for this engine. When enabled, every\n * subsequent `bindHooks` call rejects on the first unresolved hook\n * instead of silently warning. Production runtimes should enable this.\n */\n setStrictHookBinding(strict: boolean): void {\n (this as any)._strictHookBinding = strict;\n }\n\n /** Toggle deprecation warnings for hooks still using legacy `handler` ref. */\n setWarnLegacyHandler(warn: boolean): void {\n (this as any)._warnLegacyHandler = warn;\n }\n\n /**\n * Install a metrics recorder used by every subsequent `bindHooks` call.\n * The recorder's methods are invoked per-execution to count outcomes\n * (success / error / timeout / capability_rejected), skips, and retries.\n * Defaults to no-op so the engine pays zero cost when nobody is observing.\n */\n setHookMetricsRecorder(recorder: any): void {\n (this as any)._hookMetricsRecorder = recorder;\n }\n\n /** Read the engine's installed metrics recorder, if any. */\n getHookMetricsRecorder(): any {\n return (this as any)._hookMetricsRecorder;\n }\n\n public async triggerHooks(event: string, context: HookContext) {\n const entries = this.hooks.get(event) || [];\n \n if (entries.length === 0) {\n this.logger.debug('No hooks registered for event', { event });\n return;\n }\n\n this.logger.debug('Triggering hooks', { event, count: entries.length });\n \n for (const entry of entries) {\n // Per-object matching\n if (entry.object) {\n const targets = Array.isArray(entry.object) ? entry.object : [entry.object];\n if (!targets.includes('*') && !targets.includes(context.object)) {\n continue; // Skip non-matching hooks\n }\n }\n await entry.handler(context);\n }\n }\n\n // ========================================\n // Action System\n // ========================================\n\n /**\n * Register a named action on an object.\n * Actions are custom business logic callable via `repo.execute(actionName, params)`.\n *\n * @param objectName Target object\n * @param actionName Unique action name within the object\n * @param handler Handler function\n * @param packageName Optional package owner (for cleanup)\n */\n registerAction(objectName: string, actionName: string, handler: (ctx: any) => Promise<any> | any, packageName?: string): void {\n const key = `${objectName}:${actionName}`;\n this.actions.set(key, { handler, package: packageName });\n this.logger.debug('Registered action', { objectName, actionName, package: packageName });\n }\n\n /**\n * Execute a named action on an object.\n */\n async executeAction(objectName: string, actionName: string, ctx: any): Promise<any> {\n const entry = this.actions.get(`${objectName}:${actionName}`);\n if (!entry) {\n throw new Error(`Action '${actionName}' on object '${objectName}' not found`);\n }\n return entry.handler(ctx);\n }\n\n /**\n * Remove all actions registered by a specific package.\n */\n removeActionsByPackage(packageName: string): void {\n for (const [key, entry] of this.actions.entries()) {\n if (entry.package === packageName) {\n this.actions.delete(key);\n }\n }\n }\n\n /**\n * Register a middleware function\n * Middlewares execute in onion model around every data operation.\n * @param fn The middleware function\n * @param options Optional: target object filter\n */\n registerMiddleware(fn: EngineMiddleware, options?: { object?: string }): void {\n this.middlewares.push({ fn, object: options?.object });\n this.logger.debug('Registered middleware', { object: options?.object, total: this.middlewares.length });\n }\n\n /**\n * Execute an operation through the middleware chain\n */\n private async executeWithMiddleware(ctx: OperationContext, executor: () => Promise<any>): Promise<any> {\n const applicable = this.middlewares.filter(m =>\n !m.object || m.object === '*' || m.object === ctx.object\n );\n\n let index = 0;\n const next = async (): Promise<void> => {\n if (index < applicable.length) {\n const mw = applicable[index++];\n await mw.fn(ctx, next);\n } else {\n ctx.result = await executor();\n }\n };\n\n await next();\n return ctx.result;\n }\n\n /**\n * Build a HookContext.session from ExecutionContext\n */\n private buildSession(execCtx?: ExecutionContext): HookContext['session'] {\n if (!execCtx) return undefined;\n return {\n userId: execCtx.userId,\n tenantId: execCtx.tenantId,\n roles: execCtx.roles,\n accessToken: execCtx.accessToken,\n // Propagate system-elevated flag so hooks can distinguish engine\n // self-writes (e.g. approval status mirror) from genuine user writes.\n ...((execCtx as any).isSystem ? { isSystem: true } : {}),\n } as HookContext['session'];\n }\n\n /**\n * Build the DriverOptions blob passed to every IDataDriver call.\n *\n * Always carries `tenantId` from the active ExecutionContext so the\n * driver can enforce per-tenant isolation (SQL driver auto-scopes reads\n * and auto-injects the tenant column on writes). Existing user-supplied\n * shapes (transactions, AST extras) are preserved by spreading them\n * first.\n *\n * System / isSystem callers may still cross tenants by clearing\n * `tenantId` themselves on the resulting object; this helper does not\n * mask the system path.\n */\n private buildDriverOptions(execCtx?: ExecutionContext, base?: any): any {\n const hasTx = execCtx?.transaction !== undefined;\n const hasTenant = execCtx?.tenantId !== undefined;\n const isSystem = execCtx?.isSystem === true;\n if (!hasTx && !hasTenant && !isSystem) return base;\n const opts: any = base && typeof base === 'object' ? { ...base } : {};\n if (hasTx && opts.transaction === undefined) {\n opts.transaction = execCtx!.transaction;\n }\n if (hasTenant && opts.tenantId === undefined) {\n opts.tenantId = execCtx!.tenantId;\n }\n if (isSystem && opts.bypassTenantAudit === undefined) {\n // System-elevated writes (boot-time seeds, internal mirrors, scheduled\n // hooks) are unscoped by design — silence the audit warn for them but\n // still flag genuine user-path bugs.\n opts.bypassTenantAudit = true;\n }\n return opts;\n }\n\n /**\n * Build a HookContext.api: a ScopedContext that hooks can use to\n * read/write other objects within the same execution context.\n * Falls back to a system-elevated empty context when no execCtx\n * is supplied (e.g. system-triggered hooks).\n */\n private buildHookApi(execCtx?: ExecutionContext): ScopedContext {\n const safeCtx: ExecutionContext = execCtx ?? ({ isSystem: true } as any);\n return new ScopedContext(safeCtx, this as unknown as IDataEngine);\n }\n\n /**\n * Apply field defaults to an incoming insert payload. Defaults that are\n * Expression envelopes (e.g. `{ dialect: 'cel', source: 'today()' }`,\n * `{ dialect: 'cel', source: 'os.user.id' }`) are evaluated via\n * `ExpressionEngine` against the calling user/org/now snapshot. Static\n * defaults are applied verbatim. Records that already supplied a value for a\n * field are left untouched.\n *\n * Implements ROADMAP §M9.9b — `defaultValue` accepts Expression so authors\n * can replace \"write a hook to default to today/current-user\" with a\n * declarative `defaultValue: cel\\`today()\\``.\n */\n private applyFieldDefaults(\n object: string,\n record: Record<string, unknown>,\n execCtx?: ExecutionContext,\n nowSnapshot?: Date,\n ): Record<string, unknown> {\n const schema = this.getSchema(object);\n const fieldsRaw = (schema as any)?.fields;\n if (!fieldsRaw || typeof fieldsRaw !== 'object') return record;\n // `fields` may be a Record<string, Field> (canonical) or an array (legacy).\n const fieldEntries: Array<{ name: string; defaultValue?: unknown }> = Array.isArray(fieldsRaw)\n ? fieldsRaw\n : Object.entries(fieldsRaw).map(([name, def]) => ({ name, ...(def as object) }));\n const out = { ...record };\n const now = nowSnapshot ?? new Date();\n for (const f of fieldEntries) {\n if (out[f.name] !== undefined) continue;\n if (f.defaultValue == null) continue;\n const dv = f.defaultValue;\n if (typeof dv === 'object' && dv !== null && (dv as any).dialect && typeof (dv as any).source === 'string') {\n const result = ExpressionEngine.evaluate(dv as any, {\n now,\n user: execCtx?.userId ? { id: String(execCtx.userId), role: execCtx?.roles?.[0] } : undefined,\n org: execCtx?.tenantId ? { id: String(execCtx.tenantId) } : undefined,\n record: out,\n extra: { object },\n });\n if (result.ok) {\n out[f.name] = result.value as unknown;\n } else {\n this.logger.warn('Failed to evaluate default expression', {\n object, field: f.name, error: result.error,\n });\n }\n } else {\n out[f.name] = dv;\n }\n }\n return out;\n }\n\n /**\n * Register contribution (Manifest)\n * \n * Installs the manifest as a Package (the unit of installation),\n * then decomposes it into individual metadata items (objects, apps, actions, etc.)\n * and registers each into the SchemaRegistry.\n * \n * Key: Package ≠ App. The manifest is the package. The apps[] array inside\n * the manifest contains UI navigation definitions (AppSchema).\n */\n registerApp(manifest: any) {\n const id = manifest.id || manifest.name;\n const namespace = manifest.namespace as string | undefined;\n this.logger.debug('Registering package manifest', { id, namespace });\n console.warn(`[ObjectQL:registerApp] id=${id} flows=${Array.isArray(manifest.flows) ? manifest.flows.length : typeof manifest.flows} keys=${Object.keys(manifest).join(',')}`);\n\n // Store manifest for defaultDatasource lookup\n if (id) {\n this.manifests.set(id, manifest);\n }\n\n // 1. Register the Package (manifest + lifecycle state)\n this._registry.installPackage(manifest);\n this.logger.debug('Installed Package', { id: manifest.id, name: manifest.name, namespace });\n\n // 2. Register owned objects\n if (manifest.objects) {\n if (Array.isArray(manifest.objects)) {\n this.logger.debug('Registering objects from manifest (Array)', { id, objectCount: manifest.objects.length });\n for (const objDef of manifest.objects) {\n const fqn = this._registry.registerObject(objDef, id, namespace, 'own');\n this.logger.debug('Registered Object', { fqn, from: id });\n }\n } else {\n this.logger.debug('Registering objects from manifest (Map)', { id, objectCount: Object.keys(manifest.objects).length });\n for (const [name, objDef] of Object.entries(manifest.objects)) {\n // Ensure name in definition matches key\n (objDef as any).name = name;\n const fqn = this._registry.registerObject(objDef as any, id, namespace, 'own');\n this.logger.debug('Registered Object', { fqn, from: id });\n }\n }\n }\n\n // 2b. Register object extensions (fields added to objects owned by other packages)\n if (Array.isArray(manifest.objectExtensions) && manifest.objectExtensions.length > 0) {\n this.logger.debug('Registering object extensions', { id, count: manifest.objectExtensions.length });\n for (const ext of manifest.objectExtensions) {\n const targetFqn = ext.extend;\n const priority = ext.priority ?? 200;\n // Create a partial object definition for the extension\n const extDef = {\n name: targetFqn, // Use the target FQN as name\n fields: ext.fields,\n label: ext.label,\n pluralLabel: ext.pluralLabel,\n description: ext.description,\n validations: ext.validations,\n indexes: ext.indexes,\n };\n // Register as extension (namespace is undefined since we're targeting by FQN)\n this._registry.registerObject(extDef as any, id, undefined, 'extend', priority);\n this.logger.debug('Registered Object Extension', { target: targetFqn, priority, from: id });\n }\n }\n\n // 3. Register apps (UI navigation definitions) as their own metadata type\n // Resolve short objectName references in navigation to FQN so the\n // Console UI can match them against the object registry.\n if (Array.isArray(manifest.apps) && manifest.apps.length > 0) {\n this.logger.debug('Registering apps from manifest', { id, count: manifest.apps.length });\n for (const app of manifest.apps) {\n const appName = app.name || app.id;\n if (appName) {\n const resolved = namespace ? this.resolveNavObjectNames(app, namespace) : app;\n this._registry.registerApp(resolved, id);\n this.logger.debug('Registered App', { app: appName, from: id });\n }\n }\n }\n\n // 4. If manifest itself looks like an App (has navigation), also register as app\n // This handles the case where the manifest IS the app definition (legacy/simple packages)\n if (manifest.name && manifest.navigation && !manifest.apps?.length) {\n const resolved = namespace ? this.resolveNavObjectNames(manifest, namespace) : manifest;\n this._registry.registerApp(resolved, id);\n this.logger.debug('Registered manifest-as-app', { app: manifest.name, from: id });\n }\n\n // 5. Register all other metadata types generically\n const metadataArrayKeys = [\n // UI Protocol\n 'actions', 'views', 'pages', 'dashboards', 'reports', 'themes',\n // Automation Protocol\n 'flows', 'workflows', 'approvals', 'webhooks',\n // Security Protocol\n 'roles', 'permissions', 'profiles', 'sharingRules', 'policies',\n // AI Protocol\n 'agents', 'ragPipelines',\n // API Protocol\n 'apis',\n // Data Extensions\n 'hooks', 'mappings', 'analyticsCubes',\n // Integration Protocol\n 'connectors',\n ];\n for (const key of metadataArrayKeys) {\n const items = (manifest as any)[key];\n if (Array.isArray(items) && items.length > 0) {\n this.logger.debug(`Registering ${key} from manifest`, { id, count: items.length });\n for (const item of items) {\n const itemName = resolveMetadataItemName(key, item);\n if (itemName) {\n const toRegister = item.name === itemName ? item : { ...item, name: itemName };\n this._registry.registerItem(pluralToSingular(key), toRegister, 'name' as any, id);\n } else {\n this.logger.warn(`Skipping ${pluralToSingular(key)} without a derivable name`, { id });\n }\n }\n }\n }\n\n // 6. Register seed data as metadata (keyed by target object name)\n const seedData = (manifest as any).data;\n if (Array.isArray(seedData) && seedData.length > 0) {\n this.logger.debug('Registering seed data datasets', { id, count: seedData.length });\n for (const dataset of seedData) {\n if (dataset.object) {\n this._registry.registerItem('data', dataset, 'object' as any, id);\n }\n }\n }\n\n // 6. Register contributions\n if (manifest.contributes?.kinds) {\n this.logger.debug('Registering kinds from manifest', { id, kindCount: manifest.contributes.kinds.length });\n for (const kind of manifest.contributes.kinds) {\n this._registry.registerKind(kind);\n this.logger.debug('Registered Kind', { kind: kind.name || kind.type, from: id });\n }\n }\n\n // 7. Recursively register nested plugins\n if (Array.isArray(manifest.plugins) && manifest.plugins.length > 0) {\n this.logger.debug('Processing nested plugins', { id, count: manifest.plugins.length });\n for (const plugin of manifest.plugins) {\n if (plugin && typeof plugin === 'object') {\n const pluginName = plugin.name || plugin.id || 'unnamed-plugin';\n this.logger.debug('Registering nested plugin', { pluginName, parentId: id });\n this.registerPlugin(plugin, id, namespace);\n }\n }\n }\n }\n\n /**\n * Deep-clone an app definition, resolving objectName references in navigation\n * items via the registry. Object names are canonical identifiers — no FQN\n * expansion is applied.\n */\n private resolveNavObjectNames(app: any, namespace: string): any {\n if (!app.navigation) return app;\n\n const resolveItems = (items: any[]): any[] =>\n items.map((item: any) => {\n const resolved = { ...item };\n if (resolved.objectName && !resolved.objectName.includes('__')) {\n resolved.objectName = computeFQN(namespace, resolved.objectName);\n }\n if (Array.isArray(resolved.children)) {\n resolved.children = resolveItems(resolved.children);\n }\n return resolved;\n });\n\n return { ...app, navigation: resolveItems(app.navigation) };\n }\n\n /**\n * Register a nested plugin's metadata (objects, actions, views, etc.)\n *\n * Unlike registerApp(), this does NOT call SchemaRegistry.installPackage()\n * because plugins are not formal manifests — they are lightweight config\n * bundles with objects, actions, triggers, and navigation.\n *\n * @param plugin - The plugin config object\n * @param parentId - The parent package ID (for ownership tracking)\n * @param parentNamespace - The parent package's namespace (for FQN resolution)\n */\n private registerPlugin(plugin: any, parentId: string, parentNamespace?: string) {\n const pluginName = plugin.name || plugin.id || 'unnamed';\n const pluginNamespace = plugin.namespace || parentNamespace;\n\n // Use parentId as the owning package for namespace consistency.\n // The parent package already claimed the namespace — nested plugins\n // contribute objects UNDER the parent's ownership.\n const ownerId = parentId;\n\n // Register objects (supports both Array and Map formats)\n if (plugin.objects) {\n try {\n if (Array.isArray(plugin.objects)) {\n this.logger.debug('Registering plugin objects (Array)', { pluginName, count: plugin.objects.length });\n for (const objDef of plugin.objects) {\n const fqn = this._registry.registerObject(objDef, ownerId, pluginNamespace, 'own');\n this.logger.debug('Registered Object', { fqn, from: pluginName });\n }\n } else {\n const entries = Object.entries(plugin.objects);\n this.logger.debug('Registering plugin objects (Map)', { pluginName, count: entries.length });\n for (const [name, objDef] of entries) {\n (objDef as any).name = name;\n const fqn = this._registry.registerObject(objDef as any, ownerId, pluginNamespace, 'own');\n this.logger.debug('Registered Object', { fqn, from: pluginName });\n }\n }\n } catch (err: any) {\n this.logger.warn('Failed to register plugin objects', { pluginName, error: err.message });\n }\n }\n\n // Register plugin as app if it has navigation (for sidebar display)\n if (plugin.name && plugin.navigation) {\n try {\n const resolved = pluginNamespace ? this.resolveNavObjectNames(plugin, pluginNamespace) : plugin;\n this._registry.registerApp(resolved, ownerId);\n this.logger.debug('Registered plugin-as-app', { app: plugin.name, from: pluginName });\n } catch (err: any) {\n this.logger.warn('Failed to register plugin as app', { pluginName, error: err.message });\n }\n }\n\n // Register metadata arrays (actions, views, triggers, etc.)\n const metadataArrayKeys = [\n 'actions', 'views', 'pages', 'dashboards', 'reports', 'themes',\n 'flows', 'workflows', 'approvals', 'webhooks',\n 'roles', 'permissions', 'profiles', 'sharingRules', 'policies',\n 'agents', 'ragPipelines', 'apis',\n 'hooks', 'mappings', 'analyticsCubes', 'connectors',\n ];\n for (const key of metadataArrayKeys) {\n const items = (plugin as any)[key];\n if (Array.isArray(items) && items.length > 0) {\n for (const item of items) {\n const itemName = resolveMetadataItemName(key, item);\n if (itemName) {\n const toRegister = item.name === itemName ? item : { ...item, name: itemName };\n this._registry.registerItem(pluralToSingular(key), toRegister, 'name' as any, ownerId);\n }\n }\n }\n }\n }\n\n /**\n * Register a new storage driver\n */\n registerDriver(driver: DriverInterface, isDefault: boolean = false) {\n if (this.drivers.has(driver.name)) {\n this.logger.warn('Driver already registered, skipping', { driverName: driver.name });\n return;\n }\n\n this.drivers.set(driver.name, driver);\n this.logger.info('Registered driver', {\n driverName: driver.name,\n version: driver.version\n });\n\n if (isDefault || this.drivers.size === 1) {\n this.defaultDriver = driver.name;\n this.logger.info('Set default driver', { driverName: driver.name });\n }\n }\n\n /**\n * Set the realtime service for publishing data change events.\n * Should be called after kernel resolves the realtime service.\n *\n * @param service - An IRealtimeService instance for event publishing\n */\n setRealtimeService(service: IRealtimeService): void {\n this.realtimeService = service;\n this.logger.info('RealtimeService configured for data events');\n }\n\n /**\n * Helper to get object definition\n */\n getSchema(objectName: string): ServiceObject | undefined {\n return this._registry.getObject(objectName);\n }\n\n /**\n * Resolve any object identifier to the physical storage name used by drivers.\n *\n * Accepts the canonical short name (e.g., 'account') or, for explicit\n * cross-package disambiguation, the canonical object name (e.g., 'account'). The result is\n * the physical table name derived via `StorageNameMapping.resolveTableName`.\n */\n private resolveObjectName(name: string): string {\n const schema = this._registry.getObject(name);\n if (schema) {\n return StorageNameMapping.resolveTableName(schema);\n }\n // Return name as-is (canonical name = table name; no FQN prefix to strip)\n return StorageNameMapping.resolveTableName({ name });\n }\n\n /**\n * Helper to get the target driver\n *\n * Resolution priority (first match wins):\n * 1. Object's explicit `datasource` field (if not 'default')\n * 2. DatasourceMapping rules (namespace/package/pattern matching)\n * 3. Package's `defaultDatasource` from manifest\n * 4. Global default driver\n */\n private getDriver(objectName: string): DriverInterface {\n const object = this._registry.getObject(objectName);\n\n // 1. Object's explicit datasource field (highest priority)\n if (object?.datasource && object.datasource !== 'default') {\n if (this.drivers.has(object.datasource)) {\n return this.drivers.get(object.datasource)!;\n }\n throw new Error(`[ObjectQL] Datasource '${object.datasource}' configured for object '${objectName}' is not registered.`);\n }\n\n // 2. Check datasourceMapping rules\n const mappedDatasource = this.resolveDatasourceFromMapping(objectName, object);\n if (mappedDatasource && this.drivers.has(mappedDatasource)) {\n this.logger.debug('Resolved datasource from mapping', {\n object: objectName,\n datasource: mappedDatasource\n });\n return this.drivers.get(mappedDatasource)!;\n }\n\n // 3. Check package's defaultDatasource\n // Use the object's FQN name (from getObject) for ownership lookup\n const fqn = object?.name || objectName;\n const owner = this._registry.getObjectOwner(fqn);\n if (owner?.packageId) {\n const manifest = this.manifests.get(owner.packageId);\n if (manifest?.defaultDatasource && manifest.defaultDatasource !== 'default') {\n if (this.drivers.has(manifest.defaultDatasource)) {\n this.logger.debug('Resolved datasource from package manifest', {\n object: objectName,\n package: owner.packageId,\n datasource: manifest.defaultDatasource\n });\n return this.drivers.get(manifest.defaultDatasource)!;\n }\n }\n }\n\n // 4. Fallback to global default driver\n if (this.defaultDriver && this.drivers.has(this.defaultDriver)) {\n return this.drivers.get(this.defaultDriver)!;\n }\n\n throw new Error(`[ObjectQL] No driver available for object '${objectName}'`);\n }\n\n /**\n * Resolve datasource from mapping rules\n *\n * Rules are evaluated in order (or by priority if specified).\n * First matching rule wins.\n */\n private resolveDatasourceFromMapping(\n objectName: string,\n object?: any\n ): string | null {\n if (!this.datasourceMapping || this.datasourceMapping.length === 0) {\n return null;\n }\n\n // Sort rules by priority if any have priority set\n const sortedRules = [...this.datasourceMapping].sort((a, b) => {\n const aPriority = a.priority ?? 1000;\n const bPriority = b.priority ?? 1000;\n return aPriority - bPriority;\n });\n\n for (const rule of sortedRules) {\n // 1. Match by namespace\n if (rule.namespace && object?.namespace === rule.namespace) {\n return rule.datasource;\n }\n\n // 2. Match by package ID\n if (rule.package && object?.packageId === rule.package) {\n return rule.datasource;\n }\n\n // 3. Match by object name pattern (glob-style)\n if (rule.objectPattern && this.matchPattern(objectName, rule.objectPattern)) {\n return rule.datasource;\n }\n\n // 4. Default fallback rule\n if (rule.default) {\n return rule.datasource;\n }\n }\n\n return null;\n }\n\n /**\n * Simple glob pattern matching\n * Supports * (any chars) and ? (single char)\n */\n private matchPattern(objectName: string, pattern: string): boolean {\n const regexPattern = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex special chars\n .replace(/\\*/g, '.*') // * → .*\n .replace(/\\?/g, '.'); // ? → .\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(objectName);\n }\n\n /**\n * Set datasource mapping rules\n * Called by ObjectQLPlugin during bootstrap\n */\n setDatasourceMapping(rules: Array<{\n namespace?: string;\n package?: string;\n objectPattern?: string;\n default?: boolean;\n datasource: string;\n priority?: number;\n }>) {\n this.datasourceMapping = rules;\n this.logger.info('Datasource mapping rules configured', {\n ruleCount: rules.length\n });\n }\n\n /**\n * Initialize the engine and all registered drivers\n */\n async init() {\n this.logger.info('Initializing ObjectQL engine', { \n driverCount: this.drivers.size,\n drivers: Array.from(this.drivers.keys())\n });\n \n const failedDrivers: string[] = [];\n for (const [name, driver] of this.drivers) {\n try {\n await driver.connect();\n this.logger.info('Driver connected successfully', { driverName: name });\n } catch (e) {\n failedDrivers.push(name);\n this.logger.error('Failed to connect driver', e as Error, { driverName: name });\n }\n }\n\n if (failedDrivers.length > 0) {\n this.logger.warn(\n `${failedDrivers.length} of ${this.drivers.size} driver(s) failed initial connect. ` +\n `Operations may recover via lazy reconnection or fail at query time.`,\n { failedDrivers }\n );\n }\n \n this.logger.info('ObjectQL engine initialization complete');\n }\n\n async destroy() {\n this.logger.info('Destroying ObjectQL engine', { driverCount: this.drivers.size });\n \n for (const [name, driver] of this.drivers.entries()) {\n try {\n await driver.disconnect();\n } catch (e) {\n this.logger.error('Error disconnecting driver', e as Error, { driverName: name });\n }\n }\n \n this.logger.info('ObjectQL engine destroyed');\n }\n\n // ============================================\n // Helper: Expand Related Records\n // ============================================\n\n /** Maximum depth for recursive expand to prevent infinite loops */\n private static readonly MAX_EXPAND_DEPTH = 3;\n\n /**\n * Post-process expand: resolve lookup/master_detail fields by batch-loading related records.\n * \n * This is a driver-agnostic implementation that uses secondary queries ($in batches)\n * to load related records, then injects them into the result set.\n * \n * @param objectName - The source object name\n * @param records - The records returned by the driver\n * @param expand - The expand map from QueryAST (field name → nested QueryAST)\n * @param depth - Current recursion depth (0-based)\n * @returns Records with expanded lookup fields (IDs replaced by full objects)\n */\n private async expandRelatedRecords(\n objectName: string,\n records: any[],\n expand: Record<string, QueryAST>,\n depth: number = 0,\n execCtx?: ExecutionContext,\n ): Promise<any[]> {\n if (!records || records.length === 0) return records;\n if (depth >= ObjectQL.MAX_EXPAND_DEPTH) return records;\n\n const objectSchema = this._registry.getObject(objectName);\n // If no schema registered, skip expand — return raw data\n if (!objectSchema || !objectSchema.fields) return records;\n\n for (const [fieldName, nestedAST] of Object.entries(expand)) {\n const fieldDef = objectSchema.fields[fieldName];\n\n // Skip if field not found or not a relationship type\n if (!fieldDef || !fieldDef.reference) continue;\n if (fieldDef.type !== 'lookup' && fieldDef.type !== 'master_detail') continue;\n\n const referenceObject = fieldDef.reference;\n\n // Collect all foreign key IDs from records (handle both single and multiple values)\n const allIds: any[] = [];\n for (const record of records) {\n const val = record[fieldName];\n if (val == null) continue;\n if (Array.isArray(val)) {\n allIds.push(...val.filter((id: any) => id != null));\n } else if (typeof val === 'object') {\n // Already expanded — skip\n continue;\n } else {\n allIds.push(val);\n }\n }\n\n // De-duplicate IDs\n const uniqueIds = [...new Set(allIds)];\n if (uniqueIds.length === 0) continue;\n\n // Batch-load related records using $in query\n try {\n const relatedQuery: QueryAST = {\n object: referenceObject,\n where: { id: { $in: uniqueIds } },\n ...(nestedAST.fields ? { fields: nestedAST.fields } : {}),\n ...(nestedAST.orderBy ? { orderBy: nestedAST.orderBy } : {}),\n };\n\n const driver = this.getDriver(referenceObject);\n // Propagate tenantId so cross-object expansion respects isolation —\n // e.g. a contact expansion only resolves IDs visible to the caller's\n // tenant. Without this the driver returns the raw FK target which\n // would let a maliciously crafted FK reach across tenants.\n const expandOpts = this.buildDriverOptions(execCtx);\n const relatedRecords = await driver.find(referenceObject, relatedQuery, expandOpts) ?? [];\n\n // Build a lookup map: id → record\n const recordMap = new Map<string, any>();\n for (const rec of relatedRecords) {\n const id = rec.id;\n if (id != null) recordMap.set(String(id), rec);\n }\n\n // Recursively expand nested relations if present\n if (nestedAST.expand && Object.keys(nestedAST.expand).length > 0) {\n const expandedRelated = await this.expandRelatedRecords(\n referenceObject,\n relatedRecords,\n nestedAST.expand,\n depth + 1,\n execCtx,\n );\n // Rebuild map with expanded records\n recordMap.clear();\n for (const rec of expandedRelated) {\n const id = rec.id;\n if (id != null) recordMap.set(String(id), rec);\n }\n }\n\n // Inject expanded records back into the original result set\n for (const record of records) {\n const val = record[fieldName];\n if (val == null) continue;\n\n if (Array.isArray(val)) {\n record[fieldName] = val.map((id: any) => recordMap.get(String(id)) ?? id);\n } else if (typeof val !== 'object') {\n record[fieldName] = recordMap.get(String(val)) ?? val;\n }\n // If val is already an object, leave it as-is\n }\n } catch (e) {\n // Graceful degradation: if expand fails, keep original IDs\n this.logger.warn('Failed to expand relationship field; retaining foreign key IDs', {\n object: objectName,\n field: fieldName,\n reference: referenceObject,\n error: (e as Error).message,\n });\n }\n }\n\n return records;\n }\n\n // ============================================\n // Data Access Methods (IDataEngine Interface)\n // ============================================\n\n async find(object: string, query?: EngineQueryOptions): Promise<any[]> {\n object = this.resolveObjectName(object);\n this.logger.debug('Find operation starting', { object, query });\n const driver = this.getDriver(object);\n const ast: QueryAST = { object, ...query };\n // Remove context from the AST — it's not a driver concern\n delete (ast as any).context;\n // Normalize OData `top` alias → standard `limit`\n if ((ast as any).top != null && ast.limit == null) {\n ast.limit = (ast as any).top;\n }\n delete (ast as any).top;\n\n // Plan formula projection: rewrite ast.fields to drop virtual formula\n // names and inject their dependencies, so the driver returns the raw\n // fields needed to compute the formulas after fetch.\n const _findSchema = this._registry.getObject(object);\n const _findFormula = planFormulaProjection(_findSchema, ast.fields as string[] | undefined);\n if (_findFormula.projected) ast.fields = _findFormula.projected;\n\n // Drop any requested field that doesn't exist on the schema. Without\n // this, drivers (notably SqlDriver) emit `SELECT unknown_col FROM ...`\n // which the DB rejects (\"no such column\") — and SqlDriver swallows\n // that error and returns `[]`, making a frontend bug (e.g. a generic\n // view requesting `name`/`due_date` on every object) look like \"no\n // records exist\". Silently filtering matches the existing OData\n // tolerance and Salesforce/Postgres behavior of `SELECT *` semantics.\n if (_findSchema?.fields && Array.isArray(ast.fields) && ast.fields.length > 0) {\n const known = new Set(Object.keys(_findSchema.fields));\n // Always allow the primary key + audit columns even if not present in\n // schema.fields. Without this, callers requesting `select=id,name`\n // silently get the `id` projected away, breaking record navigation.\n known.add('id');\n known.add('created_at');\n known.add('updated_at');\n const filtered = (ast.fields as string[]).filter(f => {\n // Keep relationship paths like `owner.name` — the engine will\n // resolve those via populate; only validate top-level segment.\n const head = String(f).split('.')[0];\n return known.has(head);\n });\n // Guard against an empty projection — fall back to `*` so the\n // request still returns rows. An empty SELECT list would either\n // 400 in Postgres or silently project nothing.\n ast.fields = filtered.length > 0 ? filtered : undefined;\n }\n\n const opCtx: OperationContext = {\n object,\n operation: 'find',\n ast,\n options: query,\n context: query?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const hookContext: HookContext = {\n object,\n event: 'beforeFind',\n input: { ast: opCtx.ast, options: opCtx.options },\n session: this.buildSession(opCtx.context),\n api: this.buildHookApi(opCtx.context),\n transaction: opCtx.context?.transaction,\n ql: this\n };\n await this.triggerHooks('beforeFind', hookContext);\n hookContext.input.options = this.buildDriverOptions(opCtx.context, hookContext.input.options as any);\n\n try {\n let result = await driver.find(object, hookContext.input.ast as QueryAST, hookContext.input.options as any);\n\n // Post-process: evaluate formula virtual fields against the raw rows\n if (Array.isArray(result)) applyFormulaPlan(_findFormula.plan, result);\n\n // Post-process: expand related records if expand is requested\n if (ast.expand && Object.keys(ast.expand).length > 0 && Array.isArray(result)) {\n result = await this.expandRelatedRecords(object, result, ast.expand, 0, opCtx.context);\n }\n \n hookContext.event = 'afterFind';\n hookContext.result = result;\n await this.triggerHooks('afterFind', hookContext);\n \n return hookContext.result;\n } catch (e) {\n this.logger.error('Find operation failed', e as Error, { object });\n throw e;\n }\n });\n\n return opCtx.result as any[];\n }\n\n async findOne(objectName: string, query?: EngineQueryOptions): Promise<any> {\n objectName = this.resolveObjectName(objectName);\n this.logger.debug('FindOne operation', { objectName });\n const driver = this.getDriver(objectName);\n const ast: QueryAST = { object: objectName, ...query, limit: 1 };\n // Remove context and top alias from the AST\n delete (ast as any).context;\n delete (ast as any).top;\n\n // Plan formula projection (same as find): rewrite ast.fields so the driver\n // returns the raw dependency fields, then evaluate formulas after fetch.\n const _findOneSchema = this._registry.getObject(objectName);\n const _findOneFormula = planFormulaProjection(_findOneSchema, ast.fields as string[] | undefined);\n if (_findOneFormula.projected) ast.fields = _findOneFormula.projected;\n\n // Drop unknown fields — see equivalent block in `find()` for rationale.\n if (_findOneSchema?.fields && Array.isArray(ast.fields) && ast.fields.length > 0) {\n const known = new Set(Object.keys(_findOneSchema.fields));\n // Always allow the primary key + audit columns even if not present\n // in schema.fields (matches `find()` behavior).\n known.add('id');\n known.add('created_at');\n known.add('updated_at');\n const filtered = (ast.fields as string[]).filter(f => known.has(String(f).split('.')[0]));\n ast.fields = filtered.length > 0 ? filtered : undefined;\n }\n\n const opCtx: OperationContext = {\n object: objectName,\n operation: 'findOne',\n ast,\n options: query,\n context: query?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const findOneOpts = this.buildDriverOptions(opCtx.context);\n let result = await driver.findOne(objectName, opCtx.ast as QueryAST, findOneOpts);\n\n // Post-process: evaluate formula virtual fields against the raw row\n if (result != null) applyFormulaPlan(_findOneFormula.plan, [result]);\n\n // Post-process: expand related records if expand is requested\n if (ast.expand && Object.keys(ast.expand).length > 0 && result != null) {\n const expanded = await this.expandRelatedRecords(objectName, [result], ast.expand, 0, opCtx.context);\n result = expanded[0];\n }\n\n return result;\n });\n\n return opCtx.result;\n }\n\n async insert(object: string, data: any | any[], options?: DataEngineInsertOptions): Promise<any> {\n object = this.resolveObjectName(object);\n this.logger.debug('Insert operation starting', { object, isBatch: Array.isArray(data) });\n const driver = this.getDriver(object);\n\n const opCtx: OperationContext = {\n object,\n operation: 'insert',\n data,\n options,\n context: options?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const hookContext: HookContext = {\n object,\n event: 'beforeInsert',\n input: { data: opCtx.data, options: opCtx.options },\n session: this.buildSession(opCtx.context),\n api: this.buildHookApi(opCtx.context),\n transaction: opCtx.context?.transaction,\n ql: this\n };\n await this.triggerHooks('beforeInsert', hookContext);\n // Thread the open transaction (if any) into the driver-facing\n // options so that knex's `.transacting(trx)` is honoured. Without\n // this, calls inside a `engine.transaction(...)` block would deadlock\n // on SQLite's single-connection pool. Also propagates tenantId so\n // the driver can enforce per-tenant isolation.\n hookContext.input.options = this.buildDriverOptions(opCtx.context, hookContext.input.options as any);\n\n try {\n let result;\n const nowSnap = new Date();\n const schemaForValidation = this._registry.getObject(object);\n if (Array.isArray(hookContext.input.data)) {\n // Bulk Create — apply defaults per row\n const rows = (hookContext.input.data as any[]).map((row) =>\n this.applyFieldDefaults(object, row as Record<string, unknown>, opCtx.context, nowSnap),\n );\n for (const r of rows) validateRecord(schemaForValidation, r, 'insert');\n if (driver.bulkCreate) {\n result = await driver.bulkCreate(object, rows, hookContext.input.options as any);\n } else {\n // Fallback loop\n result = await Promise.all(rows.map((item) => driver.create(object, item, hookContext.input.options as any)));\n }\n } else {\n const row = this.applyFieldDefaults(\n object,\n hookContext.input.data as Record<string, unknown>,\n opCtx.context,\n nowSnap,\n );\n validateRecord(schemaForValidation, row, 'insert');\n result = await driver.create(object, row, hookContext.input.options as any);\n }\n\n hookContext.event = 'afterInsert';\n hookContext.result = result;\n await this.triggerHooks('afterInsert', hookContext);\n\n // Publish data.record.created event to realtime service\n if (this.realtimeService) {\n try {\n if (Array.isArray(result)) {\n // Bulk insert - publish event for each record\n for (const record of result) {\n const event: RealtimeEventPayload = {\n type: 'data.record.created',\n object,\n payload: {\n recordId: record.id,\n after: record,\n },\n timestamp: new Date().toISOString(),\n };\n await this.realtimeService.publish(event);\n }\n this.logger.debug(`Published ${result.length} data.record.created events`, { object });\n } else {\n const event: RealtimeEventPayload = {\n type: 'data.record.created',\n object,\n payload: {\n recordId: result.id,\n after: result,\n },\n timestamp: new Date().toISOString(),\n };\n await this.realtimeService.publish(event);\n this.logger.debug('Published data.record.created event', { object, recordId: result.id });\n }\n } catch (error) {\n this.logger.warn('Failed to publish data event', { object, error });\n }\n }\n\n return hookContext.result;\n } catch (e) {\n this.logger.error('Insert operation failed', e as Error, { object });\n throw e;\n }\n });\n\n return opCtx.result;\n }\n\n async update(object: string, data: any, options?: EngineUpdateOptions): Promise<any> {\n object = this.resolveObjectName(object);\n this.logger.debug('Update operation starting', { object });\n const driver = this.getDriver(object);\n \n // 1. Extract ID from data or where if it's a single update by ID\n let id = data.id;\n if (!id && options?.where && typeof options.where === 'object' && 'id' in options.where) {\n id = (options.where as Record<string, unknown>).id;\n }\n\n const opCtx: OperationContext = {\n object,\n operation: 'update',\n data,\n options,\n context: options?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const hookContext: HookContext = {\n object,\n event: 'beforeUpdate',\n input: { id, data: opCtx.data, options: opCtx.options },\n session: this.buildSession(opCtx.context),\n api: this.buildHookApi(opCtx.context),\n transaction: opCtx.context?.transaction,\n ql: this\n };\n await this.triggerHooks('beforeUpdate', hookContext);\n hookContext.input.options = this.buildDriverOptions(opCtx.context, hookContext.input.options as any);\n\n try {\n let result;\n if (hookContext.input.id) {\n validateRecord(this._registry.getObject(object), hookContext.input.data as Record<string, unknown>, 'update');\n result = await driver.update(object, hookContext.input.id as string, hookContext.input.data as Record<string, unknown>, hookContext.input.options as any);\n } else if (options?.multi && driver.updateMany) {\n validateRecord(this._registry.getObject(object), hookContext.input.data as Record<string, unknown>, 'update');\n const ast: QueryAST = { object, where: options.where };\n result = await driver.updateMany(object, ast, hookContext.input.data as Record<string, unknown>, hookContext.input.options as any);\n } else {\n throw new Error('Update requires an ID or options.multi=true');\n }\n\n hookContext.event = 'afterUpdate';\n hookContext.result = result;\n await this.triggerHooks('afterUpdate', hookContext);\n\n // Publish data.record.updated event to realtime service\n if (this.realtimeService) {\n try {\n const resultId = (typeof result === 'object' && result && 'id' in result) ? (result as any).id : undefined;\n const recordId = String(hookContext.input.id || resultId || '');\n const event: RealtimeEventPayload = {\n type: 'data.record.updated',\n object,\n payload: {\n recordId,\n changes: hookContext.input.data,\n after: result,\n },\n timestamp: new Date().toISOString(),\n };\n await this.realtimeService.publish(event);\n this.logger.debug('Published data.record.updated event', { object, recordId });\n } catch (error) {\n this.logger.warn('Failed to publish data event', { object, error });\n }\n }\n\n return hookContext.result;\n } catch (e) {\n this.logger.error('Update operation failed', e as Error, { object });\n throw e;\n }\n });\n\n return opCtx.result;\n }\n\n async delete(object: string, options?: EngineDeleteOptions): Promise<any> {\n object = this.resolveObjectName(object);\n this.logger.debug('Delete operation starting', { object });\n const driver = this.getDriver(object);\n\n // Extract ID logic similar to update\n let id: any = undefined;\n if (options?.where && typeof options.where === 'object' && 'id' in options.where) {\n id = (options.where as Record<string, unknown>).id;\n }\n\n const opCtx: OperationContext = {\n object,\n operation: 'delete',\n options,\n context: options?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const hookContext: HookContext = {\n object,\n event: 'beforeDelete',\n input: { id, options: opCtx.options },\n session: this.buildSession(opCtx.context),\n api: this.buildHookApi(opCtx.context),\n transaction: opCtx.context?.transaction,\n ql: this\n };\n await this.triggerHooks('beforeDelete', hookContext);\n hookContext.input.options = this.buildDriverOptions(opCtx.context, hookContext.input.options as any);\n\n try {\n let result;\n if (hookContext.input.id) {\n result = await driver.delete(object, hookContext.input.id as string, hookContext.input.options as any);\n } else if (options?.multi && driver.deleteMany) {\n const ast: QueryAST = { object, where: options.where };\n result = await driver.deleteMany(object, ast, hookContext.input.options as any);\n } else {\n throw new Error('Delete requires an ID or options.multi=true');\n }\n\n hookContext.event = 'afterDelete';\n hookContext.result = result;\n await this.triggerHooks('afterDelete', hookContext);\n\n // Publish data.record.deleted event to realtime service\n if (this.realtimeService) {\n try {\n const resultId = (typeof result === 'object' && result && 'id' in result) ? (result as any).id : undefined;\n const recordId = String(hookContext.input.id || resultId || '');\n const event: RealtimeEventPayload = {\n type: 'data.record.deleted',\n object,\n payload: {\n recordId,\n },\n timestamp: new Date().toISOString(),\n };\n await this.realtimeService.publish(event);\n this.logger.debug('Published data.record.deleted event', { object, recordId });\n } catch (error) {\n this.logger.warn('Failed to publish data event', { object, error });\n }\n }\n\n return hookContext.result;\n } catch (e) {\n this.logger.error('Delete operation failed', e as Error, { object });\n throw e;\n }\n });\n\n return opCtx.result;\n }\n\n async count(object: string, query?: EngineCountOptions): Promise<number> {\n object = this.resolveObjectName(object);\n const driver = this.getDriver(object);\n\n const opCtx: OperationContext = {\n object,\n operation: 'count',\n options: query,\n context: query?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const countOpts = this.buildDriverOptions(opCtx.context);\n if (driver.count) {\n const ast: QueryAST = { object, where: query?.where };\n return driver.count(object, ast, countOpts);\n }\n // Fallback to find().length\n const res = await this.find(object, { where: query?.where, fields: ['id'], context: opCtx.context });\n return res.length;\n });\n\n return opCtx.result as number;\n }\n\n async aggregate(object: string, query: EngineAggregateOptions): Promise<any[]> {\n object = this.resolveObjectName(object);\n const driver = this.getDriver(object);\n this.logger.debug(`Aggregate on ${object} using ${driver.name}`, query);\n\n const opCtx: OperationContext = {\n object,\n operation: 'aggregate',\n options: query,\n context: query?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const ast: QueryAST = {\n object,\n where: query.where,\n groupBy: query.groupBy as any,\n aggregations: query.aggregations,\n };\n\n // Prefer driver.aggregate() when available — driver.find() in many\n // drivers (e.g. driver-sql) does not honor `groupBy` / `aggregations`\n // and would silently return ungrouped raw rows. Fall back to find()\n // for drivers that handle aggregations through their query AST.\n const drv = driver as any;\n // Structured groupBy items ({field, dateGranularity}) require the\n // driver to advertise per-granularity native bucket support via\n // `supports.queryDateGranularity[g]`. If every structured item is\n // supported we can push the aggregate down to the driver; otherwise\n // we fall back to driver.find() + in-memory bucketing so the result\n // remains correct on partial-support dialects (e.g. SQLite + week).\n const groupByItems = Array.isArray(query.groupBy) ? (query.groupBy as any[]) : [];\n const granularityCaps: Record<string, boolean> | undefined =\n drv?.supports?.queryDateGranularity;\n const structuredItems = groupByItems.filter((g) => typeof g !== 'string');\n const allStructuredSupported = structuredItems.every((g: any) => {\n if (!g?.dateGranularity) return true; // plain {field} object is fine\n return granularityCaps?.[g.dateGranularity] === true;\n });\n if (typeof drv.aggregate === 'function' && allStructuredSupported) {\n return drv.aggregate(object, ast, this.buildDriverOptions(opCtx.context));\n }\n // In-memory fallback path: ask the driver for raw rows, then bucket +\n // aggregate here. This guarantees `groupBy` (incl. structured items\n // carrying `dateGranularity`) and `aggregations` always work even on\n // drivers that have no native aggregation support (driver-rest,\n // driver-memory, partial SQL drivers).\n const raw = await driver.find(object, ast, this.buildDriverOptions(opCtx.context));\n return applyInMemoryAggregation(raw, ast);\n });\n\n return opCtx.result as any[];\n }\n \n /**\n * Run raw driver-specific commands (SQL for SqlDriver, REST for RestDriver, …).\n *\n * ⚠️ **Tenant isolation bypass.** Raw `execute()` does NOT thread the\n * caller's `ExecutionContext.tenantId` into a `WHERE organization_id`\n * predicate — drivers see the command verbatim. Callers MUST inline the\n * tenant filter themselves, or restrict raw execution to genuinely global\n * statements (schema migrations, sys_* / control-plane tables).\n *\n * Prefer the typed entry points (`find`, `update`, `delete`, `count`, …)\n * whenever feasible — they auto-apply tenancy + soft-delete + audit warnings.\n */\n async execute(command: any, options?: Record<string, any>): Promise<any> {\n // Driver selection priority:\n // 1. options.object → route via getDriver(objectName)\n // 2. options.datasource → explicit driver name\n // 3. default driver (set via datasourceMapping or defaultDriver)\n // This lets system services (e.g. PackageService, AuditService) issue raw\n // SQL against the control-plane / default DB without having to know the\n // object name behind every CREATE TABLE / SELECT statement.\n let driver: DriverInterface | undefined;\n if (options?.object) {\n driver = this.getDriver(options.object);\n } else if (options?.datasource && this.drivers.has(options.datasource)) {\n driver = this.drivers.get(options.datasource);\n } else if (this.defaultDriver && this.drivers.has(this.defaultDriver)) {\n driver = this.drivers.get(this.defaultDriver);\n } else if (this.drivers.size === 1) {\n // Single registered driver — unambiguously the right one.\n driver = this.drivers.values().next().value;\n }\n\n if (!driver) {\n throw new Error(\n 'Execute requires options.object to select a driver, or a default driver to be configured. ' +\n 'Configure datasourceMapping with `default: true` or pass `{ object }` / `{ datasource }` in options.',\n );\n }\n if (!driver.execute) {\n throw new Error('Selected driver does not implement execute()');\n }\n\n // Support both call shapes:\n // execute('SELECT ...', { args: [...] })\n // execute({ sql: 'SELECT ...', args: [...] })\n let rawCommand: any = command;\n let params: any[] | undefined = options?.args ?? options?.params;\n if (command && typeof command === 'object' && !Array.isArray(command) && 'sql' in command) {\n rawCommand = command.sql;\n if (params === undefined) {\n params = command.args ?? command.params;\n }\n }\n\n return driver.execute(rawCommand, params, options);\n }\n\n /**\n * Execute a callback inside a database transaction.\n *\n * The callback receives a context object that should be passed to all\n * downstream `engine.insert/update/delete/find/findOne` calls (as\n * `{ context: trxCtx }`). The transaction handle threads through\n * `OperationContext.context.transaction` and the SQL driver's per-builder\n * `.transacting(trx)` call.\n *\n * - If the default driver does not support `beginTransaction`, the callback\n * runs directly with the supplied base context (no rollback). This keeps\n * the API safe to call on drivers without ACID support (e.g. the\n * in-memory driver in tests).\n * - On callback success the transaction is committed; on any thrown error\n * it is rolled back and the original error is re-thrown.\n *\n * Use case: multi-step operations that must be atomic (e.g. CRM\n * `convertLead`, which creates an account + contact + opportunity + flips\n * the lead in a single unit of work).\n */\n async transaction<T>(\n callback: (trxCtx: any) => Promise<T>,\n baseContext?: any,\n ): Promise<T> {\n const driver = this.defaultDriver ? this.drivers.get(this.defaultDriver) : undefined;\n const drv = driver as any;\n if (!drv?.beginTransaction) {\n return callback(baseContext);\n }\n const trx = await drv.beginTransaction();\n const trxCtx = { ...(baseContext ?? {}), transaction: trx };\n try {\n const result = await callback(trxCtx);\n if (drv.commit) await drv.commit(trx);\n else if (drv.commitTransaction) await drv.commitTransaction(trx);\n return result;\n } catch (err) {\n try {\n if (drv.rollback) await drv.rollback(trx);\n else if (drv.rollbackTransaction) await drv.rollbackTransaction(trx);\n } catch {\n // swallow rollback failures so the original error surfaces\n }\n throw err;\n }\n }\n\n // ============================================\n // Compatibility / Convenience API\n // ============================================\n // These methods provide a higher-level API matching the @objectql/core\n // ObjectQL interface, enabling painless migration from the legacy layer.\n\n /**\n * Register a single object definition.\n * \n * Proxies to SchemaRegistry.registerObject() with sensible defaults.\n * Fields without a `name` property are auto-assigned from their key.\n */\n registerObject(\n schema: ServiceObject,\n packageId: string = '__runtime__',\n namespace?: string\n ): string {\n // Auto-assign field names from keys\n if (schema.fields) {\n for (const [key, field] of Object.entries(schema.fields)) {\n if (field && typeof field === 'object' && !('name' in field)) {\n (field as any).name = key;\n }\n }\n }\n return this._registry.registerObject(schema, packageId, namespace);\n }\n\n /**\n * Unregister a single object by name.\n */\n unregisterObject(name: string, packageId?: string): void {\n if (packageId) {\n this._registry.unregisterObjectsByPackage(packageId);\n } else {\n // Remove from generic metadata as fallback\n this._registry.unregisterItem('object', name);\n }\n }\n\n /**\n * Get an object definition by name.\n * Alias for getSchema() — matches @objectql/core API.\n */\n getObject(name: string): ServiceObject | undefined {\n return this.getSchema(name);\n }\n\n /**\n * Get all registered object configs as a name→config map.\n * Matches @objectql/core getConfigs() API.\n */\n getConfigs(): Record<string, ServiceObject> {\n const result: Record<string, ServiceObject> = {};\n const objects = this._registry.getAllObjects();\n for (const obj of objects) {\n if (obj.name) {\n result[obj.name] = obj;\n }\n }\n return result;\n }\n\n /**\n * Get a registered driver by datasource name.\n * \n * Unlike the private getDriver() (which resolves by object name),\n * this method directly looks up a driver by its registered name.\n */\n getDriverByName(name: string): DriverInterface | undefined {\n return this.drivers.get(name);\n }\n\n /**\n * Get the driver responsible for the given object.\n *\n * Resolves datasource binding from the object's schema definition,\n * falling back to the default driver. This is a public version of\n * the internal getDriver() used by CRUD operations.\n *\n * @param objectName - FQN or short name of the registered object.\n * @returns The resolved DriverInterface, or undefined if no driver is available.\n */\n getDriverForObject(objectName: string): DriverInterface | undefined {\n try {\n return this.getDriver(objectName);\n } catch {\n return undefined;\n }\n }\n\n /**\n * Sync all registered object schemas to their respective drivers.\n * Call this after dynamically registering new objects at runtime\n * (e.g. after template seeding) to ensure tables/collections exist\n * before inserting seed data.\n */\n async syncSchemas(): Promise<void> {\n const allObjects = this._registry.getAllObjects();\n for (const obj of allObjects) {\n const driver = this.getDriverForObject(obj.name);\n if (!driver) continue;\n const tableName = StorageNameMapping.resolveTableName(obj);\n if (typeof (driver as any).syncSchemasBatch === 'function' && (driver as any).supports?.batchSchemaSync) {\n // Already handled per-driver below; skip individual call\n }\n if (typeof (driver as any).syncSchema === 'function') {\n try {\n await (driver as any).syncSchema(tableName, obj);\n } catch {\n // best effort — log suppressed to avoid noise on already-synced tables\n }\n }\n }\n }\n\n /**\n * Get a registered driver by datasource name.\n * Alias matching @objectql/core datasource() API.\n *\n * @throws Error if the datasource is not found\n */\n datasource(name: string): DriverInterface {\n const driver = this.drivers.get(name);\n if (!driver) {\n throw new Error(`[ObjectQL] Datasource '${name}' not found`);\n }\n return driver;\n }\n\n /**\n * Register a hook handler.\n * Convenience alias for registerHook() matching @objectql/core on() API.\n * \n * Usage:\n * ql.on('beforeInsert', 'user', async (ctx) => { ... });\n */\n on(\n event: string,\n objectName: string,\n handler: (ctx: HookContext) => Promise<void> | void,\n packageId?: string\n ): void {\n this.registerHook(event, handler, { object: objectName, packageId });\n }\n\n /**\n * Remove all hooks, actions, and objects contributed by a package.\n */\n removePackage(packageId: string): void {\n // Remove hooks\n for (const [key, handlers] of this.hooks.entries()) {\n const filtered = handlers.filter(h => h.packageId !== packageId);\n if (filtered.length !== handlers.length) {\n this.hooks.set(key, filtered);\n }\n }\n // Remove actions\n this.removeActionsByPackage(packageId);\n // Remove objects\n this._registry.unregisterObjectsByPackage(packageId, true);\n }\n\n /**\n * Gracefully shut down the engine, disconnecting all drivers.\n * Alias for destroy() — matches @objectql/core close() API.\n */\n async close(): Promise<void> {\n return this.destroy();\n }\n\n /**\n * Create a scoped execution context bound to this engine.\n * \n * Usage:\n * const ctx = engine.createContext({ userId: '...', tenantId: '...' });\n * const users = ctx.object('user');\n * await users.find({ filter: { status: 'active' } });\n */\n createContext(ctx: Partial<ExecutionContext>): ScopedContext {\n return new ScopedContext(\n ExecutionContextSchema.parse(ctx),\n this\n );\n }\n\n /**\n * Static factory: create a fully configured ObjectQL instance.\n * \n * Matches @objectql/core's `new ObjectQL(config)` pattern but also\n * registers drivers and objects, then calls init().\n * \n * Usage:\n * const ql = await ObjectQL.create({\n * datasources: { default: myDriver },\n * objects: { user: { name: 'user', fields: { ... } } }\n * });\n */\n static async create(config: {\n datasources?: Record<string, DriverInterface>;\n objects?: Record<string, ServiceObject>;\n hooks?: Array<{ event: string; object: string; handler: (ctx: HookContext) => Promise<void> | void }>;\n }): Promise<ObjectQL> {\n const ql = new ObjectQL();\n\n // Register drivers\n if (config.datasources) {\n for (const [name, driver] of Object.entries(config.datasources)) {\n // Set driver name if not already set\n if (!driver.name) {\n (driver as any).name = name;\n }\n ql.registerDriver(driver, name === 'default');\n }\n }\n\n // Register objects\n if (config.objects) {\n for (const [_key, schema] of Object.entries(config.objects)) {\n ql.registerObject(schema);\n }\n }\n\n // Register hooks\n if (config.hooks) {\n for (const hook of config.hooks) {\n ql.on(hook.event, hook.object, hook.handler);\n }\n }\n\n // Initialize (connect drivers)\n await ql.init();\n\n return ql;\n }\n}\n\n/**\n * Repository scoped to a single object, bound to an execution context.\n *\n * Provides both IDataEngine-style methods (find, insert, update, delete)\n * and convenience aliases (create, updateById, deleteById) matching\n * the @objectql/core ObjectRepository API.\n */\nexport class ObjectRepository {\n constructor(\n private objectName: string,\n private context: ExecutionContext,\n private engine: IDataEngine & { executeAction?: (o: string, a: string, c: any) => Promise<any> }\n ) {}\n\n async find(query: any = {}): Promise<any[]> {\n return this.engine.find(this.objectName, {\n ...query,\n context: this.context,\n });\n }\n\n async findOne(query: any = {}): Promise<any> {\n return this.engine.findOne(this.objectName, {\n ...query,\n context: this.context,\n });\n }\n\n async insert(data: any): Promise<any> {\n return this.engine.insert(this.objectName, data, {\n context: this.context,\n });\n }\n\n /** Alias for insert() — matches @objectql/core convention */\n async create(data: any): Promise<any> {\n return this.insert(data);\n }\n\n async update(data: any, options: any = {}): Promise<any> {\n return this.engine.update(this.objectName, data, {\n ...options,\n context: this.context,\n });\n }\n\n /** Update a single record by ID */\n async updateById(id: string | number, data: any): Promise<any> {\n return this.engine.update(this.objectName, { ...data, id: id }, {\n where: { id: id },\n context: this.context,\n });\n }\n\n async delete(options: any = {}): Promise<any> {\n return this.engine.delete(this.objectName, {\n ...options,\n context: this.context,\n });\n }\n\n /** Delete a single record by ID */\n async deleteById(id: string | number): Promise<any> {\n return this.engine.delete(this.objectName, {\n where: { id: id },\n context: this.context,\n });\n }\n\n async count(query: any = {}): Promise<number> {\n return this.engine.count(this.objectName, {\n ...query,\n context: this.context,\n });\n }\n\n /** Aggregate query */\n async aggregate(query: any = {}): Promise<any[]> {\n return this.engine.aggregate(this.objectName, {\n ...query,\n context: this.context,\n });\n }\n\n /** Execute a named action registered on this object */\n async execute(actionName: string, params?: any): Promise<any> {\n if (this.engine.executeAction) {\n return this.engine.executeAction(this.objectName, actionName, {\n ...params,\n userId: this.context.userId,\n tenantId: this.context.tenantId,\n roles: this.context.roles,\n });\n }\n throw new Error(`Actions not supported by engine`);\n }\n}\n\n/**\n * Scoped execution context with object() accessor.\n * \n * Provides identity (userId, tenantId/spaceId, roles),\n * repository access via object(), privilege escalation via sudo(),\n * and transactional execution via transaction().\n */\nexport class ScopedContext {\n constructor(\n private executionContext: ExecutionContext,\n private engine: IDataEngine\n ) {}\n\n /** Get a repository scoped to this context */\n object(name: string): ObjectRepository {\n return new ObjectRepository(name, this.executionContext, this.engine as any);\n }\n\n /** Create an elevated (system) context */\n sudo(): ScopedContext {\n return new ScopedContext(\n { ...this.executionContext, isSystem: true },\n this.engine\n );\n }\n\n /**\n * Execute a callback within a database transaction.\n *\n * The callback receives a new ScopedContext whose operations\n * share the same transaction handle. If the callback throws,\n * the transaction is rolled back; otherwise it is committed.\n *\n * Falls back to non-transactional execution if the driver\n * does not support transactions.\n */\n async transaction(callback: (trxCtx: ScopedContext) => Promise<any>): Promise<any> {\n const engine = this.engine as any;\n\n // Find the default driver for transaction support\n const driver = engine.defaultDriver\n ? engine.drivers?.get(engine.defaultDriver)\n : undefined;\n\n if (!driver?.beginTransaction) {\n // No transaction support — execute directly\n return callback(this);\n }\n\n const trx = await driver.beginTransaction();\n const trxCtx = new ScopedContext(\n { ...this.executionContext, transaction: trx },\n this.engine\n );\n\n try {\n const result = await callback(trxCtx);\n if (driver.commit) await driver.commit(trx);\n else if (driver.commitTransaction) await driver.commitTransaction(trx);\n return result;\n } catch (error) {\n if (driver.rollback) await driver.rollback(trx);\n else if (driver.rollbackTransaction) await driver.rollbackTransaction(trx);\n throw error;\n }\n }\n\n get userId() { return this.executionContext.userId; }\n get tenantId() { return this.executionContext.tenantId; }\n /** Alias for tenantId — matches ObjectQLContext.spaceId convention */\n get spaceId() { return this.executionContext.tenantId; }\n get roles() { return this.executionContext.roles; }\n get isSystem() { return this.executionContext.isSystem; }\n\n /** Internal: expose the transaction handle for driver-level access */\n get transactionHandle() { return this.executionContext.transaction; }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Declarative Hook Wrappers\n *\n * Turns a raw `HookHandler` into one that honours the declarative metadata\n * fields defined on `HookSchema` (`condition`, `async`, `retryPolicy`,\n * `timeout`, `onError`). This lives outside the engine's `triggerHooks`\n * loop so the engine stays minimal and the semantics are unit-testable in\n * isolation.\n *\n * The resulting wrapped handler keeps the original `(ctx) => Promise<void>`\n * signature, so `engine.registerHook` does not need to know anything about\n * the metadata-driven behaviours.\n */\nimport type { Hook, HookContext } from '@objectstack/spec/data';\nimport type { Expression } from '@objectstack/spec';\nimport type { HookHandler } from './engine.js';\nimport { ExpressionEngine } from '@objectstack/formula';\nimport { noopHookMetricsRecorder, type HookMetricsRecorder, type HookMetricOutcome } from './hook-metrics.js';\n\nexport interface WrapDeclarativeOptions {\n /** Logger for declarative-layer diagnostics (timeouts, retries, swallowed errors). */\n logger?: {\n debug: (msg: string, meta?: any) => void;\n info: (msg: string, meta?: any) => void;\n warn: (msg: string, meta?: any) => void;\n error: (msg: string, meta?: any) => void;\n };\n /** Optional per-execution metrics sink. Defaults to no-op. */\n metrics?: HookMetricsRecorder;\n}\n\nconst noopLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/**\n * Wrap a hook handler so it honours the declarative fields defined on\n * `HookSchema`. The wrapping order, from outermost to innermost, is:\n *\n * 1. condition → skip when formula evaluates falsy\n * 2. async → fire-and-forget (after* events only)\n * 3. retry → repeat on throw with backoff\n * 4. timeout → abort if handler runs too long\n * 5. onError → swallow when set to 'log'\n *\n * The condition formula is evaluated against the most useful record-shaped\n * payload available on the context (write payloads first, then `previous`,\n * then a flat merge of input). Read events typically have no record yet,\n * so a condition on a `beforeFind` will simply skip when no data is\n * present.\n */\nexport function wrapDeclarativeHook(\n meta: Hook,\n handler: HookHandler,\n opts: WrapDeclarativeOptions = {},\n): HookHandler {\n const logger = opts.logger ?? noopLogger;\n const metrics = opts.metrics ?? noopHookMetricsRecorder;\n const isAfterEvent = meta.events?.some((e) => typeof e === 'string' && e.startsWith('after')) ?? false;\n const hasBody = Boolean((meta as any).body);\n const labelFor = (ctx: HookContext) => ({\n hook: meta.name,\n object: ctx.object ?? (typeof (meta as any).object === 'string' ? (meta as any).object : undefined),\n event: ctx.event,\n body: hasBody,\n });\n\n // Pre-compile condition once so each invocation is cheap.\n let conditionFn: ((record: any) => boolean) | undefined;\n if (meta.condition) {\n // Accept either string shorthand or full Expression envelope.\n const expr: Expression = typeof meta.condition === 'string'\n ? { dialect: 'cel', source: meta.condition }\n : (meta.condition as Expression);\n if (expr.source && expr.source.trim()) {\n const check = ExpressionEngine.compile(expr);\n if (check.ok) {\n conditionFn = (record: any) => {\n const r = ExpressionEngine.evaluate<boolean>(expr, { record: record ?? {} });\n if (!r.ok) {\n logger.warn('[hook] condition evaluation failed; treating as false', {\n hook: meta.name,\n condition: expr.source,\n error: r.error.message,\n });\n return false;\n }\n return Boolean(r.value);\n };\n } else {\n logger.warn('[hook] condition formula failed to compile; condition ignored', {\n hook: meta.name,\n condition: expr.source,\n error: check.error.message,\n });\n }\n }\n }\n\n const retryMax = Math.max(0, Number(meta.retryPolicy?.maxRetries ?? 0));\n const retryBackoffMs = Math.max(0, Number(meta.retryPolicy?.backoffMs ?? 0));\n const timeoutMs = typeof meta.timeout === 'number' && meta.timeout > 0 ? meta.timeout : undefined;\n const onError = meta.onError ?? 'abort';\n // `async` is only meaningful for after* events; ignore on before* (we must\n // wait for the handler to potentially mutate ctx.input).\n const fireAndForget = Boolean(meta.async) && isAfterEvent;\n\n const runWithTimeout = async (ctx: HookContext): Promise<void> => {\n if (!timeoutMs) {\n await handler(ctx);\n return;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n Promise.resolve().then(() => handler(ctx)),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(new Error(`Hook '${meta.name}' timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n }),\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n };\n\n const runWithRetry = async (ctx: HookContext): Promise<void> => {\n let attempt = 0;\n let lastErr: unknown;\n // attempts = 1 + retryMax\n while (attempt <= retryMax) {\n try {\n await runWithTimeout(ctx);\n return;\n } catch (err) {\n lastErr = err;\n attempt += 1;\n if (attempt > retryMax) break;\n if (retryBackoffMs > 0) {\n await new Promise((r) => setTimeout(r, retryBackoffMs * attempt));\n }\n try { metrics.recordRetry(labelFor(ctx), attempt); } catch { /* noop */ }\n logger.warn('[hook] retrying after failure', {\n hook: meta.name,\n attempt,\n maxRetries: retryMax,\n error: (err as any)?.message,\n });\n }\n }\n throw lastErr;\n };\n\n const runWithErrorPolicy = async (ctx: HookContext): Promise<void> => {\n try {\n await runWithRetry(ctx);\n } catch (err) {\n if (onError === 'log') {\n logger.error('[hook] handler failed (onError=log; suppressing)', {\n hook: meta.name,\n object: ctx.object,\n event: ctx.event,\n error: (err as any)?.message,\n });\n return;\n }\n throw err;\n }\n };\n\n return async (ctx: HookContext): Promise<void> => {\n // 1. Condition gate\n if (conditionFn) {\n const record = pickRecordPayload(ctx);\n if (!conditionFn(record)) {\n logger.debug('[hook] skipped by condition', {\n hook: meta.name,\n object: ctx.object,\n event: ctx.event,\n });\n try { metrics.recordSkip(labelFor(ctx), 'condition'); } catch { /* noop */ }\n return;\n }\n }\n\n const restore = installFlatInput(ctx);\n const startedAt = Date.now();\n\n const recordOutcome = (err?: any) => {\n const elapsed = Date.now() - startedAt;\n let outcome: HookMetricOutcome = 'success';\n if (err) {\n const msg = String(err?.message ?? err ?? '');\n if (/timed out after/i.test(msg)) outcome = 'timeout';\n else if (/capability|cap-rejection|capability_rejected/i.test(msg)) outcome = 'capability_rejected';\n else outcome = 'error';\n }\n try { metrics.recordExecution(labelFor(ctx), outcome, elapsed); } catch { /* noop */ }\n };\n\n try {\n // 2. Fire-and-forget for declarative async after* hooks\n if (fireAndForget) {\n try { metrics.recordSkip(labelFor(ctx), 'fire_and_forget'); } catch { /* noop */ }\n // For fire-and-forget we can't keep ctx.input swapped while the\n // engine moves on — copy what we need, restore, and run async.\n void runWithErrorPolicy(ctx)\n .then(() => recordOutcome())\n .catch((err) => {\n recordOutcome(err);\n logger.error('[hook] async handler error (fire-and-forget)', {\n hook: meta.name,\n error: (err as any)?.message,\n });\n });\n return;\n }\n\n try {\n await runWithErrorPolicy(ctx);\n recordOutcome();\n } catch (err) {\n recordOutcome(err);\n throw err;\n }\n } finally {\n restore();\n }\n };\n}\n\n/**\n * Swap `ctx.input` in place for a Proxy that exposes a flat record view\n * over the engine's `{ data, options, id? }` wrapper. Returns a function\n * that restores the original `ctx.input` reference. Reads of\n * `id` / `options` / `ast` / `data` fall through to the wrapper; reads\n * of any other key fall through to `data`. Writes always go to `data`\n * (creating it if missing) so the engine's downstream `input.data`\n * read picks up mutations made by user code as `input.field = value`.\n */\nfunction installFlatInput(ctx: HookContext): () => void {\n const raw: any = ctx.input ?? {};\n const looksWrapped =\n raw && typeof raw === 'object' &&\n ('data' in raw || 'options' in raw || 'id' in raw || 'ast' in raw);\n if (!looksWrapped) return () => {};\n\n const ensureData = (): Record<string, unknown> => {\n if (!raw.data || typeof raw.data !== 'object') {\n raw.data = {};\n }\n return raw.data as Record<string, unknown>;\n };\n\n const proxy = new Proxy(raw, {\n get(target, prop, receiver) {\n if (prop === 'id' || prop === 'options' || prop === 'ast' || prop === 'data') {\n return Reflect.get(target, prop, receiver);\n }\n const data = target.data;\n if (data && typeof data === 'object' && prop in data) {\n return (data as any)[prop];\n }\n return Reflect.get(target, prop, receiver);\n },\n set(target, prop, value) {\n if (prop === 'id' || prop === 'options' || prop === 'ast' || prop === 'data') {\n (target as any)[prop] = value;\n return true;\n }\n ensureData()[prop as string] = value;\n return true;\n },\n has(target, prop) {\n if (prop === 'id' || prop === 'options' || prop === 'ast' || prop === 'data') {\n return prop in target;\n }\n const data = target.data;\n if (data && typeof data === 'object' && prop in data) return true;\n return prop in target;\n },\n ownKeys(target) {\n // Only enumerate the flat record fields. Wrapper keys\n // (id/options/ast/data) remain accessible via dot/bracket notation\n // but are hidden from Object.keys/for-in so user code that does\n // `Object.keys(input).filter(k => input[k] !== previous[k])` only\n // sees actual record fields.\n const dataKeys = target.data && typeof target.data === 'object'\n ? Object.keys(target.data)\n : [];\n return Array.from(new Set(dataKeys));\n },\n getOwnPropertyDescriptor(target, prop) {\n const data = target.data;\n if (data && typeof data === 'object' && prop in data) {\n return { configurable: true, enumerable: true, writable: true, value: (data as any)[prop] };\n }\n // Wrapper keys: still descriptors so `prop in input` works, but\n // marked non-enumerable so they don't appear in Object.keys().\n if (prop === 'id' || prop === 'options' || prop === 'ast' || prop === 'data') {\n const desc = Object.getOwnPropertyDescriptor(target, prop);\n return desc ? { ...desc, enumerable: false } : undefined;\n }\n return Object.getOwnPropertyDescriptor(target, prop);\n },\n });\n\n (ctx as any).input = proxy;\n return () => {\n (ctx as any).input = raw;\n };\n}\n\n/**\n * Choose the record-shaped object the condition formula should evaluate\n * against. Order:\n * 1. ctx.input.data — write operations carry the new record here\n * 2. ctx.previous — update/delete carry pre-image here\n * 3. ctx.input — fall back to flat input bag (read ops, custom shapes)\n */\nfunction pickRecordPayload(ctx: HookContext): any {\n const input: any = ctx.input ?? {};\n if (input && typeof input === 'object' && input.data && typeof input.data === 'object') {\n return input.data;\n }\n if (ctx.previous && typeof ctx.previous === 'object') {\n return ctx.previous;\n }\n return input;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Hook Execution Metrics\n *\n * Lightweight, transport-agnostic recorder interface for per-hook execution\n * counters and latencies. The default implementation is a no-op so the\n * engine pays zero cost when nobody is observing.\n *\n * Wire a real recorder by calling `engine.setHookMetricsRecorder(recorder)`.\n * The runtime / kernel can adapt this to Otel, Prometheus, StatsD, or\n * whatever telemetry pipeline ships with the deployment.\n *\n * Recorded events:\n * - `recordExecution(label, outcome, durationMs)`\n * outcome ∈ 'success' | 'error' | 'timeout' | 'capability_rejected'\n * - `recordSkip(label, reason)`\n * reason ∈ 'condition' | 'fire_and_forget'\n * - `recordRetry(label, attempt)`\n */\n\nexport type HookMetricOutcome =\n | 'success'\n | 'error'\n | 'timeout'\n | 'capability_rejected';\n\nexport type HookSkipReason = 'condition' | 'fire_and_forget';\n\nexport interface HookMetricLabel {\n /** Hook name (stable id from metadata). */\n hook: string;\n /** Object name the hook is bound to. May be undefined for global hooks. */\n object?: string;\n /** Lifecycle event (`beforeInsert`, `afterUpdate`, etc.). */\n event?: string;\n /** True when the handler comes from a metadata `body` (sandboxed JS). */\n body?: boolean;\n}\n\nexport interface HookMetricsRecorder {\n recordExecution(label: HookMetricLabel, outcome: HookMetricOutcome, durationMs: number): void;\n recordSkip(label: HookMetricLabel, reason: HookSkipReason): void;\n recordRetry(label: HookMetricLabel, attempt: number): void;\n}\n\nexport const noopHookMetricsRecorder: HookMetricsRecorder = {\n recordExecution: () => {},\n recordSkip: () => {},\n recordRetry: () => {},\n};\n\n/**\n * In-memory recorder useful for tests, dev-mode dashboards, and as a\n * starting point for adapter implementations. Aggregates counts + a\n * rolling sum of latency per (hook, outcome).\n */\nexport class InMemoryHookMetricsRecorder implements HookMetricsRecorder {\n private executions = new Map<string, { count: number; totalMs: number }>();\n private skips = new Map<string, number>();\n private retries = new Map<string, number>();\n\n recordExecution(label: HookMetricLabel, outcome: HookMetricOutcome, durationMs: number): void {\n const key = `${label.hook}|${outcome}`;\n const cur = this.executions.get(key) ?? { count: 0, totalMs: 0 };\n cur.count += 1;\n cur.totalMs += Math.max(0, durationMs);\n this.executions.set(key, cur);\n }\n\n recordSkip(label: HookMetricLabel, reason: HookSkipReason): void {\n const key = `${label.hook}|${reason}`;\n this.skips.set(key, (this.skips.get(key) ?? 0) + 1);\n }\n\n recordRetry(label: HookMetricLabel, _attempt: number): void {\n this.retries.set(label.hook, (this.retries.get(label.hook) ?? 0) + 1);\n }\n\n snapshot(): {\n executions: Array<{ hook: string; outcome: HookMetricOutcome; count: number; totalMs: number }>;\n skips: Array<{ hook: string; reason: HookSkipReason; count: number }>;\n retries: Array<{ hook: string; count: number }>;\n } {\n return {\n executions: Array.from(this.executions, ([key, v]) => {\n const [hook, outcome] = key.split('|');\n return { hook, outcome: outcome as HookMetricOutcome, count: v.count, totalMs: v.totalMs };\n }),\n skips: Array.from(this.skips, ([key, count]) => {\n const [hook, reason] = key.split('|');\n return { hook, reason: reason as HookSkipReason, count };\n }),\n retries: Array.from(this.retries, ([hook, count]) => ({ hook, count })),\n };\n }\n\n reset(): void {\n this.executions.clear();\n this.skips.clear();\n this.retries.clear();\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Hook Binder\n *\n * Single, canonical entry point that turns declarative `Hook` metadata into\n * runtime registrations on the `ObjectQL` engine. Every metadata source —\n * `defineStack({ hooks })` (consumed by `AppPlugin`), the per-project\n * template seeder (`MultiProjectPlugin`), and the metadata service\n * (`ObjectQLPlugin.loadMetadataFromService`) — funnels through here so\n * that:\n *\n * - Inline function handlers and string-named handlers share one resolver.\n * - Declarative fields (`condition`, `async`, `retryPolicy`, `timeout`,\n * `onError`) are honoured uniformly via `wrapDeclarativeHook`.\n * - Hooks can be unregistered as a unit via `packageId`, enabling clean\n * hot-reload and app uninstall.\n *\n * The ObjectQL engine itself stays simple — it knows how to store and\n * trigger handlers, but knows nothing about declarative semantics. All\n * metadata-aware behaviour lives in this binder + the wrapper module.\n */\n\nimport type { Hook } from '@objectstack/spec/data';\nimport type { ObjectQL, HookHandler } from './engine.js';\nimport { wrapDeclarativeHook } from './hook-wrappers.js';\nimport type { HookMetricsRecorder } from './hook-metrics.js';\n\nexport interface BindHooksOptions {\n /** Owning package / app id — used for `unregisterHooksByPackage`. */\n packageId?: string;\n\n /**\n * Optional name → function map for resolving string `handler` references.\n * Typically supplied by `defineStack({ functions })` and merged with any\n * functions previously registered on the engine.\n */\n functions?: Record<string, HookHandler>;\n\n /**\n * Optional factory that converts a metadata-only `Hook.body` (L1 expression\n * or L2 sandboxed JS source) into an executable `HookHandler`. The runtime\n * package wires this up using `QuickJSScriptRunner`; objectql itself stays\n * sandbox-free so it can run in lightweight environments.\n *\n * If `hook.body` is set and this factory is missing, the hook is skipped\n * with a clear error.\n */\n bodyRunner?: (hook: Hook) => HookHandler | undefined;\n\n /**\n * When true, treat unresolved hooks (body present but no runner, or handler\n * string with no implementation) as fatal errors instead of warnings. Used\n * by production runtimes to fail fast on misconfiguration. Defaults false.\n */\n strict?: boolean;\n\n /**\n * When true, emit a deprecation warning for every hook that still relies\n * on a `handler` ref string instead of the metadata-only `body`. Used by\n * the CLI (compile time) and runtime (boot time) to nudge users away from\n * the legacy `.mjs` runtime bundle path. Defaults false.\n */\n warnLegacyHandler?: boolean;\n\n /** Per-hook execution metrics sink. Defaults to no-op. */\n metrics?: HookMetricsRecorder;\n\n /** Logger; defaults to a silent no-op. */\n logger?: {\n debug: (msg: string, meta?: any) => void;\n info: (msg: string, meta?: any) => void;\n warn: (msg: string, meta?: any) => void;\n error: (msg: string, meta?: any) => void;\n };\n}\n\nconst noopLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/** Counter for stats. */\nexport interface BindHooksResult {\n registered: number;\n skipped: number;\n errors: Array<{ hook: string; reason: string }>;\n}\n\n/**\n * Bind a list of declarative `Hook` definitions to a running ObjectQL engine.\n *\n * Idempotent on `(packageId, hook.name, event, object)`: re-binding the\n * same set after a hot reload first calls `unregisterHooksByPackage`\n * (when `packageId` is provided).\n */\nexport function bindHooksToEngine(\n engine: ObjectQL,\n hooks: Hook[] | undefined,\n opts: BindHooksOptions = {},\n): BindHooksResult {\n const logger = opts.logger ?? noopLogger;\n const result: BindHooksResult = { registered: 0, skipped: 0, errors: [] };\n\n if (!Array.isArray(hooks) || hooks.length === 0) {\n return result;\n }\n\n // Hot-reload friendly: drop anything we previously bound under this\n // packageId so the new set fully replaces the old.\n if (opts.packageId && typeof (engine as any).unregisterHooksByPackage === 'function') {\n try {\n (engine as any).unregisterHooksByPackage(opts.packageId);\n } catch (err: any) {\n logger.warn('[hook-binder] unregister-by-package failed; continuing', {\n packageId: opts.packageId,\n error: err?.message,\n });\n }\n }\n\n // Pre-load any inline functions supplied via `bundle.functions` so\n // string-handler resolution works.\n if (opts.functions && typeof (engine as any).registerFunction === 'function') {\n for (const [name, fn] of Object.entries(opts.functions)) {\n try {\n (engine as any).registerFunction(name, fn, opts.packageId);\n } catch (err: any) {\n logger.warn('[hook-binder] failed to register function', {\n name,\n error: err?.message,\n });\n }\n }\n }\n\n for (const hook of hooks) {\n try {\n const resolved = resolveHandler(engine, hook, opts);\n if (!resolved) {\n result.skipped += 1;\n const reason = (hook as any).body\n ? `hook body present but no bodyRunner supplied to bindHooksToEngine (runtime must wire QuickJSScriptRunner)`\n : typeof hook.handler === 'string'\n ? `unknown function '${hook.handler}'`\n : 'no handler';\n result.errors.push({ hook: hook.name, reason });\n if (opts.strict) {\n throw new Error(`[hook-binder] strict: cannot bind hook '${hook.name}': ${reason}`);\n }\n logger.warn('[hook-binder] skipping hook with unresolved handler', {\n hook: hook.name,\n handler: hook.handler,\n hasBody: Boolean((hook as any).body),\n });\n continue;\n }\n\n if (opts.warnLegacyHandler && !(hook as any).body && typeof hook.handler === 'string') {\n logger.warn('[hook-binder] DEPRECATED: hook uses legacy handler ref without body', {\n hook: hook.name,\n handler: hook.handler,\n hint: 'Move the handler source into Hook.body so the artifact stays metadata-only and the .mjs runtime bundle can be dropped.',\n });\n }\n\n const wrapped = wrapDeclarativeHook(hook, resolved, { logger, metrics: opts.metrics });\n const objects = normalizeObjects(hook.object);\n const events = Array.isArray(hook.events) ? hook.events : [];\n\n for (const event of events) {\n for (const object of objects) {\n engine.registerHook(event, wrapped, {\n object,\n priority: typeof hook.priority === 'number' ? hook.priority : 100,\n packageId: opts.packageId,\n // Reflect metadata so future tooling can introspect / unregister\n // and so we can detect duplicate name collisions.\n // The engine ignores unknown options today; this is forward-only.\n ...({ meta: hook, hookName: hook.name } as any),\n } as any);\n result.registered += 1;\n }\n }\n } catch (err: any) {\n result.errors.push({ hook: hook.name, reason: err?.message ?? String(err) });\n logger.error('[hook-binder] failed to bind hook', {\n hook: hook.name,\n error: err?.message,\n });\n }\n }\n\n if (result.registered > 0) {\n logger.debug('[hook-binder] hooks bound', {\n packageId: opts.packageId,\n registered: result.registered,\n skipped: result.skipped,\n });\n }\n\n return result;\n}\n\nfunction normalizeObjects(target: Hook['object']): string[] {\n if (Array.isArray(target)) return target.length > 0 ? target : ['*'];\n if (typeof target === 'string' && target.length > 0) return [target];\n return ['*'];\n}\n\nfunction resolveHandler(\n engine: ObjectQL,\n hook: Hook,\n opts: BindHooksOptions,\n): HookHandler | undefined {\n // Metadata-only body (L1 expression or L2 sandboxed JS) takes precedence\n // over the legacy `handler` field. This is the cloud-deployable path —\n // the body string ships inside the artifact JSON and runs under a\n // capability-gated sandbox supplied by the runtime.\n const body = (hook as any).body;\n if (body && typeof body === 'object') {\n let runner = opts.bodyRunner;\n if (typeof runner !== 'function') {\n const fallback = (engine as any)?._defaultBodyRunner;\n if (typeof fallback === 'function') runner = fallback;\n }\n if (typeof runner !== 'function') {\n return undefined;\n }\n const fn = runner(hook);\n if (typeof fn === 'function') return fn;\n return undefined;\n }\n\n const h = hook.handler;\n if (typeof h === 'function') return h as HookHandler;\n if (typeof h === 'string' && h.length > 0) {\n // Try the per-bundle map first (hot path during initial bind),\n // then fall back to whatever the engine already knows.\n const fromBundle = opts.functions?.[h];\n if (typeof fromBundle === 'function') return fromBundle;\n if (typeof (engine as any).resolveFunction === 'function') {\n const fn = (engine as any).resolveFunction(h);\n if (typeof fn === 'function') return fn as HookHandler;\n }\n }\n return undefined;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Record Validator\n *\n * Validates an incoming insert/update payload against the canonical\n * `Field` metadata of an `ObjectSchema`. Implements ROADMAP §M10.4 —\n * \"Zod-at-rest\" — but does not require constructing a Zod schema:\n * we walk the field map directly, which is both faster and lets us\n * produce per-field error envelopes shaped for REST consumption.\n *\n * Rules applied (in order, stop at first error per field):\n *\n * - `required` missing/null/empty-string is rejected (insert only;\n * PATCH validates only fields actually supplied)\n * - `maxLength` / `minLength` (text/textarea/email/url/phone/password)\n * - `min` / `max` (number/currency/percent/rating/slider)\n * - format email / url / phone (lightweight RFC-aware regex)\n * - select / multiselect: value must appear in `options`\n * - boolean / toggle: must coerce to boolean\n * - date / datetime: must be ISO-parsable\n *\n * System-injected fields (`id`, `created_at`, `created_by`,\n * `updated_at`, `updated_by`, `organization_id`) are never validated\n * here — the engine and the audit plugin manage them.\n *\n * On failure, a `ValidationError` is thrown with `.fields[]` holding\n * one entry per offending field. REST translates this into a\n * `400 { code: 'VALIDATION_FAILED', message, fields }` envelope so\n * the UI can highlight the specific input.\n */\n\nconst SKIP_FIELDS = new Set<string>([\n 'id', 'created_at', 'created_by', 'updated_at', 'updated_by',\n 'organization_id', 'tenant_id',\n]);\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n// Permissive URL pattern: accept any scheme:// + non-empty body so that\n// non-HTTP URIs used by drivers (libsql://, postgres://, mysql://, file://, s3://, …)\n// pass field-level validation. Stricter per-field checks can be enforced\n// via custom validators where needed.\nconst URL_RE = /^[a-z][a-z0-9+.\\-]*:\\/\\/[^\\s]+$/i;\nconst PHONE_RE = /^[+()\\-\\s\\d.]{5,}$/;\n\nexport interface FieldValidationError {\n field: string;\n code:\n | 'required'\n | 'min_length'\n | 'max_length'\n | 'min_value'\n | 'max_value'\n | 'invalid_email'\n | 'invalid_url'\n | 'invalid_phone'\n | 'invalid_number'\n | 'invalid_boolean'\n | 'invalid_date'\n | 'invalid_option';\n message: string;\n /** Allowed values for select/multiselect, when applicable. */\n options?: string[];\n}\n\nexport class ValidationError extends Error {\n readonly code = 'VALIDATION_FAILED';\n readonly fields: FieldValidationError[];\n constructor(fields: FieldValidationError[]) {\n super(\n `Validation failed for ${fields.length} field(s): ` +\n fields.map((f) => `${f.field} (${f.code})`).join(', '),\n );\n this.name = 'ValidationError';\n this.fields = fields;\n }\n}\n\ntype Mode = 'insert' | 'update';\n\ninterface FieldDef {\n name?: string;\n type: string;\n required?: boolean;\n readonly?: boolean;\n system?: boolean;\n multiple?: boolean;\n maxLength?: number;\n minLength?: number;\n min?: number;\n max?: number;\n options?: Array<{ value: string | number; label?: string } | string | number>;\n}\n\nfunction isMissing(v: unknown): boolean {\n return v === undefined || v === null || (typeof v === 'string' && v.trim() === '');\n}\n\nfunction optionValues(options: FieldDef['options']): string[] {\n if (!Array.isArray(options)) return [];\n return options.map((o) =>\n typeof o === 'object' && o !== null ? String((o as any).value) : String(o),\n );\n}\n\nfunction validateOne(name: string, def: FieldDef, value: unknown): FieldValidationError | null {\n // ── required ────────────────────────────────────────────────────\n if (def.required && isMissing(value)) {\n return { field: name, code: 'required', message: `${name} is required` };\n }\n if (isMissing(value)) return null; // nothing else to check\n\n const t = def.type;\n\n // ── string types ────────────────────────────────────────────────\n if (t === 'text' || t === 'textarea' || t === 'email' || t === 'url' || t === 'phone' || t === 'password' || t === 'markdown' || t === 'html' || t === 'richtext' || t === 'code') {\n const s = typeof value === 'string' ? value : String(value);\n if (def.maxLength !== undefined && s.length > def.maxLength) {\n return { field: name, code: 'max_length', message: `${name} must be ≤ ${def.maxLength} characters (got ${s.length})` };\n }\n if (def.minLength !== undefined && s.length < def.minLength) {\n return { field: name, code: 'min_length', message: `${name} must be ≥ ${def.minLength} characters (got ${s.length})` };\n }\n if (t === 'email' && !EMAIL_RE.test(s)) {\n return { field: name, code: 'invalid_email', message: `${name} must be a valid email address` };\n }\n if (t === 'url' && !URL_RE.test(s)) {\n return { field: name, code: 'invalid_url', message: `${name} must be a valid URL (scheme://...)` };\n }\n if (t === 'phone' && !PHONE_RE.test(s)) {\n return { field: name, code: 'invalid_phone', message: `${name} must be a valid phone number` };\n }\n return null;\n }\n\n // ── number types ────────────────────────────────────────────────\n if (t === 'number' || t === 'currency' || t === 'percent' || t === 'rating' || t === 'slider') {\n const n = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(n)) {\n return { field: name, code: 'invalid_number', message: `${name} must be a number` };\n }\n if (def.min !== undefined && n < def.min) {\n return { field: name, code: 'min_value', message: `${name} must be ≥ ${def.min}` };\n }\n if (def.max !== undefined && n > def.max) {\n return { field: name, code: 'max_value', message: `${name} must be ≤ ${def.max}` };\n }\n return null;\n }\n\n // ── boolean ────────────────────────────────────────────────────\n if (t === 'boolean' || t === 'toggle') {\n if (typeof value === 'boolean') return null;\n if (value === 0 || value === 1 || value === '0' || value === '1' || value === 'true' || value === 'false') return null;\n return { field: name, code: 'invalid_boolean', message: `${name} must be true or false` };\n }\n\n // ── date/datetime ───────────────────────────────────────────────\n if (t === 'date' || t === 'datetime' || t === 'time') {\n if (value instanceof Date) return null;\n if (typeof value === 'string' && !Number.isNaN(Date.parse(value))) return null;\n return { field: name, code: 'invalid_date', message: `${name} must be a valid ${t} (ISO-8601)` };\n }\n\n // ── select / multiselect / radio ────────────────────────────────\n if (t === 'select' || t === 'radio') {\n const allowed = optionValues(def.options);\n if (allowed.length > 0 && !allowed.includes(String(value))) {\n return { field: name, code: 'invalid_option', message: `${name} must be one of: ${allowed.join(', ')}`, options: allowed };\n }\n return null;\n }\n if (t === 'multiselect' || t === 'checkboxes' || t === 'tags') {\n const allowed = optionValues(def.options);\n if (allowed.length === 0) return null;\n const arr = Array.isArray(value) ? value : [value];\n for (const v of arr) {\n if (!allowed.includes(String(v))) {\n return { field: name, code: 'invalid_option', message: `${name}: \"${v}\" is not one of: ${allowed.join(', ')}`, options: allowed };\n }\n }\n return null;\n }\n\n // Other types (lookup, file, formula, json, location, etc.) — no\n // strict shape check at this layer; reference integrity is handled\n // elsewhere (lookup) and the rest are opaque payloads.\n return null;\n}\n\n/**\n * Validate a payload against a list of declared fields. `objectSchema`\n * comes from `ObjectQL.getRegistry().getObject(name)` and exposes a\n * `fields` map of `{ [fieldName]: FieldDef }`.\n *\n * Returns void on success; throws `ValidationError` on failure.\n */\nexport function validateRecord(\n objectSchema: { fields?: Record<string, FieldDef> } | undefined | null,\n data: Record<string, unknown> | undefined | null,\n mode: Mode,\n): void {\n if (!objectSchema?.fields || !data) return;\n\n const errors: FieldValidationError[] = [];\n const fields = objectSchema.fields;\n\n if (mode === 'insert') {\n // Walk all declared fields — required check applies even when\n // the caller didn't supply the field at all.\n for (const [name, def] of Object.entries(fields)) {\n if (SKIP_FIELDS.has(name)) continue;\n if (def.system || def.readonly) continue;\n const err = validateOne(name, def, data[name]);\n if (err) errors.push(err);\n }\n } else {\n // Update — validate only supplied fields, skip required check.\n for (const [name, value] of Object.entries(data)) {\n if (SKIP_FIELDS.has(name)) continue;\n const def = fields[name];\n if (!def) continue;\n if (def.system || def.readonly) continue;\n // Clone def with required=false so PATCH-omitted-fields don't 400.\n const err = validateOne(name, { ...def, required: false }, value);\n if (err) errors.push(err);\n }\n }\n\n if (errors.length > 0) throw new ValidationError(errors);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// In-memory implementation of the QueryAST aggregation contract.\n//\n// This module is the engine's last-resort path: when the underlying driver\n// returned raw rows but the caller asked for `groupBy` / `aggregations`, the\n// engine pipes the rows through here so the abstract contract is always\n// honoured even on drivers without native aggregation (driver-rest, partial\n// SQL drivers, mock drivers in tests).\n//\n// Capabilities:\n// * Flat groupBy strings: `['region']`\n// * Structured groupBy with date bucketing: `[{ field: 'closed_at',\n// dateGranularity: 'quarter' }]`\n// * Aggregation functions: count, count_distinct, sum, avg, min, max,\n// array_agg, string_agg\n// * `distinct: true` on aggregations (collapse duplicates before applying\n// the function)\n// * `filter: FilterCondition` on aggregations is **not** evaluated here —\n// the engine routes filtered aggregations through the driver where\n// possible; the in-memory fallback ignores the per-aggregation filter and\n// logs a warning if one is present.\n//\n// Date bucketing uses ISO-8601 conventions (weeks start Monday). Null /\n// invalid values bucket as the literal string `'(null)'` to remain\n// consistent with the client `useReportData` hook.\n\nimport type { QueryAST, GroupByNode, AggregationNode, DateGranularityValue } from '@objectstack/spec/data';\n\n/**\n * Group + aggregate raw rows according to the AST's `groupBy` /\n * `aggregations`. When neither is present, returns the rows unchanged.\n */\nexport function applyInMemoryAggregation(\n rows: any[],\n ast: Pick<QueryAST, 'groupBy' | 'aggregations'>,\n): any[] {\n const groupBy = (ast.groupBy ?? []) as GroupByNode[];\n const aggregations = (ast.aggregations ?? []) as AggregationNode[];\n if (groupBy.length === 0 && aggregations.length === 0) return rows;\n\n if (groupBy.length === 0) {\n // Pure aggregation — single result row.\n return [aggregateBucket(rows, aggregations)];\n }\n\n const buckets = new Map<string, { key: Record<string, any>; rows: any[] }>();\n for (const row of rows) {\n const key: Record<string, any> = {};\n const parts: string[] = [];\n for (const g of groupBy) {\n const fieldName = typeof g === 'string' ? g : (g.alias ?? g.field);\n const value = projectGroupValue(row, g);\n key[fieldName] = value;\n parts.push(`${fieldName}=${value}`);\n }\n const id = parts.join('\\u0001');\n let bucket = buckets.get(id);\n if (!bucket) {\n bucket = { key, rows: [] };\n buckets.set(id, bucket);\n }\n bucket.rows.push(row);\n }\n\n const out: any[] = [];\n for (const { key, rows: bucketRows } of buckets.values()) {\n const aggValues = aggregateBucket(bucketRows, aggregations);\n out.push({ ...key, ...aggValues });\n }\n return out;\n}\n\nfunction projectGroupValue(row: any, g: GroupByNode): string {\n const field = typeof g === 'string' ? g : g.field;\n const v = row?.[field];\n if (typeof g !== 'string' && g.dateGranularity) {\n return bucketDateValue(v, g.dateGranularity);\n }\n return v == null ? '(null)' : String(v);\n}\n\nfunction aggregateBucket(rows: any[], aggregations: AggregationNode[]): Record<string, any> {\n const out: Record<string, any> = {};\n for (const agg of aggregations) {\n const alias = agg.alias;\n const fn = agg.function;\n if (fn === 'count') {\n if (!agg.field) {\n out[alias] = rows.length;\n } else {\n out[alias] = rows.reduce(\n (acc, r) => (r[agg.field as string] != null ? acc + 1 : acc),\n 0,\n );\n }\n continue;\n }\n const field = agg.field;\n if (!field) {\n out[alias] = null;\n continue;\n }\n const values = collectValues(rows, field, !!agg.distinct);\n\n switch (fn) {\n case 'count_distinct':\n out[alias] = new Set(values.filter((v) => v != null)).size;\n break;\n case 'sum':\n out[alias] = values.reduce((a, b) => a + toNumber(b), 0);\n break;\n case 'avg': {\n const nums = values.filter((v) => v != null).map(toNumber);\n out[alias] = nums.length === 0 ? null : nums.reduce((a, b) => a + b, 0) / nums.length;\n break;\n }\n case 'min': {\n const defined = values.filter((v) => v != null);\n out[alias] = defined.length === 0 ? null : defined.reduce((a, b) => (a < b ? a : b));\n break;\n }\n case 'max': {\n const defined = values.filter((v) => v != null);\n out[alias] = defined.length === 0 ? null : defined.reduce((a, b) => (a > b ? a : b));\n break;\n }\n case 'array_agg':\n out[alias] = values.slice();\n break;\n case 'string_agg':\n out[alias] = values.filter((v) => v != null).map(String).join(',');\n break;\n default:\n out[alias] = null;\n }\n }\n return out;\n}\n\nfunction collectValues(rows: any[], field: string, distinct: boolean): any[] {\n if (!distinct) return rows.map((r) => r?.[field]);\n const seen = new Set<unknown>();\n const out: any[] = [];\n for (const r of rows) {\n const v = r?.[field];\n if (seen.has(v)) continue;\n seen.add(v);\n out.push(v);\n }\n return out;\n}\n\nfunction toNumber(v: any): number {\n if (typeof v === 'number') return v;\n if (v == null) return 0;\n const n = Number(v);\n return Number.isFinite(n) ? n : 0;\n}\n\n/**\n * Bucket a date-like value into an ISO-formatted period label. Weeks start\n * Monday and use ISO week numbering.\n */\nexport function bucketDateValue(value: unknown, granularity: DateGranularityValue): string {\n if (value == null) return '(null)';\n const d = value instanceof Date ? value : new Date(String(value));\n if (Number.isNaN(d.getTime())) return '(null)';\n const y = d.getUTCFullYear();\n const m = d.getUTCMonth() + 1;\n switch (granularity) {\n case 'year':\n return String(y);\n case 'quarter':\n return `${y}-Q${Math.floor((m - 1) / 3) + 1}`;\n case 'month':\n return `${y}-${String(m).padStart(2, '0')}`;\n case 'day':\n return `${y}-${String(m).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n case 'week': {\n // ISO-8601 week date: week 1 contains the first Thursday of the year.\n const target = new Date(Date.UTC(y, d.getUTCMonth(), d.getUTCDate()));\n const dayNum = (target.getUTCDay() + 6) % 7; // Mon=0..Sun=6\n target.setUTCDate(target.getUTCDate() - dayNum + 3);\n const firstThursday = new Date(Date.UTC(target.getUTCFullYear(), 0, 4));\n const weekNo = 1 + Math.round(\n ((target.getTime() - firstThursday.getTime()) / 86400000 - 3 + ((firstThursday.getUTCDay() + 6) % 7)) / 7,\n );\n return `${target.getUTCFullYear()}-W${String(weekNo).padStart(2, '0')}`;\n }\n default:\n return String(value);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { SchemaRegistry } from './registry.js';\n\n/**\n * MetadataFacade\n *\n * Provides a clean, injectable interface over SchemaRegistry.\n * Registered as the 'metadata' kernel service to eliminate\n * downstream packages needing to manually wrap SchemaRegistry.\n *\n * Implements the async IMetadataService interface.\n * Internally delegates to SchemaRegistry (in-memory) with Promise wrappers.\n *\n * Each facade is bound to a specific SchemaRegistry instance — passed in the\n * constructor — so that multi-kernel servers can give every kernel its own\n * metadata surface without leaking state across tenants.\n */\nexport class MetadataFacade {\n constructor(private registry: SchemaRegistry) {}\n\n /**\n * Register a metadata item\n */\n async register(type: string, name: string, data: any): Promise<void> {\n const definition = typeof data === 'object' && data !== null\n ? { ...data, name: data.name ?? name }\n : data;\n if (type === 'object') {\n this.registry.registerItem(type, definition, 'name' as any);\n } else {\n this.registry.registerItem(type, definition, definition.id ? 'id' as any : 'name' as any);\n }\n }\n\n /**\n * Get a metadata item by type and name\n */\n async get(type: string, name: string): Promise<any> {\n const item = this.registry.getItem(type, name) as any;\n return item?.content ?? item;\n }\n\n /**\n * Get the raw entry (with metadata wrapper)\n */\n getEntry(type: string, name: string): any {\n return this.registry.getItem(type, name);\n }\n\n /**\n * List all items of a type\n */\n async list(type: string): Promise<any[]> {\n const items = this.registry.listItems(type);\n return items.map((item: any) => item?.content ?? item);\n }\n\n /**\n * Unregister a metadata item\n */\n async unregister(type: string, name: string): Promise<void> {\n this.registry.unregisterItem(type, name);\n }\n\n /**\n * Check if a metadata item exists\n */\n async exists(type: string, name: string): Promise<boolean> {\n const item = this.registry.getItem(type, name);\n return item !== undefined && item !== null;\n }\n\n /**\n * List all names of metadata items of a given type\n */\n async listNames(type: string): Promise<string[]> {\n const items = this.registry.listItems(type);\n return items.map((item: any) => item?.name ?? item?.content?.name ?? '').filter(Boolean);\n }\n\n /**\n * Unregister all metadata from a package\n */\n async unregisterPackage(packageName: string): Promise<void> {\n this.registry.unregisterObjectsByPackage(packageName);\n }\n\n /**\n * Convenience: get object definition\n */\n async getObject(name: string): Promise<any> {\n return this.registry.getObject(name);\n }\n\n /**\n * Convenience: list all objects\n */\n async listObjects(): Promise<any[]> {\n return this.registry.getAllObjects();\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectQL } from './engine.js';\nimport { ObjectStackProtocolImplementation } from './protocol.js';\nimport { Plugin, PluginContext } from '@objectstack/core';\nimport { StorageNameMapping } from '@objectstack/spec/system';\n\nexport type { Plugin, PluginContext };\n\n/**\n * Protocol extension for DB-based metadata hydration.\n * `loadMetaFromDb` is implemented by ObjectStackProtocolImplementation but\n * is NOT (yet) part of the canonical ObjectStackProtocol wire-contract in\n * `@objectstack/spec`, since it is a server-side bootstrap concern only.\n */\ninterface ProtocolWithDbRestore {\n loadMetaFromDb(): Promise<{ loaded: number; errors: number }>;\n}\n\n/** Type guard — checks whether the service exposes `loadMetaFromDb`. */\nfunction hasLoadMetaFromDb(service: unknown): service is ProtocolWithDbRestore {\n return (\n typeof service === 'object' &&\n service !== null &&\n typeof (service as Record<string, unknown>)['loadMetaFromDb'] === 'function'\n );\n}\n\n/**\n * Options for ObjectQLPlugin.\n *\n * `projectId` scopes all metadata writes + reads to a specific project.\n * When set, `protocol.saveMetaItem` stamps `project_id = <projectId>` on\n * new sys_metadata rows, and `protocol.loadMetaFromDb` filters by the same\n * column. Leave undefined in single-kernel / self-hosted mode — rows land\n * in the platform-global scope (project_id IS NULL).\n */\nexport interface ObjectQLPluginOptions {\n /** Optional pre-built engine. When absent, one is lazily created in init. */\n ql?: ObjectQL;\n /** Passed to `new ObjectQL(...)` when `ql` is not supplied. */\n hostContext?: Record<string, any>;\n /** Scope sys_metadata reads/writes to this project. */\n projectId?: string;\n /**\n * Override the kernel's default plugin-start timeout for this plugin.\n * Defaults to 120000 (120s). Schema sync to a remote SQL backend\n * (Neon/Postgres/Turso) is latency-bound — the SQL driver currently\n * does NOT support `batchSchemaSync`, so it issues one round-trip per\n * registered object × twice (Phase 1 + Phase 3 in `start()`). On a\n * cold remote DB with N tables this can blow past the kernel's\n * default 30s easily, even though everything is healthy.\n */\n startupTimeout?: number;\n /**\n * Skip both `syncRegisteredSchemas()` calls inside `start()` and\n * assume DDL is managed out-of-band (e.g. an `apps/cloud/scripts/migrate.ts`\n * run before deploy that connects directly to the database and creates\n * all `sys_*` + custom tables once).\n *\n * Use this on cold-start-sensitive runtimes (Cloudflare Containers,\n * Lambda) where the platform's inbound-request budget is shorter than\n * a fresh remote-DB schema sync. The plugin still hydrates the\n * SchemaRegistry from `sys_metadata` (Phase 2), so custom user\n * objects come up — they just aren't re-DDL'd on every cold boot.\n *\n * Falls back to `process.env.OS_SKIP_SCHEMA_SYNC === '1'` when the\n * option is unset, so containers can flip it via their env without a\n * code change.\n */\n skipSchemaSync?: boolean;\n}\n\nexport class ObjectQLPlugin implements Plugin {\n name = 'com.objectstack.engine.objectql';\n type = 'objectql';\n version = '1.0.0';\n /**\n * Schema sync to remote SQL DBs is latency-bound (one round-trip per\n * table × 2 phases). Default to 120s instead of the kernel's 30s so\n * cold Neon/Turso starts don't get killed mid-sync.\n */\n startupTimeout = 120_000;\n\n private ql: ObjectQL | undefined;\n private hostContext?: Record<string, any>;\n private projectId?: string;\n private skipSchemaSync = false;\n /** Unsubscribe handles for metadata-event subscriptions (ADR-0008 PR-7). */\n private metadataUnsubscribes: Array<() => void> = [];\n\n constructor(qlOrOptions?: ObjectQL | ObjectQLPluginOptions, hostContext?: Record<string, any>) {\n // Back-compat: legacy callers passed `(ObjectQL, hostContext)` positionally.\n if (qlOrOptions instanceof ObjectQL) {\n this.ql = qlOrOptions;\n this.hostContext = hostContext;\n return;\n }\n // New signature: options bag.\n const opts = (qlOrOptions as ObjectQLPluginOptions | undefined) ?? {};\n if (opts.ql) {\n this.ql = opts.ql;\n }\n this.hostContext = opts.hostContext ?? hostContext;\n this.projectId = opts.projectId;\n if (typeof opts.startupTimeout === 'number' && opts.startupTimeout > 0) {\n this.startupTimeout = opts.startupTimeout;\n }\n this.skipSchemaSync =\n typeof opts.skipSchemaSync === 'boolean'\n ? opts.skipSchemaSync\n : process.env.OS_SKIP_SCHEMA_SYNC === '1';\n }\n\n init = async (ctx: PluginContext) => {\n if (!this.ql) {\n // Pass kernel logger to engine to avoid creating a separate logger instance\n const hostCtx = { ...this.hostContext, logger: ctx.logger };\n this.ql = new ObjectQL(hostCtx);\n }\n \n // Register as provider for Core Kernel Services\n ctx.registerService('objectql', this.ql);\n\n ctx.registerService('data', this.ql); // ObjectQL implements IDataEngine\n\n // Register manifest service for direct app/package registration.\n // Plugins call ctx.getService('manifest').register(manifestData)\n // instead of the legacy ctx.registerService('app.<id>', manifestData) convention.\n const ql = this.ql;\n ctx.registerService('manifest', {\n register: (manifest: any) => {\n ql.registerApp(manifest);\n ctx.logger.debug('Manifest registered via manifest service', {\n id: manifest.id || manifest.name\n });\n }\n });\n\n ctx.logger.info('ObjectQL engine registered', {\n services: ['objectql', 'data', 'manifest'],\n });\n\n // Register Protocol Implementation\n const protocolShim = new ObjectStackProtocolImplementation(\n this.ql,\n () => ctx.getServices ? ctx.getServices() : new Map(),\n undefined,\n this.projectId,\n );\n\n ctx.registerService('protocol', protocolShim);\n ctx.logger.info('Protocol service registered');\n\n // Register an `analytics` service adapter that maps the dispatcher's\n // expected interface (query / getMeta / generateSql) onto the\n // protocol shim's `analyticsQuery`. Without this, HttpDispatcher's\n // `handleAnalytics` cannot resolve a service and `/api/v1/analytics/*`\n // returns ROUTE_NOT_FOUND, even though discovery advertises the route\n // (objectql's getDiscovery hardcodes `analytics: enabled:true`). The\n // adapter delegates `query` to the cube → engine.aggregate translator\n // already implemented in protocol.ts; getMeta/generateSql return a\n // structured \"not implemented\" payload so callers see something\n // useful instead of a 500.\n ctx.registerService('analytics', {\n query: (body: any) => protocolShim.analyticsQuery(body),\n getMeta: async () => ({\n cubes: [],\n message: 'Analytics meta endpoint not implemented by ObjectQL adapter',\n }),\n generateSql: async (_body: any) => ({\n sql: null,\n message: 'Analytics SQL generation not implemented by ObjectQL adapter',\n }),\n });\n }\n\n start = async (ctx: PluginContext) => {\n ctx.logger.info('ObjectQL engine starting...');\n\n // Sync from external metadata service (e.g. MetadataPlugin) if available\n try {\n const metadataService = ctx.getService('metadata') as any;\n if (metadataService && typeof metadataService.loadMany === 'function' && this.ql) {\n await this.loadMetadataFromService(metadataService, ctx);\n }\n // ── ADR-0008 PR-7: subscribe to object metadata events so the\n // SchemaRegistry cache is invalidated on edits (Studio HMR).\n // The metadata service bubbles repo events through its own\n // `subscribe(type, cb)` API (PR-6 bridge), so we don't talk\n // to the repo directly here — this keeps ObjectQL decoupled\n // from the storage backend.\n if (metadataService && typeof metadataService.subscribe === 'function' && this.ql) {\n this.subscribeToMetadataEvents(metadataService, ctx);\n }\n } catch (e: any) {\n ctx.logger.debug('No external metadata service to sync from');\n }\n \n // Discover features from Kernel Services\n if (ctx.getServices && this.ql) {\n const services = ctx.getServices();\n for (const [name, service] of services.entries()) {\n if (name.startsWith('driver.')) {\n // Register Driver\n this.ql.registerDriver(service);\n ctx.logger.debug('Discovered and registered driver service', { serviceName: name });\n }\n if (name.startsWith('app.')) {\n // Legacy fallback: discover app.* services (DEPRECATED)\n ctx.logger.warn(\n `[DEPRECATED] Service \"${name}\" uses legacy app.* convention. ` +\n `Migrate to ctx.getService('manifest').register(data).`\n );\n this.ql.registerApp(service); // service is Manifest\n ctx.logger.debug('Discovered and registered app service (legacy)', { serviceName: name });\n }\n }\n\n // Bridge realtime service from kernel service registry to ObjectQL.\n // RealtimeServicePlugin registers as 'realtime' service during init().\n // This enables ObjectQL to publish data change events.\n try {\n const realtimeService = ctx.getService('realtime');\n if (realtimeService && typeof realtimeService === 'object' && 'publish' in realtimeService) {\n ctx.logger.info('[ObjectQLPlugin] Bridging realtime service to ObjectQL for event publishing');\n this.ql.setRealtimeService(realtimeService as any);\n }\n } catch (e: any) {\n ctx.logger.debug('[ObjectQLPlugin] No realtime service found — data events will not be published', {\n error: e.message,\n });\n }\n }\n\n // Initialize drivers (calls driver.connect() which sets up persistence)\n await this.ql?.init();\n\n // Phase 1: Sync built-in schemas so sys_metadata table exists before reading it.\n //\n // Cold-start-sensitive runtimes (Cloudflare Containers, Lambda) can\n // opt out via `skipSchemaSync` / `OS_SKIP_SCHEMA_SYNC=1`. In that\n // mode an out-of-band migration must have already created every\n // table; we only assume the DDL is in place and skip straight to\n // hydration. This avoids one round-trip per table × N objects on\n // every cold boot.\n if (this.skipSchemaSync) {\n ctx.logger.info('Skipping schema sync (OS_SKIP_SCHEMA_SYNC=1) — assuming DDL is managed out-of-band');\n } else {\n await this.syncRegisteredSchemas(ctx);\n }\n\n // Phase 2: Hydrate SchemaRegistry from sys_metadata (loads custom/template objects).\n // Project kernels (projectId set) never persist sys_metadata locally —\n // metadata is sourced from the artifact (MetadataPlugin) or routed to the\n // control plane via ControlPlaneProxyDriver. Skip to avoid querying a table\n // that does not exist on local project DBs.\n if (this.projectId === undefined) {\n await this.restoreMetadataFromDb(ctx);\n } else {\n ctx.logger.info('Project kernel — skipping sys_metadata hydration (metadata sourced from artifact)');\n }\n\n // Phase 3: Sync any new schemas that were just hydrated from the DB\n // (e.g. CRM objects seeded via template — they must have tables before use).\n if (!this.skipSchemaSync) {\n await this.syncRegisteredSchemas(ctx);\n }\n\n // Bridge all SchemaRegistry objects to metadata service.\n //\n // `SchemaRegistry` is a process-wide singleton, so project kernels in a\n // multi-project server would otherwise inherit every object ever\n // registered by any sibling project. When this plugin was constructed\n // with a `projectId`, the kernel is project-scoped — its\n // metadata comes from the artifact (MetadataPlugin) or the\n // control-plane proxy, not from local sys_metadata. The bridge would\n // only pollute its metadata service with cross-project leakage, so\n // skip it in that case.\n if (this.projectId === undefined) {\n await this.bridgeObjectsToMetadataService(ctx);\n }\n\n // Register built-in audit hooks\n this.registerAuditHooks(ctx);\n\n // Tenant isolation is now handled by `@objectstack/plugin-security`\n // via the `member_default` permission set's RLS rule\n // (`organization_id = current_user.organization_id`, with\n // field-existence guards). The legacy hard-coded `tenant_id` filter\n // middleware was removed because it (a) collided with the\n // SecurityPlugin RLS pipeline and (b) blindly filtered tables that\n // don't have a `tenant_id` column (e.g. `sys_organization`),\n // returning 0 rows instead of all rows.\n\n ctx.logger.info('ObjectQL engine started', {\n driversRegistered: this.ql?.['drivers']?.size || 0,\n objectsRegistered: this.ql?.registry?.getAllObjects?.()?.length || 0\n });\n }\n\n stop = async (ctx: PluginContext) => {\n // ADR-0008 PR-7: tear down metadata subscriptions on plugin stop so\n // tests don't leak watchers and reloaded plugins don't double-subscribe.\n for (const unsub of this.metadataUnsubscribes) {\n try { unsub(); } catch (e: any) {\n ctx.logger.debug('[ObjectQLPlugin] metadata-event unsubscribe failed', { error: e?.message });\n }\n }\n this.metadataUnsubscribes = [];\n }\n\n /**\n * Subscribe to `object` metadata events from the metadata service and\n * invalidate the SchemaRegistry merge cache on each event (ADR-0008\n * PR-7). For create/update we also re-load the affected object from\n * the metadata service so subsequent reads see the new definition;\n * for delete we unregister it from every contributing package.\n *\n * Events are filtered to the canonical `object` type — view/dashboard\n * /flow edits go through their own consumers (Studio SSE, REST cache).\n *\n * Stored unsubscribe handle is invoked from {@link stop}.\n */\n private subscribeToMetadataEvents(metadataService: any, ctx: PluginContext) {\n const handler = async (evt: any) => {\n if (!this.ql) return;\n const name: string = evt?.name ?? '';\n if (!name) return;\n const eventType: 'added' | 'changed' | 'deleted' =\n evt?.type === 'added' || evt?.type === 'changed' || evt?.type === 'deleted'\n ? evt.type\n : 'changed';\n\n try {\n // Drop the merged-schema cache entry first so any in-flight\n // resolveObject() races recompute against the new state.\n this.ql.registry.invalidate(name);\n\n if (eventType === 'deleted') {\n ctx.logger.info('[ObjectQLPlugin] object metadata deleted — registry invalidated', { name });\n return;\n }\n\n // Re-fetch the canonical definition from the metadata service.\n // The metadata service goes through its loader chain (FS, DB,\n // attached repository), so this picks up edits from any source.\n const fresh = typeof metadataService.get === 'function'\n ? await metadataService.get('object', name)\n : undefined;\n if (fresh && typeof fresh === 'object') {\n // Re-register with the original contributor metadata. We use\n // 'metadata-service' as packageId to match how the initial\n // load enrolls these objects (see `loadMetadataFromService`).\n const packageId = (fresh as any)._packageId ?? 'metadata-service';\n const namespace = (fresh as any).namespace;\n this.ql.registry.registerObject(\n fresh as any,\n packageId,\n namespace,\n 'own',\n );\n ctx.logger.info('[ObjectQLPlugin] object metadata updated — registry refreshed', {\n name,\n packageId,\n });\n } else {\n ctx.logger.debug('[ObjectQLPlugin] object event received but metadata service has no fresh body', { name });\n }\n } catch (e: any) {\n ctx.logger.warn('[ObjectQLPlugin] metadata event handler failed', {\n name,\n error: e?.message,\n });\n }\n };\n\n const unsub = metadataService.subscribe('object', handler);\n if (typeof unsub === 'function') {\n this.metadataUnsubscribes.push(unsub);\n } else if (unsub && typeof unsub.unsubscribe === 'function') {\n // Support `MetadataWatchHandle` style return shape.\n this.metadataUnsubscribes.push(() => unsub.unsubscribe());\n }\n ctx.logger.info('[ObjectQLPlugin] subscribed to object metadata events (ADR-0008 PR-7)');\n }\n\n /**\n * Register built-in audit hooks for auto-stamping created_by/updated_by\n * and fetching previousData for update/delete operations. These are\n * declared as canonical `Hook` metadata and bound through the same\n * `bindHooksToEngine` path used by `defineStack({ hooks })`, so the\n * engine's built-ins flow through the same rails as user code\n * (dogfooding the protocol).\n */\n private registerAuditHooks(ctx: PluginContext) {\n if (!this.ql) return;\n\n const stamp = () => new Date().toISOString();\n\n /**\n * Returns true when the resolved object schema declares a field with the\n * given name. Audit fields (`created_by`, `updated_by`, `tenant_id`) are\n * NOT auto-injected by the SQL driver, so we must only stamp values for\n * fields the user has explicitly declared on the object — otherwise the\n * driver will issue an INSERT against a column that does not exist in\n * the physical table (e.g. `table lead has no column named created_by`).\n *\n * `created_at`/`updated_at` are unconditional because driver-sql creates\n * them as built-in columns on every table.\n */\n const hasField = (objectName: string, field: string): boolean => {\n try {\n const schema: any = this.ql?.getSchema?.(objectName);\n if (!schema || typeof schema !== 'object') return false;\n const fields = schema.fields;\n if (!fields || typeof fields !== 'object') return false;\n return Object.prototype.hasOwnProperty.call(fields, field);\n } catch {\n return false;\n }\n };\n\n const applyToRecord = (\n record: Record<string, any>,\n objectName: string,\n session: any,\n isInsert: boolean,\n ) => {\n const now = stamp();\n if (isInsert) {\n record.created_at = record.created_at ?? now;\n }\n record.updated_at = now;\n if (session?.userId) {\n if (isInsert && hasField(objectName, 'created_by')) {\n record.created_by = record.created_by ?? session.userId;\n }\n if (hasField(objectName, 'updated_by')) {\n record.updated_by = session.userId;\n }\n }\n if (isInsert && session?.tenantId && hasField(objectName, 'tenant_id')) {\n record.tenant_id = record.tenant_id ?? session.tenantId;\n }\n };\n\n const stampData = (\n data: unknown,\n objectName: string,\n session: any,\n isInsert: boolean,\n ) => {\n if (Array.isArray(data)) {\n for (const row of data) {\n if (row && typeof row === 'object') {\n applyToRecord(row as Record<string, any>, objectName, session, isInsert);\n }\n }\n } else if (data && typeof data === 'object') {\n applyToRecord(data as Record<string, any>, objectName, session, isInsert);\n }\n };\n\n const builtinHooks: any[] = [\n {\n name: 'sys_stamp_audit_insert',\n object: '*',\n events: ['beforeInsert'],\n priority: 10,\n description: 'Auto-stamp created_by / updated_by / created_at / updated_at / tenant_id on insert (only when the field exists on the object schema)',\n handler: async (hookCtx: any) => {\n if (hookCtx.input?.data) {\n stampData(hookCtx.input.data, hookCtx.object, hookCtx.session, true);\n }\n },\n },\n {\n name: 'sys_stamp_audit_update',\n object: '*',\n events: ['beforeUpdate'],\n priority: 10,\n description: 'Auto-stamp updated_by / updated_at on update (only when the field exists on the object schema)',\n handler: async (hookCtx: any) => {\n if (hookCtx.input?.data) {\n stampData(hookCtx.input.data, hookCtx.object, hookCtx.session, false);\n }\n },\n },\n {\n name: 'sys_fetch_previous_update',\n object: '*',\n events: ['beforeUpdate'],\n priority: 5,\n description: 'Auto-fetch the previous record for update hooks',\n handler: async (hookCtx: any) => {\n if (hookCtx.input?.id && !hookCtx.previous) {\n try {\n const existing = await this.ql!.findOne(hookCtx.object, {\n where: { id: hookCtx.input.id },\n context: {\n roles: [],\n permissions: [],\n isSystem: true,\n ...(hookCtx.transaction ? { transaction: hookCtx.transaction } : {}),\n } as any,\n });\n if (existing) hookCtx.previous = existing;\n } catch (_e) {\n // Non-fatal: some objects may not support findOne\n }\n }\n },\n },\n {\n name: 'sys_fetch_previous_delete',\n object: '*',\n events: ['beforeDelete'],\n priority: 5,\n description: 'Auto-fetch the previous record for delete hooks',\n handler: async (hookCtx: any) => {\n if (hookCtx.input?.id && !hookCtx.previous) {\n try {\n const existing = await this.ql!.findOne(hookCtx.object, {\n where: { id: hookCtx.input.id },\n context: {\n roles: [],\n permissions: [],\n isSystem: true,\n ...(hookCtx.transaction ? { transaction: hookCtx.transaction } : {}),\n } as any,\n });\n if (existing) hookCtx.previous = existing;\n } catch (_e) {\n // Non-fatal\n }\n }\n },\n },\n ];\n\n if (typeof (this.ql as any).bindHooks === 'function') {\n (this.ql as any).bindHooks(builtinHooks, { packageId: 'sys:audit' });\n } else {\n // Defensive fallback if binder isn't available (older builds).\n for (const h of builtinHooks) {\n for (const event of h.events) {\n this.ql.registerHook(event, h.handler, {\n object: h.object,\n priority: h.priority,\n packageId: 'sys:audit',\n });\n }\n }\n }\n\n ctx.logger.debug('Audit hooks registered via binder (created_by/updated_by, previousData)');\n }\n\n /**\n * Tenant isolation moved to `@objectstack/plugin-security`'s\n * `member_default` permission set RLS\n * (`organization_id = current_user.organization_id`, with\n * field-existence guards). The legacy `registerTenantMiddleware`\n * method was removed because it (a) collided with SecurityPlugin's\n * RLS pipeline and (b) blindly filtered tables that don't have a\n * `tenant_id` column (e.g. `sys_organization`), returning 0 rows\n * instead of all rows.\n */\n\n /**\n * Synchronize all registered object schemas to the database.\n *\n * Groups objects by their responsible driver, then:\n * - If the driver advertises `supports.batchSchemaSync` and implements\n * `syncSchemasBatch()`, submits all schemas in a single call (reducing\n * network round-trips for remote drivers like Turso).\n * - Otherwise falls back to sequential `syncSchema()` per object.\n *\n * This is idempotent — drivers must tolerate repeated calls without\n * duplicating tables or erroring out.\n *\n * Drivers that do not implement `syncSchema` are silently skipped.\n */\n private async syncRegisteredSchemas(ctx: PluginContext) {\n if (!this.ql) return;\n\n const allObjects = this.ql.registry?.getAllObjects?.() ?? [];\n if (allObjects.length === 0) return;\n\n let synced = 0;\n let skipped = 0;\n\n // Group objects by driver for potential batch optimization\n const driverGroups = new Map<any, Array<{ obj: any; tableName: string }>>();\n\n for (const obj of allObjects) {\n const driver = this.ql.getDriverForObject(obj.name);\n if (!driver) {\n ctx.logger.debug('No driver available for object, skipping schema sync', {\n object: obj.name,\n });\n skipped++;\n continue;\n }\n\n if (typeof driver.syncSchema !== 'function') {\n ctx.logger.debug('Driver does not support syncSchema, skipping', {\n object: obj.name,\n driver: driver.name,\n });\n skipped++;\n continue;\n }\n\n const tableName = StorageNameMapping.resolveTableName(obj);\n\n let group = driverGroups.get(driver);\n if (!group) {\n group = [];\n driverGroups.set(driver, group);\n }\n group.push({ obj, tableName });\n }\n\n // Process each driver group\n for (const [driver, entries] of driverGroups) {\n // Batch path: driver supports batch schema sync\n if (\n driver.supports?.batchSchemaSync &&\n typeof driver.syncSchemasBatch === 'function'\n ) {\n const batchPayload = entries.map((e) => ({\n object: e.tableName,\n schema: e.obj,\n }));\n try {\n await driver.syncSchemasBatch(batchPayload);\n synced += entries.length;\n ctx.logger.debug('Batch schema sync succeeded', {\n driver: driver.name,\n count: entries.length,\n });\n } catch (e: unknown) {\n ctx.logger.warn('Batch schema sync failed, falling back to sequential', {\n driver: driver.name,\n error: e instanceof Error ? e.message : String(e),\n });\n // Fallback: sequential sync for this driver's objects\n for (const { obj, tableName } of entries) {\n try {\n await driver.syncSchema(tableName, obj);\n synced++;\n } catch (seqErr: unknown) {\n ctx.logger.warn('Failed to sync schema for object', {\n object: obj.name,\n tableName,\n driver: driver.name,\n error: seqErr instanceof Error ? seqErr.message : String(seqErr),\n });\n }\n }\n }\n } else {\n // Sequential path: no batch support\n for (const { obj, tableName } of entries) {\n try {\n await driver.syncSchema(tableName, obj);\n synced++;\n } catch (e: unknown) {\n ctx.logger.warn('Failed to sync schema for object', {\n object: obj.name,\n tableName,\n driver: driver.name,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n }\n }\n\n if (synced > 0 || skipped > 0) {\n ctx.logger.info('Schema sync complete', { synced, skipped, total: allObjects.length });\n }\n }\n\n /**\n * Restore persisted metadata from the database (sys_metadata) on startup.\n *\n * Calls `protocol.loadMetaFromDb()` to bulk-load all active metadata\n * records (objects, views, apps, etc.) into the in-memory SchemaRegistry.\n * This closes the persistence loop so that user-created schemas survive\n * kernel cold starts and redeployments.\n *\n * Gracefully degrades when:\n * - The protocol service is unavailable (e.g., in-memory-only mode).\n * - `loadMetaFromDb` is not implemented by the protocol shim.\n * - The underlying driver/table does not exist yet (first-run scenario).\n */\n private async restoreMetadataFromDb(ctx: PluginContext): Promise<void> {\n // Phase 1: Resolve protocol service (separate from DB I/O for clearer diagnostics)\n let protocol: ProtocolWithDbRestore;\n try {\n const service = ctx.getService('protocol');\n if (!service || !hasLoadMetaFromDb(service)) {\n ctx.logger.debug('Protocol service does not support loadMetaFromDb, skipping DB restore');\n return;\n }\n protocol = service;\n } catch (e: unknown) {\n ctx.logger.debug('Protocol service unavailable, skipping DB restore', {\n error: e instanceof Error ? e.message : String(e),\n });\n return;\n }\n\n // Phase 2: DB hydration (loads into SchemaRegistry)\n try {\n const { loaded, errors } = await protocol.loadMetaFromDb();\n\n if (loaded > 0 || errors > 0) {\n ctx.logger.info('Metadata restored from database to SchemaRegistry', { loaded, errors });\n } else {\n ctx.logger.debug('No persisted metadata found in database');\n }\n } catch (e: unknown) {\n // Non-fatal: first-run or in-memory driver may not have sys_metadata yet\n ctx.logger.debug('DB metadata restore failed (non-fatal)', {\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n\n /**\n * Bridge all SchemaRegistry objects to the metadata service.\n *\n * This ensures objects registered by plugins and loaded from sys_metadata\n * are visible to AI tools and other consumers that query IMetadataService.\n *\n * Runs after both restoreMetadataFromDb() and syncRegisteredSchemas() to\n * catch all objects in the SchemaRegistry regardless of their source.\n */\n private async bridgeObjectsToMetadataService(ctx: PluginContext): Promise<void> {\n try {\n const metadataService = ctx.getService<any>('metadata');\n if (!metadataService || typeof metadataService.register !== 'function') {\n ctx.logger.debug('Metadata service unavailable for bridging, skipping');\n return;\n }\n\n if (!this.ql?.registry) {\n ctx.logger.debug('SchemaRegistry unavailable for bridging, skipping');\n return;\n }\n\n const objects = this.ql.registry.getAllObjects();\n let bridged = 0;\n\n for (const obj of objects) {\n try {\n // Check if object is already in metadata service to avoid duplicates\n const existing = await metadataService.getObject(obj.name);\n if (!existing) {\n // Register object that exists in SchemaRegistry but not in metadata service\n await metadataService.register('object', obj.name, obj);\n bridged++;\n }\n } catch (e: unknown) {\n ctx.logger.debug('Failed to bridge object to metadata service', {\n object: obj.name,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n\n if (bridged > 0) {\n ctx.logger.info('Bridged objects from SchemaRegistry to metadata service', {\n count: bridged,\n total: objects.length\n });\n } else {\n ctx.logger.debug('No objects needed bridging (all already in metadata service)');\n }\n } catch (e: unknown) {\n ctx.logger.debug('Failed to bridge objects to metadata service', {\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n\n /**\n * Load metadata from external metadata service into ObjectQL registry\n * This enables ObjectQL to use file-based or remote metadata\n */\n private async loadMetadataFromService(metadataService: any, ctx: PluginContext) {\n ctx.logger.info('Syncing metadata from external service into ObjectQL registry...');\n \n // Metadata types to sync\n const metadataTypes = ['object', 'view', 'app', 'flow', 'workflow', 'function', 'hook'];\n let totalLoaded = 0;\n \n for (const type of metadataTypes) {\n try {\n // Check if service has loadMany method\n if (typeof metadataService.loadMany === 'function') {\n const items = await metadataService.loadMany(type);\n\n if (items && items.length > 0) {\n // Functions arrive as JSON-safe records ({name, handler})\n // where `handler` is a function reference or compiled code\n // already attached by the metadata pipeline. Register them\n // BEFORE binding hooks so string-named hook handlers can\n // resolve.\n if (type === 'function' && this.ql && typeof (this.ql as any).registerFunction === 'function') {\n for (const item of items) {\n if (item?.name && typeof item.handler === 'function') {\n (this.ql as any).registerFunction(item.name, item.handler, 'metadata-service');\n }\n }\n }\n\n items.forEach((item: any) => {\n // Determine key field (usually 'name' or 'id')\n const keyField = item.id ? 'id' : 'name';\n \n // For objects, use the ownership-aware registration\n if (type === 'object' && this.ql) {\n // Objects are registered differently (ownership model)\n // Skip for now - handled by app registration\n return;\n }\n \n // Register other types in the registry\n if (this.ql?.registry?.registerItem) {\n this.ql.registry.registerItem(type, item, keyField);\n }\n });\n\n // Hooks need to be wired into the execution pipeline,\n // not just stored in the registry. Funnel through the\n // canonical binder so declarative semantics (condition,\n // retry, timeout, async, onError, priority, packageId)\n // are honoured uniformly with the AppPlugin path.\n if (type === 'hook' && this.ql && typeof (this.ql as any).bindHooks === 'function') {\n (this.ql as any).bindHooks(items, {\n packageId: 'metadata-service',\n });\n }\n\n totalLoaded += items.length;\n ctx.logger.info(`Synced ${items.length} ${type}(s) from metadata service`);\n }\n }\n } catch (e: any) {\n // Type might not exist in metadata service - that's ok\n ctx.logger.debug(`No ${type} metadata found or error loading`, { \n error: e.message \n });\n }\n }\n \n if (totalLoaded > 0) {\n ctx.logger.info(`Metadata sync complete: ${totalLoaded} items loaded into ObjectQL registry`);\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectKernel } from '@objectstack/core';\nimport { ObjectQLPlugin } from './plugin.js';\nimport type { Plugin } from '@objectstack/core';\n\n/**\n * Options for creating an ObjectQL Kernel.\n */\nexport interface ObjectQLKernelOptions {\n /**\n * Additional plugins to register with the kernel.\n */\n plugins?: Plugin[];\n}\n\n/**\n * Convenience factory for creating an ObjectQL-ready kernel.\n *\n * Creates an ObjectKernel pre-configured with the ObjectQLPlugin\n * (data engine, schema registry, protocol implementation) plus any\n * additional plugins provided.\n *\n * @example\n * ```typescript\n * import { createObjectQLKernel } from '@objectstack/objectql';\n *\n * const kernel = createObjectQLKernel({\n * plugins: [myDriverPlugin, myAuthPlugin],\n * });\n * await kernel.bootstrap();\n * ```\n */\nexport async function createObjectQLKernel(options: ObjectQLKernelOptions = {}): Promise<ObjectKernel> {\n const kernel = new ObjectKernel();\n\n // Register the core ObjectQLPlugin first\n await kernel.use(new ObjectQLPlugin());\n\n // Register any additional plugins\n if (options.plugins) {\n for (const plugin of options.plugins) {\n await kernel.use(plugin);\n }\n }\n\n return kernel;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { ServiceObject } from '@objectstack/spec/data';\n\n// ── Introspection Types ──────────────────────────────────────────────────────\n\n/**\n * Column metadata from database introspection.\n */\nexport interface IntrospectedColumn {\n /** Column name */\n name: string;\n /** Native database type (e.g., 'varchar', 'integer', 'timestamp') */\n type: string;\n /** Whether the column is nullable */\n nullable: boolean;\n /** Default value if any */\n defaultValue?: unknown;\n /** Whether this is a primary key */\n isPrimary?: boolean;\n /** Whether this column has a unique constraint */\n isUnique?: boolean;\n /** Maximum length for string types */\n maxLength?: number;\n}\n\n/**\n * Foreign key relationship metadata.\n */\nexport interface IntrospectedForeignKey {\n /** Column name in the source table */\n columnName: string;\n /** Referenced table name */\n referencedTable: string;\n /** Referenced column name */\n referencedColumn: string;\n /** Constraint name */\n constraintName?: string;\n}\n\n/**\n * Table metadata from database introspection.\n */\nexport interface IntrospectedTable {\n /** Table name */\n name: string;\n /** List of columns */\n columns: IntrospectedColumn[];\n /** List of foreign key relationships */\n foreignKeys: IntrospectedForeignKey[];\n /** Primary key columns */\n primaryKeys: string[];\n}\n\n/**\n * Complete database schema introspection result.\n */\nexport interface IntrospectedSchema {\n /** Map of table name to table metadata */\n tables: Record<string, IntrospectedTable>;\n}\n\n// ── Utility Functions ────────────────────────────────────────────────────────\n\n/**\n * Convert a snake_case or plain string to Title Case.\n *\n * @example\n * toTitleCase('first_name') // => 'First Name'\n * toTitleCase('project_task') // => 'Project Task'\n */\nexport function toTitleCase(str: string): string {\n return str\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\n/**\n * Map a native database column type to an ObjectStack FieldType.\n */\nfunction mapDatabaseTypeToFieldType(\n dbType: string\n): 'text' | 'textarea' | 'number' | 'boolean' | 'datetime' | 'date' | 'time' | 'json' {\n const type = dbType.toLowerCase();\n\n // Text types\n if (type.includes('char') || type.includes('varchar') || type.includes('text')) {\n if (type.includes('text')) return 'textarea';\n return 'text';\n }\n\n // Numeric types\n if (\n type.includes('int') || type === 'integer' || type === 'bigint' || type === 'smallint'\n ) {\n return 'number';\n }\n if (\n type.includes('float') || type.includes('double') || type.includes('decimal') ||\n type.includes('numeric') || type === 'real'\n ) {\n return 'number';\n }\n\n // Boolean\n if (type.includes('bool')) {\n return 'boolean';\n }\n\n // Date / Time types\n if (type.includes('timestamp') || type === 'datetime') {\n return 'datetime';\n }\n if (type === 'date') {\n return 'date';\n }\n if (type === 'time') {\n return 'time';\n }\n\n // JSON types\n if (type === 'json' || type === 'jsonb') {\n return 'json';\n }\n\n // Default to text\n return 'text';\n}\n\n/**\n * Convert an introspected database schema to ObjectStack object definitions.\n *\n * This allows using existing database tables without manually defining metadata.\n *\n * @param introspectedSchema - The schema returned from driver.introspectSchema()\n * @param options - Optional filtering / conversion settings\n * @returns Array of ServiceObject definitions that can be registered with ObjectQL\n *\n * @example\n * ```typescript\n * const schema = await driver.introspectSchema();\n * const objects = convertIntrospectedSchemaToObjects(schema);\n * for (const obj of objects) {\n * engine.registerObject(obj);\n * }\n * ```\n */\nexport function convertIntrospectedSchemaToObjects(\n introspectedSchema: IntrospectedSchema,\n options?: {\n /** Tables to exclude from conversion */\n excludeTables?: string[];\n /** Tables to include (if specified, only these will be converted) */\n includeTables?: string[];\n /** Whether to skip system columns like id, created_at, updated_at (default: true) */\n skipSystemColumns?: boolean;\n }\n): ServiceObject[] {\n const objects: ServiceObject[] = [];\n const excludeTables = options?.excludeTables || [];\n const includeTables = options?.includeTables;\n const skipSystemColumns = options?.skipSystemColumns !== false;\n\n for (const [tableName, table] of Object.entries(introspectedSchema.tables)) {\n if (excludeTables.includes(tableName)) continue;\n if (includeTables && !includeTables.includes(tableName)) continue;\n\n const fields: Record<string, any> = {};\n\n for (const column of table.columns) {\n // Skip system columns if requested\n if (skipSystemColumns && ['id', 'created_at', 'updated_at'].includes(column.name)) {\n continue;\n }\n\n // Check for foreign key → lookup field\n const foreignKey = table.foreignKeys.find((fk) => fk.columnName === column.name);\n\n if (foreignKey) {\n fields[column.name] = {\n name: column.name,\n type: 'lookup' as const,\n reference: foreignKey.referencedTable,\n label: toTitleCase(column.name),\n required: !column.nullable,\n };\n } else {\n const fieldType = mapDatabaseTypeToFieldType(column.type);\n\n const field: Record<string, any> = {\n name: column.name,\n type: fieldType,\n label: toTitleCase(column.name),\n required: !column.nullable,\n };\n\n if (column.isUnique) {\n field.unique = true;\n }\n if (column.maxLength && (fieldType === 'text' || fieldType === 'textarea')) {\n field.maxLength = column.maxLength;\n }\n if (column.defaultValue != null) {\n field.defaultValue = column.defaultValue;\n }\n\n fields[column.name] = field;\n }\n }\n\n objects.push({\n name: tableName,\n label: toTitleCase(tableName),\n fields,\n } as ServiceObject);\n }\n\n return objects;\n}\n"],"mappings":"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","names":["item","ConflictError","DEFAULT_METADATA_TYPE_REGISTRY","records","ExpressionEngine","noopLogger","ExpressionEngine","StorageNameMapping"]}
1
+ {"version":3,"sources":["../src/registry.ts","../src/sys-metadata-repository.ts","../src/protocol.ts","../src/engine.ts","../src/hook-wrappers.ts","../src/hook-metrics.ts","../src/hook-binder.ts","../src/validation/record-validator.ts","../src/in-memory-aggregation.ts","../src/metadata-facade.ts","../src/plugin.ts","../src/kernel-factory.ts","../src/util.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ServiceObject, ObjectSchema, ObjectOwnership } from '@objectstack/spec/data';\nimport { ObjectStackManifest, ManifestSchema, InstalledPackage, InstalledPackageSchema } from '@objectstack/spec/kernel';\nimport { AppSchema } from '@objectstack/spec/ui';\n\n/**\n * Reserved namespaces that do not get FQN prefix applied.\n * Objects in these namespaces keep their short names (e.g., \"user\" — short name IS the canonical key).\n */\nexport const RESERVED_NAMESPACES = new Set(['base', 'system']);\n\n/**\n * Default priorities for ownership types.\n */\nexport const DEFAULT_OWNER_PRIORITY = 100;\nexport const DEFAULT_EXTENDER_PRIORITY = 200;\n\n/**\n * Contributor Record\n * Tracks how a package contributes to an object (own or extend).\n */\nexport interface ObjectContributor {\n packageId: string;\n namespace: string;\n ownership: ObjectOwnership;\n priority: number;\n definition: ServiceObject;\n}\n\n/**\n * Compute canonical registry key for an object.\n *\n * Under the current naming convention, object names are canonical identifiers\n * and are used as-is (no namespace__ prefix). The namespace parameter is\n * retained for backward compatibility but no longer affects the returned key.\n *\n * @param namespace - The package namespace (unused, kept for API compatibility)\n * @param shortName - The object's name (already the canonical identifier)\n * @returns The object name unchanged\n *\n * @example\n * computeFQN('crm', 'account') // => 'account'\n * computeFQN(undefined, 'task') // => 'task'\n */\nexport function computeFQN(_namespace: string | undefined, shortName: string): string {\n return shortName;\n}\n\n/**\n * Parse FQN back to namespace and short name.\n * \n * @param fqn - Object name (e.g., \"account\" or legacy \"crm__account\" for backward compat)\n * @returns { namespace, shortName } - namespace is undefined for unprefixed names\n */\nexport function parseFQN(fqn: string): { namespace: string | undefined; shortName: string } {\n const idx = fqn.indexOf('__');\n if (idx === -1) {\n return { namespace: undefined, shortName: fqn };\n }\n return {\n namespace: fqn.slice(0, idx),\n shortName: fqn.slice(idx + 2),\n };\n}\n\n/**\n * Deep merge two ServiceObject definitions.\n * Fields are merged additively. Other props: later value wins.\n */\nfunction mergeObjectDefinitions(base: ServiceObject, extension: Partial<ServiceObject>): ServiceObject {\n const merged = { ...base };\n\n // Merge fields additively\n if (extension.fields) {\n merged.fields = { ...base.fields, ...extension.fields };\n }\n\n // Merge validations additively\n if (extension.validations) {\n merged.validations = [...(base.validations || []), ...extension.validations];\n }\n\n // Merge indexes additively\n if (extension.indexes) {\n merged.indexes = [...(base.indexes || []), ...extension.indexes];\n }\n\n // Override scalar props (last writer wins)\n if (extension.label !== undefined) merged.label = extension.label;\n if (extension.pluralLabel !== undefined) merged.pluralLabel = extension.pluralLabel;\n if (extension.description !== undefined) merged.description = extension.description;\n\n return merged;\n}\n\n/**\n * Global Schema Registry\n * Unified storage for all metadata types (Objects, Apps, Flows, Layouts, etc.)\n * \n * ## Namespace & Ownership Model\n * \n * Objects use a namespace-based FQN system:\n * - `namespace`: Short identifier from package manifest (e.g., \"crm\", \"todo\")\n * - `name`: canonical object name (e.g., \"account\", \"sys_user\")\n * - Reserved namespaces (`base`, `system`) don't get prefixed\n * \n * Ownership modes:\n * - `own`: One package owns the object (creates the table, defines base schema)\n * - `extend`: Multiple packages can extend an object (add fields, merge by priority)\n * \n * ## Package vs App Distinction\n * - **Package**: The unit of installation, stored under type 'package'.\n * Each InstalledPackage wraps a ManifestSchema with lifecycle state.\n * - **App**: A UI navigation shell (AppSchema), registered under type 'apps'.\n * Apps are extracted from packages during registration.\n * - A package may contain 0, 1, or many apps.\n */\nexport type RegistryLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\n/**\n * Construction options for {@link SchemaRegistry}.\n */\nexport interface SchemaRegistryOptions {\n /**\n * Whether the host kernel runs in multi-tenant mode. When `true` (default),\n * the registry auto-injects `organization_id` (lookup → sys_organization)\n * into every registered user object that doesn't already declare it and\n * isn't `managedBy` an external subsystem or explicitly opted-out via\n * `systemFields: false`.\n *\n * Sourced from the `OS_MULTI_TENANT` env var when not explicitly set —\n * matches how the SecurityPlugin and CLI startup banner pick the mode.\n * Pass an explicit boolean to override (useful in tests).\n */\n multiTenant?: boolean;\n}\n\n/**\n * Augment a registered object with implicit system fields.\n *\n * Returns a *new* schema object when fields are added; returns the input\n * unchanged when nothing applies (the cheap path for system tables).\n *\n * Author-declared fields always win — we splice the system fields at the\n * front of the field map, so any same-named author field overwrites them\n * via the natural `{ ...sys, ...authored }` merge.\n *\n * Currently injects:\n * - `organization_id` — multi-tenant deployments. Required-false (the\n * SecurityPlugin populates it on insert; nullable rows are still\n * filtered out by the `tenant_isolation` RLS USING clause).\n * - `created_at` / `created_by` / `updated_at` / `updated_by` — audit\n * fields. Marked `system: true, readonly: true` so detail views can\n * surface them in a dedicated \"System Information\" section while\n * edit forms / drawers filter them out. The driver populates the\n * timestamps; the `*_by` lookups are filled by the runtime when an\n * authenticated session is present (NULL otherwise — e.g. seeded\n * rows).\n */\nexport function applySystemFields(\n schema: ServiceObject,\n opts: { multiTenant: boolean }\n): ServiceObject {\n // 1. Hard opt-out at object level (e.g. seed/migration tables).\n if ((schema as any).systemFields === false) return schema;\n\n // 2. Skip only `better-auth` managed tables. Their column layout is\n // driven by better-auth's own migrations (sys_user, sys_session,\n // sys_organization, …) and injecting extra columns here would\n // collide with what better-auth expects. Other `managedBy` buckets\n // (`platform`, `config`, `system`, `append-only`) all need the\n // tenant + audit columns for multi-tenant isolation and time-travel\n // history — withholding them silently broke RLS reads on\n // sys_audit_log / sys_activity (the SecurityPlugin's\n // field-existence safety net dropped `organization_id =\n // current_user.organization_id` as \"field missing\", producing\n // RLS_DENY_FILTER → 0 rows for every non-admin caller).\n if (schema.managedBy === 'better-auth') return schema;\n\n const sf =\n typeof (schema as any).systemFields === 'object' && (schema as any).systemFields !== null\n ? ((schema as any).systemFields as { tenant?: boolean; audit?: boolean })\n : undefined;\n\n // Honor explicit opt-out via either `systemFields.tenant === false`\n // OR `tenancy.enabled === false`. The latter is the schema-level\n // declaration that the table is a shared/global catalog (e.g.\n // sys_package — the Marketplace registry). Without this, the\n // registry would still inject `organization_id`, and the\n // SecurityPlugin's RLS layer would filter every cross-org read down\n // to 0 rows even though the schema explicitly disabled multi-tenancy.\n const tenancyDisabled = (schema as any).tenancy?.enabled === false;\n const wantTenant = opts.multiTenant && sf?.tenant !== false && !tenancyDisabled;\n const wantAudit = sf?.audit !== false;\n\n const additions: Record<string, any> = {};\n\n if (wantTenant && !schema.fields?.organization_id) {\n additions.organization_id = {\n type: 'lookup',\n reference: 'sys_organization',\n label: 'Organization',\n required: false,\n indexed: true,\n hidden: true,\n readonly: true,\n system: true,\n description: 'Tenant scope (auto-populated by SecurityPlugin on insert).',\n };\n }\n\n if (wantAudit) {\n if (!schema.fields?.created_at) {\n additions.created_at = {\n type: 'datetime',\n label: 'Created At',\n required: false,\n readonly: true,\n system: true,\n description: 'Timestamp when the record was created (auto-populated by the driver).',\n };\n }\n if (!schema.fields?.created_by) {\n additions.created_by = {\n type: 'lookup',\n reference: 'sys_user',\n label: 'Created By',\n required: false,\n readonly: true,\n system: true,\n description: 'User who created the record (populated when an authenticated session is present).',\n };\n }\n if (!schema.fields?.updated_at) {\n additions.updated_at = {\n type: 'datetime',\n label: 'Last Modified At',\n required: false,\n readonly: true,\n system: true,\n description: 'Timestamp of the most recent modification (auto-populated by the driver).',\n };\n }\n if (!schema.fields?.updated_by) {\n additions.updated_by = {\n type: 'lookup',\n reference: 'sys_user',\n label: 'Last Modified By',\n required: false,\n readonly: true,\n system: true,\n description: 'User who last modified the record (populated when an authenticated session is present).',\n };\n }\n }\n\n if (Object.keys(additions).length === 0) return schema;\n\n return {\n ...schema,\n fields: { ...additions, ...(schema.fields ?? {}) },\n };\n}\n\nexport class SchemaRegistry {\n // ==========================================\n // Logging control\n // ==========================================\n\n /** Controls verbosity of registry console messages. Default: 'info'. */\n private _logLevel: RegistryLogLevel = 'info';\n\n /** Whether to auto-inject multi-tenant system fields. */\n private readonly multiTenant: boolean;\n\n constructor(options: SchemaRegistryOptions = {}) {\n if (options.multiTenant !== undefined) {\n this.multiTenant = options.multiTenant;\n } else {\n // Mirror the SecurityPlugin / CLI banner default (env-driven, on by default).\n this.multiTenant =\n String(process.env.OS_MULTI_TENANT ?? 'true').toLowerCase() !== 'false';\n }\n }\n\n get logLevel(): RegistryLogLevel { return this._logLevel; }\n set logLevel(level: RegistryLogLevel) { this._logLevel = level; }\n\n private log(msg: string): void {\n if (this._logLevel === 'silent' || this._logLevel === 'error' || this._logLevel === 'warn') return;\n console.log(msg);\n }\n\n // ==========================================\n // Object-specific storage (Ownership Model)\n // ==========================================\n\n /** FQN → Contributor[] (all packages that own/extend this object) */\n private objectContributors = new Map<string, ObjectContributor[]>();\n\n /** FQN → Merged ServiceObject (cached, invalidated on changes) */\n private mergedObjectCache = new Map<string, ServiceObject>();\n\n /** Namespace → Set<PackageId> (multiple packages can share a namespace) */\n private namespaceRegistry = new Map<string, Set<string>>();\n\n // ==========================================\n // Generic metadata storage (non-object types)\n // ==========================================\n\n /** Type → Name/ID → MetadataItem */\n private metadata = new Map<string, Map<string, any>>();\n\n // ==========================================\n // Namespace Management\n // ==========================================\n\n /**\n * Register a namespace for a package.\n * Multiple packages can share the same namespace (e.g. 'sys').\n */\n registerNamespace(namespace: string, packageId: string): void {\n if (!namespace) return;\n\n let owners = this.namespaceRegistry.get(namespace);\n if (!owners) {\n owners = new Set();\n this.namespaceRegistry.set(namespace, owners);\n }\n owners.add(packageId);\n this.log(`[Registry] Registered namespace: ${namespace} → ${packageId}`);\n }\n\n /**\n * Unregister a namespace when a package is uninstalled.\n */\n unregisterNamespace(namespace: string, packageId: string): void {\n const owners = this.namespaceRegistry.get(namespace);\n if (owners) {\n owners.delete(packageId);\n if (owners.size === 0) {\n this.namespaceRegistry.delete(namespace);\n }\n this.log(`[Registry] Unregistered namespace: ${namespace} ← ${packageId}`);\n }\n }\n\n /**\n * Get the packages that use a namespace.\n */\n getNamespaceOwner(namespace: string): string | undefined {\n const owners = this.namespaceRegistry.get(namespace);\n if (!owners || owners.size === 0) return undefined;\n // Return the first registered package for backwards compatibility\n return owners.values().next().value;\n }\n\n /**\n * Get all packages that share a namespace.\n */\n getNamespaceOwners(namespace: string): string[] {\n const owners = this.namespaceRegistry.get(namespace);\n return owners ? Array.from(owners) : [];\n }\n\n // ==========================================\n // Object Registration (Ownership Model)\n // ==========================================\n\n /**\n * Register an object with ownership semantics.\n * \n * @param schema - The object definition\n * @param packageId - The owning package ID\n * @param namespace - The package namespace (for FQN computation)\n * @param ownership - 'own' (single owner) or 'extend' (additive merge)\n * @param priority - Merge priority (lower applied first, higher wins on conflict)\n * \n * @throws Error if trying to 'own' an object that already has an owner\n */\n registerObject(\n schema: ServiceObject,\n packageId: string,\n namespace?: string,\n ownership: ObjectOwnership = 'own',\n priority: number = ownership === 'own' ? DEFAULT_OWNER_PRIORITY : DEFAULT_EXTENDER_PRIORITY\n ): string {\n // Apply system-field injection (multi-tenant org_id, future owner/audit)\n // BEFORE FQN computation and contributor storage so every consumer of\n // the registered schema (driver syncSchema, REST projector, hooks)\n // sees the same canonical shape. Author-declared fields win — see\n // applySystemFields().\n schema = applySystemFields(schema, { multiTenant: this.multiTenant });\n\n const shortName = schema.name;\n const fqn = computeFQN(namespace, shortName);\n\n // Ensure namespace is registered\n if (namespace) {\n this.registerNamespace(namespace, packageId);\n }\n\n // Get or create contributor list\n let contributors = this.objectContributors.get(fqn);\n if (!contributors) {\n contributors = [];\n this.objectContributors.set(fqn, contributors);\n }\n\n // Validate ownership rules\n if (ownership === 'own') {\n const existingOwner = contributors.find(c => c.ownership === 'own');\n if (existingOwner && existingOwner.packageId !== packageId) {\n throw new Error(\n `Object \"${fqn}\" is already owned by package \"${existingOwner.packageId}\". ` +\n `Package \"${packageId}\" cannot claim ownership. Use 'extend' to add fields.`\n );\n }\n // Remove existing owner contribution from same package (re-registration)\n const idx = contributors.findIndex(c => c.packageId === packageId && c.ownership === 'own');\n if (idx !== -1) {\n contributors.splice(idx, 1);\n console.warn(`[Registry] Re-registering owned object: ${fqn} from ${packageId}`);\n }\n } else {\n // extend mode: remove existing extension from same package\n const idx = contributors.findIndex(c => c.packageId === packageId && c.ownership === 'extend');\n if (idx !== -1) {\n contributors.splice(idx, 1);\n }\n }\n\n // Add new contributor\n const contributor: ObjectContributor = {\n packageId,\n namespace: namespace || '',\n ownership,\n priority,\n definition: { ...schema, name: fqn }, // Store with FQN as name\n };\n contributors.push(contributor);\n\n // Sort by priority (ascending: lower priority applied first)\n contributors.sort((a, b) => a.priority - b.priority);\n\n // Invalidate merge cache\n this.mergedObjectCache.delete(fqn);\n\n this.log(`[Registry] Registered object: ${fqn} (${ownership}, priority=${priority}) from ${packageId}`);\n return fqn;\n }\n\n /**\n * Resolve an object by FQN, merging all contributions.\n * Returns the merged object or undefined if not found.\n */\n resolveObject(fqn: string): ServiceObject | undefined {\n // Check cache first\n const cached = this.mergedObjectCache.get(fqn);\n if (cached) return cached;\n\n const contributors = this.objectContributors.get(fqn);\n if (!contributors || contributors.length === 0) {\n return undefined;\n }\n\n // Find owner (must exist for a valid object)\n const ownerContrib = contributors.find(c => c.ownership === 'own');\n if (!ownerContrib) {\n console.warn(`[Registry] Object \"${fqn}\" has extenders but no owner. Skipping.`);\n return undefined;\n }\n\n // Start with owner's definition\n let merged = { ...ownerContrib.definition };\n\n // Apply extensions in priority order (already sorted)\n for (const contrib of contributors) {\n if (contrib.ownership === 'extend') {\n merged = mergeObjectDefinitions(merged, contrib.definition);\n }\n }\n\n // Cache the result\n this.mergedObjectCache.set(fqn, merged);\n return merged;\n }\n\n /**\n * Get object by name (short name canonical, FQN supported for disambiguation).\n *\n * Short names are canonical for user code, AI generation, and most lookups.\n * FQN is accepted as an explicit fallback for cross-package disambiguation\n * when two packages contribute objects with the same short name.\n *\n * Resolution order:\n * 1. Exact name match — the name IS the canonical key.\n * If multiple packages contribute the same short name, a warning is logged\n * and the first match wins — disambiguate by passing the FQN explicitly.\n * 2. Legacy FQN match (e.g., 'crm__account') — backward compat.\n */\n getObject(name: string): ServiceObject | undefined {\n // Canonical: short name lookup\n const matches: string[] = [];\n for (const fqn of this.objectContributors.keys()) {\n const { shortName } = parseFQN(fqn);\n if (shortName === name) {\n matches.push(fqn);\n }\n }\n if (matches.length > 0) {\n if (matches.length > 1) {\n console.warn(\n `[SchemaRegistry] Ambiguous short name \"${name}\" matches: ${matches.join(', ')}. ` +\n `Returning first match. Use FQN to disambiguate.`\n );\n }\n return this.resolveObject(matches[0]);\n }\n\n // Fallback: explicit FQN\n return this.resolveObject(name);\n }\n\n /**\n * Get all registered objects (merged).\n * \n * @param packageId - Optional filter: only objects contributed by this package\n */\n getAllObjects(packageId?: string): ServiceObject[] {\n const results: ServiceObject[] = [];\n\n for (const fqn of this.objectContributors.keys()) {\n // If filtering by package, check if this package contributes\n if (packageId) {\n const contributors = this.objectContributors.get(fqn);\n const hasContribution = contributors?.some(c => c.packageId === packageId);\n if (!hasContribution) continue;\n }\n\n const merged = this.resolveObject(fqn);\n if (merged) {\n // Tag with contributor info for UI\n (merged as any)._packageId = this.getObjectOwner(fqn)?.packageId;\n results.push(merged);\n }\n }\n\n return results;\n }\n\n /**\n * Get all contributors for an object.\n */\n getObjectContributors(fqn: string): ObjectContributor[] {\n return this.objectContributors.get(fqn) || [];\n }\n\n /**\n * Get the owner contributor for an object.\n */\n getObjectOwner(fqn: string): ObjectContributor | undefined {\n const contributors = this.objectContributors.get(fqn);\n return contributors?.find(c => c.ownership === 'own');\n }\n\n /**\n * Unregister all objects contributed by a package.\n * \n * @throws Error if trying to uninstall an owner that has extenders\n */\n unregisterObjectsByPackage(packageId: string, force: boolean = false): void {\n for (const [fqn, contributors] of this.objectContributors.entries()) {\n // Find this package's contributions\n const packageContribs = contributors.filter(c => c.packageId === packageId);\n \n for (const contrib of packageContribs) {\n if (contrib.ownership === 'own' && !force) {\n // Check if there are extenders from other packages\n const otherExtenders = contributors.filter(\n c => c.packageId !== packageId && c.ownership === 'extend'\n );\n if (otherExtenders.length > 0) {\n throw new Error(\n `Cannot uninstall package \"${packageId}\": object \"${fqn}\" is extended by ` +\n `${otherExtenders.map(c => c.packageId).join(', ')}. Uninstall extenders first.`\n );\n }\n }\n\n // Remove contribution\n const idx = contributors.indexOf(contrib);\n if (idx !== -1) {\n contributors.splice(idx, 1);\n this.log(`[Registry] Removed ${contrib.ownership} contribution to ${fqn} from ${packageId}`);\n }\n }\n\n // Clean up empty contributor lists\n if (contributors.length === 0) {\n this.objectContributors.delete(fqn);\n }\n\n // Invalidate cache\n this.mergedObjectCache.delete(fqn);\n }\n }\n\n // ==========================================\n // Generic Metadata (Non-Object Types)\n // ==========================================\n\n /**\n * Universal Register Method for non-object metadata.\n */\n registerItem<T>(type: string, item: T, keyField: keyof T = 'name' as keyof T, packageId?: string) {\n if (!this.metadata.has(type)) {\n this.metadata.set(type, new Map());\n }\n const collection = this.metadata.get(type)!;\n const baseName = String(item[keyField]);\n \n // Tag item with owning package for scoped queries\n if (packageId) {\n (item as any)._packageId = packageId;\n }\n\n // Validation Hook\n try {\n this.validate(type, item);\n } catch (e: any) {\n console.error(`[Registry] Validation failed for ${type} ${baseName}: ${e.message}`);\n }\n\n // Use composite key (packageId:name) when packageId is provided\n const storageKey = packageId ? `${packageId}:${baseName}` : baseName;\n\n if (collection.has(storageKey)) {\n this.log(`[Registry] Overwriting ${type}: ${storageKey}`);\n }\n collection.set(storageKey, item);\n this.log(`[Registry] Registered ${type}: ${storageKey}`);\n }\n\n /**\n * Validate Metadata against Spec Zod Schemas\n */\n validate(type: string, item: any): unknown {\n if (type === 'object') {\n return ObjectSchema.parse(item);\n }\n if (type === 'app') {\n return AppSchema.parse(item);\n }\n if (type === 'package') {\n return InstalledPackageSchema.parse(item);\n }\n if (type === 'plugin') {\n return ManifestSchema.parse(item);\n }\n return true;\n }\n\n /**\n * Universal Unregister Method\n */\n unregisterItem(type: string, name: string) {\n const collection = this.metadata.get(type);\n if (!collection) {\n console.warn(`[Registry] Attempted to unregister non-existent ${type}: ${name}`);\n return;\n }\n if (collection.has(name)) {\n collection.delete(name);\n this.log(`[Registry] Unregistered ${type}: ${name}`);\n return;\n }\n // Scan composite keys\n for (const key of collection.keys()) {\n if (key.endsWith(`:${name}`)) {\n collection.delete(key);\n this.log(`[Registry] Unregistered ${type}: ${key}`);\n return;\n }\n }\n console.warn(`[Registry] Attempted to unregister non-existent ${type}: ${name}`);\n }\n\n /**\n * Universal Get Method\n */\n getItem<T>(type: string, name: string): T | undefined {\n // Special handling for 'object' and 'objects' types - use objectContributors\n if (type === 'object' || type === 'objects') {\n return this.getObject(name) as unknown as T | undefined;\n }\n \n const collection = this.metadata.get(type);\n if (!collection) return undefined;\n const direct = collection.get(name);\n if (direct) return direct as T;\n // Scan for composite keys\n for (const [key, item] of collection) {\n if (key.endsWith(`:${name}`)) return item as T;\n }\n return undefined;\n }\n\n /**\n * Universal List Method\n */\n listItems<T>(type: string, packageId?: string): T[] {\n // Special handling for 'object' and 'objects' types - use objectContributors\n if (type === 'object' || type === 'objects') {\n return this.getAllObjects(packageId) as unknown as T[];\n }\n\n const items = Array.from(this.metadata.get(type)?.values() || []) as T[];\n if (packageId) {\n return items.filter((item: any) => item._packageId === packageId);\n }\n return items;\n }\n\n /**\n * Get all registered metadata types (Kinds)\n */\n getRegisteredTypes(): string[] {\n const types = Array.from(this.metadata.keys());\n // Always include 'object' even if stored separately\n if (!types.includes('object') && this.objectContributors.size > 0) {\n types.push('object');\n }\n return types;\n }\n\n // ==========================================\n // Package Management\n // ==========================================\n\n installPackage(manifest: ObjectStackManifest, settings?: Record<string, any>): InstalledPackage {\n const now = new Date().toISOString();\n const pkg: InstalledPackage = {\n manifest,\n status: 'installed',\n enabled: true,\n installedAt: now,\n updatedAt: now,\n settings,\n };\n \n // Register namespace if present\n if (manifest.namespace) {\n this.registerNamespace(manifest.namespace, manifest.id);\n }\n \n if (!this.metadata.has('package')) {\n this.metadata.set('package', new Map());\n }\n const collection = this.metadata.get('package')!;\n if (collection.has(manifest.id)) {\n console.warn(`[Registry] Overwriting package: ${manifest.id}`);\n }\n collection.set(manifest.id, pkg);\n this.log(`[Registry] Installed package: ${manifest.id} (${manifest.name})`);\n return pkg;\n }\n\n uninstallPackage(id: string): boolean {\n const pkg = this.getPackage(id);\n if (!pkg) {\n console.warn(`[Registry] Package not found for uninstall: ${id}`);\n return false;\n }\n\n // Unregister namespace\n if (pkg.manifest.namespace) {\n this.unregisterNamespace(pkg.manifest.namespace, id);\n }\n\n // Unregister objects (will throw if extenders exist)\n this.unregisterObjectsByPackage(id);\n\n // Remove package record\n const collection = this.metadata.get('package');\n if (collection) {\n collection.delete(id);\n this.log(`[Registry] Uninstalled package: ${id}`);\n return true;\n }\n return false;\n }\n\n getPackage(id: string): InstalledPackage | undefined {\n return this.metadata.get('package')?.get(id) as InstalledPackage | undefined;\n }\n\n getAllPackages(): InstalledPackage[] {\n return this.listItems<InstalledPackage>('package');\n }\n\n enablePackage(id: string): InstalledPackage | undefined {\n const pkg = this.getPackage(id);\n if (pkg) {\n pkg.enabled = true;\n pkg.status = 'installed';\n pkg.statusChangedAt = new Date().toISOString();\n pkg.updatedAt = new Date().toISOString();\n this.log(`[Registry] Enabled package: ${id}`);\n }\n return pkg;\n }\n\n disablePackage(id: string): InstalledPackage | undefined {\n const pkg = this.getPackage(id);\n if (pkg) {\n pkg.enabled = false;\n pkg.status = 'disabled';\n pkg.statusChangedAt = new Date().toISOString();\n pkg.updatedAt = new Date().toISOString();\n this.log(`[Registry] Disabled package: ${id}`);\n }\n return pkg;\n }\n\n // ==========================================\n // App Helpers\n // ==========================================\n\n registerApp(app: any, packageId?: string) {\n this.registerItem('app', app, 'name', packageId);\n }\n\n getApp(name: string): any {\n return this.getItem('app', name);\n }\n\n getAllApps(): any[] {\n return this.listItems('app');\n }\n\n // ==========================================\n // Plugin Helpers\n // ==========================================\n\n registerPlugin(manifest: ObjectStackManifest) {\n this.registerItem('plugin', manifest, 'id');\n }\n\n getAllPlugins(): ObjectStackManifest[] {\n return this.listItems<ObjectStackManifest>('plugin');\n }\n\n // ==========================================\n // Kind Helpers\n // ==========================================\n\n registerKind(kind: { id: string, globs: string[] }) {\n this.registerItem('kind', kind, 'id');\n }\n \n getAllKinds(): { id: string, globs: string[] }[] {\n return this.listItems('kind');\n }\n\n // ==========================================\n // Reset (for testing)\n // ==========================================\n\n /**\n * Invalidate the merged-schema cache for a single FQN (or short name).\n *\n * Call this from event-driven consumers (ADR-0008 M0 PR-7) when an\n * upstream metadata change makes the cached merged definition stale.\n * The contributor list is preserved — only the cached merge result is\n * dropped, so the next `resolveObject(fqn)` recomputes from scratch.\n *\n * Accepts either an FQN (`acme__contact`) or a bare short name\n * (`contact`); for the latter, all entries whose suffix matches the\n * name are invalidated.\n */\n invalidate(fqnOrName: string): void {\n if (this.mergedObjectCache.has(fqnOrName)) {\n this.mergedObjectCache.delete(fqnOrName);\n return;\n }\n // Short-name path: drop any cached merge whose FQN ends with `__<name>` or equals `<name>`.\n const suffix = `__${fqnOrName}`;\n for (const fqn of Array.from(this.mergedObjectCache.keys())) {\n if (fqn === fqnOrName || fqn.endsWith(suffix)) {\n this.mergedObjectCache.delete(fqn);\n }\n }\n }\n\n /** Drop every entry from the merged-schema cache. */\n invalidateAll(): void {\n this.mergedObjectCache.clear();\n }\n\n /**\n * Clear all registry state. Use only for testing.\n */\n reset(): void {\n this.objectContributors.clear();\n this.mergedObjectCache.clear();\n this.namespaceRegistry.clear();\n this.metadata.clear();\n this.log('[Registry] Reset complete');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * ADR-0008 PR-10b — `SysMetadataRepository`.\n *\n * Wraps the existing `sys_metadata` table behind the canonical\n * `MetadataRepository` interface. Implements the *single-row update*\n * semantics that ADR-0005 already ships — append-only event-log\n * persistence is M1 work.\n *\n * What this layer DOES (M0 + M1):\n * - get / put / delete / list against `sys_metadata`\n * - tenancy scope = `organization_id` (per-org overlays only;\n * project/branch concepts removed — see ADR-0008 §0 amendment)\n * - hash stamping with `hashSpec` (PR-10a guarantees stability)\n * - watch() implemented via an in-memory event broadcaster fed by\n * every successful put/delete on THIS instance\n * - whitelist enforcement: refuses to persist types whose registry\n * entry has `allowOrgOverride: false` (Prime Directive #8)\n * - **M1**: every successful put/delete appends a durable row to\n * `sys_metadata_history` inside the same engine.transaction() as the\n * parent `sys_metadata` write. No-op puts (identical hash) skip the\n * history write. Failed optimistic-lock checks abort before any\n * write reaches the database.\n * - **M1**: history() yields events from the durable log, ordered by\n * per-(org,type,name) `version` ASC.\n *\n * What this layer does NOT do (and will not, by design):\n * - cross-replica push notifications (LISTEN/NOTIFY, pub/sub, etc.).\n * The watch() contract is scoped to the local repository instance.\n * Multi-replica deployments are not a supported topology for the\n * metadata overlay — see ADR-0008 §11.\n * - hashSpec backfill for legacy rows missing `checksum`\n *\n * Schema mapping (ADR-0008 PR-10d.2):\n * Repository concept sys_metadata column\n * ─────────────────────── ───────────────────\n * body → metadata (JSON string)\n * hash (sha256) → checksum (text(64))\n * monotonic version int → version (number)\n * org isolation → organization_id (lookup)\n * actor → updated_by (lookup, optional)\n *\n * Composition: PR-10c will compose\n * `LayeredRepository([FileSystemRepository, SysMetadataRepository])`\n * and the manager bridge will route reads through that. Until then this\n * file is intentionally NOT wired into any production path — it has its\n * own test surface so we can build confidence before flipping the\n * switch.\n */\n\nimport { hashSpec, ConflictError } from '@objectstack/metadata-core';\nimport type {\n MetadataRepository,\n MetaRef,\n MetadataItem,\n MetadataItemHeader,\n MetadataEvent,\n PutOptions,\n PutResult,\n DeleteOptions,\n DeleteResult,\n ListFilter,\n WatchFilter,\n HistoryOptions,\n} from '@objectstack/metadata-core';\nimport { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel';\n\n/**\n * Sub-set of the ObjectQL engine shape we depend on. Kept narrow so\n * tests can stub it with a plain mock. Mirrors the real engine's\n * `options.context` pattern so transactions can thread through.\n */\nexport interface SysMetadataEngine {\n find(\n table: string,\n options: { where: Record<string, unknown>; limit?: number; orderBy?: any; context?: any },\n ): Promise<any[]>;\n findOne(\n table: string,\n options: { where: Record<string, unknown>; context?: any },\n ): Promise<any | null>;\n insert(\n table: string,\n data: Record<string, unknown>,\n options?: { context?: any },\n ): Promise<{ id: string }>;\n update(\n table: string,\n data: Record<string, unknown>,\n options: { where: Record<string, unknown>; context?: any },\n ): Promise<{ id: string }>;\n delete(\n table: string,\n options: { where: Record<string, unknown>; context?: any },\n ): Promise<{ deleted: number }>;\n /**\n * Optional. Falls through to direct callback invocation if the\n * underlying driver lacks ACID support (matches the real\n * `ObjectQL.transaction` semantics). Repository code must not rely on\n * rollback for correctness against in-memory drivers.\n */\n transaction?<T>(callback: (trxCtx: any) => Promise<T>, baseContext?: any): Promise<T>;\n}\n\nexport interface SysMetadataRepositoryOptions {\n engine: SysMetadataEngine;\n /**\n * Tenancy scope. `null` writes to env-wide overlay rows; a string\n * scopes to one organization (the supported shared-DB tenant model\n * — see ADR-0005 amendment).\n */\n organizationId?: string | null;\n /** Org label embedded in returned MetaRefs. Defaults to organizationId or `\"system\"`. */\n orgLabel?: string;\n}\n\n/** Derived from registry — single source of truth (Prime Directive #8). */\nconst OVERLAY_ALLOWED_TYPES: ReadonlySet<string> = new Set(\n DEFAULT_METADATA_TYPE_REGISTRY\n .filter((e) => e.allowOrgOverride)\n .map((e) => e.type),\n);\n\nexport class SysMetadataRepository implements MetadataRepository {\n private readonly engine: SysMetadataEngine;\n private readonly organizationId: string | null;\n private readonly orgLabel: string;\n\n /**\n * Local seq counter for in-memory watch() event broadcasts. Mirrors\n * the durable `event_seq` we write into `sys_metadata_history` on\n * each successful put/delete — assigned AFTER the transaction commits\n * so we never broadcast events that got rolled back.\n */\n private seqCounter = 0;\n private readonly watchers = new Set<(evt: MetadataEvent) => void>();\n private closed = false;\n\n /** Table name for the durable event log. */\n private readonly historyTable = 'sys_metadata_history';\n\n constructor(opts: SysMetadataRepositoryOptions) {\n this.engine = opts.engine;\n this.organizationId = opts.organizationId ?? null;\n this.orgLabel = opts.orgLabel ?? (opts.organizationId ?? 'system');\n }\n\n /**\n * Run `cb` inside `engine.transaction(...)` if the engine supports it,\n * otherwise fall through to a direct call. Matches the real\n * `ObjectQL.transaction` semantics — in-memory drivers (and our test\n * fakes) get no rollback, which is acceptable because production\n * always runs on a SQL driver with real ACID.\n */\n private async withTxn<T>(cb: (ctx: any) => Promise<T>): Promise<T> {\n if (typeof this.engine.transaction === 'function') {\n return this.engine.transaction(cb);\n }\n return cb(undefined);\n }\n\n /**\n * Read the current overlay row. Returns null if no row exists —\n * callers (e.g. LayeredRepository) fall through to lower layers.\n */\n async get(ref: MetaRef): Promise<MetadataItem | null> {\n this.assertOpen();\n const row = await this.engine.findOne('sys_metadata', {\n where: this.whereFor(ref),\n });\n if (!row) return null;\n return this.rowToItem(ref, row);\n }\n\n /**\n * Resolve a historical version by content hash (ADR-0009).\n *\n * Looks up `sys_metadata_history` by `(organization_id, type, name,\n * checksum)`. Returns null if no row matches. `executionPinned` types\n * are guaranteed to find their body here because history GC skips\n * them.\n */\n async getByHash(ref: MetaRef, hash: string): Promise<MetadataItem | null> {\n this.assertOpen();\n const full = this.fullRef(ref);\n const row = await this.engine.findOne(this.historyTable, {\n where: {\n organization_id: this.organizationId,\n type: full.type,\n name: full.name,\n checksum: hash,\n },\n });\n if (!row) return null;\n const rawBody = (row as any).metadata;\n if (rawBody === null || rawBody === undefined) {\n // Tombstone — body is gone, do not resurrect.\n return null;\n }\n const body =\n typeof rawBody === 'string' ? JSON.parse(rawBody) : (rawBody as Record<string, unknown>);\n return {\n ref: { ...full, version: undefined },\n body: body as Record<string, unknown>,\n hash,\n parentHash: (row as any).previous_checksum ?? null,\n authoredBy: (row as any).recorded_by ?? 'unknown',\n authoredAt: (row as any).recorded_at ?? new Date(0).toISOString(),\n message: (row as any).change_note ?? undefined,\n seq: ((row as any).event_seq as number) ?? 0,\n };\n }\n\n async put(ref: MetaRef, spec: unknown, opts: PutOptions): Promise<PutResult> {\n this.assertOpen();\n this.assertAllowed(ref.type);\n\n const body = (spec ?? {}) as Record<string, unknown>;\n const hash = hashSpec(body);\n\n // Run all reads + writes inside one transaction so the optimistic\n // lock, the parent-row mutation, and the history append are atomic.\n const result = await this.withTxn(async (ctx) => {\n const existing = await this.engine.findOne('sys_metadata', {\n where: this.whereFor(ref),\n context: ctx,\n });\n const existingHash: string | null = existing?.checksum ?? null;\n if (opts.parentVersion !== existingHash) {\n throw new ConflictError(this.fullRef(ref), opts.parentVersion, existingHash);\n }\n\n // No-op short-circuit: identical body → no write, no history row,\n // no event. We re-yield the existing item so callers see the\n // canonical hash but the seqCounter is unchanged.\n if (existing && existingHash === hash) {\n const item = this.rowToItem(ref, existing);\n return { skipped: true as const, version: hash, seq: item.seq, item };\n }\n\n const now = new Date().toISOString();\n const op: 'create' | 'update' = existing ? 'update' : 'create';\n\n // Per-(org,type,name) lineage counter. Use MAX from history so\n // delete+recreate continues incrementing instead of restarting\n // at 1 (which the prior `sys_metadata.version` semantics did).\n const version = await this.nextItemVersion(ref, ctx);\n // Per-org monotonic event log cursor.\n const eventSeq = await this.nextEventSeq(ctx);\n\n const parentRowData: Record<string, unknown> = {\n type: ref.type,\n name: ref.name,\n organization_id: this.organizationId,\n metadata: JSON.stringify(body),\n checksum: hash,\n state: 'active',\n version,\n updated_at: now,\n };\n if (existing) {\n const existingId = (existing as { id?: string }).id;\n if (existingId === undefined) {\n throw new Error(\n `SysMetadataRepository.put: existing row for ${ref.type}/${ref.name} has no id column`,\n );\n }\n await this.engine.update('sys_metadata', parentRowData, {\n where: { id: existingId },\n context: ctx,\n });\n } else {\n parentRowData.created_at = now;\n await this.engine.insert('sys_metadata', parentRowData, { context: ctx });\n }\n\n // Durable history append — same transaction, so the parent write\n // and the audit row commit together or roll back together.\n await this.engine.insert(\n this.historyTable,\n {\n id: this.uuid(),\n event_seq: eventSeq,\n type: ref.type,\n name: ref.name,\n version,\n operation_type: op,\n metadata: JSON.stringify(body),\n checksum: hash,\n previous_checksum: existingHash,\n change_note: opts.message,\n source: opts.source ?? 'sys-metadata-repo',\n organization_id: this.organizationId,\n recorded_by: opts.actor,\n recorded_at: now,\n },\n { context: ctx },\n );\n\n const item: MetadataItem = {\n ref: this.fullRef(ref),\n body,\n hash,\n parentHash: existingHash,\n authoredBy: opts.actor,\n authoredAt: now,\n message: opts.message,\n seq: eventSeq,\n };\n\n return {\n skipped: false as const,\n version: hash,\n seq: eventSeq,\n item,\n op,\n existingHash,\n now,\n source: opts.source ?? 'sys-metadata-repo',\n message: opts.message,\n actor: opts.actor,\n };\n });\n\n if (result.skipped) {\n return { version: result.version, seq: result.seq, item: result.item };\n }\n\n // Broadcast AFTER commit. seqCounter tracks the durable event_seq\n // so watch() consumers and history() consumers see the same cursor.\n this.seqCounter = result.seq;\n this.broadcast({\n seq: result.seq,\n op: result.op,\n ref: this.fullRef(ref),\n hash: result.version,\n parentHash: result.existingHash,\n actor: result.actor,\n message: result.message,\n ts: result.now,\n source: result.source,\n });\n\n return { version: result.version, seq: result.seq, item: result.item };\n }\n\n async delete(ref: MetaRef, opts: DeleteOptions): Promise<DeleteResult> {\n this.assertOpen();\n this.assertAllowed(ref.type);\n\n const result = await this.withTxn(async (ctx) => {\n const existing = await this.engine.findOne('sys_metadata', {\n where: this.whereFor(ref),\n context: ctx,\n });\n if (!existing) {\n throw new ConflictError(this.fullRef(ref), opts.parentVersion, null);\n }\n const existingHash: string | null = existing.checksum ?? null;\n if (opts.parentVersion !== existingHash) {\n throw new ConflictError(this.fullRef(ref), opts.parentVersion, existingHash);\n }\n\n const existingId = (existing as { id?: string }).id;\n if (existingId === undefined) {\n throw new Error(\n `SysMetadataRepository.delete: existing row for ${ref.type}/${ref.name} has no id column`,\n );\n }\n\n const now = new Date().toISOString();\n const version = await this.nextItemVersion(ref, ctx);\n const eventSeq = await this.nextEventSeq(ctx);\n\n await this.engine.delete('sys_metadata', {\n where: { id: existingId },\n context: ctx,\n });\n\n // Tombstone row — metadata/checksum are intentionally null.\n // Identity is preserved via (organization_id, type, name, version);\n // the parent row's id is not retained.\n await this.engine.insert(\n this.historyTable,\n {\n id: this.uuid(),\n event_seq: eventSeq,\n type: ref.type,\n name: ref.name,\n version,\n operation_type: 'delete',\n metadata: null,\n checksum: null,\n previous_checksum: existingHash,\n change_note: opts.message,\n source: opts.source ?? 'sys-metadata-repo',\n organization_id: this.organizationId,\n recorded_by: opts.actor,\n recorded_at: now,\n },\n { context: ctx },\n );\n\n return {\n eventSeq,\n existingHash,\n now,\n source: opts.source ?? 'sys-metadata-repo',\n message: opts.message,\n actor: opts.actor,\n };\n });\n\n this.seqCounter = result.eventSeq;\n this.broadcast({\n seq: result.eventSeq,\n op: 'delete',\n ref: this.fullRef(ref),\n hash: null,\n parentHash: result.existingHash,\n actor: result.actor,\n message: result.message,\n ts: result.now,\n source: result.source,\n });\n\n return { seq: result.eventSeq };\n }\n\n async *list(filter: ListFilter): AsyncIterable<MetadataItemHeader> {\n this.assertOpen();\n const where: Record<string, unknown> = {\n organization_id: this.organizationId,\n state: 'active',\n };\n if (filter.type) where.type = filter.type;\n const rows = await this.engine.find('sys_metadata', {\n where,\n limit: filter.limit,\n });\n for (const row of rows) {\n if (filter.nameContains && !String(row.name).includes(filter.nameContains)) continue;\n const item = this.rowToItem(\n { ...this.fullRef({ type: row.type, name: row.name } as MetaRef) },\n row,\n );\n // Strip body for the header projection.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { body, ...header } = item;\n yield header;\n }\n }\n\n /**\n * Yield every history event for `(org, type?, name?)` from the\n * durable log, ordered by per-(type,name) `version` ascending. When\n * `filter.type`/`filter.name` are unset the consumer gets the full\n * org-scoped event stream — still ordered by version within each\n * (type,name) bucket, then by `recorded_at` across buckets (we sort\n * client-side because the test engine doesn't honor `orderBy`).\n */\n async *history(ref: MetaRef, opts?: HistoryOptions): AsyncIterable<MetadataEvent> {\n this.assertOpen();\n const full = this.fullRef(ref);\n const where: Record<string, unknown> = {\n organization_id: this.organizationId,\n type: full.type,\n name: full.name,\n };\n const rows = await this.engine.find(this.historyTable, { where });\n rows.sort((a: any, b: any) => {\n const va = typeof a.event_seq === 'number' ? a.event_seq : 0;\n const vb = typeof b.event_seq === 'number' ? b.event_seq : 0;\n return va - vb;\n });\n let yielded = 0;\n for (const row of rows) {\n if (opts?.sinceSeq !== undefined && (row.event_seq ?? 0) <= opts.sinceSeq) continue;\n if (opts?.limit !== undefined && yielded >= opts.limit) break;\n yielded++;\n yield {\n seq: (row.event_seq as number) ?? 0,\n op: (row.operation_type as MetadataEvent['op']) ?? 'update',\n ref: full,\n hash: (row.checksum as string | null) ?? null,\n parentHash: (row.previous_checksum as string | null) ?? null,\n actor: (row.recorded_by as string | undefined) ?? 'unknown',\n message: (row.change_note as string | undefined) ?? undefined,\n ts: (row.recorded_at as string) ?? new Date(0).toISOString(),\n source: (row.source as string | undefined) ?? 'sys-metadata-repo',\n };\n }\n }\n\n /**\n * Live event stream. Fires for every successful put/delete on THIS\n * instance — cross-replica fan-out is M1. Manual AsyncIterator (not\n * an async generator) so we can deterministically tear down via\n * `iter.return()`, matching the pattern used by InMemoryRepository.\n */\n watch(filter: WatchFilter, since?: number): AsyncIterable<MetadataEvent> {\n const self = this;\n return {\n [Symbol.asyncIterator]: () => {\n const queue: MetadataEvent[] = [];\n let pendingResolve: ((r: IteratorResult<MetadataEvent>) => void) | null = null;\n let stopped = false;\n\n const dispatch = (evt: MetadataEvent) => {\n if (stopped) return;\n if (!self.matchesFilter(evt, filter)) return;\n if (since !== undefined && evt.seq <= since) return;\n if (pendingResolve) {\n const r = pendingResolve;\n pendingResolve = null;\n r({ value: evt, done: false });\n } else {\n queue.push(evt);\n }\n };\n self.watchers.add(dispatch);\n\n return {\n next(): Promise<IteratorResult<MetadataEvent>> {\n if (stopped) return Promise.resolve({ value: undefined as any, done: true });\n const buffered = queue.shift();\n if (buffered) return Promise.resolve({ value: buffered, done: false });\n return new Promise((resolve) => {\n pendingResolve = resolve;\n });\n },\n return(): Promise<IteratorResult<MetadataEvent>> {\n stopped = true;\n self.watchers.delete(dispatch);\n if (pendingResolve) {\n const r = pendingResolve;\n pendingResolve = null;\n r({ value: undefined as any, done: true });\n }\n return Promise.resolve({ value: undefined as any, done: true });\n },\n };\n },\n };\n }\n\n /** Shut down all watch iterators. */\n close(): void {\n this.closed = true;\n // Drain watchers — each one's `return()` removes itself.\n const snapshot = Array.from(this.watchers);\n for (const w of snapshot) {\n try {\n w({\n seq: -1,\n op: 'delete',\n ref: { org: '', type: 'view', name: '_close' } as MetaRef,\n hash: null,\n parentHash: null,\n actor: 'system',\n ts: new Date().toISOString(),\n source: 'sys-metadata-repo-close',\n });\n } catch { /* noop */ }\n }\n this.watchers.clear();\n }\n\n // ── helpers ─────────────────────────────────────────────────────────\n\n private assertOpen(): void {\n if (this.closed) throw new Error('SysMetadataRepository is closed');\n }\n\n private assertAllowed(type: string): void {\n if (!OVERLAY_ALLOWED_TYPES.has(type)) {\n const err: any = new Error(\n `[not_overridable] '${type}' is not allowOrgOverride in the registry. ` +\n `Allowed: ${Array.from(OVERLAY_ALLOWED_TYPES).join(', ')}.`,\n );\n err.code = 'not_overridable';\n err.status = 403;\n throw err;\n }\n }\n\n private whereFor(ref: Pick<MetaRef, 'type' | 'name'>): Record<string, unknown> {\n return {\n type: ref.type,\n name: ref.name,\n organization_id: this.organizationId,\n state: 'active',\n };\n }\n\n private fullRef(ref: Pick<MetaRef, 'type' | 'name'>): MetaRef {\n return {\n org: this.orgLabel,\n type: ref.type,\n name: ref.name,\n };\n }\n\n private rowToItem(ref: Pick<MetaRef, 'type' | 'name'>, row: any): MetadataItem {\n const body: Record<string, unknown> =\n typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata ?? {});\n const hash: string = row.checksum ?? hashSpec(body);\n return {\n ref: this.fullRef(ref),\n body,\n hash,\n parentHash: null,\n authoredBy: row.updated_by ?? row.created_by ?? 'unknown',\n authoredAt: row.updated_at ?? row.created_at ?? new Date().toISOString(),\n message: undefined,\n seq: this.seqCounter,\n };\n }\n\n private broadcast(evt: MetadataEvent): void {\n for (const w of Array.from(this.watchers)) {\n try { w(evt); } catch { /* listener errors don't break the repo */ }\n }\n }\n\n private matchesFilter(evt: MetadataEvent, filter: WatchFilter): boolean {\n if (filter.type && evt.ref.type !== filter.type) return false;\n if (filter.name && evt.ref.name !== filter.name) return false;\n if (filter.org && evt.ref.org !== filter.org) return false;\n return true;\n }\n\n /**\n * Per-org monotonic event sequence. Reads `MAX(event_seq) + 1` from\n * `sys_metadata_history` scoped by `organization_id`. MUST be called\n * inside a transaction (the only caller is the put/delete txn body) —\n * concurrent writers in the same org race otherwise.\n */\n private async nextEventSeq(ctx: any): Promise<number> {\n try {\n const rows = await this.engine.find(this.historyTable, {\n where: { organization_id: this.organizationId },\n context: ctx,\n });\n let max = 0;\n for (const row of rows as Array<{ event_seq?: number | null }>) {\n const v = typeof row.event_seq === 'number' ? row.event_seq : 0;\n if (v > max) max = v;\n }\n return max + 1;\n } catch {\n // Table not provisioned yet (fresh DB) — start at 1.\n return 1;\n }\n }\n\n /**\n * Per-(org,type,name) lineage counter. Reads from history (not from\n * `sys_metadata.version`) so delete + recreate continues incrementing\n * instead of restarting at 1.\n */\n private async nextItemVersion(\n ref: Pick<MetaRef, 'type' | 'name'>,\n ctx: any,\n ): Promise<number> {\n try {\n const rows = await this.engine.find(this.historyTable, {\n where: {\n organization_id: this.organizationId,\n type: ref.type,\n name: ref.name,\n },\n context: ctx,\n });\n let max = 0;\n for (const row of rows as Array<{ version?: number | null }>) {\n const v = typeof row.version === 'number' ? row.version : 0;\n if (v > max) max = v;\n }\n return max + 1;\n } catch {\n return 1;\n }\n }\n\n /** Lightweight UUID-ish id for history rows; sufficient for an audit log. */\n private uuid(): string {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return globalThis.crypto.randomUUID();\n }\n return `evt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectStackProtocol } from '@objectstack/spec/api';\nimport { IDataEngine } from '@objectstack/core';\nimport type { ObjectQL } from './engine.js';\nimport { SysMetadataRepository, type SysMetadataEngine } from './sys-metadata-repository.js';\nimport { ConflictError } from '@objectstack/metadata-core';\nimport type {\n BatchUpdateRequest,\n BatchUpdateResponse,\n UpdateManyDataRequest,\n DeleteManyDataRequest\n} from '@objectstack/spec/api';\nimport type { MetadataCacheRequest, MetadataCacheResponse, ServiceInfo, ApiRoutes, WellKnownCapabilities } from '@objectstack/spec/api';\nimport type { IFeedService } from '@objectstack/spec/contracts';\nimport { parseFilterAST, isFilterAST } from '@objectstack/spec/data';\nimport { PLURAL_TO_SINGULAR, SINGULAR_TO_PLURAL } from '@objectstack/spec/shared';\nimport { ListViewSchema, FormViewSchema, DashboardSchema } from '@objectstack/spec/ui';\nimport { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel';\nimport { z } from 'zod';\n\n/**\n * Zod schemas used to validate overlay items before they are persisted into\n * `sys_metadata` by {@link ObjectStackProtocolImplementation.saveMetaItem}.\n *\n * Some types (notably `view`) are *not* a single schema but a discriminated\n * family — a grid/kanban/calendar list view vs. a simple/tabbed/wizard form\n * view. We dispatch to the right schema based on the `type` discriminant\n * rather than using `z.union([...])`, which would collapse all branch errors\n * into an opaque \"Invalid input\" union error.\n *\n * Validation policy:\n * - `safeParse` is used so we can craft a 422 with structured `issues`.\n * - We do NOT replace the persisted document with `parsed.data`; the\n * original payload is stored verbatim so Studio-only auxiliary fields\n * (e.g. `isPinned`, `isDefault`, `sortOrder`) survive the round-trip.\n * - Schemas are referenced lazily through the Spec's `lazySchema` Proxy,\n * so importing this module does not trigger eager Zod construction.\n * - Types without a registered schema (e.g. `app`, `package`) fall through\n * unvalidated for backwards compatibility — they were never enforced\n * historically and existing control-plane writes rely on the lenient\n * behaviour.\n */\nconst FORM_VIEW_TYPES = new Set(['simple', 'tabbed', 'wizard', 'split', 'drawer', 'modal']);\n\nfunction resolveOverlaySchema(type: string, item: unknown): z.ZodTypeAny | null {\n const singular = PLURAL_TO_SINGULAR[type] ?? type;\n switch (singular) {\n case 'view': {\n // Form views and list views share the `view` overlay type. Pick\n // the right Zod schema by inspecting the discriminant. Defaults\n // to ListViewSchema (matches the ListViewSchema `type.default('grid')`).\n const t = (item && typeof item === 'object' && 'type' in item)\n ? String((item as any).type)\n : undefined;\n return t && FORM_VIEW_TYPES.has(t) ? FormViewSchema : ListViewSchema;\n }\n case 'dashboard':\n return DashboardSchema;\n default:\n return null;\n }\n}\n\n/**\n * Simple hash function for ETag generation (browser-compatible)\n * Uses a basic hash algorithm instead of crypto.createHash\n */\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(16);\n}\n\n/**\n * Thrown by `updateData` / `deleteData` when the caller supplies an\n * `expectedVersion` that does not match the current record's `updated_at`.\n *\n * The HTTP layer maps this to `409 Conflict` with code `CONCURRENT_UPDATE`,\n * and includes both the current server-side version and the current record\n * payload so the client can render an informed conflict-resolution UI\n * (\"Reload latest\" vs. \"Overwrite anyway\").\n *\n * NOTE: This is an *application-level* compare-and-set — not an atomic\n * storage-layer CAS. There is a small TOCTOU window between the version\n * check and the subsequent write. For the conflict frequency this targets\n * (different users seconds-to-minutes apart in B2B record editing) this\n * is more than adequate; a future revision can push the check into the\n * driver's UPDATE statement (`WHERE id=? AND updated_at=?`) for true\n * atomicity.\n */\nexport class ConcurrentUpdateError extends Error {\n readonly code = 'CONCURRENT_UPDATE';\n readonly status = 409;\n readonly currentVersion: string | null;\n readonly currentRecord: unknown;\n constructor(opts: { currentVersion: string | null; currentRecord: unknown; message?: string }) {\n super(opts.message ?? 'Record was modified by another user');\n this.name = 'ConcurrentUpdateError';\n this.currentVersion = opts.currentVersion;\n this.currentRecord = opts.currentRecord;\n }\n}\n\n/**\n * Normalises a version token for comparison. Strips RFC-7232-style quotes\n * (`\"…\"`) that an HTTP `If-Match` header may carry, trims whitespace, and\n * returns null for empty / nullish input.\n */\nfunction normaliseVersionToken(v: unknown): string | null {\n if (v === null || v === undefined) return null;\n const s = String(v).trim();\n if (!s) return null;\n if (s.length >= 2 && s.startsWith('\"') && s.endsWith('\"')) {\n return s.slice(1, -1);\n }\n return s;\n}\n\n/**\n * Service Configuration for Discovery\n * Maps service names to their routes and plugin providers\n */\nconst SERVICE_CONFIG: Record<string, { route: string; plugin: string }> = {\n auth: { route: '/api/v1/auth', plugin: 'plugin-auth' },\n automation: { route: '/api/v1/automation', plugin: 'plugin-automation' },\n cache: { route: '/api/v1/cache', plugin: 'plugin-redis' },\n queue: { route: '/api/v1/queue', plugin: 'plugin-bullmq' },\n job: { route: '/api/v1/jobs', plugin: 'job-scheduler' },\n ui: { route: '/api/v1/ui', plugin: 'ui-plugin' },\n workflow: { route: '/api/v1/workflow', plugin: 'plugin-workflow' },\n realtime: { route: '/api/v1/realtime', plugin: 'plugin-realtime' },\n notification: { route: '/api/v1/notifications', plugin: 'plugin-notifications' },\n ai: { route: '/api/v1/ai', plugin: 'plugin-ai' },\n i18n: { route: '/api/v1/i18n', plugin: 'service-i18n' },\n graphql: { route: '/graphql', plugin: 'plugin-graphql' }, // GraphQL uses /graphql by convention (not versioned REST)\n 'file-storage': { route: '/api/v1/storage', plugin: 'plugin-storage' },\n search: { route: '/api/v1/search', plugin: 'plugin-search' },\n};\n\nexport class ObjectStackProtocolImplementation implements ObjectStackProtocol {\n private engine: ObjectQL;\n private getServicesRegistry?: () => Map<string, any>;\n private getFeedService?: () => IFeedService | undefined;\n /**\n * Project scope applied to sys_metadata reads/writes. When undefined\n * (single-kernel deployments), rows land in / come from the\n * platform-global bucket (`project_id IS NULL`). When set, every\n * saveMetaItem insert/update and loadMetaFromDb query is filtered by\n * `project_id = projectId`, so per-project kernels see only their own\n * metadata even if several projects share the same physical database.\n */\n private projectId?: string;\n\n /**\n * Lazily-instantiated SysMetadataRepository per organization. Keyed by\n * `${organizationId ?? '__env__'}`. Repositories are stateful — they\n * carry the per-org `seqCounter` and watch subscribers — so we cache\n * them rather than constructing one per call.\n */\n private overlayRepos = new Map<string, SysMetadataRepository>();\n\n constructor(\n engine: IDataEngine,\n getServicesRegistry?: () => Map<string, any>,\n getFeedService?: () => IFeedService | undefined,\n projectId?: string,\n ) {\n this.engine = engine as ObjectQL;\n this.getServicesRegistry = getServicesRegistry;\n this.getFeedService = getFeedService;\n this.projectId = projectId;\n }\n\n /**\n * Lazily obtain a SysMetadataRepository for the given organization.\n * Env-wide overlays (organizationId == null) share a singleton under\n * the `__env__` key.\n */\n private getOverlayRepo(organizationId: string | null): SysMetadataRepository {\n const key = organizationId ?? '__env__';\n let repo = this.overlayRepos.get(key);\n if (!repo) {\n repo = new SysMetadataRepository({\n engine: this.engine as unknown as SysMetadataEngine,\n organizationId,\n orgLabel: organizationId ?? 'env',\n });\n this.overlayRepos.set(key, repo);\n }\n return repo;\n }\n\n /**\n * One-time guard for ensuring the overlay-uniqueness UNIQUE INDEX exists\n * on `sys_metadata`. ADR-0005: scopes overlays by\n * `(type, name, organization_id, project_id, scope)` for active rows only.\n * Idempotent SQL — safe to attempt on every protocol instance.\n *\n * Inlined here (rather than importing from @objectstack/metadata/migrations)\n * to avoid a circular dependency: metadata already depends on objectql.\n */\n private overlayIndexEnsured = false;\n private async ensureOverlayIndex(): Promise<void> {\n if (this.overlayIndexEnsured) return;\n this.overlayIndexEnsured = true;\n try {\n const engineAny = this.engine as any;\n let driver: any = engineAny?.driver ?? engineAny?.getDriver?.();\n if (!driver && engineAny?.drivers instanceof Map) {\n for (const candidate of engineAny.drivers.values()) {\n if (\n candidate &&\n (typeof (candidate as any).raw === 'function' ||\n typeof (candidate as any).execute === 'function')\n ) {\n driver = candidate;\n break;\n }\n }\n }\n if (!driver) return;\n const exec = async (sql: string): Promise<void> => {\n if (typeof (driver as any).raw === 'function') {\n await (driver as any).raw(sql);\n } else if (typeof (driver as any).execute === 'function') {\n await (driver as any).execute(sql);\n } else {\n throw new Error('driver has neither raw nor execute');\n }\n };\n // ADR-0005 (revised 2026-05): per-env DBs replace the old\n // \"per-project\" isolation, so `project_id` is no longer a\n // discriminator. Overlay uniqueness is `(type, name,\n // organization_id)` filtered to active rows. Drop the legacy\n // composite index first so the new partial UNIQUE can claim\n // the same name — DROP INDEX IF EXISTS is idempotent.\n try { await exec(\"DROP INDEX IF EXISTS idx_sys_metadata_overlay_active\"); } catch { /* best-effort */ }\n const partialSql =\n \"CREATE UNIQUE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active \" +\n \"ON sys_metadata (type, name, organization_id) \" +\n \"WHERE state = 'active'\";\n const fallbackSql =\n \"CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active \" +\n \"ON sys_metadata (type, name, organization_id)\";\n try {\n await exec(partialSql);\n } catch (err: any) {\n const msg = err instanceof Error ? err.message : String(err);\n if (/partial|where clause|syntax/i.test(msg)) {\n try {\n await exec(fallbackSql);\n } catch {\n // ignore — non-essential optimization\n }\n }\n // \"already exists\" or anything else: best-effort\n }\n } catch {\n // ignore — index is an optimization, not a correctness invariant\n }\n }\n\n /**\n * Exposes the project scope the protocol is bound to. Consumers like\n * the HTTP dispatcher use this to decide whether to trust the process-\n * wide SchemaRegistry or whether they must route a read through the\n * protocol's project_id-filtered lookup.\n */\n getProjectId(): string | undefined {\n return this.projectId;\n }\n\n private requireFeedService(): IFeedService {\n const svc = this.getFeedService?.();\n if (!svc) {\n throw new Error('Feed service not available. Install and register service-feed to enable feed operations.');\n }\n return svc;\n }\n\n async getDiscovery() {\n // Get registered services from kernel if available\n const registeredServices = this.getServicesRegistry ? this.getServicesRegistry() : new Map();\n \n // Build dynamic service info with proper typing\n const services: Record<string, ServiceInfo> = {\n // --- Kernel-provided (objectql is an example kernel implementation) ---\n metadata: { enabled: true, status: 'available' as const, route: '/api/v1/meta', provider: 'objectql' },\n data: { enabled: true, status: 'available' as const, route: '/api/v1/data', provider: 'objectql' },\n analytics: { enabled: true, status: 'available' as const, route: '/api/v1/analytics', provider: 'objectql' },\n };\n\n // Check which services are actually registered\n for (const [serviceName, config] of Object.entries(SERVICE_CONFIG)) {\n if (registeredServices.has(serviceName)) {\n // Service is registered and available\n services[serviceName] = {\n enabled: true,\n status: 'available' as const,\n route: config.route,\n provider: config.plugin,\n };\n } else {\n // Service is not registered\n services[serviceName] = {\n enabled: false,\n status: 'unavailable' as const,\n message: `Install ${config.plugin} to enable`,\n };\n }\n }\n\n // Build routes from services — a flat convenience map for client routing\n const serviceToRouteKey: Record<string, keyof ApiRoutes> = {\n auth: 'auth',\n automation: 'automation',\n ui: 'ui',\n workflow: 'workflow',\n realtime: 'realtime',\n notification: 'notifications',\n ai: 'ai',\n i18n: 'i18n',\n graphql: 'graphql',\n 'file-storage': 'storage',\n };\n\n const optionalRoutes: Partial<ApiRoutes> = {\n analytics: '/api/v1/analytics',\n };\n\n // Add routes for available plugin services\n for (const [serviceName, config] of Object.entries(SERVICE_CONFIG)) {\n if (registeredServices.has(serviceName)) {\n const routeKey = serviceToRouteKey[serviceName];\n if (routeKey) {\n optionalRoutes[routeKey] = config.route;\n }\n }\n }\n\n // Add feed service status\n if (registeredServices.has('feed')) {\n services['feed'] = {\n enabled: true,\n status: 'available' as const,\n route: '/api/v1/data',\n provider: 'service-feed',\n };\n } else {\n services['feed'] = {\n enabled: false,\n status: 'unavailable' as const,\n message: 'Install service-feed to enable',\n };\n }\n\n const routes: ApiRoutes = {\n data: '/api/v1/data',\n metadata: '/api/v1/meta',\n ...optionalRoutes,\n };\n\n // Build well-known capabilities from registered services.\n // DiscoverySchema defines capabilities as Record<string, { enabled, features?, description? }>\n // (hierarchical format). We also keep a flat WellKnownCapabilities for backward compat.\n const wellKnown: WellKnownCapabilities = {\n feed: registeredServices.has('feed'),\n comments: registeredServices.has('feed'),\n automation: registeredServices.has('automation'),\n cron: registeredServices.has('job'),\n search: registeredServices.has('search'),\n export: registeredServices.has('automation') || registeredServices.has('queue'),\n chunkedUpload: registeredServices.has('file-storage'),\n };\n\n // Convert flat booleans → hierarchical capability objects\n const capabilities: Record<string, { enabled: boolean; description?: string }> = {};\n for (const [key, enabled] of Object.entries(wellKnown)) {\n capabilities[key] = { enabled };\n }\n\n return {\n version: '1.0',\n apiName: 'ObjectStack API',\n routes,\n services,\n capabilities,\n };\n }\n\n async getMetaTypes() {\n const schemaTypes = this.engine.registry.getRegisteredTypes();\n\n // Also include types from MetadataService (runtime-registered: agent, tool, etc.)\n let runtimeTypes: string[] = [];\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.getRegisteredTypes === 'function') {\n runtimeTypes = await metadataService.getRegisteredTypes();\n }\n } catch {\n // MetadataService not available\n }\n\n const allTypes = Array.from(new Set([...schemaTypes, ...runtimeTypes]));\n return { types: allTypes };\n }\n\n async getMetaItems(request: { type: string; packageId?: string; organizationId?: string }) {\n const { packageId } = request;\n let items: unknown[] = [];\n\n // Unscoped kernels (control plane): read everything from SchemaRegistry.\n // Scoped (project) kernels: skip user-project entries in SchemaRegistry to\n // prevent cross-project leakage, but DO include scope:'system' packages\n // (plugin-auth, plugin-security, plugin-audit, …) — those are globally\n // shared and must be visible at every project's meta endpoint.\n if (this.projectId === undefined) {\n items = [...this.engine.registry.listItems(request.type, packageId)];\n // Normalize singular/plural using explicit mapping\n if (items.length === 0) {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) items = [...this.engine.registry.listItems(alt, packageId)];\n }\n } else {\n // For project kernels: the SchemaRegistry is owned by THIS\n // kernel's ObjectQL instance (not shared across projects in the\n // process), so we can safely include every package — system\n // plugins (auth/security/audit) and the project's own app\n // package alike. The `_packageId` tag added by `listItems`\n // (registry.ts) is preserved for the sidebar to compute the\n // correct navigation URL.\n items = [...this.engine.registry.listItems(request.type, packageId)];\n if (items.length === 0) {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) items = [...this.engine.registry.listItems(alt, packageId)];\n }\n }\n\n // Always consult the DB so metadata persisted by the seeder /\n // bulkRegister shows up even when the registry already has unrelated\n // entries (the previous fallback-only logic meant per-env metadata\n // was never surfaced whenever system-bridged items populated the\n // registry). Deduplicate against whatever the registry returned.\n //\n // ADR-0005 (revised 2026-05): isolation is now per-organization, since\n // each env has its own physical DB. We surface both org-scoped overlays\n // (when an active org is provided) and env-wide (organization_id IS NULL)\n // overlays; org-scoped rows win on name collision.\n try {\n const orgId = (request as any).organizationId as string | undefined;\n const queryByOrg = async (oid: string | null): Promise<any[]> => {\n const whereClause: Record<string, unknown> = {\n type: request.type,\n state: 'active',\n organization_id: oid,\n };\n if (packageId) whereClause._packageId = packageId;\n let rs = await this.engine.find('sys_metadata', { where: whereClause });\n if ((!rs || rs.length === 0)) {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) {\n const altWhere: Record<string, unknown> = { type: alt, state: 'active', organization_id: oid };\n if (packageId) altWhere._packageId = packageId;\n rs = await this.engine.find('sys_metadata', { where: altWhere });\n }\n }\n return rs ?? [];\n };\n const envWideRecords = await queryByOrg(null);\n const orgRecords = orgId ? await queryByOrg(orgId) : [];\n // org-specific rows override env-wide rows on name collision\n const mergedMap = new Map<string, any>();\n for (const r of envWideRecords) mergedMap.set(r.name, r);\n for (const r of orgRecords) mergedMap.set(r.name, r);\n const records = Array.from(mergedMap.values());\n if (records && records.length > 0) {\n const byName = new Map<string, any>();\n for (const existing of items) {\n const entry = existing as any;\n if (entry && typeof entry === 'object' && 'name' in entry) {\n byName.set(entry.name, entry);\n }\n }\n for (const record of records) {\n const data = typeof record.metadata === 'string'\n ? JSON.parse(record.metadata)\n : record.metadata;\n if (data && typeof data === 'object' && 'name' in data) {\n byName.set(data.name, data);\n }\n // Only hydrate the global registry for unscoped calls —\n // scoped project entries must not leak process-wide.\n if (this.projectId === undefined) {\n this.engine.registry.registerItem(request.type, data, 'name' as any);\n }\n }\n items = Array.from(byName.values());\n }\n } catch {\n // DB not available — fall through with whatever we already have.\n }\n\n // Merge with MetadataService (runtime-registered items: agents, tools, etc.)\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.list === 'function') {\n let runtimeItems = await metadataService.list(request.type);\n // When filtering by packageId, only include runtime items that\n // belong to the requested package. MetadataService.list() returns\n // items from ALL packages, so we must filter here to respect the\n // package scope requested by the caller (e.g., Studio sidebar).\n if (packageId && runtimeItems && runtimeItems.length > 0) {\n runtimeItems = runtimeItems.filter((item: any) => item?._packageId === packageId);\n }\n if (runtimeItems && runtimeItems.length > 0) {\n // Merge, avoiding duplicates by name\n const itemMap = new Map<string, any>();\n for (const item of items) {\n const entry = item as any;\n if (entry && typeof entry === 'object' && 'name' in entry) {\n itemMap.set(entry.name, entry);\n }\n }\n for (const item of runtimeItems) {\n const entry = item as any;\n if (entry && typeof entry === 'object' && 'name' in entry) {\n // Do not overwrite entries already present in the\n // map: those came from sys_metadata (customization\n // overlays) or the SchemaRegistry and must win\n // over the MetadataService's artifact baseline.\n // Without this guard, saved per-org dashboard /\n // view overlays disappear from list endpoints on\n // refresh (detail endpoint kept showing the\n // overlay because it uses a different code path).\n if (!itemMap.has(entry.name)) {\n itemMap.set(entry.name, entry);\n }\n }\n }\n items = Array.from(itemMap.values());\n }\n }\n } catch {\n // MetadataService not available or doesn't support this type\n }\n\n return {\n type: request.type,\n items\n };\n }\n\n async getMetaItem(request: { type: string, name: string, packageId?: string, organizationId?: string }) {\n let item: unknown;\n const orgId = request.organizationId;\n\n // 1. Customization overlay lookup (sys_metadata).\n // Per ADR-0005 (revised), org-scoped row wins; env-wide\n // (organization_id IS NULL) row is the fallback before falling\n // through to the in-memory registry / MetadataService.\n try {\n const findOverlay = async (oid: string | null): Promise<any | undefined> => {\n const where: Record<string, unknown> = {\n type: request.type,\n name: request.name,\n state: 'active',\n organization_id: oid,\n };\n const rec = await this.engine.findOne('sys_metadata', { where });\n if (rec) return rec;\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) {\n const altWhere: Record<string, unknown> = {\n type: alt,\n name: request.name,\n state: 'active',\n organization_id: oid,\n };\n return await this.engine.findOne('sys_metadata', { where: altWhere });\n }\n return undefined;\n };\n const record = (orgId ? await findOverlay(orgId) : undefined)\n ?? await findOverlay(null);\n if (record) {\n item = typeof record.metadata === 'string'\n ? JSON.parse(record.metadata)\n : record.metadata;\n }\n } catch {\n // DB not available — fall through to registry / MetadataService\n }\n\n // 2. MetadataService (runtime-registered items: HMR-updated view/page/\n // dashboard/agent/tool, plus FilesystemLoader-sourced items). This\n // is consulted BEFORE the in-memory SchemaRegistry because the\n // registry is a boot-time cache populated by `loadMetadataFromService`\n // and is NOT invalidated on `MetadataManager.register()` (which is\n // how the CLI dev watcher pushes recompiled metadata into the\n // running server). Without this ordering, edits to `*.view.ts`\n // source files appear to take effect (MetadataManager learns the\n // new value) but reads continue to return the stale registry copy.\n if (item === undefined) {\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.get === 'function') {\n const fromService = await metadataService.get(request.type, request.name);\n if (fromService !== undefined && fromService !== null) {\n item = fromService;\n } else {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) {\n const altFromService = await metadataService.get(alt, request.name);\n if (altFromService !== undefined && altFromService !== null) {\n item = altFromService;\n }\n }\n }\n }\n } catch {\n // MetadataService not available — fall through\n }\n }\n\n // 3. In-memory SchemaRegistry (artifact-loaded out-of-box values, and\n // items that bypass MetadataService — e.g. some object-schema\n // extension chains registered by AppPlugin directly).\n // Both control-plane (unscoped) and project kernels consult the\n // registry. The previous guard that skipped the registry for\n // project kernels was meant to prevent cross-project leakage at\n // the LIST level — but for a single-item lookup the kernel's own\n // `engine.registry` is project-local (each ObjectQL instance has\n // its own SchemaRegistry), so reading from it is safe and\n // necessary. Without this, project-kernel callers of\n // `GET /api/v1/meta/object/<name>` 404 even though the object is\n // registered and visible via the list endpoint.\n if (item === undefined) {\n item = this.engine.registry.getItem(request.type, request.name);\n if (item === undefined) {\n const alt = PLURAL_TO_SINGULAR[request.type] ?? SINGULAR_TO_PLURAL[request.type];\n if (alt) item = this.engine.registry.getItem(alt, request.name);\n }\n }\n\n return {\n type: request.type,\n name: request.name,\n item\n };\n }\n\n async getUiView(request: { object: string, type: 'list' | 'form' }) {\n const schema = this.engine.registry.getObject(request.object);\n if (!schema) throw new Error(`Object ${request.object} not found`);\n\n const fields = schema.fields || {};\n const fieldKeys = Object.keys(fields);\n\n if (request.type === 'list') {\n // Intelligent Column Selection\n // 1. Always include 'name' or name-like fields\n // 2. Limit to 6 columns by default\n const priorityFields = ['name', 'title', 'label', 'subject', 'email', 'status', 'type', 'category', 'created_at'];\n \n let columns = fieldKeys.filter(k => priorityFields.includes(k));\n \n // If few priority fields, add others until 5\n if (columns.length < 5) {\n const remaining = fieldKeys.filter(k => !columns.includes(k) && k !== 'id' && !fields[k].hidden);\n columns = [...columns, ...remaining.slice(0, 5 - columns.length)];\n }\n \n // Sort columns by priority then alphabet or schema order\n // For now, just keep them roughly in order they appear in schema or priority list\n \n return {\n list: {\n type: 'grid' as const,\n object: request.object,\n label: schema.label || schema.name,\n columns: columns.map(f => ({\n field: f,\n label: fields[f]?.label || f,\n sortable: true\n })),\n sort: fields['created_at'] ? ([{ field: 'created_at', order: 'desc' }] as any) : undefined,\n searchableFields: columns.slice(0, 3) // Make first few textual columns searchable\n }\n };\n } else {\n // Form View Generation\n // Simple single-section layout for now\n const formFields = fieldKeys\n .filter(k => k !== 'id' && k !== 'created_at' && k !== 'updated_at' && !fields[k].hidden)\n .map(f => ({\n field: f,\n label: fields[f]?.label,\n required: fields[f]?.required,\n readonly: fields[f]?.readonly,\n type: fields[f]?.type,\n // Default to 2 columns for most, 1 for textareas\n colSpan: (fields[f]?.type === 'textarea' || fields[f]?.type === 'html') ? 2 : 1\n }));\n\n return {\n form: {\n type: 'simple' as const,\n object: request.object,\n label: `Edit ${schema.label || schema.name}`,\n sections: [\n {\n label: 'General Information',\n columns: 2 as const,\n collapsible: false,\n collapsed: false,\n fields: formFields\n }\n ]\n }\n };\n }\n }\n\n async findData(request: { object: string, query?: any, context?: any }) {\n const options: any = { ...request.query };\n // Forward the dispatcher's ExecutionContext so RBAC/RLS middleware\n // can apply per-request enforcement. The protocol layer is purely\n // a normalizer — it must never strip security context.\n if (request.context !== undefined) {\n options.context = request.context;\n }\n\n // ====================================================================\n // Normalize legacy params → QueryAST standard (where/fields/orderBy/offset/expand)\n // ====================================================================\n\n // OData-style `$`-prefixed params → bare aliases that the rest of\n // this function knows how to normalize. Without this step, params\n // like `?$top=2&$orderby=...` survive into the catch-all\n // implicit-filter pass below and get merged into `where` as\n // bogus field-equality predicates (e.g. `where.$top = \"2\"`),\n // which silently returns zero rows for every list endpoint.\n for (const [dollar, bare] of [\n ['$top', 'top'],\n ['$skip', 'skip'],\n ['$orderby', 'orderBy'],\n ['$select', 'select'],\n ['$count', 'count'],\n ] as const) {\n if (options[dollar] != null && options[bare] == null) {\n options[bare] = options[dollar];\n }\n delete options[dollar];\n }\n\n // Numeric fields — normalize top → limit, skip → offset\n if (options.top != null) {\n options.limit = Number(options.top);\n delete options.top;\n }\n if (options.skip != null) {\n options.offset = Number(options.skip);\n delete options.skip;\n }\n if (options.limit != null) options.limit = Number(options.limit);\n if (options.offset != null) options.offset = Number(options.offset);\n\n // Select → fields: comma-separated string → array\n if (typeof options.select === 'string') {\n options.fields = options.select.split(',').map((s: string) => s.trim()).filter(Boolean);\n } else if (Array.isArray(options.select)) {\n options.fields = options.select;\n }\n if (options.select !== undefined) delete options.select;\n\n // Sort/orderBy → orderBy: string → SortNode[] array\n const sortValue = options.orderBy ?? options.sort;\n if (typeof sortValue === 'string') {\n const parsed = sortValue.split(',').map((part: string) => {\n const trimmed = part.trim();\n if (trimmed.startsWith('-')) {\n return { field: trimmed.slice(1), order: 'desc' as const };\n }\n const [field, order] = trimmed.split(/\\s+/);\n return { field, order: (order?.toLowerCase() === 'desc' ? 'desc' : 'asc') as 'asc' | 'desc' };\n }).filter((s: any) => s.field);\n options.orderBy = parsed;\n } else if (Array.isArray(sortValue)) {\n options.orderBy = sortValue;\n }\n delete options.sort;\n\n // Filter/filters/$filter → where: normalize all filter aliases\n const filterValue = options.filter ?? options.filters ?? options.$filter ?? options.where;\n delete options.filter;\n delete options.filters;\n delete options.$filter;\n\n if (filterValue !== undefined) {\n let parsedFilter = filterValue;\n // JSON string → object\n if (typeof parsedFilter === 'string') {\n try { parsedFilter = JSON.parse(parsedFilter); } catch { /* keep as-is */ }\n }\n // Filter AST array → FilterCondition object\n if (isFilterAST(parsedFilter)) {\n parsedFilter = parseFilterAST(parsedFilter);\n }\n options.where = parsedFilter;\n }\n\n // Populate/expand/$expand → expand (Record<string, QueryAST>)\n const populateValue = options.populate;\n const expandValue = options.$expand ?? options.expand;\n const expandNames: string[] = [];\n if (typeof populateValue === 'string') {\n expandNames.push(...populateValue.split(',').map((s: string) => s.trim()).filter(Boolean));\n } else if (Array.isArray(populateValue)) {\n expandNames.push(...populateValue);\n }\n if (!expandNames.length && expandValue) {\n if (typeof expandValue === 'string') {\n expandNames.push(...expandValue.split(',').map((s: string) => s.trim()).filter(Boolean));\n } else if (Array.isArray(expandValue)) {\n expandNames.push(...expandValue);\n }\n }\n delete options.populate;\n delete options.$expand;\n // Clean up non-object expand (e.g. string) BEFORE the Record conversion\n // below, so that populate-derived names can create the expand Record even\n // when a legacy string expand was also present.\n if (typeof options.expand !== 'object' || options.expand === null) {\n delete options.expand;\n }\n // Only set expand if not already an object (advanced usage)\n if (expandNames.length > 0 && !options.expand) {\n options.expand = {} as Record<string, any>;\n for (const rel of expandNames) {\n options.expand[rel] = { object: rel };\n }\n }\n\n // Boolean fields\n for (const key of ['distinct', 'count']) {\n if (options[key] === 'true') options[key] = true;\n else if (options[key] === 'false') options[key] = false;\n }\n \n // Flat field filters: REST-style query params like ?id=abc&status=open\n // After extracting all known query parameters, any remaining keys are\n // treated as implicit field-level equality filters merged into `where`.\n const knownParams = new Set([\n 'top', 'limit', 'offset',\n 'orderBy',\n 'fields',\n 'where',\n 'expand',\n 'distinct', 'count',\n 'aggregations', 'groupBy',\n 'search', 'context', 'cursor',\n ]);\n if (!options.where) {\n const implicitFilters: Record<string, unknown> = {};\n for (const key of Object.keys(options)) {\n if (!knownParams.has(key)) {\n implicitFilters[key] = options[key];\n delete options[key];\n }\n }\n if (Object.keys(implicitFilters).length > 0) {\n options.where = implicitFilters;\n }\n }\n \n // Route to engine.aggregate() when the query has GROUP BY / aggregations.\n // engine.find() does not do in-memory aggregation fallback, so without\n // this branch a spec-shape aggregate request would silently return\n // ungrouped raw rows on drivers (e.g. SqlDriver) that don't natively\n // honor groupBy/aggregations in find().\n const hasGroupBy = Array.isArray(options.groupBy) && options.groupBy.length > 0;\n const hasAggregations = Array.isArray(options.aggregations) && options.aggregations.length > 0;\n if (hasGroupBy || hasAggregations) {\n const records = await this.engine.aggregate(request.object, {\n where: options.where,\n groupBy: options.groupBy,\n aggregations: options.aggregations,\n context: options.context,\n } as any);\n // Apply limit client-side (EngineAggregateOptions doesn't carry limit)\n const limited = typeof options.limit === 'number' && options.limit > 0\n ? records.slice(0, options.limit)\n : records;\n return {\n object: request.object,\n records: limited,\n total: limited.length,\n hasMore: false,\n };\n }\n\n const records = await this.engine.find(request.object, options);\n // Spec: FindDataResponseSchema — only `records` is returned.\n // OData `value` adaptation (if needed) is handled in the HTTP dispatch layer.\n return {\n object: request.object,\n records,\n total: records.length,\n hasMore: false\n };\n }\n\n async getData(request: { object: string, id: string, expand?: string | string[], select?: string | string[], context?: any }) {\n const queryOptions: any = {\n where: { id: request.id }\n };\n if (request.context !== undefined) {\n queryOptions.context = request.context;\n }\n\n // Support fields for single-record retrieval\n if (request.select) {\n queryOptions.fields = typeof request.select === 'string'\n ? request.select.split(',').map((s: string) => s.trim()).filter(Boolean)\n : request.select;\n }\n\n // Support expand for single-record retrieval\n if (request.expand) {\n const expandNames = typeof request.expand === 'string'\n ? request.expand.split(',').map((s: string) => s.trim()).filter(Boolean)\n : request.expand;\n queryOptions.expand = {} as Record<string, any>;\n for (const rel of expandNames) {\n queryOptions.expand[rel] = { object: rel };\n }\n }\n\n const result = await this.engine.findOne(request.object, queryOptions);\n if (result) {\n return {\n object: request.object,\n id: request.id,\n record: result\n };\n }\n const err = new Error(`Record ${request.id} not found in ${request.object}`) as Error & {\n code?: string;\n status?: number;\n object?: string;\n };\n err.code = 'RECORD_NOT_FOUND';\n err.status = 404;\n err.object = request.object;\n throw err;\n }\n\n async createData(request: { object: string, data: any, context?: any }) {\n const result = await this.engine.insert(\n request.object,\n request.data,\n request.context !== undefined ? { context: request.context } as any : undefined,\n );\n return {\n object: request.object,\n id: result.id,\n record: result\n };\n }\n\n async updateData(request: { object: string, id: string, data: any, expectedVersion?: string, context?: any }) {\n await this.assertVersionMatch(request.object, request.id, request.expectedVersion, request.context);\n const opts: any = { where: { id: request.id } };\n if (request.context !== undefined) opts.context = request.context;\n const result = await this.engine.update(request.object, request.data, opts);\n return {\n object: request.object,\n id: request.id,\n record: result\n };\n }\n\n async deleteData(request: { object: string, id: string, expectedVersion?: string, context?: any }) {\n await this.assertVersionMatch(request.object, request.id, request.expectedVersion, request.context);\n const opts: any = { where: { id: request.id } };\n if (request.context !== undefined) opts.context = request.context;\n await this.engine.delete(request.object, opts);\n return {\n object: request.object,\n id: request.id,\n success: true\n };\n }\n\n /**\n * Optimistic Concurrency Control gate shared by updateData/deleteData.\n *\n * When the caller passes a non-empty `expectedVersion` token (typically\n * the `updated_at` value they read), this fetches the current record\n * and compares its `updated_at` against the token. Mismatch → throw\n * `ConcurrentUpdateError` which the REST layer maps to 409.\n *\n * Behaviour:\n * - Empty/missing token → no check (opt-in semantics; existing callers\n * that haven't yet adopted OCC are unaffected).\n * - Record not found → no check; downstream `engine.update` will\n * surface the usual `RECORD_NOT_FOUND` 404. We intentionally do not\n * treat \"missing record\" as a concurrency conflict.\n * - Record has no `updated_at` field (timestamps disabled) → no check.\n * Logging would be noisy here; OCC is opt-in and the absence of a\n * version column is an explicit \"this object doesn't support OCC\"\n * signal.\n */\n private async assertVersionMatch(\n object: string,\n id: string,\n expectedVersion: string | undefined,\n context: any\n ): Promise<void> {\n const expected = normaliseVersionToken(expectedVersion);\n if (!expected) return;\n const findOpts: any = { where: { id } };\n if (context !== undefined) findOpts.context = context;\n const current = await this.engine.findOne(object, findOpts);\n if (!current) return;\n const currentVersion = normaliseVersionToken((current as any).updated_at);\n if (!currentVersion) return;\n if (currentVersion !== expected) {\n throw new ConcurrentUpdateError({\n currentVersion,\n currentRecord: current,\n message: `Record ${object}/${id} was modified by another user (current version ${currentVersion}, expected ${expected})`,\n });\n }\n }\n\n // ==========================================\n // Global Search (M10.5)\n // ==========================================\n /**\n * Cross-object substring search across all registered objects that opt in\n * via `enable.searchable !== false` and `enable.apiEnabled !== false`.\n * Searches text-like fields (text/textarea/email/url/phone/markdown/html/string)\n * whose `searchable: true` flag is set, falling back to the object's\n * `displayNameField` (or `name`) when no fields are explicitly searchable.\n *\n * The query is split into whitespace-separated terms; each term must match\n * (case-insensitive LIKE) at least one searchable field. RBAC/RLS is\n * enforced by forwarding the caller's `context` to `engine.find` so users\n * only see records they are entitled to read.\n */\n async searchAll(request: {\n q: string;\n objects?: string[];\n limit?: number;\n perObject?: number;\n context?: any;\n }): Promise<{\n query: string;\n hits: Array<{\n object: string;\n id: string;\n title: string;\n snippet?: string;\n record: any;\n }>;\n totalObjects: number;\n totalHits: number;\n truncated: boolean;\n }> {\n const q = (request.q ?? '').trim();\n if (!q) {\n return { query: '', hits: [], totalObjects: 0, totalHits: 0, truncated: false };\n }\n\n const overallLimit = Math.max(1, Math.min(100, Number(request.limit ?? 20)));\n const perObject = Math.max(1, Math.min(25, Number(request.perObject ?? 5)));\n const objectsFilter = request.objects && request.objects.length\n ? new Set(request.objects)\n : null;\n\n // Tokenise: each token must match (LIKE %term%) at least one searchable field\n const terms = q.split(/\\s+/).filter(Boolean).slice(0, 8);\n\n const allObjects = (this.engine as any).registry?.getAllObjects?.() ?? [];\n const hits: Array<{ object: string; id: string; title: string; snippet?: string; record: any }> = [];\n let objectsScanned = 0;\n\n for (const obj of allObjects) {\n if (hits.length >= overallLimit) break;\n if (!obj?.name) continue;\n if (objectsFilter && !objectsFilter.has(obj.name)) continue;\n\n // Skip platform/system tables and opt-outs\n const enable = obj.enable ?? {};\n if (enable.searchable === false) continue;\n if (enable.apiEnabled === false) continue;\n // Skip noisy system tables by name prefix\n if (obj.name.startsWith('sys_audit_log')\n || obj.name.startsWith('sys_activity')\n || obj.name.startsWith('sys_session')\n || obj.name.startsWith('sys_presence')\n || obj.name.startsWith('sys_metadata')\n || obj.name.startsWith('sys_account')) {\n continue;\n }\n\n const fieldsRaw = obj.fields;\n const fields: Array<{ name: string; type: string; searchable?: boolean }> =\n Array.isArray(fieldsRaw)\n ? fieldsRaw\n : (fieldsRaw && typeof fieldsRaw === 'object'\n ? Object.entries(fieldsRaw).map(([name, f]: [string, any]) => ({ name, ...(f || {}) }))\n : []);\n const TEXT_TYPES = new Set(['text', 'textarea', 'string', 'email', 'url', 'phone', 'markdown', 'html']);\n const fieldByName = new Map(fields.map(f => [f.name, f]));\n const hasField = (n: string) => fieldByName.has(n);\n // Resolve title for a record using titleFormat → displayNameField →\n // common conventional fields → id. titleFormat supports simple\n // `{field}` placeholders (the `template` dialect); unresolved\n // placeholders fall through to the next strategy.\n const titleFormatSource = (obj.titleFormat && (obj.titleFormat.source || obj.titleFormat))\n || undefined;\n const renderTitle = (row: any): string => {\n if (typeof titleFormatSource === 'string') {\n let allResolved = true;\n const rendered = titleFormatSource.replace(/\\{\\{?\\s*([a-zA-Z0-9_.]+)\\s*\\}?\\}/g, (_m, key) => {\n const v = row[key];\n if (v == null || v === '') { allResolved = false; return ''; }\n return String(v);\n }).trim();\n if (rendered && allResolved) return rendered;\n if (rendered) return rendered.replace(/\\s+-\\s+$/, '').replace(/^\\s+-\\s+/, '').trim() || row.id;\n }\n const candidates = [\n obj.displayNameField,\n 'name', 'full_name', 'title', 'subject', 'label', 'company',\n ].filter((c): c is string => typeof c === 'string' && hasField(c));\n for (const c of candidates) {\n const v = row[c];\n if (v != null && String(v).trim()) return String(v);\n }\n const fn = row.first_name, ln = row.last_name;\n if (fn || ln) return `${fn ?? ''} ${ln ?? ''}`.trim();\n return String(row.id);\n };\n\n const titleFieldName = obj.displayNameField\n || (hasField('name') ? 'name' : undefined)\n || (hasField('title') ? 'title' : undefined)\n || fields.find(f => TEXT_TYPES.has(f.type))?.name;\n\n let searchableFields = fields\n .filter(f => f && TEXT_TYPES.has(f.type) && f.searchable === true)\n .map(f => f.name as string);\n\n // Fallback: if no field is explicitly searchable, scan the title field\n if (searchableFields.length === 0 && titleFieldName) {\n searchableFields = [titleFieldName];\n }\n if (searchableFields.length === 0) continue;\n\n objectsScanned++;\n\n // Build AND-of-OR filter: every term must hit at least one field.\n // ObjectQL exposes case-insensitive substring matching via `$contains`.\n const andClauses = terms.map(term => ({\n $or: searchableFields.map(f => ({ [f]: { $contains: term } })),\n }));\n const where = andClauses.length === 1 ? andClauses[0] : { $and: andClauses };\n\n try {\n const opts: any = {\n where,\n limit: perObject,\n orderBy: [{ field: 'updated_at', direction: 'desc' }],\n };\n if (request.context !== undefined) opts.context = request.context;\n\n const rows = await this.engine.find(obj.name, opts);\n for (const row of rows || []) {\n if (hits.length >= overallLimit) break;\n const title = renderTitle(row);\n // Build snippet from first searchable field that contains a term\n let snippet: string | undefined;\n for (const f of searchableFields) {\n const v = row[f];\n if (typeof v === 'string' && v) {\n const lc = v.toLowerCase();\n const idx = terms.map(t => lc.indexOf(t.toLowerCase())).find(i => i >= 0);\n if (idx != null && idx >= 0) {\n const start = Math.max(0, idx - 30);\n const end = Math.min(v.length, idx + 90);\n snippet = (start > 0 ? '…' : '') + v.slice(start, end) + (end < v.length ? '…' : '');\n break;\n }\n }\n }\n hits.push({\n object: obj.name,\n id: row.id,\n title,\n snippet,\n record: row,\n });\n }\n } catch {\n // RBAC denial or driver hiccup — skip silently per object\n continue;\n }\n }\n\n return {\n query: q,\n hits,\n totalObjects: objectsScanned,\n totalHits: hits.length,\n truncated: hits.length >= overallLimit,\n };\n }\n\n // ==========================================\n // Lead Convert (M10.6)\n // ==========================================\n /**\n * Convert a qualified Lead into an Account + Contact (+ optional\n * Opportunity) and mark the Lead as converted. Mirrors the Salesforce\n * lead-conversion model:\n *\n * - If `accountId` is provided, the lead's company info is NOT used\n * to create a new account; the new contact and opportunity link to\n * the existing account instead.\n * - If `contactId` is provided, no new contact is created either —\n * useful when the lead is a new contact at an existing account.\n * - `createOpportunity` defaults to true; pass `false` to convert\n * without producing an opportunity (some teams convert \"logos\n * only\" first).\n * - Lead is updated atomically: `is_converted=true`,\n * `converted_account`/`converted_contact`/`converted_opportunity`\n * pointers, `converted_date`, and `status='converted'`.\n *\n * Atomicity is enforced via the default driver's transaction support\n * when available; otherwise a best-effort compensation (delete\n * already-created child records on failure) is attempted. Permission\n * checks on each child object are inherited from the caller's\n * execution context so SecurityPlugin still gates account/contact/\n * opportunity creates.\n */\n async convertLead(request: {\n leadId: string;\n accountId?: string;\n contactId?: string;\n createOpportunity?: boolean;\n opportunity?: {\n name?: string;\n amount?: number;\n close_date?: string;\n stage?: string;\n };\n convertedStatus?: string;\n context?: any;\n }): Promise<{\n lead: any;\n account: any;\n contact: any;\n opportunity: any | null;\n }> {\n const leadId = String(request.leadId || '').trim();\n if (!leadId) {\n const err: any = new Error('leadId is required');\n err.status = 400;\n err.code = 'INVALID_REQUEST';\n throw err;\n }\n const ctx = request.context;\n const ctxOpt = ctx !== undefined ? { context: ctx } : undefined;\n\n // Load lead\n const lead = await this.engine.findOne('lead', { where: { id: leadId }, ...(ctxOpt as any) } as any);\n if (!lead) {\n const err: any = new Error(`Lead '${leadId}' not found`);\n err.status = 404;\n err.code = 'LEAD_NOT_FOUND';\n throw err;\n }\n if (lead.is_converted) {\n const err: any = new Error(`Lead '${leadId}' is already converted`);\n err.status = 409;\n err.code = 'LEAD_ALREADY_CONVERTED';\n throw err;\n }\n\n // Wrap the whole conversion in a single DB transaction so that a\n // partial failure (e.g. opportunity insert fails after we've\n // already created the account/contact) rolls back atomically\n // instead of leaving orphan rows. Falls back to direct execution\n // on drivers without transaction support — in that case the\n // operations are still ordered so callers see the same partial\n // state we'd get from any non-atomic sequence.\n const runConversion = async (trxCtx: any) => {\n const opCtx = trxCtx ?? ctx;\n const trxCtxOpt = opCtx !== undefined ? { context: opCtx } : undefined;\n\n // 1) Account\n let account: any;\n if (request.accountId) {\n account = await this.engine.findOne('account', { where: { id: request.accountId }, ...(trxCtxOpt as any) } as any);\n if (!account) {\n const err: any = new Error(`Account '${request.accountId}' not found`);\n err.status = 404;\n err.code = 'ACCOUNT_NOT_FOUND';\n throw err;\n }\n } else {\n const accountPayload: Record<string, any> = {\n name: lead.company || `${lead.first_name ?? ''} ${lead.last_name ?? ''}`.trim() || 'Untitled Account',\n };\n if (lead.industry) accountPayload.industry = lead.industry;\n if (lead.annual_revenue) accountPayload.annual_revenue = lead.annual_revenue;\n if (lead.number_of_employees) accountPayload.employees = lead.number_of_employees;\n if (lead.website) accountPayload.website = lead.website;\n if (lead.phone) accountPayload.phone = lead.phone;\n if (lead.address) accountPayload.billing_address = lead.address;\n if (lead.owner) accountPayload.owner = lead.owner;\n account = await this.engine.insert('account', accountPayload, trxCtxOpt as any);\n }\n\n // 2) Contact\n let contact: any;\n if (request.contactId) {\n contact = await this.engine.findOne('contact', { where: { id: request.contactId }, ...(trxCtxOpt as any) } as any);\n if (!contact) {\n const err: any = new Error(`Contact '${request.contactId}' not found`);\n err.status = 404;\n err.code = 'CONTACT_NOT_FOUND';\n throw err;\n }\n } else {\n const contactPayload: Record<string, any> = {\n first_name: lead.first_name ?? '',\n last_name: lead.last_name ?? lead.company ?? 'Unknown',\n };\n if (lead.salutation) contactPayload.salutation = lead.salutation;\n if (lead.email) contactPayload.email = lead.email;\n if (lead.phone) contactPayload.phone = lead.phone;\n if (lead.mobile) contactPayload.mobile = lead.mobile;\n if (lead.title) contactPayload.title = lead.title;\n if (lead.address) contactPayload.mailing_address = lead.address;\n if (lead.owner) contactPayload.owner = lead.owner;\n if (account?.id) contactPayload.account = account.id;\n contact = await this.engine.insert('contact', contactPayload, trxCtxOpt as any);\n }\n\n // 3) Opportunity (optional)\n let opportunity: any | null = null;\n const shouldCreateOpp = request.createOpportunity !== false;\n if (shouldCreateOpp) {\n const oppOverrides = request.opportunity ?? {};\n const defaultName = oppOverrides.name\n || `${account?.name ?? lead.company ?? 'Lead'} - New Opportunity`;\n const defaultClose = oppOverrides.close_date\n || new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);\n const oppPayload: Record<string, any> = {\n name: defaultName,\n stage: oppOverrides.stage ?? 'qualification',\n close_date: defaultClose,\n };\n if (oppOverrides.amount !== undefined) oppPayload.amount = oppOverrides.amount;\n else if (lead.annual_revenue) oppPayload.amount = lead.annual_revenue;\n if (account?.id) oppPayload.account = account.id;\n if (contact?.id) oppPayload.primary_contact = contact.id;\n if (lead.owner) oppPayload.owner = lead.owner;\n if (lead.lead_source) oppPayload.lead_source = lead.lead_source;\n opportunity = await this.engine.insert('opportunity', oppPayload, trxCtxOpt as any);\n }\n\n // 4) Mark lead converted\n const leadUpdate: Record<string, any> = {\n is_converted: true,\n status: request.convertedStatus ?? 'converted',\n converted_account: account?.id ?? null,\n converted_contact: contact?.id ?? null,\n converted_opportunity: opportunity?.id ?? null,\n converted_date: new Date().toISOString(),\n };\n const updatedLead = await this.engine.update('lead', leadUpdate, {\n where: { id: leadId },\n ...(trxCtxOpt as any),\n } as any);\n\n return {\n lead: updatedLead ?? { ...lead, ...leadUpdate },\n account,\n contact,\n opportunity,\n };\n };\n\n return (this.engine as any).transaction(runConversion, ctx);\n }\n\n // ==========================================\n // Metadata Caching\n // ==========================================\n\n async getMetaItemCached(request: { type: string, name: string, cacheRequest?: MetadataCacheRequest }): Promise<MetadataCacheResponse> {\n try {\n // Delegate to getMetaItem so the customization-overlay read order\n // (sys_metadata → registry → MetadataService) is honoured here too\n // (ADR-0005). Without this, cached reads silently bypass overlays.\n const result = await this.getMetaItem({ type: request.type, name: request.name });\n const item = (result as any)?.item;\n\n if (!item) {\n throw new Error(`Metadata item ${request.type}/${request.name} not found`);\n }\n\n // Calculate ETag (simple hash of the stringified metadata)\n const content = JSON.stringify(item);\n const hash = simpleHash(content);\n const etag = { value: hash, weak: false };\n\n // Check If-None-Match header\n if (request.cacheRequest?.ifNoneMatch) {\n const clientEtag = request.cacheRequest.ifNoneMatch.replace(/^\"(.*)\"$/, '$1').replace(/^W\\/\"(.*)\"$/, '$1');\n if (clientEtag === hash) {\n // Return 304 Not Modified\n return {\n notModified: true,\n etag,\n };\n }\n }\n\n // Return full metadata with cache headers\n return {\n data: item,\n etag,\n lastModified: new Date().toISOString(),\n cacheControl: {\n directives: ['public', 'max-age'],\n maxAge: 3600, // 1 hour\n },\n notModified: false,\n };\n } catch (error: any) {\n throw error;\n }\n }\n\n // ==========================================\n // Batch Operations\n // ==========================================\n\n async batchData(request: { object: string, request: BatchUpdateRequest }): Promise<BatchUpdateResponse> {\n const { object, request: batchReq } = request;\n const { operation, records, options } = batchReq;\n const results: Array<{ id?: string; success: boolean; error?: string; record?: any }> = [];\n let succeeded = 0;\n let failed = 0;\n\n for (const record of records) {\n try {\n switch (operation) {\n case 'create': {\n const created = await this.engine.insert(object, record.data || record);\n results.push({ id: created.id, success: true, record: created });\n succeeded++;\n break;\n }\n case 'update': {\n if (!record.id) throw new Error('Record id is required for update');\n const updated = await this.engine.update(object, record.data || {}, { where: { id: record.id } });\n results.push({ id: record.id, success: true, record: updated });\n succeeded++;\n break;\n }\n case 'upsert': {\n // Try update first, then create if not found\n if (record.id) {\n try {\n const existing = await this.engine.findOne(object, { where: { id: record.id } });\n if (existing) {\n const updated = await this.engine.update(object, record.data || {}, { where: { id: record.id } });\n results.push({ id: record.id, success: true, record: updated });\n } else {\n const created = await this.engine.insert(object, { id: record.id, ...(record.data || {}) });\n results.push({ id: created.id, success: true, record: created });\n }\n } catch {\n const created = await this.engine.insert(object, { id: record.id, ...(record.data || {}) });\n results.push({ id: created.id, success: true, record: created });\n }\n } else {\n const created = await this.engine.insert(object, record.data || record);\n results.push({ id: created.id, success: true, record: created });\n }\n succeeded++;\n break;\n }\n case 'delete': {\n if (!record.id) throw new Error('Record id is required for delete');\n await this.engine.delete(object, { where: { id: record.id } });\n results.push({ id: record.id, success: true });\n succeeded++;\n break;\n }\n default:\n results.push({ id: record.id, success: false, error: `Unknown operation: ${operation}` });\n failed++;\n }\n } catch (err: any) {\n results.push({ id: record.id, success: false, error: err.message });\n failed++;\n if (options?.atomic) {\n // Abort remaining operations on first failure in atomic mode\n break;\n }\n if (!options?.continueOnError) {\n break;\n }\n }\n }\n\n return {\n success: failed === 0,\n operation,\n total: records.length,\n succeeded,\n failed,\n results: options?.returnRecords !== false ? results : results.map(r => ({ id: r.id, success: r.success, error: r.error })),\n } as BatchUpdateResponse;\n }\n \n async createManyData(request: { object: string, records: any[] }): Promise<any> {\n const records = await this.engine.insert(request.object, request.records);\n return {\n object: request.object,\n records,\n count: records.length\n };\n }\n \n async updateManyData(request: UpdateManyDataRequest): Promise<BatchUpdateResponse> {\n const { object, records, options } = request;\n const results: Array<{ id?: string; success: boolean; error?: string; record?: any }> = [];\n let succeeded = 0;\n let failed = 0;\n\n for (const record of records) {\n try {\n const updated = await this.engine.update(object, record.data, { where: { id: record.id } });\n results.push({ id: record.id, success: true, record: updated });\n succeeded++;\n } catch (err: any) {\n results.push({ id: record.id, success: false, error: err.message });\n failed++;\n if (!options?.continueOnError) {\n break;\n }\n }\n }\n\n return {\n success: failed === 0,\n operation: 'update',\n total: records.length,\n succeeded,\n failed,\n results,\n } as BatchUpdateResponse;\n }\n\n async analyticsQuery(request: any): Promise<any> {\n // Map AnalyticsQuery (cube-style) to engine aggregation.\n // cube name maps to object name; measures → aggregations; dimensions → groupBy.\n const { query, cube } = request;\n const object = cube;\n\n // Build groupBy from dimensions\n const groupBy = query.dimensions || [];\n\n // Build aggregations from measures\n // Measures can be simple field names like \"count\" or \"field_name.sum\"\n // Or cube-defined measure names. We support: field.function or just function(field).\n const aggregations: Array<{ field: string; method: string; alias: string }> = [];\n if (query.measures) {\n for (const measure of query.measures) {\n // Support formats: \"count\", \"amount.sum\", \"revenue.avg\"\n if (measure === 'count' || measure === 'count_all') {\n aggregations.push({ field: '*', method: 'count', alias: 'count' });\n } else if (measure.includes('.')) {\n const [field, method] = measure.split('.');\n aggregations.push({ field, method, alias: `${field}_${method}` });\n } else {\n // Treat as count of the field\n aggregations.push({ field: measure, method: 'sum', alias: measure });\n }\n }\n }\n\n // Build filter from analytics filters\n let filter: any = undefined;\n if (query.filters && query.filters.length > 0) {\n const conditions: any[] = query.filters.map((f: any) => {\n const op = this.mapAnalyticsOperator(f.operator);\n if (f.values && f.values.length === 1) {\n return { [f.member]: { [op]: f.values[0] } };\n } else if (f.values && f.values.length > 1) {\n return { [f.member]: { $in: f.values } };\n }\n return { [f.member]: { [op]: true } };\n });\n filter = conditions.length === 1 ? conditions[0] : { $and: conditions };\n }\n\n // Execute via engine.aggregate (which delegates to driver.find with groupBy/aggregations)\n const rows = await this.engine.aggregate(object, {\n where: filter,\n groupBy: groupBy.length > 0 ? groupBy : undefined,\n aggregations: aggregations.length > 0\n ? aggregations.map(a => ({ function: a.method as any, field: a.field, alias: a.alias }))\n : [{ function: 'count' as any, alias: 'count' }],\n });\n\n // Build field metadata\n const fields = [\n ...groupBy.map((d: string) => ({ name: d, type: 'string' })),\n ...aggregations.map(a => ({ name: a.alias, type: 'number' })),\n ];\n\n return {\n success: true,\n data: {\n rows,\n fields,\n },\n };\n }\n\n async getAnalyticsMeta(request: any): Promise<any> {\n // Auto-generate cube metadata from registered objects in SchemaRegistry.\n // Each object becomes a cube; number fields → measures; other fields → dimensions.\n const objects = this.engine.registry.listItems('object');\n const cubeFilter = request?.cube;\n\n const cubes: any[] = [];\n for (const obj of objects) {\n const schema = obj as any;\n if (cubeFilter && schema.name !== cubeFilter) continue;\n\n const measures: Record<string, any> = {};\n const dimensions: Record<string, any> = {};\n const fields = schema.fields || {};\n\n // Always add a count measure\n measures['count'] = {\n name: 'count',\n label: 'Count',\n type: 'count',\n sql: '*',\n };\n\n for (const [fieldName, fieldDef] of Object.entries(fields)) {\n const fd = fieldDef as any;\n const fieldType = fd.type || 'text';\n\n if (['number', 'currency', 'percent'].includes(fieldType)) {\n // Numeric fields become both measures and dimensions\n measures[`${fieldName}_sum`] = {\n name: `${fieldName}_sum`,\n label: `${fd.label || fieldName} (Sum)`,\n type: 'sum',\n sql: fieldName,\n };\n measures[`${fieldName}_avg`] = {\n name: `${fieldName}_avg`,\n label: `${fd.label || fieldName} (Avg)`,\n type: 'avg',\n sql: fieldName,\n };\n dimensions[fieldName] = {\n name: fieldName,\n label: fd.label || fieldName,\n type: 'number',\n sql: fieldName,\n };\n } else if (['date', 'datetime'].includes(fieldType)) {\n dimensions[fieldName] = {\n name: fieldName,\n label: fd.label || fieldName,\n type: 'time',\n sql: fieldName,\n granularities: ['day', 'week', 'month', 'quarter', 'year'],\n };\n } else if (['boolean'].includes(fieldType)) {\n dimensions[fieldName] = {\n name: fieldName,\n label: fd.label || fieldName,\n type: 'boolean',\n sql: fieldName,\n };\n } else {\n // text, select, lookup, etc. → dimension\n dimensions[fieldName] = {\n name: fieldName,\n label: fd.label || fieldName,\n type: 'string',\n sql: fieldName,\n };\n }\n }\n\n cubes.push({\n name: schema.name,\n title: schema.label || schema.name,\n description: schema.description,\n sql: schema.name,\n measures,\n dimensions,\n public: true,\n });\n }\n\n return {\n success: true,\n data: { cubes },\n };\n }\n\n private mapAnalyticsOperator(op: string): string {\n const map: Record<string, string> = {\n equals: '$eq',\n notEquals: '$ne',\n contains: '$contains',\n notContains: '$notContains',\n gt: '$gt',\n gte: '$gte',\n lt: '$lt',\n lte: '$lte',\n set: '$ne',\n notSet: '$eq',\n };\n return map[op] || '$eq';\n }\n\n async triggerAutomation(_request: any): Promise<any> {\n throw new Error('triggerAutomation requires plugin-automation service. Install and register a plugin that provides the \"automation\" service.');\n }\n\n async deleteManyData(request: DeleteManyDataRequest): Promise<any> {\n // This expects deleting by IDs.\n return this.engine.delete(request.object, {\n where: { id: { $in: request.ids } },\n ...request.options\n });\n }\n\n /**\n * Metadata types that are customer-overridable via {@link saveMetaItem}/\n * {@link deleteMetaItem} in project-kernel mode. Derived from the canonical\n * registry in {@link DEFAULT_METADATA_TYPE_REGISTRY}: a type opts in by\n * setting `allowOrgOverride: true` on its registry entry. The set is\n * augmented with the plural form of every singular so callers using REST\n * conventions (`/api/v1/meta/views/...`) get the same gate. See ADR-0005\n * §\"Whitelist enforcement\" for the rationale and the per-type rollout\n * checklist.\n */\n private static readonly OVERLAY_ALLOWED_TYPES: ReadonlySet<string> = (() => {\n const out = new Set<string>();\n for (const entry of DEFAULT_METADATA_TYPE_REGISTRY) {\n if (!entry.allowOrgOverride) continue;\n out.add(entry.type);\n const plural = SINGULAR_TO_PLURAL[entry.type];\n if (plural) out.add(plural);\n }\n return out;\n })();\n\n /** Normalize plural→singular before consulting the allow-list. */\n private static isOverlayAllowed(type: string): boolean {\n const singular = PLURAL_TO_SINGULAR[type] ?? type;\n return ObjectStackProtocolImplementation.OVERLAY_ALLOWED_TYPES.has(singular)\n || ObjectStackProtocolImplementation.OVERLAY_ALLOWED_TYPES.has(type);\n }\n\n /**\n * Mirror an object-type overlay write into the in-memory engine\n * registry so subsequent CRUD finds the new schema. Idempotent and\n * safe to call after a successful persistence call. For the legacy\n * write path this is invoked BEFORE persistence (historical behavior\n * preserved); for the PR-10d.3 repository path it is invoked only\n * AFTER `put()` resolves successfully, so a failed write — DB error,\n * optimistic-lock conflict, validation failure — never leaks a\n * stale schema into the registry.\n */\n private applyObjectRegistryMutation(request: { type: string; name: string; item?: any }): void {\n if (request.type !== 'object' && request.type !== 'objects') return;\n this.engine.registry.registerItem(request.type, request.item, 'name');\n try {\n this.engine.registry.registerObject(request.item as any, 'sys_metadata');\n } catch (err: any) {\n console.warn(\n `[Protocol] registerObject failed for ${request.name}: ${err?.message ?? err}`,\n );\n }\n }\n\n async saveMetaItem(request: { type: string, name: string, item?: any, organizationId?: string, parentVersion?: string | null, actor?: string }) {\n if (!request.item) {\n throw new Error('Item data is required');\n }\n\n // ADR-0005 opt-in gate: project-kernel customization is only allowed\n // for types whose registry entry sets `allowOrgOverride: true`.\n // Returns 403 `not_overridable` so the caller can distinguish from a\n // generic 400 (validation) or 422 (spec mismatch).\n if (this.projectId !== undefined\n && !ObjectStackProtocolImplementation.isOverlayAllowed(request.type)) {\n const allowed = Array.from(ObjectStackProtocolImplementation.OVERLAY_ALLOWED_TYPES).join(', ');\n const err = new Error(\n `[not_overridable] Metadata type '${request.type}' has not opted into per-org overlay writes. `\n + `Set allowOrgOverride: true on its DEFAULT_METADATA_TYPE_REGISTRY entry to enable. `\n + `Currently allowed: ${allowed}. See docs/adr/0005-metadata-customization-overlay.md.`\n );\n (err as any).code = 'not_overridable';\n (err as any).status = 403;\n throw err;\n }\n\n // Spec-conformance check: if a Zod schema is registered for this\n // overlay type (see OVERLAY_VALIDATION_SCHEMAS), validate the payload\n // before persisting. We surface invalid payloads as `422\n // invalid_metadata` with structured Zod issues so the Studio form can\n // highlight the offending field. The original `item` is kept verbatim\n // — `parsed.data` would strip Studio-only auxiliary fields (e.g.\n // isPinned, isDefault, sortOrder) that intentionally ride along with\n // the overlay document. ADR-0005 §\"Validation\".\n {\n const schema = resolveOverlaySchema(request.type, request.item);\n if (schema) {\n const parsed = schema.safeParse(request.item);\n if (!parsed.success) {\n const issues = parsed.error.issues.map((i: z.ZodIssue) => ({\n path: i.path.join('.'),\n message: i.message,\n code: i.code,\n }));\n const summary = issues.slice(0, 3)\n .map((i: { path: string; message: string }) => `${i.path || '<root>'}: ${i.message}`)\n .join('; ');\n const err = new Error(\n `[invalid_metadata] ${request.type}/${request.name} failed spec validation: ${summary}`\n + (issues.length > 3 ? ` (+${issues.length - 3} more)` : '')\n );\n (err as any).code = 'invalid_metadata';\n (err as any).status = 422;\n (err as any).issues = issues;\n throw err;\n }\n }\n }\n\n // 1. Update the in-memory registry (runtime cache) ONLY for the\n // `object` type — schema definitions feed engine.syncSchema and\n // must be reflected immediately for CRUD to work. For all other\n // metadata types (view, dashboard, ...) we deliberately do NOT\n // mutate the artifact-loaded registry — sys_metadata is the\n // authoritative overlay store and `getMetaItem` consults it\n // first (ADR-0005). Mutating the registry here would create a\n // \"stale overlay\" hazard: `deleteMetaItem` cannot restore the\n // original artifact value because it was overwritten in-place.\n // 1. (deferred) — Object-type runtime-registry mutation used to happen\n // here unconditionally. Moved to AFTER successful persistence\n // (PR-10d.3 rubber-duck #3): a failed put() — DB error, optimistic\n // conflict, validation — must not leave a stale object schema in\n // the in-memory registry. See `applyObjectRegistryMutation` below.\n\n // 2. Persist to sys_metadata as a customization overlay row.\n // ADR-0005 (revised 2026-05): isolation key is `organization_id`\n // (each env = its own DB, so project_id is redundant). Org-scoped\n // rows belong to the active organization in the request; env-wide\n // overlays are written with organization_id = NULL.\n await this.ensureOverlayIndex();\n\n // ADR-0008 — overlay-allowed metadata types ALWAYS route through the\n // repository write path: every mutation appends to the change log\n // and emits a watch event with a monotonic `seq` (which Studio /\n // browser clients consume for HMR). Non-overlay-allowed types\n // (`object`, `flow`, `agent`, ...) take the legacy raw-engine path\n // below — this preserves the control-plane bootstrap semantic where\n // `saveMetaItem` is permitted by the outer protocol gate to write\n // any metadata type when `projectId` is undefined (the repository's\n // `assertAllowed()` would 403 those writes).\n //\n // PR-10d.6 (this PR) removed the `useRepositoryWritePath` flag.\n // For overlay-allowed types the repo path is no longer opt-out-able.\n //\n // Callers that omit `parentVersion` get backward-compatible\n // \"last-write-wins\" semantics: we read the current row's checksum\n // and use it as the parent, so the conflict check tautologically\n // passes (best-effort — racy under concurrent writes; explicit\n // optimistic-lock is opt-in via `parentVersion`).\n // Callers that pass an explicit `parentVersion` (e.g. Studio after\n // reading an item) get true optimistic-lock conflict detection\n // surfaced as a 409.\n const singularTypeForRepo = PLURAL_TO_SINGULAR[request.type] ?? request.type;\n if (ObjectStackProtocolImplementation.isOverlayAllowed(singularTypeForRepo)) {\n const orgId = request.organizationId ?? null;\n const repo = this.getOverlayRepo(orgId);\n const ref = {\n type: singularTypeForRepo,\n name: request.name,\n org: orgId ?? 'env',\n } as Parameters<typeof repo.put>[0];\n let parentVersion: string | null;\n if (request.parentVersion !== undefined) {\n parentVersion = request.parentVersion;\n } else {\n const current = await repo.get(ref);\n parentVersion = current?.hash ?? null;\n }\n try {\n const result = await repo.put(ref, request.item, {\n parentVersion,\n actor: request.actor ?? 'system',\n source: 'protocol.saveMetaItem',\n });\n // Persistence succeeded — NOW it's safe to mutate the\n // in-memory object registry. If put() had thrown, the\n // registry would still reflect the prior state.\n this.applyObjectRegistryMutation(request);\n return {\n success: true,\n version: result.version,\n seq: result.seq,\n message: orgId\n ? `Saved customization overlay (org=${orgId}) — type=${request.type}, name=${request.name} [seq=${result.seq}]`\n : `Saved customization overlay (env-wide) — type=${request.type}, name=${request.name} [seq=${result.seq}]`,\n };\n } catch (err: any) {\n if (err instanceof ConflictError) {\n const conflict = new Error(\n `[metadata_conflict] ${request.type}/${request.name} has been modified since you loaded it. `\n + `Expected parent ${err.expectedParent ?? 'null'} but current is ${err.actualHead ?? 'null'}.`,\n );\n (conflict as any).code = 'metadata_conflict';\n (conflict as any).status = 409;\n (conflict as any).expectedParent = err.expectedParent;\n (conflict as any).actualHead = err.actualHead;\n throw conflict;\n }\n throw err;\n }\n }\n\n // Legacy raw-engine path — taken when the type is NOT overlay-allowed\n // (control-plane bootstrap of `object`/`flow`/etc. when `projectId` is\n // undefined). This branch is intentionally retained: the repository\n // write path's `assertAllowed()` would 403 these types. There is no\n // change-log / HMR machinery for non-overlay metadata because\n // control-plane mutations are bootstrap-only and not subject to\n // per-org overlay semantics.\n //\n // Note: the registry mutation for the legacy path happens BEFORE\n // persistence (preserved historical behaviour). The overlay-allowed\n // path moved it to AFTER persistence in PR-10d.3 (rubber-duck #3).\n this.applyObjectRegistryMutation(request);\n\n try {\n const now = new Date().toISOString();\n const orgId = request.organizationId ?? null;\n const scopedWhere: Record<string, unknown> = {\n type: request.type,\n name: request.name,\n organization_id: orgId,\n state: 'active',\n };\n const existing = await this.engine.findOne('sys_metadata', {\n where: scopedWhere,\n });\n\n if (existing) {\n await this.engine.update('sys_metadata', {\n metadata: JSON.stringify(request.item),\n updated_at: now,\n version: (existing.version || 0) + 1,\n state: 'active',\n }, {\n where: { id: existing.id }\n });\n } else {\n // Use crypto.randomUUID() when available (modern browsers and Node ≥ 14.17);\n // fall back to a time+random ID for older or restricted environments.\n const id = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `meta_${Date.now()}_${Math.random().toString(36).slice(2)}`;\n const row: Record<string, unknown> = {\n id,\n name: request.name,\n type: request.type,\n // `scope` enum is ['system','platform','user']; per-org\n // overlays use 'platform' as the informational tag. The\n // authoritative isolation key is `organization_id`.\n scope: 'platform',\n metadata: JSON.stringify(request.item),\n state: 'active',\n version: 1,\n created_at: now,\n updated_at: now,\n organization_id: orgId,\n };\n await this.engine.insert('sys_metadata', row);\n }\n\n return {\n success: true,\n message: orgId\n ? `Saved customization overlay (org=${orgId}) — type=${request.type}, name=${request.name}`\n : `Saved customization overlay (env-wide) — type=${request.type}, name=${request.name}`,\n };\n } catch (dbError: any) {\n // DB write failed — surface as an error rather than silently\n // succeeding (regression from the pre-ADR-0005 \"silent loss\" bug).\n console.error(\n `[Protocol] sys_metadata persistence failed for ${request.type}/${request.name}: ${dbError.message}`,\n );\n const err = new Error(\n `Failed to persist customization overlay to sys_metadata: ${dbError.message}. `\n + `In-memory registry was updated but will be lost on restart.`,\n );\n (err as any).code = 'overlay_persistence_failed';\n (err as any).status = 500;\n throw err;\n }\n }\n\n /**\n * Yield the durable change-log for a single metadata item — every\n * put/delete recorded in `sys_metadata_history` for `(org, type, name)`,\n * in event_seq order. Powers the Studio \"History\" tab and any\n * client-side audit timeline.\n *\n * Returns `[]` for non-overlay-allowed types (the legacy raw-engine\n * path doesn't record history) instead of throwing — callers can treat\n * \"no history\" uniformly.\n */\n async historyMetaItem(request: {\n type: string;\n name: string;\n organizationId?: string;\n sinceSeq?: number;\n limit?: number;\n }): Promise<{ events: import('@objectstack/metadata-core').MetadataEvent[] }> {\n const singularType = PLURAL_TO_SINGULAR[request.type] ?? request.type;\n if (!ObjectStackProtocolImplementation.isOverlayAllowed(singularType)) {\n return { events: [] };\n }\n const orgId = request.organizationId ?? null;\n const repo = this.getOverlayRepo(orgId);\n const ref = {\n type: singularType,\n name: request.name,\n org: orgId ?? 'env',\n } as Parameters<typeof repo.history>[0];\n\n const events: import('@objectstack/metadata-core').MetadataEvent[] = [];\n const opts: { sinceSeq?: number; limit?: number } = {};\n if (request.sinceSeq !== undefined) opts.sinceSeq = request.sinceSeq;\n if (request.limit !== undefined) opts.limit = request.limit;\n for await (const ev of repo.history(ref, opts)) events.push(ev);\n return { events };\n }\n\n /**\n * Remove a customization overlay row for the given metadata item, so the\n * next read falls through to the artifact-loaded default. Implements the\n * \"Reset to factory default\" semantic from ADR-0005. Whitelist is shared\n * with {@link saveMetaItem}.\n */\n async deleteMetaItem(request: {\n type: string;\n name: string;\n organizationId?: string;\n parentVersion?: string | null;\n actor?: string;\n }): Promise<{\n success: boolean;\n message?: string;\n reset?: boolean;\n seq?: number;\n }> {\n if (this.projectId !== undefined\n && !ObjectStackProtocolImplementation.isOverlayAllowed(request.type)) {\n const err = new Error(\n `[not_overridable] Metadata type '${request.type}' has not opted into per-org overlay writes. `\n + `See docs/adr/0005-metadata-customization-overlay.md.`\n );\n (err as any).code = 'not_overridable';\n (err as any).status = 403;\n throw err;\n }\n\n const singularTypeForRepo = PLURAL_TO_SINGULAR[request.type] ?? request.type;\n const useRepoPath = ObjectStackProtocolImplementation.isOverlayAllowed(singularTypeForRepo);\n\n // ADR-0008 — overlay-allowed types route through SysMetadataRepository\n // so the delete (a) is wrapped in engine.transaction(), (b) appends a\n // tombstone row to sys_metadata_history, and (c) emits a watch event\n // with a monotonic `seq` for HMR. Non-overlay-allowed types (only\n // reachable in control-plane bootstrap mode where projectId is\n // undefined) take the legacy raw-engine path below — the repository's\n // `assertAllowed()` whitelist would 403 those deletes.\n if (useRepoPath) {\n const orgId = request.organizationId ?? null;\n const repo = this.getOverlayRepo(orgId);\n const ref = {\n type: singularTypeForRepo,\n name: request.name,\n org: orgId ?? 'env',\n } as Parameters<typeof repo.delete>[0];\n\n try {\n // Probe first — \"no overlay exists\" is a success/no-op, not\n // a conflict. The repo would otherwise throw ConflictError.\n const current = await repo.get(ref);\n if (!current) {\n return {\n success: true,\n reset: false,\n message: `No customization overlay found for ${request.type}/${request.name} — already at artifact default.`,\n };\n }\n\n // Last-write-wins parent resolution unless the caller pinned\n // an explicit version (Studio's \"Reset\" button is unpinned;\n // a future \"delete vN\" flow can pass parentVersion).\n const parentVersion: string = request.parentVersion !== undefined\n ? (request.parentVersion ?? current.hash)\n : current.hash;\n\n const result = await repo.delete(ref, {\n parentVersion,\n actor: request.actor ?? 'system',\n source: 'protocol.deleteMetaItem',\n });\n\n // Refresh the in-memory artifact-side state on control-plane\n // kernels (same logic as the legacy branch — see comments\n // there for why this only runs when projectId === undefined).\n if (this.projectId === undefined) {\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.get === 'function') {\n const artifactItem = await metadataService.get(request.type, request.name);\n if (artifactItem !== undefined) {\n this.engine.registry.registerItem(request.type, artifactItem, 'name');\n }\n }\n } catch {\n // Best-effort registry refresh; next read fixes it anyway\n }\n }\n\n return {\n success: true,\n reset: true,\n seq: result.seq,\n message: `Customization overlay deleted — ${request.type}/${request.name} reset to artifact default. [seq=${result.seq}]`,\n };\n } catch (err: any) {\n if (err instanceof ConflictError) {\n const conflict = new Error(\n `[metadata_conflict] ${request.type}/${request.name} has been modified since you loaded it. `\n + `Expected parent ${err.expectedParent ?? 'null'} but current is ${err.actualHead ?? 'null'}.`,\n );\n (conflict as any).code = 'metadata_conflict';\n (conflict as any).status = 409;\n (conflict as any).expectedParent = err.expectedParent;\n (conflict as any).actualHead = err.actualHead;\n throw conflict;\n }\n const e = new Error(`Failed to delete customization overlay: ${err.message ?? err}`);\n (e as any).status = err?.status ?? 500;\n throw e;\n }\n }\n\n // ── Legacy raw-engine path: only reachable in control-plane bootstrap\n // (projectId === undefined) for non-overlay-allowed types like\n // `object`, `flow`, `agent`. No history row, no watch event — these\n // types don't participate in the change-log model.\n const scopedWhere: Record<string, unknown> = {\n type: request.type,\n name: request.name,\n organization_id: request.organizationId ?? null,\n };\n\n try {\n const existing = await this.engine.findOne('sys_metadata', { where: scopedWhere });\n if (!existing) {\n return {\n success: true,\n reset: false,\n message: `No customization overlay found for ${request.type}/${request.name} — already at artifact default.`,\n };\n }\n await this.engine.delete('sys_metadata', { where: { id: existing.id } });\n\n if (this.projectId === undefined) {\n try {\n const services = this.getServicesRegistry?.();\n const metadataService = services?.get('metadata');\n if (metadataService && typeof metadataService.get === 'function') {\n const artifactItem = await metadataService.get(request.type, request.name);\n if (artifactItem !== undefined) {\n this.engine.registry.registerItem(request.type, artifactItem, 'name');\n }\n }\n } catch {\n // Best-effort registry refresh; next read fixes it anyway\n }\n }\n\n return {\n success: true,\n reset: true,\n message: `Customization overlay deleted — ${request.type}/${request.name} reset to artifact default.`,\n };\n } catch (err: any) {\n const e = new Error(`Failed to delete customization overlay: ${err.message}`);\n (e as any).status = 500;\n throw e;\n }\n }\n\n /**\n * Hydrate SchemaRegistry from the database on startup.\n * Loads all active metadata records and registers them in the in-memory registry.\n * Safe to call repeatedly — idempotent (latest DB record wins).\n *\n * Per ADR-0005, project-kernel mode ALSO hydrates from sys_metadata —\n * customization overlay rows must survive restart. Scope filter\n * (`project_id = this.projectId ?? null`) keeps tenants isolated.\n */\n async loadMetaFromDb(): Promise<{ loaded: number; errors: number }> {\n let loaded = 0;\n let errors = 0;\n try {\n // ADR-0005 (revised 2026-05): hydrate only env-wide rows\n // (organization_id IS NULL). Per-org overlays are loaded on\n // demand by getMetaItem to avoid cross-org leakage into the\n // process-wide SchemaRegistry.\n const where: Record<string, unknown> = {\n state: 'active',\n organization_id: null,\n };\n const records = await this.engine.find('sys_metadata', { where });\n for (const record of records) {\n try {\n const data = typeof record.metadata === 'string'\n ? JSON.parse(record.metadata)\n : record.metadata;\n // Normalize DB type to singular (DB may store legacy plural forms)\n const normalizedType = PLURAL_TO_SINGULAR[record.type] ?? record.type;\n if (normalizedType === 'object') {\n this.engine.registry.registerObject(data as any, record.packageId || 'sys_metadata');\n } else {\n this.engine.registry.registerItem(normalizedType, data, 'name' as any);\n }\n loaded++;\n } catch (e) {\n errors++;\n console.warn(`[Protocol] Failed to hydrate ${record.type}/${record.name}: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n } catch (e: any) {\n // \"no such table\" is expected on first run before migrations execute — not an error.\n if (!/no such table/i.test(e.message ?? '')) {\n console.warn(`[Protocol] DB hydration skipped: ${e.message}`);\n }\n }\n return { loaded, errors };\n }\n\n // ==========================================\n // Feed Operations\n // ==========================================\n\n async listFeed(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const result = await svc.listFeed({\n object: request.object,\n recordId: request.recordId,\n filter: request.type,\n limit: request.limit,\n cursor: request.cursor,\n });\n return { success: true, data: result };\n }\n\n async createFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.createFeedItem({\n object: request.object,\n recordId: request.recordId,\n type: request.type,\n actor: { type: 'user', id: 'current_user' },\n body: request.body,\n mentions: request.mentions,\n parentId: request.parentId,\n visibility: request.visibility,\n });\n return { success: true, data: item };\n }\n\n async updateFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.updateFeedItem(request.feedId, {\n body: request.body,\n mentions: request.mentions,\n visibility: request.visibility,\n });\n return { success: true, data: item };\n }\n\n async deleteFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n await svc.deleteFeedItem(request.feedId);\n return { success: true, data: { feedId: request.feedId } };\n }\n\n async addReaction(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const reactions = await svc.addReaction(request.feedId, request.emoji, 'current_user');\n return { success: true, data: { reactions } };\n }\n\n async removeReaction(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const reactions = await svc.removeReaction(request.feedId, request.emoji, 'current_user');\n return { success: true, data: { reactions } };\n }\n\n async pinFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.getFeedItem(request.feedId);\n if (!item) throw new Error(`Feed item ${request.feedId} not found`);\n // IFeedService doesn't have dedicated pin/unpin — use updateFeedItem to persist pin state\n await svc.updateFeedItem(request.feedId, { visibility: item.visibility });\n return { success: true, data: { feedId: request.feedId, pinned: true, pinnedAt: new Date().toISOString() } };\n }\n\n async unpinFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.getFeedItem(request.feedId);\n if (!item) throw new Error(`Feed item ${request.feedId} not found`);\n await svc.updateFeedItem(request.feedId, { visibility: item.visibility });\n return { success: true, data: { feedId: request.feedId, pinned: false } };\n }\n\n async starFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.getFeedItem(request.feedId);\n if (!item) throw new Error(`Feed item ${request.feedId} not found`);\n // IFeedService doesn't have dedicated star/unstar — verify item exists then return state\n await svc.updateFeedItem(request.feedId, { visibility: item.visibility });\n return { success: true, data: { feedId: request.feedId, starred: true, starredAt: new Date().toISOString() } };\n }\n\n async unstarFeedItem(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const item = await svc.getFeedItem(request.feedId);\n if (!item) throw new Error(`Feed item ${request.feedId} not found`);\n await svc.updateFeedItem(request.feedId, { visibility: item.visibility });\n return { success: true, data: { feedId: request.feedId, starred: false } };\n }\n\n async searchFeed(request: any): Promise<any> {\n const svc = this.requireFeedService();\n // Search delegates to listFeed with filter since IFeedService doesn't have a dedicated search\n const result = await svc.listFeed({\n object: request.object,\n recordId: request.recordId,\n filter: request.type,\n limit: request.limit,\n cursor: request.cursor,\n });\n // Filter by query text in body\n const queryLower = (request.query || '').toLowerCase();\n const filtered = result.items.filter((item: any) =>\n item.body?.toLowerCase().includes(queryLower)\n );\n return { success: true, data: { items: filtered, total: filtered.length, hasMore: false } };\n }\n\n async getChangelog(request: any): Promise<any> {\n const svc = this.requireFeedService();\n // Changelog retrieves field_change type feed items\n const result = await svc.listFeed({\n object: request.object,\n recordId: request.recordId,\n filter: 'changes_only',\n limit: request.limit,\n cursor: request.cursor,\n });\n const entries = result.items.map((item: any) => ({\n id: item.id,\n object: item.object,\n recordId: item.recordId,\n actor: item.actor,\n changes: item.changes || [],\n timestamp: item.createdAt,\n source: item.source,\n }));\n return { success: true, data: { entries, total: result.total, nextCursor: result.nextCursor, hasMore: result.hasMore } };\n }\n\n async feedSubscribe(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const subscription = await svc.subscribe({\n object: request.object,\n recordId: request.recordId,\n userId: 'current_user',\n events: request.events,\n channels: request.channels,\n });\n return { success: true, data: subscription };\n }\n\n async feedUnsubscribe(request: any): Promise<any> {\n const svc = this.requireFeedService();\n const unsubscribed = await svc.unsubscribe(request.object, request.recordId, 'current_user');\n return { success: true, data: { object: request.object, recordId: request.recordId, unsubscribed } };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { QueryAST, HookContext, ServiceObject } from '@objectstack/spec/data';\nimport {\n EngineQueryOptions,\n DataEngineInsertOptions,\n EngineUpdateOptions,\n EngineDeleteOptions,\n EngineAggregateOptions,\n EngineCountOptions\n} from '@objectstack/spec/data';\nimport { ExecutionContext, ExecutionContextSchema } from '@objectstack/spec/kernel';\nimport { DriverInterface, IDataEngine, Logger, createLogger } from '@objectstack/core';\nimport { CoreServiceName, StorageNameMapping } from '@objectstack/spec/system';\nimport { IRealtimeService, RealtimeEventPayload } from '@objectstack/spec/contracts';\nimport { pluralToSingular } from '@objectstack/spec/shared';\nimport { SchemaRegistry, computeFQN } from './registry.js';\nimport { ExpressionEngine } from '@objectstack/formula';\nimport type { Expression } from '@objectstack/spec';\nimport { bindHooksToEngine } from './hook-binder.js';\nimport { validateRecord } from './validation/record-validator.js';\nimport { applyInMemoryAggregation } from './in-memory-aggregation.js';\n\ninterface FormulaPlanEntry { name: string; expression: Expression; }\n\nfunction planFormulaProjection(\n schema: any,\n requestedFields: string[] | undefined\n): { plan: FormulaPlanEntry[]; projected?: string[] } {\n if (!schema?.fields) return { plan: [] };\n const allFieldNames = Object.keys(schema.fields);\n // When no explicit projection, evaluate every formula field on the schema —\n // matches REST default of \"return everything\". Explicit projection still\n // honours the caller's selection.\n const targets = (Array.isArray(requestedFields) && requestedFields.length > 0)\n ? requestedFields\n : allFieldNames;\n const plan: FormulaPlanEntry[] = [];\n const projected = new Set<string>();\n for (const f of targets) {\n const def = (schema.fields as any)[f];\n if (def?.type === 'formula' && def.expression) {\n // Normalize string-shorthand → Expression envelope (M9 transition).\n const expr: Expression = typeof def.expression === 'string'\n ? { dialect: 'cel', source: def.expression }\n : def.expression;\n plan.push({ name: f, expression: expr });\n // Pre-compile to surface syntax errors at planning stage rather than\n // per-row eval. Dependency discovery (which fields the formula reads)\n // is no longer used — CEL uses dynamic projection via `record.<field>`.\n ExpressionEngine.compile(expr);\n } else if (Array.isArray(requestedFields) && requestedFields.length > 0) {\n projected.add(f);\n }\n }\n if (plan.length === 0) return { plan: [] };\n // For formulas: project all schema fields so CEL `record.<field>` lookups\n // see complete data. Static dependency analysis on AST is M9.7 work.\n if (Array.isArray(requestedFields) && requestedFields.length > 0) {\n if (!projected.has('id')) projected.add('id');\n for (const fname of allFieldNames) {\n // Skip formula fields themselves — they are virtual and not\n // projectable by the underlying driver. Without this guard the\n // SQL driver emits `SELECT response_rate ...` which fails as\n // \"no such column\" and the driver returns [] (silently).\n const fdef = (schema.fields as any)[fname];\n if (fdef?.type === 'formula') continue;\n projected.add(fname);\n }\n return { plan, projected: Array.from(projected) };\n }\n // Implicit/full projection — leave projected undefined so the driver\n // returns its default columns (typically *).\n return { plan };\n}\n\nfunction applyFormulaPlan(plan: FormulaPlanEntry[], records: any[]): void {\n if (!plan.length) return;\n for (const rec of records) {\n if (rec == null) continue;\n for (const fp of plan) {\n const r = ExpressionEngine.evaluate(fp.expression, { record: rec });\n rec[fp.name] = r.ok ? r.value : null;\n }\n }\n}\n\nexport type HookHandler = (context: HookContext) => Promise<void> | void;\n\n/**\n * Per-object hook entry with priority support\n */\nexport interface HookEntry {\n handler: HookHandler;\n object?: string | string[]; // undefined = global hook\n priority: number;\n packageId?: string;\n /**\n * Original metadata-form `Hook` definition this entry was bound from\n * (when registered via `bindHooksToEngine`). Pure code-paths that call\n * `engine.registerHook` directly leave this undefined.\n */\n meta?: any;\n /** Hook `name` from metadata; used for diagnostics & deduplication. */\n hookName?: string;\n}\n\n/** Function registry entry — see `registerFunction`. */\ninterface FunctionEntry {\n handler: HookHandler;\n packageId?: string;\n}\n\n/**\n * Operation Context for Middleware Chain\n */\nexport interface OperationContext {\n object: string;\n operation: 'find' | 'findOne' | 'insert' | 'update' | 'delete' | 'count' | 'aggregate';\n ast?: QueryAST;\n data?: any;\n options?: any;\n context?: ExecutionContext;\n result?: any;\n}\n\n/**\n * Engine Middleware (Onion model)\n */\nexport type EngineMiddleware = (\n ctx: OperationContext,\n next: () => Promise<void>\n) => Promise<void>;\n\n/**\n * Host Context provided to plugins (Internal ObjectQL Plugin System)\n */\nexport interface ObjectQLHostContext {\n ql: ObjectQL;\n logger: Logger;\n // Extensible map for host-specific globals (like HTTP Router, etc.)\n [key: string]: any;\n}\n\n/**\n * Derive the registry key for a metadata item.\n *\n * Most metadata items expose a top-level `name` (or `id`). The `View`\n * container defined by `@objectstack/spec/ui` is special: it aggregates\n * `list / form / listViews / formViews` for a single object and is\n * keyed implicitly by its target object name (see `data.object`).\n *\n * Per spec, `ViewSchema` does NOT have a top-level `name` field\n * (view.zod.ts), so we resolve it from the inner data source. This\n * matches the server-side metadata API contract (`/api/v1/meta/views/:object`).\n */\nfunction resolveMetadataItemName(key: string, item: any): string | undefined {\n if (!item) return undefined;\n if (item.name) return item.name;\n if (item.id) return item.id;\n if (key === 'views') {\n return (\n item?.list?.data?.object ||\n item?.form?.data?.object ||\n undefined\n );\n }\n return undefined;\n}\n\n/**\n * ObjectQL Engine\n * \n * Implements the IDataEngine interface for data persistence.\n * Acts as the reference implementation for:\n * - CoreServiceName.data (CRUD)\n * - CoreServiceName.metadata (Schema Registry)\n */\nexport class ObjectQL implements IDataEngine {\n private drivers = new Map<string, DriverInterface>();\n private defaultDriver: string | null = null;\n private logger: Logger;\n\n // Datasource mapping rules (imported from defineStack)\n private datasourceMapping: Array<{\n namespace?: string;\n package?: string;\n objectPattern?: string;\n default?: boolean;\n datasource: string;\n priority?: number;\n }> = [];\n\n // Package manifests registry (for defaultDatasource lookup)\n private manifests = new Map<string, any>();\n\n // Per-object hooks with priority support\n private hooks: Map<string, HookEntry[]> = new Map([\n ['beforeFind', []], ['afterFind', []],\n ['beforeInsert', []], ['afterInsert', []],\n ['beforeUpdate', []], ['afterUpdate', []],\n ['beforeDelete', []], ['afterDelete', []],\n ]);\n\n // Middleware chain (onion model)\n private middlewares: Array<{\n fn: EngineMiddleware;\n object?: string;\n }> = [];\n\n // Action registry: key = \"objectName:actionName\"\n private actions = new Map<string, { handler: (ctx: any) => Promise<any> | any; package?: string }>();\n\n // Function registry: name → handler. Used by `bindHooksToEngine` to\n // resolve string-named hook handlers (the JSON-safe form). Populated by\n // `defineStack({ functions })` via `AppPlugin`, or directly via\n // `engine.registerFunction(...)`.\n private functions = new Map<string, FunctionEntry>();\n\n // Host provided context additions (e.g. Server router)\n private hostContext: Record<string, any> = {};\n\n // Realtime service for event publishing\n private realtimeService?: IRealtimeService;\n\n // Per-engine SchemaRegistry instance.\n //\n // Historically SchemaRegistry was a process-wide singleton of static state,\n // which broke multi-project servers: a project kernel would inherit every\n // object registered by the control plane (e.g. sys_metadata), and\n // getDriver()'s owner lookup would route CRUD to the wrong database. Each\n // engine now owns its registry so kernels are fully isolated.\n private _registry: SchemaRegistry = new SchemaRegistry();\n\n constructor(hostContext: Record<string, any> = {}) {\n this.hostContext = hostContext;\n // Use provided logger or create a new one\n this.logger = hostContext.logger || createLogger({ level: 'info', format: 'pretty' });\n // Pick up production hardening switches from env so deployers can\n // enforce strict-body without code changes:\n // OBJECTQL_STRICT_HOOKS=1 → unresolved hooks throw at bind time\n // OBJECTQL_WARN_LEGACY_HANDLER=1 → log a deprecation per legacy bind\n if (process?.env?.OBJECTQL_STRICT_HOOKS === '1') {\n (this as any)._strictHookBinding = true;\n }\n if (process?.env?.OBJECTQL_WARN_LEGACY_HANDLER === '1') {\n (this as any)._warnLegacyHandler = true;\n }\n this.logger.info('ObjectQL Engine Instance Created');\n }\n\n /**\n * Service Status Report\n * Used by Kernel to verify health and capabilities.\n */\n getStatus() {\n return {\n name: CoreServiceName.enum.data,\n status: 'running',\n version: '0.9.0',\n features: ['crud', 'query', 'aggregate', 'transactions', 'metadata']\n };\n }\n\n /**\n * Expose the SchemaRegistry for plugins to register metadata.\n *\n * Returns the per-engine instance, NOT the class. Each ObjectQL engine\n * owns its registry so multi-project kernels remain isolated.\n */\n get registry(): SchemaRegistry {\n return this._registry;\n }\n\n /**\n * Load and Register a Plugin\n */\n async use(manifestPart: any, runtimePart?: any) {\n this.logger.debug('Loading plugin', { \n hasManifest: !!manifestPart, \n hasRuntime: !!runtimePart \n });\n\n // 1. Validate / Register Manifest\n if (manifestPart) {\n this.registerApp(manifestPart);\n }\n\n // 2. Execute Runtime\n if (runtimePart) {\n const pluginDef = (runtimePart as any).default || runtimePart;\n if (pluginDef.onEnable) {\n this.logger.debug('Executing plugin runtime onEnable');\n \n const context: ObjectQLHostContext = {\n ql: this,\n logger: this.logger,\n // Expose the driver registry helper explicitly if needed\n drivers: {\n register: (driver: DriverInterface) => this.registerDriver(driver)\n },\n ...this.hostContext\n };\n \n await pluginDef.onEnable(context);\n this.logger.debug('Plugin runtime onEnable completed');\n }\n }\n }\n\n /**\n * Register a hook\n * @param event The event name (e.g. 'beforeFind', 'afterInsert')\n * @param handler The handler function\n * @param options Optional: target object(s) and priority\n */\n registerHook(event: string, handler: HookHandler, options?: {\n object?: string | string[];\n priority?: number;\n packageId?: string;\n /** Original metadata Hook definition (set by `bindHooksToEngine`). */\n meta?: any;\n /** Stable name from metadata (set by `bindHooksToEngine`). */\n hookName?: string;\n }) {\n if (!this.hooks.has(event)) {\n this.hooks.set(event, []);\n }\n const entries = this.hooks.get(event)!;\n entries.push({\n handler,\n object: options?.object,\n priority: options?.priority ?? 100,\n packageId: options?.packageId,\n meta: options?.meta,\n hookName: options?.hookName,\n });\n // Sort by priority (lower runs first)\n entries.sort((a, b) => a.priority - b.priority);\n this.logger.debug('Registered hook', { event, object: options?.object, priority: options?.priority ?? 100, totalHandlers: entries.length });\n }\n\n /**\n * Remove all hooks registered under a given `packageId`. Used by\n * `bindHooksToEngine` to make re-binding (hot reload, app reinstall)\n * idempotent, and by app uninstall flows.\n */\n unregisterHooksByPackage(packageId: string): number {\n if (!packageId) return 0;\n let removed = 0;\n for (const [event, entries] of this.hooks.entries()) {\n const before = entries.length;\n const kept = entries.filter((e) => e.packageId !== packageId);\n if (kept.length !== before) {\n this.hooks.set(event, kept);\n removed += before - kept.length;\n }\n }\n if (removed > 0) {\n this.logger.debug('Unregistered hooks by package', { packageId, removed });\n }\n return removed;\n }\n\n /**\n * Register a named function handler that can later be referenced by\n * string from a `Hook.handler` field. This is the JSON-safe form of\n * handler binding — declarative metadata persisted to disk or shipped\n * over the wire only carries the name.\n */\n registerFunction(name: string, handler: HookHandler, packageId?: string): void {\n if (!name || typeof handler !== 'function') return;\n this.functions.set(name, { handler, packageId });\n this.logger.debug('Registered function', { name, packageId });\n }\n\n /** Look up a registered function by name. */\n resolveFunction(name: string): HookHandler | undefined {\n return this.functions.get(name)?.handler;\n }\n\n /** Remove all functions registered under a given `packageId`. */\n unregisterFunctionsByPackage(packageId: string): number {\n if (!packageId) return 0;\n let removed = 0;\n for (const [name, entry] of this.functions.entries()) {\n if (entry.packageId === packageId) {\n this.functions.delete(name);\n removed += 1;\n }\n }\n if (removed > 0) {\n this.logger.debug('Unregistered functions by package', { packageId, removed });\n }\n return removed;\n }\n\n /**\n * Bind a list of declarative `Hook` metadata definitions to this engine.\n *\n * Convenience proxy to the canonical `bindHooksToEngine` so callers do\n * not need a separate import. Use `import { bindHooksToEngine } from\n * '@objectstack/objectql'` directly when you want the result object.\n */\n bindHooks(hooks: any[] | undefined, opts?: {\n packageId?: string;\n functions?: Record<string, HookHandler>;\n bodyRunner?: any;\n strict?: boolean;\n warnLegacyHandler?: boolean;\n metrics?: any;\n }): void {\n const merged = { ...(opts ?? {}), logger: this.logger } as any;\n if (!merged.bodyRunner && (this as any)._defaultBodyRunner) {\n merged.bodyRunner = (this as any)._defaultBodyRunner;\n }\n if (merged.strict === undefined && (this as any)._strictHookBinding) {\n merged.strict = true;\n }\n if (merged.warnLegacyHandler === undefined && (this as any)._warnLegacyHandler) {\n merged.warnLegacyHandler = true;\n }\n if (!merged.metrics && (this as any)._hookMetricsRecorder) {\n merged.metrics = (this as any)._hookMetricsRecorder;\n }\n bindHooksToEngine(this, hooks, merged);\n }\n\n /**\n * Install a default body-runner used when `bindHooks` is called without\n * an explicit one. The runtime layer sets this once on each per-project\n * engine so every binding path (template seed, metadata sync, AppPlugin)\n * can execute hook `body.source` consistently.\n */\n setDefaultBodyRunner(runner: any): void {\n (this as any)._defaultBodyRunner = runner;\n }\n\n /**\n * Toggle strict hook-binding mode for this engine. When enabled, every\n * subsequent `bindHooks` call rejects on the first unresolved hook\n * instead of silently warning. Production runtimes should enable this.\n */\n setStrictHookBinding(strict: boolean): void {\n (this as any)._strictHookBinding = strict;\n }\n\n /** Toggle deprecation warnings for hooks still using legacy `handler` ref. */\n setWarnLegacyHandler(warn: boolean): void {\n (this as any)._warnLegacyHandler = warn;\n }\n\n /**\n * Install a metrics recorder used by every subsequent `bindHooks` call.\n * The recorder's methods are invoked per-execution to count outcomes\n * (success / error / timeout / capability_rejected), skips, and retries.\n * Defaults to no-op so the engine pays zero cost when nobody is observing.\n */\n setHookMetricsRecorder(recorder: any): void {\n (this as any)._hookMetricsRecorder = recorder;\n }\n\n /** Read the engine's installed metrics recorder, if any. */\n getHookMetricsRecorder(): any {\n return (this as any)._hookMetricsRecorder;\n }\n\n public async triggerHooks(event: string, context: HookContext) {\n const entries = this.hooks.get(event) || [];\n \n if (entries.length === 0) {\n this.logger.debug('No hooks registered for event', { event });\n return;\n }\n\n this.logger.debug('Triggering hooks', { event, count: entries.length });\n \n for (const entry of entries) {\n // Per-object matching\n if (entry.object) {\n const targets = Array.isArray(entry.object) ? entry.object : [entry.object];\n if (!targets.includes('*') && !targets.includes(context.object)) {\n continue; // Skip non-matching hooks\n }\n }\n await entry.handler(context);\n }\n }\n\n // ========================================\n // Action System\n // ========================================\n\n /**\n * Register a named action on an object.\n * Actions are custom business logic callable via `repo.execute(actionName, params)`.\n *\n * @param objectName Target object\n * @param actionName Unique action name within the object\n * @param handler Handler function\n * @param packageName Optional package owner (for cleanup)\n */\n registerAction(objectName: string, actionName: string, handler: (ctx: any) => Promise<any> | any, packageName?: string): void {\n const key = `${objectName}:${actionName}`;\n this.actions.set(key, { handler, package: packageName });\n this.logger.debug('Registered action', { objectName, actionName, package: packageName });\n }\n\n /**\n * Execute a named action on an object.\n */\n async executeAction(objectName: string, actionName: string, ctx: any): Promise<any> {\n const entry = this.actions.get(`${objectName}:${actionName}`);\n if (!entry) {\n throw new Error(`Action '${actionName}' on object '${objectName}' not found`);\n }\n return entry.handler(ctx);\n }\n\n /**\n * Remove all actions registered by a specific package.\n */\n removeActionsByPackage(packageName: string): void {\n for (const [key, entry] of this.actions.entries()) {\n if (entry.package === packageName) {\n this.actions.delete(key);\n }\n }\n }\n\n /**\n * Register a middleware function\n * Middlewares execute in onion model around every data operation.\n * @param fn The middleware function\n * @param options Optional: target object filter\n */\n registerMiddleware(fn: EngineMiddleware, options?: { object?: string }): void {\n this.middlewares.push({ fn, object: options?.object });\n this.logger.debug('Registered middleware', { object: options?.object, total: this.middlewares.length });\n }\n\n /**\n * Execute an operation through the middleware chain\n */\n private async executeWithMiddleware(ctx: OperationContext, executor: () => Promise<any>): Promise<any> {\n const applicable = this.middlewares.filter(m =>\n !m.object || m.object === '*' || m.object === ctx.object\n );\n\n let index = 0;\n const next = async (): Promise<void> => {\n if (index < applicable.length) {\n const mw = applicable[index++];\n await mw.fn(ctx, next);\n } else {\n ctx.result = await executor();\n }\n };\n\n await next();\n return ctx.result;\n }\n\n /**\n * Build a HookContext.session from ExecutionContext\n */\n private buildSession(execCtx?: ExecutionContext): HookContext['session'] {\n if (!execCtx) return undefined;\n return {\n userId: execCtx.userId,\n tenantId: execCtx.tenantId,\n roles: execCtx.roles,\n accessToken: execCtx.accessToken,\n // Propagate system-elevated flag so hooks can distinguish engine\n // self-writes (e.g. approval status mirror) from genuine user writes.\n ...((execCtx as any).isSystem ? { isSystem: true } : {}),\n } as HookContext['session'];\n }\n\n /**\n * Build the DriverOptions blob passed to every IDataDriver call.\n *\n * Always carries `tenantId` from the active ExecutionContext so the\n * driver can enforce per-tenant isolation (SQL driver auto-scopes reads\n * and auto-injects the tenant column on writes). Existing user-supplied\n * shapes (transactions, AST extras) are preserved by spreading them\n * first.\n *\n * System / isSystem callers may still cross tenants by clearing\n * `tenantId` themselves on the resulting object; this helper does not\n * mask the system path.\n */\n private buildDriverOptions(execCtx?: ExecutionContext, base?: any): any {\n const hasTx = execCtx?.transaction !== undefined;\n const hasTenant = execCtx?.tenantId !== undefined;\n const isSystem = execCtx?.isSystem === true;\n if (!hasTx && !hasTenant && !isSystem) return base;\n const opts: any = base && typeof base === 'object' ? { ...base } : {};\n if (hasTx && opts.transaction === undefined) {\n opts.transaction = execCtx!.transaction;\n }\n if (hasTenant && opts.tenantId === undefined) {\n opts.tenantId = execCtx!.tenantId;\n }\n if (isSystem && opts.bypassTenantAudit === undefined) {\n // System-elevated writes (boot-time seeds, internal mirrors, scheduled\n // hooks) are unscoped by design — silence the audit warn for them but\n // still flag genuine user-path bugs.\n opts.bypassTenantAudit = true;\n }\n return opts;\n }\n\n /**\n * Build a HookContext.api: a ScopedContext that hooks can use to\n * read/write other objects within the same execution context.\n * Falls back to a system-elevated empty context when no execCtx\n * is supplied (e.g. system-triggered hooks).\n */\n private buildHookApi(execCtx?: ExecutionContext): ScopedContext {\n const safeCtx: ExecutionContext = execCtx ?? ({ isSystem: true } as any);\n return new ScopedContext(safeCtx, this as unknown as IDataEngine);\n }\n\n /**\n * Apply field defaults to an incoming insert payload. Defaults that are\n * Expression envelopes (e.g. `{ dialect: 'cel', source: 'today()' }`,\n * `{ dialect: 'cel', source: 'os.user.id' }`) are evaluated via\n * `ExpressionEngine` against the calling user/org/now snapshot. Static\n * defaults are applied verbatim. Records that already supplied a value for a\n * field are left untouched.\n *\n * Implements ROADMAP §M9.9b — `defaultValue` accepts Expression so authors\n * can replace \"write a hook to default to today/current-user\" with a\n * declarative `defaultValue: cel\\`today()\\``.\n */\n private applyFieldDefaults(\n object: string,\n record: Record<string, unknown>,\n execCtx?: ExecutionContext,\n nowSnapshot?: Date,\n ): Record<string, unknown> {\n const schema = this.getSchema(object);\n const fieldsRaw = (schema as any)?.fields;\n if (!fieldsRaw || typeof fieldsRaw !== 'object') return record;\n // `fields` may be a Record<string, Field> (canonical) or an array (legacy).\n const fieldEntries: Array<{ name: string; defaultValue?: unknown }> = Array.isArray(fieldsRaw)\n ? fieldsRaw\n : Object.entries(fieldsRaw).map(([name, def]) => ({ name, ...(def as object) }));\n const out = { ...record };\n const now = nowSnapshot ?? new Date();\n for (const f of fieldEntries) {\n if (out[f.name] !== undefined) continue;\n if (f.defaultValue == null) continue;\n const dv = f.defaultValue;\n if (typeof dv === 'object' && dv !== null && (dv as any).dialect && typeof (dv as any).source === 'string') {\n const result = ExpressionEngine.evaluate(dv as any, {\n now,\n user: execCtx?.userId ? { id: String(execCtx.userId), role: execCtx?.roles?.[0] } : undefined,\n org: execCtx?.tenantId ? { id: String(execCtx.tenantId) } : undefined,\n record: out,\n extra: { object },\n });\n if (result.ok) {\n out[f.name] = result.value as unknown;\n } else {\n this.logger.warn('Failed to evaluate default expression', {\n object, field: f.name, error: result.error,\n });\n }\n } else {\n out[f.name] = dv;\n }\n }\n return out;\n }\n\n /**\n * Register contribution (Manifest)\n * \n * Installs the manifest as a Package (the unit of installation),\n * then decomposes it into individual metadata items (objects, apps, actions, etc.)\n * and registers each into the SchemaRegistry.\n * \n * Key: Package ≠ App. The manifest is the package. The apps[] array inside\n * the manifest contains UI navigation definitions (AppSchema).\n */\n registerApp(manifest: any) {\n const id = manifest.id || manifest.name;\n const namespace = manifest.namespace as string | undefined;\n this.logger.debug('Registering package manifest', { id, namespace });\n console.warn(`[ObjectQL:registerApp] id=${id} flows=${Array.isArray(manifest.flows) ? manifest.flows.length : typeof manifest.flows} keys=${Object.keys(manifest).join(',')}`);\n\n // Store manifest for defaultDatasource lookup\n if (id) {\n this.manifests.set(id, manifest);\n }\n\n // 1. Register the Package (manifest + lifecycle state)\n this._registry.installPackage(manifest);\n this.logger.debug('Installed Package', { id: manifest.id, name: manifest.name, namespace });\n\n // 2. Register owned objects\n if (manifest.objects) {\n if (Array.isArray(manifest.objects)) {\n this.logger.debug('Registering objects from manifest (Array)', { id, objectCount: manifest.objects.length });\n for (const objDef of manifest.objects) {\n const fqn = this._registry.registerObject(objDef, id, namespace, 'own');\n this.logger.debug('Registered Object', { fqn, from: id });\n }\n } else {\n this.logger.debug('Registering objects from manifest (Map)', { id, objectCount: Object.keys(manifest.objects).length });\n for (const [name, objDef] of Object.entries(manifest.objects)) {\n // Ensure name in definition matches key\n (objDef as any).name = name;\n const fqn = this._registry.registerObject(objDef as any, id, namespace, 'own');\n this.logger.debug('Registered Object', { fqn, from: id });\n }\n }\n }\n\n // 2b. Register object extensions (fields added to objects owned by other packages)\n if (Array.isArray(manifest.objectExtensions) && manifest.objectExtensions.length > 0) {\n this.logger.debug('Registering object extensions', { id, count: manifest.objectExtensions.length });\n for (const ext of manifest.objectExtensions) {\n const targetFqn = ext.extend;\n const priority = ext.priority ?? 200;\n // Create a partial object definition for the extension\n const extDef = {\n name: targetFqn, // Use the target FQN as name\n fields: ext.fields,\n label: ext.label,\n pluralLabel: ext.pluralLabel,\n description: ext.description,\n validations: ext.validations,\n indexes: ext.indexes,\n };\n // Register as extension (namespace is undefined since we're targeting by FQN)\n this._registry.registerObject(extDef as any, id, undefined, 'extend', priority);\n this.logger.debug('Registered Object Extension', { target: targetFqn, priority, from: id });\n }\n }\n\n // 3. Register apps (UI navigation definitions) as their own metadata type\n // Resolve short objectName references in navigation to FQN so the\n // Console UI can match them against the object registry.\n if (Array.isArray(manifest.apps) && manifest.apps.length > 0) {\n this.logger.debug('Registering apps from manifest', { id, count: manifest.apps.length });\n for (const app of manifest.apps) {\n const appName = app.name || app.id;\n if (appName) {\n const resolved = namespace ? this.resolveNavObjectNames(app, namespace) : app;\n this._registry.registerApp(resolved, id);\n this.logger.debug('Registered App', { app: appName, from: id });\n }\n }\n }\n\n // 4. If manifest itself looks like an App (has navigation), also register as app\n // This handles the case where the manifest IS the app definition (legacy/simple packages)\n if (manifest.name && manifest.navigation && !manifest.apps?.length) {\n const resolved = namespace ? this.resolveNavObjectNames(manifest, namespace) : manifest;\n this._registry.registerApp(resolved, id);\n this.logger.debug('Registered manifest-as-app', { app: manifest.name, from: id });\n }\n\n // 5. Register all other metadata types generically\n const metadataArrayKeys = [\n // UI Protocol\n 'actions', 'views', 'pages', 'dashboards', 'reports', 'themes',\n // Automation Protocol\n 'flows', 'workflows', 'approvals', 'webhooks',\n // Security Protocol\n 'roles', 'permissions', 'profiles', 'sharingRules', 'policies',\n // AI Protocol\n 'agents', 'ragPipelines',\n // API Protocol\n 'apis',\n // Data Extensions\n 'hooks', 'mappings', 'analyticsCubes',\n // Integration Protocol\n 'connectors',\n ];\n for (const key of metadataArrayKeys) {\n const items = (manifest as any)[key];\n if (Array.isArray(items) && items.length > 0) {\n this.logger.debug(`Registering ${key} from manifest`, { id, count: items.length });\n for (const item of items) {\n const itemName = resolveMetadataItemName(key, item);\n if (itemName) {\n const toRegister = item.name === itemName ? item : { ...item, name: itemName };\n this._registry.registerItem(pluralToSingular(key), toRegister, 'name' as any, id);\n } else {\n this.logger.warn(`Skipping ${pluralToSingular(key)} without a derivable name`, { id });\n }\n }\n }\n }\n\n // 6. Register seed data as metadata (keyed by target object name)\n const seedData = (manifest as any).data;\n if (Array.isArray(seedData) && seedData.length > 0) {\n this.logger.debug('Registering seed data datasets', { id, count: seedData.length });\n for (const dataset of seedData) {\n if (dataset.object) {\n this._registry.registerItem('data', dataset, 'object' as any, id);\n }\n }\n }\n\n // 6. Register contributions\n if (manifest.contributes?.kinds) {\n this.logger.debug('Registering kinds from manifest', { id, kindCount: manifest.contributes.kinds.length });\n for (const kind of manifest.contributes.kinds) {\n this._registry.registerKind(kind);\n this.logger.debug('Registered Kind', { kind: kind.name || kind.type, from: id });\n }\n }\n\n // 7. Recursively register nested plugins\n if (Array.isArray(manifest.plugins) && manifest.plugins.length > 0) {\n this.logger.debug('Processing nested plugins', { id, count: manifest.plugins.length });\n for (const plugin of manifest.plugins) {\n if (plugin && typeof plugin === 'object') {\n const pluginName = plugin.name || plugin.id || 'unnamed-plugin';\n this.logger.debug('Registering nested plugin', { pluginName, parentId: id });\n this.registerPlugin(plugin, id, namespace);\n }\n }\n }\n }\n\n /**\n * Deep-clone an app definition, resolving objectName references in navigation\n * items via the registry. Object names are canonical identifiers — no FQN\n * expansion is applied.\n */\n private resolveNavObjectNames(app: any, namespace: string): any {\n if (!app.navigation) return app;\n\n const resolveItems = (items: any[]): any[] =>\n items.map((item: any) => {\n const resolved = { ...item };\n if (resolved.objectName && !resolved.objectName.includes('__')) {\n resolved.objectName = computeFQN(namespace, resolved.objectName);\n }\n if (Array.isArray(resolved.children)) {\n resolved.children = resolveItems(resolved.children);\n }\n return resolved;\n });\n\n return { ...app, navigation: resolveItems(app.navigation) };\n }\n\n /**\n * Register a nested plugin's metadata (objects, actions, views, etc.)\n *\n * Unlike registerApp(), this does NOT call SchemaRegistry.installPackage()\n * because plugins are not formal manifests — they are lightweight config\n * bundles with objects, actions, triggers, and navigation.\n *\n * @param plugin - The plugin config object\n * @param parentId - The parent package ID (for ownership tracking)\n * @param parentNamespace - The parent package's namespace (for FQN resolution)\n */\n private registerPlugin(plugin: any, parentId: string, parentNamespace?: string) {\n const pluginName = plugin.name || plugin.id || 'unnamed';\n const pluginNamespace = plugin.namespace || parentNamespace;\n\n // Use parentId as the owning package for namespace consistency.\n // The parent package already claimed the namespace — nested plugins\n // contribute objects UNDER the parent's ownership.\n const ownerId = parentId;\n\n // Register objects (supports both Array and Map formats)\n if (plugin.objects) {\n try {\n if (Array.isArray(plugin.objects)) {\n this.logger.debug('Registering plugin objects (Array)', { pluginName, count: plugin.objects.length });\n for (const objDef of plugin.objects) {\n const fqn = this._registry.registerObject(objDef, ownerId, pluginNamespace, 'own');\n this.logger.debug('Registered Object', { fqn, from: pluginName });\n }\n } else {\n const entries = Object.entries(plugin.objects);\n this.logger.debug('Registering plugin objects (Map)', { pluginName, count: entries.length });\n for (const [name, objDef] of entries) {\n (objDef as any).name = name;\n const fqn = this._registry.registerObject(objDef as any, ownerId, pluginNamespace, 'own');\n this.logger.debug('Registered Object', { fqn, from: pluginName });\n }\n }\n } catch (err: any) {\n this.logger.warn('Failed to register plugin objects', { pluginName, error: err.message });\n }\n }\n\n // Register plugin as app if it has navigation (for sidebar display)\n if (plugin.name && plugin.navigation) {\n try {\n const resolved = pluginNamespace ? this.resolveNavObjectNames(plugin, pluginNamespace) : plugin;\n this._registry.registerApp(resolved, ownerId);\n this.logger.debug('Registered plugin-as-app', { app: plugin.name, from: pluginName });\n } catch (err: any) {\n this.logger.warn('Failed to register plugin as app', { pluginName, error: err.message });\n }\n }\n\n // Register metadata arrays (actions, views, triggers, etc.)\n const metadataArrayKeys = [\n 'actions', 'views', 'pages', 'dashboards', 'reports', 'themes',\n 'flows', 'workflows', 'approvals', 'webhooks',\n 'roles', 'permissions', 'profiles', 'sharingRules', 'policies',\n 'agents', 'ragPipelines', 'apis',\n 'hooks', 'mappings', 'analyticsCubes', 'connectors',\n ];\n for (const key of metadataArrayKeys) {\n const items = (plugin as any)[key];\n if (Array.isArray(items) && items.length > 0) {\n for (const item of items) {\n const itemName = resolveMetadataItemName(key, item);\n if (itemName) {\n const toRegister = item.name === itemName ? item : { ...item, name: itemName };\n this._registry.registerItem(pluralToSingular(key), toRegister, 'name' as any, ownerId);\n }\n }\n }\n }\n }\n\n /**\n * Register a new storage driver\n */\n registerDriver(driver: DriverInterface, isDefault: boolean = false) {\n if (this.drivers.has(driver.name)) {\n this.logger.warn('Driver already registered, skipping', { driverName: driver.name });\n return;\n }\n\n this.drivers.set(driver.name, driver);\n this.logger.info('Registered driver', {\n driverName: driver.name,\n version: driver.version\n });\n\n if (isDefault || this.drivers.size === 1) {\n this.defaultDriver = driver.name;\n this.logger.info('Set default driver', { driverName: driver.name });\n }\n }\n\n /**\n * Set the realtime service for publishing data change events.\n * Should be called after kernel resolves the realtime service.\n *\n * @param service - An IRealtimeService instance for event publishing\n */\n setRealtimeService(service: IRealtimeService): void {\n this.realtimeService = service;\n this.logger.info('RealtimeService configured for data events');\n }\n\n /**\n * Helper to get object definition\n */\n getSchema(objectName: string): ServiceObject | undefined {\n return this._registry.getObject(objectName);\n }\n\n /**\n * Resolve any object identifier to the physical storage name used by drivers.\n *\n * Accepts the canonical short name (e.g., 'account') or, for explicit\n * cross-package disambiguation, the canonical object name (e.g., 'account'). The result is\n * the physical table name derived via `StorageNameMapping.resolveTableName`.\n */\n private resolveObjectName(name: string): string {\n const schema = this._registry.getObject(name);\n if (schema) {\n return StorageNameMapping.resolveTableName(schema);\n }\n // Return name as-is (canonical name = table name; no FQN prefix to strip)\n return StorageNameMapping.resolveTableName({ name });\n }\n\n /**\n * Helper to get the target driver\n *\n * Resolution priority (first match wins):\n * 1. Object's explicit `datasource` field (if not 'default')\n * 2. DatasourceMapping rules (namespace/package/pattern matching)\n * 3. Package's `defaultDatasource` from manifest\n * 4. Global default driver\n */\n private getDriver(objectName: string): DriverInterface {\n const object = this._registry.getObject(objectName);\n\n // 1. Object's explicit datasource field (highest priority)\n if (object?.datasource && object.datasource !== 'default') {\n if (this.drivers.has(object.datasource)) {\n return this.drivers.get(object.datasource)!;\n }\n throw new Error(`[ObjectQL] Datasource '${object.datasource}' configured for object '${objectName}' is not registered.`);\n }\n\n // 2. Check datasourceMapping rules\n const mappedDatasource = this.resolveDatasourceFromMapping(objectName, object);\n if (mappedDatasource && this.drivers.has(mappedDatasource)) {\n this.logger.debug('Resolved datasource from mapping', {\n object: objectName,\n datasource: mappedDatasource\n });\n return this.drivers.get(mappedDatasource)!;\n }\n\n // 3. Check package's defaultDatasource\n // Use the object's FQN name (from getObject) for ownership lookup\n const fqn = object?.name || objectName;\n const owner = this._registry.getObjectOwner(fqn);\n if (owner?.packageId) {\n const manifest = this.manifests.get(owner.packageId);\n if (manifest?.defaultDatasource && manifest.defaultDatasource !== 'default') {\n if (this.drivers.has(manifest.defaultDatasource)) {\n this.logger.debug('Resolved datasource from package manifest', {\n object: objectName,\n package: owner.packageId,\n datasource: manifest.defaultDatasource\n });\n return this.drivers.get(manifest.defaultDatasource)!;\n }\n }\n }\n\n // 4. Fallback to global default driver\n if (this.defaultDriver && this.drivers.has(this.defaultDriver)) {\n return this.drivers.get(this.defaultDriver)!;\n }\n\n throw new Error(`[ObjectQL] No driver available for object '${objectName}'`);\n }\n\n /**\n * Resolve datasource from mapping rules\n *\n * Rules are evaluated in order (or by priority if specified).\n * First matching rule wins.\n */\n private resolveDatasourceFromMapping(\n objectName: string,\n object?: any\n ): string | null {\n if (!this.datasourceMapping || this.datasourceMapping.length === 0) {\n return null;\n }\n\n // Sort rules by priority if any have priority set\n const sortedRules = [...this.datasourceMapping].sort((a, b) => {\n const aPriority = a.priority ?? 1000;\n const bPriority = b.priority ?? 1000;\n return aPriority - bPriority;\n });\n\n for (const rule of sortedRules) {\n // 1. Match by namespace\n if (rule.namespace && object?.namespace === rule.namespace) {\n return rule.datasource;\n }\n\n // 2. Match by package ID\n if (rule.package && object?.packageId === rule.package) {\n return rule.datasource;\n }\n\n // 3. Match by object name pattern (glob-style)\n if (rule.objectPattern && this.matchPattern(objectName, rule.objectPattern)) {\n return rule.datasource;\n }\n\n // 4. Default fallback rule\n if (rule.default) {\n return rule.datasource;\n }\n }\n\n return null;\n }\n\n /**\n * Simple glob pattern matching\n * Supports * (any chars) and ? (single char)\n */\n private matchPattern(objectName: string, pattern: string): boolean {\n const regexPattern = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex special chars\n .replace(/\\*/g, '.*') // * → .*\n .replace(/\\?/g, '.'); // ? → .\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(objectName);\n }\n\n /**\n * Set datasource mapping rules\n * Called by ObjectQLPlugin during bootstrap\n */\n setDatasourceMapping(rules: Array<{\n namespace?: string;\n package?: string;\n objectPattern?: string;\n default?: boolean;\n datasource: string;\n priority?: number;\n }>) {\n this.datasourceMapping = rules;\n this.logger.info('Datasource mapping rules configured', {\n ruleCount: rules.length\n });\n }\n\n /**\n * Initialize the engine and all registered drivers\n */\n async init() {\n this.logger.info('Initializing ObjectQL engine', { \n driverCount: this.drivers.size,\n drivers: Array.from(this.drivers.keys())\n });\n \n const failedDrivers: string[] = [];\n for (const [name, driver] of this.drivers) {\n try {\n await driver.connect();\n this.logger.info('Driver connected successfully', { driverName: name });\n } catch (e) {\n failedDrivers.push(name);\n this.logger.error('Failed to connect driver', e as Error, { driverName: name });\n }\n }\n\n if (failedDrivers.length > 0) {\n this.logger.warn(\n `${failedDrivers.length} of ${this.drivers.size} driver(s) failed initial connect. ` +\n `Operations may recover via lazy reconnection or fail at query time.`,\n { failedDrivers }\n );\n }\n \n this.logger.info('ObjectQL engine initialization complete');\n }\n\n async destroy() {\n this.logger.info('Destroying ObjectQL engine', { driverCount: this.drivers.size });\n \n for (const [name, driver] of this.drivers.entries()) {\n try {\n await driver.disconnect();\n } catch (e) {\n this.logger.error('Error disconnecting driver', e as Error, { driverName: name });\n }\n }\n \n this.logger.info('ObjectQL engine destroyed');\n }\n\n // ============================================\n // Helper: Expand Related Records\n // ============================================\n\n /** Maximum depth for recursive expand to prevent infinite loops */\n private static readonly MAX_EXPAND_DEPTH = 3;\n\n /**\n * Post-process expand: resolve lookup/master_detail fields by batch-loading related records.\n * \n * This is a driver-agnostic implementation that uses secondary queries ($in batches)\n * to load related records, then injects them into the result set.\n * \n * @param objectName - The source object name\n * @param records - The records returned by the driver\n * @param expand - The expand map from QueryAST (field name → nested QueryAST)\n * @param depth - Current recursion depth (0-based)\n * @returns Records with expanded lookup fields (IDs replaced by full objects)\n */\n private async expandRelatedRecords(\n objectName: string,\n records: any[],\n expand: Record<string, QueryAST>,\n depth: number = 0,\n execCtx?: ExecutionContext,\n ): Promise<any[]> {\n if (!records || records.length === 0) return records;\n if (depth >= ObjectQL.MAX_EXPAND_DEPTH) return records;\n\n const objectSchema = this._registry.getObject(objectName);\n // If no schema registered, skip expand — return raw data\n if (!objectSchema || !objectSchema.fields) return records;\n\n for (const [fieldName, nestedAST] of Object.entries(expand)) {\n const fieldDef = objectSchema.fields[fieldName];\n\n // Skip if field not found or not a relationship type\n if (!fieldDef || !fieldDef.reference) continue;\n if (fieldDef.type !== 'lookup' && fieldDef.type !== 'master_detail') continue;\n\n const referenceObject = fieldDef.reference;\n\n // Collect all foreign key IDs from records (handle both single and multiple values)\n const allIds: any[] = [];\n for (const record of records) {\n const val = record[fieldName];\n if (val == null) continue;\n if (Array.isArray(val)) {\n allIds.push(...val.filter((id: any) => id != null));\n } else if (typeof val === 'object') {\n // Already expanded — skip\n continue;\n } else {\n allIds.push(val);\n }\n }\n\n // De-duplicate IDs\n const uniqueIds = [...new Set(allIds)];\n if (uniqueIds.length === 0) continue;\n\n // Batch-load related records using $in query\n try {\n const relatedQuery: QueryAST = {\n object: referenceObject,\n where: { id: { $in: uniqueIds } },\n ...(nestedAST.fields ? { fields: nestedAST.fields } : {}),\n ...(nestedAST.orderBy ? { orderBy: nestedAST.orderBy } : {}),\n };\n\n const driver = this.getDriver(referenceObject);\n // Propagate tenantId so cross-object expansion respects isolation —\n // e.g. a contact expansion only resolves IDs visible to the caller's\n // tenant. Without this the driver returns the raw FK target which\n // would let a maliciously crafted FK reach across tenants.\n const expandOpts = this.buildDriverOptions(execCtx);\n const relatedRecords = await driver.find(referenceObject, relatedQuery, expandOpts) ?? [];\n\n // Build a lookup map: id → record\n const recordMap = new Map<string, any>();\n for (const rec of relatedRecords) {\n const id = rec.id;\n if (id != null) recordMap.set(String(id), rec);\n }\n\n // Recursively expand nested relations if present\n if (nestedAST.expand && Object.keys(nestedAST.expand).length > 0) {\n const expandedRelated = await this.expandRelatedRecords(\n referenceObject,\n relatedRecords,\n nestedAST.expand,\n depth + 1,\n execCtx,\n );\n // Rebuild map with expanded records\n recordMap.clear();\n for (const rec of expandedRelated) {\n const id = rec.id;\n if (id != null) recordMap.set(String(id), rec);\n }\n }\n\n // Inject expanded records back into the original result set\n for (const record of records) {\n const val = record[fieldName];\n if (val == null) continue;\n\n if (Array.isArray(val)) {\n record[fieldName] = val.map((id: any) => recordMap.get(String(id)) ?? id);\n } else if (typeof val !== 'object') {\n record[fieldName] = recordMap.get(String(val)) ?? val;\n }\n // If val is already an object, leave it as-is\n }\n } catch (e) {\n // Graceful degradation: if expand fails, keep original IDs\n this.logger.warn('Failed to expand relationship field; retaining foreign key IDs', {\n object: objectName,\n field: fieldName,\n reference: referenceObject,\n error: (e as Error).message,\n });\n }\n }\n\n return records;\n }\n\n // ============================================\n // Data Access Methods (IDataEngine Interface)\n // ============================================\n\n async find(object: string, query?: EngineQueryOptions): Promise<any[]> {\n object = this.resolveObjectName(object);\n this.logger.debug('Find operation starting', { object, query });\n const driver = this.getDriver(object);\n const ast: QueryAST = { object, ...query };\n // Remove context from the AST — it's not a driver concern\n delete (ast as any).context;\n // Normalize OData `top` alias → standard `limit`\n if ((ast as any).top != null && ast.limit == null) {\n ast.limit = (ast as any).top;\n }\n delete (ast as any).top;\n\n // Plan formula projection: rewrite ast.fields to drop virtual formula\n // names and inject their dependencies, so the driver returns the raw\n // fields needed to compute the formulas after fetch.\n const _findSchema = this._registry.getObject(object);\n const _findFormula = planFormulaProjection(_findSchema, ast.fields as string[] | undefined);\n if (_findFormula.projected) ast.fields = _findFormula.projected;\n\n // Drop any requested field that doesn't exist on the schema. Without\n // this, drivers (notably SqlDriver) emit `SELECT unknown_col FROM ...`\n // which the DB rejects (\"no such column\") — and SqlDriver swallows\n // that error and returns `[]`, making a frontend bug (e.g. a generic\n // view requesting `name`/`due_date` on every object) look like \"no\n // records exist\". Silently filtering matches the existing OData\n // tolerance and Salesforce/Postgres behavior of `SELECT *` semantics.\n if (_findSchema?.fields && Array.isArray(ast.fields) && ast.fields.length > 0) {\n const known = new Set(Object.keys(_findSchema.fields));\n // Always allow the primary key + audit columns even if not present in\n // schema.fields. Without this, callers requesting `select=id,name`\n // silently get the `id` projected away, breaking record navigation.\n known.add('id');\n known.add('created_at');\n known.add('updated_at');\n const filtered = (ast.fields as string[]).filter(f => {\n // Keep relationship paths like `owner.name` — the engine will\n // resolve those via populate; only validate top-level segment.\n const head = String(f).split('.')[0];\n return known.has(head);\n });\n // Guard against an empty projection — fall back to `*` so the\n // request still returns rows. An empty SELECT list would either\n // 400 in Postgres or silently project nothing.\n ast.fields = filtered.length > 0 ? filtered : undefined;\n }\n\n const opCtx: OperationContext = {\n object,\n operation: 'find',\n ast,\n options: query,\n context: query?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const hookContext: HookContext = {\n object,\n event: 'beforeFind',\n input: { ast: opCtx.ast, options: opCtx.options },\n session: this.buildSession(opCtx.context),\n api: this.buildHookApi(opCtx.context),\n transaction: opCtx.context?.transaction,\n ql: this\n };\n await this.triggerHooks('beforeFind', hookContext);\n hookContext.input.options = this.buildDriverOptions(opCtx.context, hookContext.input.options as any);\n\n try {\n let result = await driver.find(object, hookContext.input.ast as QueryAST, hookContext.input.options as any);\n\n // Post-process: evaluate formula virtual fields against the raw rows\n if (Array.isArray(result)) applyFormulaPlan(_findFormula.plan, result);\n\n // Post-process: expand related records if expand is requested\n if (ast.expand && Object.keys(ast.expand).length > 0 && Array.isArray(result)) {\n result = await this.expandRelatedRecords(object, result, ast.expand, 0, opCtx.context);\n }\n \n hookContext.event = 'afterFind';\n hookContext.result = result;\n await this.triggerHooks('afterFind', hookContext);\n \n return hookContext.result;\n } catch (e) {\n this.logger.error('Find operation failed', e as Error, { object });\n throw e;\n }\n });\n\n return opCtx.result as any[];\n }\n\n async findOne(objectName: string, query?: EngineQueryOptions): Promise<any> {\n objectName = this.resolveObjectName(objectName);\n this.logger.debug('FindOne operation', { objectName });\n const driver = this.getDriver(objectName);\n const ast: QueryAST = { object: objectName, ...query, limit: 1 };\n // Remove context and top alias from the AST\n delete (ast as any).context;\n delete (ast as any).top;\n\n // Plan formula projection (same as find): rewrite ast.fields so the driver\n // returns the raw dependency fields, then evaluate formulas after fetch.\n const _findOneSchema = this._registry.getObject(objectName);\n const _findOneFormula = planFormulaProjection(_findOneSchema, ast.fields as string[] | undefined);\n if (_findOneFormula.projected) ast.fields = _findOneFormula.projected;\n\n // Drop unknown fields — see equivalent block in `find()` for rationale.\n if (_findOneSchema?.fields && Array.isArray(ast.fields) && ast.fields.length > 0) {\n const known = new Set(Object.keys(_findOneSchema.fields));\n // Always allow the primary key + audit columns even if not present\n // in schema.fields (matches `find()` behavior).\n known.add('id');\n known.add('created_at');\n known.add('updated_at');\n const filtered = (ast.fields as string[]).filter(f => known.has(String(f).split('.')[0]));\n ast.fields = filtered.length > 0 ? filtered : undefined;\n }\n\n const opCtx: OperationContext = {\n object: objectName,\n operation: 'findOne',\n ast,\n options: query,\n context: query?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const findOneOpts = this.buildDriverOptions(opCtx.context);\n let result = await driver.findOne(objectName, opCtx.ast as QueryAST, findOneOpts);\n\n // Post-process: evaluate formula virtual fields against the raw row\n if (result != null) applyFormulaPlan(_findOneFormula.plan, [result]);\n\n // Post-process: expand related records if expand is requested\n if (ast.expand && Object.keys(ast.expand).length > 0 && result != null) {\n const expanded = await this.expandRelatedRecords(objectName, [result], ast.expand, 0, opCtx.context);\n result = expanded[0];\n }\n\n return result;\n });\n\n return opCtx.result;\n }\n\n async insert(object: string, data: any | any[], options?: DataEngineInsertOptions): Promise<any> {\n object = this.resolveObjectName(object);\n this.logger.debug('Insert operation starting', { object, isBatch: Array.isArray(data) });\n const driver = this.getDriver(object);\n\n const opCtx: OperationContext = {\n object,\n operation: 'insert',\n data,\n options,\n context: options?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const hookContext: HookContext = {\n object,\n event: 'beforeInsert',\n input: { data: opCtx.data, options: opCtx.options },\n session: this.buildSession(opCtx.context),\n api: this.buildHookApi(opCtx.context),\n transaction: opCtx.context?.transaction,\n ql: this\n };\n await this.triggerHooks('beforeInsert', hookContext);\n // Thread the open transaction (if any) into the driver-facing\n // options so that knex's `.transacting(trx)` is honoured. Without\n // this, calls inside a `engine.transaction(...)` block would deadlock\n // on SQLite's single-connection pool. Also propagates tenantId so\n // the driver can enforce per-tenant isolation.\n hookContext.input.options = this.buildDriverOptions(opCtx.context, hookContext.input.options as any);\n\n try {\n let result;\n const nowSnap = new Date();\n const schemaForValidation = this._registry.getObject(object);\n if (Array.isArray(hookContext.input.data)) {\n // Bulk Create — apply defaults per row\n const rows = (hookContext.input.data as any[]).map((row) =>\n this.applyFieldDefaults(object, row as Record<string, unknown>, opCtx.context, nowSnap),\n );\n for (const r of rows) validateRecord(schemaForValidation, r, 'insert');\n if (driver.bulkCreate) {\n result = await driver.bulkCreate(object, rows, hookContext.input.options as any);\n } else {\n // Fallback loop\n result = await Promise.all(rows.map((item) => driver.create(object, item, hookContext.input.options as any)));\n }\n } else {\n const row = this.applyFieldDefaults(\n object,\n hookContext.input.data as Record<string, unknown>,\n opCtx.context,\n nowSnap,\n );\n validateRecord(schemaForValidation, row, 'insert');\n result = await driver.create(object, row, hookContext.input.options as any);\n }\n\n hookContext.event = 'afterInsert';\n hookContext.result = result;\n await this.triggerHooks('afterInsert', hookContext);\n\n // Publish data.record.created event to realtime service\n if (this.realtimeService) {\n try {\n if (Array.isArray(result)) {\n // Bulk insert - publish event for each record\n for (const record of result) {\n const event: RealtimeEventPayload = {\n type: 'data.record.created',\n object,\n payload: {\n recordId: record.id,\n after: record,\n },\n timestamp: new Date().toISOString(),\n };\n await this.realtimeService.publish(event);\n }\n this.logger.debug(`Published ${result.length} data.record.created events`, { object });\n } else {\n const event: RealtimeEventPayload = {\n type: 'data.record.created',\n object,\n payload: {\n recordId: result.id,\n after: result,\n },\n timestamp: new Date().toISOString(),\n };\n await this.realtimeService.publish(event);\n this.logger.debug('Published data.record.created event', { object, recordId: result.id });\n }\n } catch (error) {\n this.logger.warn('Failed to publish data event', { object, error });\n }\n }\n\n return hookContext.result;\n } catch (e) {\n this.logger.error('Insert operation failed', e as Error, { object });\n throw e;\n }\n });\n\n return opCtx.result;\n }\n\n async update(object: string, data: any, options?: EngineUpdateOptions): Promise<any> {\n object = this.resolveObjectName(object);\n this.logger.debug('Update operation starting', { object });\n const driver = this.getDriver(object);\n \n // 1. Extract ID from data or where if it's a single update by ID\n let id = data.id;\n if (!id && options?.where && typeof options.where === 'object' && 'id' in options.where) {\n id = (options.where as Record<string, unknown>).id;\n }\n\n const opCtx: OperationContext = {\n object,\n operation: 'update',\n data,\n options,\n context: options?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const hookContext: HookContext = {\n object,\n event: 'beforeUpdate',\n input: { id, data: opCtx.data, options: opCtx.options },\n session: this.buildSession(opCtx.context),\n api: this.buildHookApi(opCtx.context),\n transaction: opCtx.context?.transaction,\n ql: this\n };\n await this.triggerHooks('beforeUpdate', hookContext);\n hookContext.input.options = this.buildDriverOptions(opCtx.context, hookContext.input.options as any);\n\n try {\n let result;\n if (hookContext.input.id) {\n validateRecord(this._registry.getObject(object), hookContext.input.data as Record<string, unknown>, 'update');\n result = await driver.update(object, hookContext.input.id as string, hookContext.input.data as Record<string, unknown>, hookContext.input.options as any);\n } else if (options?.multi && driver.updateMany) {\n validateRecord(this._registry.getObject(object), hookContext.input.data as Record<string, unknown>, 'update');\n const ast: QueryAST = { object, where: options.where };\n result = await driver.updateMany(object, ast, hookContext.input.data as Record<string, unknown>, hookContext.input.options as any);\n } else {\n throw new Error('Update requires an ID or options.multi=true');\n }\n\n hookContext.event = 'afterUpdate';\n hookContext.result = result;\n await this.triggerHooks('afterUpdate', hookContext);\n\n // Publish data.record.updated event to realtime service\n if (this.realtimeService) {\n try {\n const resultId = (typeof result === 'object' && result && 'id' in result) ? (result as any).id : undefined;\n const recordId = String(hookContext.input.id || resultId || '');\n const event: RealtimeEventPayload = {\n type: 'data.record.updated',\n object,\n payload: {\n recordId,\n changes: hookContext.input.data,\n after: result,\n },\n timestamp: new Date().toISOString(),\n };\n await this.realtimeService.publish(event);\n this.logger.debug('Published data.record.updated event', { object, recordId });\n } catch (error) {\n this.logger.warn('Failed to publish data event', { object, error });\n }\n }\n\n return hookContext.result;\n } catch (e) {\n this.logger.error('Update operation failed', e as Error, { object });\n throw e;\n }\n });\n\n return opCtx.result;\n }\n\n async delete(object: string, options?: EngineDeleteOptions): Promise<any> {\n object = this.resolveObjectName(object);\n this.logger.debug('Delete operation starting', { object });\n const driver = this.getDriver(object);\n\n // Extract ID logic similar to update\n let id: any = undefined;\n if (options?.where && typeof options.where === 'object' && 'id' in options.where) {\n id = (options.where as Record<string, unknown>).id;\n }\n\n const opCtx: OperationContext = {\n object,\n operation: 'delete',\n options,\n context: options?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const hookContext: HookContext = {\n object,\n event: 'beforeDelete',\n input: { id, options: opCtx.options },\n session: this.buildSession(opCtx.context),\n api: this.buildHookApi(opCtx.context),\n transaction: opCtx.context?.transaction,\n ql: this\n };\n await this.triggerHooks('beforeDelete', hookContext);\n hookContext.input.options = this.buildDriverOptions(opCtx.context, hookContext.input.options as any);\n\n try {\n let result;\n if (hookContext.input.id) {\n result = await driver.delete(object, hookContext.input.id as string, hookContext.input.options as any);\n } else if (options?.multi && driver.deleteMany) {\n const ast: QueryAST = { object, where: options.where };\n result = await driver.deleteMany(object, ast, hookContext.input.options as any);\n } else {\n throw new Error('Delete requires an ID or options.multi=true');\n }\n\n hookContext.event = 'afterDelete';\n hookContext.result = result;\n await this.triggerHooks('afterDelete', hookContext);\n\n // Publish data.record.deleted event to realtime service\n if (this.realtimeService) {\n try {\n const resultId = (typeof result === 'object' && result && 'id' in result) ? (result as any).id : undefined;\n const recordId = String(hookContext.input.id || resultId || '');\n const event: RealtimeEventPayload = {\n type: 'data.record.deleted',\n object,\n payload: {\n recordId,\n },\n timestamp: new Date().toISOString(),\n };\n await this.realtimeService.publish(event);\n this.logger.debug('Published data.record.deleted event', { object, recordId });\n } catch (error) {\n this.logger.warn('Failed to publish data event', { object, error });\n }\n }\n\n return hookContext.result;\n } catch (e) {\n this.logger.error('Delete operation failed', e as Error, { object });\n throw e;\n }\n });\n\n return opCtx.result;\n }\n\n async count(object: string, query?: EngineCountOptions): Promise<number> {\n object = this.resolveObjectName(object);\n const driver = this.getDriver(object);\n\n const opCtx: OperationContext = {\n object,\n operation: 'count',\n options: query,\n context: query?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const countOpts = this.buildDriverOptions(opCtx.context);\n if (driver.count) {\n const ast: QueryAST = { object, where: query?.where };\n return driver.count(object, ast, countOpts);\n }\n // Fallback to find().length\n const res = await this.find(object, { where: query?.where, fields: ['id'], context: opCtx.context });\n return res.length;\n });\n\n return opCtx.result as number;\n }\n\n async aggregate(object: string, query: EngineAggregateOptions): Promise<any[]> {\n object = this.resolveObjectName(object);\n const driver = this.getDriver(object);\n this.logger.debug(`Aggregate on ${object} using ${driver.name}`, query);\n\n const opCtx: OperationContext = {\n object,\n operation: 'aggregate',\n options: query,\n context: query?.context,\n };\n\n await this.executeWithMiddleware(opCtx, async () => {\n const ast: QueryAST = {\n object,\n where: query.where,\n groupBy: query.groupBy as any,\n aggregations: query.aggregations,\n };\n\n // Prefer driver.aggregate() when available — driver.find() in many\n // drivers (e.g. driver-sql) does not honor `groupBy` / `aggregations`\n // and would silently return ungrouped raw rows. Fall back to find()\n // for drivers that handle aggregations through their query AST.\n const drv = driver as any;\n // Structured groupBy items ({field, dateGranularity}) require the\n // driver to advertise per-granularity native bucket support via\n // `supports.queryDateGranularity[g]`. If every structured item is\n // supported we can push the aggregate down to the driver; otherwise\n // we fall back to driver.find() + in-memory bucketing so the result\n // remains correct on partial-support dialects (e.g. SQLite + week).\n const groupByItems = Array.isArray(query.groupBy) ? (query.groupBy as any[]) : [];\n const granularityCaps: Record<string, boolean> | undefined =\n drv?.supports?.queryDateGranularity;\n const structuredItems = groupByItems.filter((g) => typeof g !== 'string');\n const allStructuredSupported = structuredItems.every((g: any) => {\n if (!g?.dateGranularity) return true; // plain {field} object is fine\n return granularityCaps?.[g.dateGranularity] === true;\n });\n if (typeof drv.aggregate === 'function' && allStructuredSupported) {\n return drv.aggregate(object, ast, this.buildDriverOptions(opCtx.context));\n }\n // In-memory fallback path: ask the driver for raw rows, then bucket +\n // aggregate here. This guarantees `groupBy` (incl. structured items\n // carrying `dateGranularity`) and `aggregations` always work even on\n // drivers that have no native aggregation support (driver-rest,\n // driver-memory, partial SQL drivers).\n const raw = await driver.find(object, ast, this.buildDriverOptions(opCtx.context));\n return applyInMemoryAggregation(raw, ast);\n });\n\n return opCtx.result as any[];\n }\n \n /**\n * Run raw driver-specific commands (SQL for SqlDriver, REST for RestDriver, …).\n *\n * ⚠️ **Tenant isolation bypass.** Raw `execute()` does NOT thread the\n * caller's `ExecutionContext.tenantId` into a `WHERE organization_id`\n * predicate — drivers see the command verbatim. Callers MUST inline the\n * tenant filter themselves, or restrict raw execution to genuinely global\n * statements (schema migrations, sys_* / control-plane tables).\n *\n * Prefer the typed entry points (`find`, `update`, `delete`, `count`, …)\n * whenever feasible — they auto-apply tenancy + soft-delete + audit warnings.\n */\n async execute(command: any, options?: Record<string, any>): Promise<any> {\n // Driver selection priority:\n // 1. options.object → route via getDriver(objectName)\n // 2. options.datasource → explicit driver name\n // 3. default driver (set via datasourceMapping or defaultDriver)\n // This lets system services (e.g. PackageService, AuditService) issue raw\n // SQL against the control-plane / default DB without having to know the\n // object name behind every CREATE TABLE / SELECT statement.\n let driver: DriverInterface | undefined;\n if (options?.object) {\n driver = this.getDriver(options.object);\n } else if (options?.datasource && this.drivers.has(options.datasource)) {\n driver = this.drivers.get(options.datasource);\n } else if (this.defaultDriver && this.drivers.has(this.defaultDriver)) {\n driver = this.drivers.get(this.defaultDriver);\n } else if (this.drivers.size === 1) {\n // Single registered driver — unambiguously the right one.\n driver = this.drivers.values().next().value;\n }\n\n if (!driver) {\n throw new Error(\n 'Execute requires options.object to select a driver, or a default driver to be configured. ' +\n 'Configure datasourceMapping with `default: true` or pass `{ object }` / `{ datasource }` in options.',\n );\n }\n if (!driver.execute) {\n throw new Error('Selected driver does not implement execute()');\n }\n\n // Support both call shapes:\n // execute('SELECT ...', { args: [...] })\n // execute({ sql: 'SELECT ...', args: [...] })\n let rawCommand: any = command;\n let params: any[] | undefined = options?.args ?? options?.params;\n if (command && typeof command === 'object' && !Array.isArray(command) && 'sql' in command) {\n rawCommand = command.sql;\n if (params === undefined) {\n params = command.args ?? command.params;\n }\n }\n\n return driver.execute(rawCommand, params, options);\n }\n\n /**\n * Execute a callback inside a database transaction.\n *\n * The callback receives a context object that should be passed to all\n * downstream `engine.insert/update/delete/find/findOne` calls (as\n * `{ context: trxCtx }`). The transaction handle threads through\n * `OperationContext.context.transaction` and the SQL driver's per-builder\n * `.transacting(trx)` call.\n *\n * - If the default driver does not support `beginTransaction`, the callback\n * runs directly with the supplied base context (no rollback). This keeps\n * the API safe to call on drivers without ACID support (e.g. the\n * in-memory driver in tests).\n * - On callback success the transaction is committed; on any thrown error\n * it is rolled back and the original error is re-thrown.\n *\n * Use case: multi-step operations that must be atomic (e.g. CRM\n * `convertLead`, which creates an account + contact + opportunity + flips\n * the lead in a single unit of work).\n */\n async transaction<T>(\n callback: (trxCtx: any) => Promise<T>,\n baseContext?: any,\n ): Promise<T> {\n const driver = this.defaultDriver ? this.drivers.get(this.defaultDriver) : undefined;\n const drv = driver as any;\n if (!drv?.beginTransaction) {\n return callback(baseContext);\n }\n const trx = await drv.beginTransaction();\n const trxCtx = { ...(baseContext ?? {}), transaction: trx };\n try {\n const result = await callback(trxCtx);\n if (drv.commit) await drv.commit(trx);\n else if (drv.commitTransaction) await drv.commitTransaction(trx);\n return result;\n } catch (err) {\n try {\n if (drv.rollback) await drv.rollback(trx);\n else if (drv.rollbackTransaction) await drv.rollbackTransaction(trx);\n } catch {\n // swallow rollback failures so the original error surfaces\n }\n throw err;\n }\n }\n\n // ============================================\n // Compatibility / Convenience API\n // ============================================\n // These methods provide a higher-level API matching the @objectql/core\n // ObjectQL interface, enabling painless migration from the legacy layer.\n\n /**\n * Register a single object definition.\n * \n * Proxies to SchemaRegistry.registerObject() with sensible defaults.\n * Fields without a `name` property are auto-assigned from their key.\n */\n registerObject(\n schema: ServiceObject,\n packageId: string = '__runtime__',\n namespace?: string\n ): string {\n // Auto-assign field names from keys\n if (schema.fields) {\n for (const [key, field] of Object.entries(schema.fields)) {\n if (field && typeof field === 'object' && !('name' in field)) {\n (field as any).name = key;\n }\n }\n }\n return this._registry.registerObject(schema, packageId, namespace);\n }\n\n /**\n * Unregister a single object by name.\n */\n unregisterObject(name: string, packageId?: string): void {\n if (packageId) {\n this._registry.unregisterObjectsByPackage(packageId);\n } else {\n // Remove from generic metadata as fallback\n this._registry.unregisterItem('object', name);\n }\n }\n\n /**\n * Get an object definition by name.\n * Alias for getSchema() — matches @objectql/core API.\n */\n getObject(name: string): ServiceObject | undefined {\n return this.getSchema(name);\n }\n\n /**\n * Get all registered object configs as a name→config map.\n * Matches @objectql/core getConfigs() API.\n */\n getConfigs(): Record<string, ServiceObject> {\n const result: Record<string, ServiceObject> = {};\n const objects = this._registry.getAllObjects();\n for (const obj of objects) {\n if (obj.name) {\n result[obj.name] = obj;\n }\n }\n return result;\n }\n\n /**\n * Get a registered driver by datasource name.\n * \n * Unlike the private getDriver() (which resolves by object name),\n * this method directly looks up a driver by its registered name.\n */\n getDriverByName(name: string): DriverInterface | undefined {\n return this.drivers.get(name);\n }\n\n /**\n * Get the driver responsible for the given object.\n *\n * Resolves datasource binding from the object's schema definition,\n * falling back to the default driver. This is a public version of\n * the internal getDriver() used by CRUD operations.\n *\n * @param objectName - FQN or short name of the registered object.\n * @returns The resolved DriverInterface, or undefined if no driver is available.\n */\n getDriverForObject(objectName: string): DriverInterface | undefined {\n try {\n return this.getDriver(objectName);\n } catch {\n return undefined;\n }\n }\n\n /**\n * Sync all registered object schemas to their respective drivers.\n * Call this after dynamically registering new objects at runtime\n * (e.g. after template seeding) to ensure tables/collections exist\n * before inserting seed data.\n */\n async syncSchemas(): Promise<void> {\n const allObjects = this._registry.getAllObjects();\n for (const obj of allObjects) {\n const driver = this.getDriverForObject(obj.name);\n if (!driver) continue;\n const tableName = StorageNameMapping.resolveTableName(obj);\n if (typeof (driver as any).syncSchemasBatch === 'function' && (driver as any).supports?.batchSchemaSync) {\n // Already handled per-driver below; skip individual call\n }\n if (typeof (driver as any).syncSchema === 'function') {\n try {\n await (driver as any).syncSchema(tableName, obj);\n } catch {\n // best effort — log suppressed to avoid noise on already-synced tables\n }\n }\n }\n }\n\n /**\n * Get a registered driver by datasource name.\n * Alias matching @objectql/core datasource() API.\n *\n * @throws Error if the datasource is not found\n */\n datasource(name: string): DriverInterface {\n const driver = this.drivers.get(name);\n if (!driver) {\n throw new Error(`[ObjectQL] Datasource '${name}' not found`);\n }\n return driver;\n }\n\n /**\n * Register a hook handler.\n * Convenience alias for registerHook() matching @objectql/core on() API.\n * \n * Usage:\n * ql.on('beforeInsert', 'user', async (ctx) => { ... });\n */\n on(\n event: string,\n objectName: string,\n handler: (ctx: HookContext) => Promise<void> | void,\n packageId?: string\n ): void {\n this.registerHook(event, handler, { object: objectName, packageId });\n }\n\n /**\n * Remove all hooks, actions, and objects contributed by a package.\n */\n removePackage(packageId: string): void {\n // Remove hooks\n for (const [key, handlers] of this.hooks.entries()) {\n const filtered = handlers.filter(h => h.packageId !== packageId);\n if (filtered.length !== handlers.length) {\n this.hooks.set(key, filtered);\n }\n }\n // Remove actions\n this.removeActionsByPackage(packageId);\n // Remove objects\n this._registry.unregisterObjectsByPackage(packageId, true);\n }\n\n /**\n * Gracefully shut down the engine, disconnecting all drivers.\n * Alias for destroy() — matches @objectql/core close() API.\n */\n async close(): Promise<void> {\n return this.destroy();\n }\n\n /**\n * Create a scoped execution context bound to this engine.\n * \n * Usage:\n * const ctx = engine.createContext({ userId: '...', tenantId: '...' });\n * const users = ctx.object('user');\n * await users.find({ filter: { status: 'active' } });\n */\n createContext(ctx: Partial<ExecutionContext>): ScopedContext {\n return new ScopedContext(\n ExecutionContextSchema.parse(ctx),\n this\n );\n }\n\n /**\n * Static factory: create a fully configured ObjectQL instance.\n * \n * Matches @objectql/core's `new ObjectQL(config)` pattern but also\n * registers drivers and objects, then calls init().\n * \n * Usage:\n * const ql = await ObjectQL.create({\n * datasources: { default: myDriver },\n * objects: { user: { name: 'user', fields: { ... } } }\n * });\n */\n static async create(config: {\n datasources?: Record<string, DriverInterface>;\n objects?: Record<string, ServiceObject>;\n hooks?: Array<{ event: string; object: string; handler: (ctx: HookContext) => Promise<void> | void }>;\n }): Promise<ObjectQL> {\n const ql = new ObjectQL();\n\n // Register drivers\n if (config.datasources) {\n for (const [name, driver] of Object.entries(config.datasources)) {\n // Set driver name if not already set\n if (!driver.name) {\n (driver as any).name = name;\n }\n ql.registerDriver(driver, name === 'default');\n }\n }\n\n // Register objects\n if (config.objects) {\n for (const [_key, schema] of Object.entries(config.objects)) {\n ql.registerObject(schema);\n }\n }\n\n // Register hooks\n if (config.hooks) {\n for (const hook of config.hooks) {\n ql.on(hook.event, hook.object, hook.handler);\n }\n }\n\n // Initialize (connect drivers)\n await ql.init();\n\n return ql;\n }\n}\n\n/**\n * Repository scoped to a single object, bound to an execution context.\n *\n * Provides both IDataEngine-style methods (find, insert, update, delete)\n * and convenience aliases (create, updateById, deleteById) matching\n * the @objectql/core ObjectRepository API.\n */\nexport class ObjectRepository {\n constructor(\n private objectName: string,\n private context: ExecutionContext,\n private engine: IDataEngine & { executeAction?: (o: string, a: string, c: any) => Promise<any> }\n ) {}\n\n async find(query: any = {}): Promise<any[]> {\n return this.engine.find(this.objectName, {\n ...query,\n context: this.context,\n });\n }\n\n async findOne(query: any = {}): Promise<any> {\n return this.engine.findOne(this.objectName, {\n ...query,\n context: this.context,\n });\n }\n\n async insert(data: any): Promise<any> {\n return this.engine.insert(this.objectName, data, {\n context: this.context,\n });\n }\n\n /** Alias for insert() — matches @objectql/core convention */\n async create(data: any): Promise<any> {\n return this.insert(data);\n }\n\n async update(data: any, options: any = {}): Promise<any> {\n return this.engine.update(this.objectName, data, {\n ...options,\n context: this.context,\n });\n }\n\n /** Update a single record by ID */\n async updateById(id: string | number, data: any): Promise<any> {\n return this.engine.update(this.objectName, { ...data, id: id }, {\n where: { id: id },\n context: this.context,\n });\n }\n\n async delete(options: any = {}): Promise<any> {\n return this.engine.delete(this.objectName, {\n ...options,\n context: this.context,\n });\n }\n\n /** Delete a single record by ID */\n async deleteById(id: string | number): Promise<any> {\n return this.engine.delete(this.objectName, {\n where: { id: id },\n context: this.context,\n });\n }\n\n async count(query: any = {}): Promise<number> {\n return this.engine.count(this.objectName, {\n ...query,\n context: this.context,\n });\n }\n\n /** Aggregate query */\n async aggregate(query: any = {}): Promise<any[]> {\n return this.engine.aggregate(this.objectName, {\n ...query,\n context: this.context,\n });\n }\n\n /** Execute a named action registered on this object */\n async execute(actionName: string, params?: any): Promise<any> {\n if (this.engine.executeAction) {\n return this.engine.executeAction(this.objectName, actionName, {\n ...params,\n userId: this.context.userId,\n tenantId: this.context.tenantId,\n roles: this.context.roles,\n });\n }\n throw new Error(`Actions not supported by engine`);\n }\n}\n\n/**\n * Scoped execution context with object() accessor.\n * \n * Provides identity (userId, tenantId/spaceId, roles),\n * repository access via object(), privilege escalation via sudo(),\n * and transactional execution via transaction().\n */\nexport class ScopedContext {\n constructor(\n private executionContext: ExecutionContext,\n private engine: IDataEngine\n ) {}\n\n /** Get a repository scoped to this context */\n object(name: string): ObjectRepository {\n return new ObjectRepository(name, this.executionContext, this.engine as any);\n }\n\n /** Create an elevated (system) context */\n sudo(): ScopedContext {\n return new ScopedContext(\n { ...this.executionContext, isSystem: true },\n this.engine\n );\n }\n\n /**\n * Execute a callback within a database transaction.\n *\n * The callback receives a new ScopedContext whose operations\n * share the same transaction handle. If the callback throws,\n * the transaction is rolled back; otherwise it is committed.\n *\n * Falls back to non-transactional execution if the driver\n * does not support transactions.\n */\n async transaction(callback: (trxCtx: ScopedContext) => Promise<any>): Promise<any> {\n const engine = this.engine as any;\n\n // Find the default driver for transaction support\n const driver = engine.defaultDriver\n ? engine.drivers?.get(engine.defaultDriver)\n : undefined;\n\n if (!driver?.beginTransaction) {\n // No transaction support — execute directly\n return callback(this);\n }\n\n const trx = await driver.beginTransaction();\n const trxCtx = new ScopedContext(\n { ...this.executionContext, transaction: trx },\n this.engine\n );\n\n try {\n const result = await callback(trxCtx);\n if (driver.commit) await driver.commit(trx);\n else if (driver.commitTransaction) await driver.commitTransaction(trx);\n return result;\n } catch (error) {\n if (driver.rollback) await driver.rollback(trx);\n else if (driver.rollbackTransaction) await driver.rollbackTransaction(trx);\n throw error;\n }\n }\n\n get userId() { return this.executionContext.userId; }\n get tenantId() { return this.executionContext.tenantId; }\n /** Alias for tenantId — matches ObjectQLContext.spaceId convention */\n get spaceId() { return this.executionContext.tenantId; }\n get roles() { return this.executionContext.roles; }\n get isSystem() { return this.executionContext.isSystem; }\n\n /** Internal: expose the transaction handle for driver-level access */\n get transactionHandle() { return this.executionContext.transaction; }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Declarative Hook Wrappers\n *\n * Turns a raw `HookHandler` into one that honours the declarative metadata\n * fields defined on `HookSchema` (`condition`, `async`, `retryPolicy`,\n * `timeout`, `onError`). This lives outside the engine's `triggerHooks`\n * loop so the engine stays minimal and the semantics are unit-testable in\n * isolation.\n *\n * The resulting wrapped handler keeps the original `(ctx) => Promise<void>`\n * signature, so `engine.registerHook` does not need to know anything about\n * the metadata-driven behaviours.\n */\nimport type { Hook, HookContext } from '@objectstack/spec/data';\nimport type { Expression } from '@objectstack/spec';\nimport type { HookHandler } from './engine.js';\nimport { ExpressionEngine } from '@objectstack/formula';\nimport { noopHookMetricsRecorder, type HookMetricsRecorder, type HookMetricOutcome } from './hook-metrics.js';\n\nexport interface WrapDeclarativeOptions {\n /** Logger for declarative-layer diagnostics (timeouts, retries, swallowed errors). */\n logger?: {\n debug: (msg: string, meta?: any) => void;\n info: (msg: string, meta?: any) => void;\n warn: (msg: string, meta?: any) => void;\n error: (msg: string, meta?: any) => void;\n };\n /** Optional per-execution metrics sink. Defaults to no-op. */\n metrics?: HookMetricsRecorder;\n}\n\nconst noopLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/**\n * Wrap a hook handler so it honours the declarative fields defined on\n * `HookSchema`. The wrapping order, from outermost to innermost, is:\n *\n * 1. condition → skip when formula evaluates falsy\n * 2. async → fire-and-forget (after* events only)\n * 3. retry → repeat on throw with backoff\n * 4. timeout → abort if handler runs too long\n * 5. onError → swallow when set to 'log'\n *\n * The condition formula is evaluated against the most useful record-shaped\n * payload available on the context (write payloads first, then `previous`,\n * then a flat merge of input). Read events typically have no record yet,\n * so a condition on a `beforeFind` will simply skip when no data is\n * present.\n */\nexport function wrapDeclarativeHook(\n meta: Hook,\n handler: HookHandler,\n opts: WrapDeclarativeOptions = {},\n): HookHandler {\n const logger = opts.logger ?? noopLogger;\n const metrics = opts.metrics ?? noopHookMetricsRecorder;\n const isAfterEvent = meta.events?.some((e) => typeof e === 'string' && e.startsWith('after')) ?? false;\n const hasBody = Boolean((meta as any).body);\n const labelFor = (ctx: HookContext) => ({\n hook: meta.name,\n object: ctx.object ?? (typeof (meta as any).object === 'string' ? (meta as any).object : undefined),\n event: ctx.event,\n body: hasBody,\n });\n\n // Pre-compile condition once so each invocation is cheap.\n let conditionFn: ((record: any) => boolean) | undefined;\n if (meta.condition) {\n // Accept either string shorthand or full Expression envelope.\n const expr: Expression = typeof meta.condition === 'string'\n ? { dialect: 'cel', source: meta.condition }\n : (meta.condition as Expression);\n if (expr.source && expr.source.trim()) {\n const check = ExpressionEngine.compile(expr);\n if (check.ok) {\n conditionFn = (record: any) => {\n const r = ExpressionEngine.evaluate<boolean>(expr, { record: record ?? {} });\n if (!r.ok) {\n logger.warn('[hook] condition evaluation failed; treating as false', {\n hook: meta.name,\n condition: expr.source,\n error: r.error.message,\n });\n return false;\n }\n return Boolean(r.value);\n };\n } else {\n logger.warn('[hook] condition formula failed to compile; condition ignored', {\n hook: meta.name,\n condition: expr.source,\n error: check.error.message,\n });\n }\n }\n }\n\n const retryMax = Math.max(0, Number(meta.retryPolicy?.maxRetries ?? 0));\n const retryBackoffMs = Math.max(0, Number(meta.retryPolicy?.backoffMs ?? 0));\n const timeoutMs = typeof meta.timeout === 'number' && meta.timeout > 0 ? meta.timeout : undefined;\n const onError = meta.onError ?? 'abort';\n // `async` is only meaningful for after* events; ignore on before* (we must\n // wait for the handler to potentially mutate ctx.input).\n const fireAndForget = Boolean(meta.async) && isAfterEvent;\n\n const runWithTimeout = async (ctx: HookContext): Promise<void> => {\n if (!timeoutMs) {\n await handler(ctx);\n return;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n Promise.resolve().then(() => handler(ctx)),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(new Error(`Hook '${meta.name}' timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n }),\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n };\n\n const runWithRetry = async (ctx: HookContext): Promise<void> => {\n let attempt = 0;\n let lastErr: unknown;\n // attempts = 1 + retryMax\n while (attempt <= retryMax) {\n try {\n await runWithTimeout(ctx);\n return;\n } catch (err) {\n lastErr = err;\n attempt += 1;\n if (attempt > retryMax) break;\n if (retryBackoffMs > 0) {\n await new Promise((r) => setTimeout(r, retryBackoffMs * attempt));\n }\n try { metrics.recordRetry(labelFor(ctx), attempt); } catch { /* noop */ }\n logger.warn('[hook] retrying after failure', {\n hook: meta.name,\n attempt,\n maxRetries: retryMax,\n error: (err as any)?.message,\n });\n }\n }\n throw lastErr;\n };\n\n const runWithErrorPolicy = async (ctx: HookContext): Promise<void> => {\n try {\n await runWithRetry(ctx);\n } catch (err) {\n if (onError === 'log') {\n logger.error('[hook] handler failed (onError=log; suppressing)', {\n hook: meta.name,\n object: ctx.object,\n event: ctx.event,\n error: (err as any)?.message,\n });\n return;\n }\n throw err;\n }\n };\n\n return async (ctx: HookContext): Promise<void> => {\n // 1. Condition gate\n if (conditionFn) {\n const record = pickRecordPayload(ctx);\n if (!conditionFn(record)) {\n logger.debug('[hook] skipped by condition', {\n hook: meta.name,\n object: ctx.object,\n event: ctx.event,\n });\n try { metrics.recordSkip(labelFor(ctx), 'condition'); } catch { /* noop */ }\n return;\n }\n }\n\n const restore = installFlatInput(ctx);\n const startedAt = Date.now();\n\n const recordOutcome = (err?: any) => {\n const elapsed = Date.now() - startedAt;\n let outcome: HookMetricOutcome = 'success';\n if (err) {\n const msg = String(err?.message ?? err ?? '');\n if (/timed out after/i.test(msg)) outcome = 'timeout';\n else if (/capability|cap-rejection|capability_rejected/i.test(msg)) outcome = 'capability_rejected';\n else outcome = 'error';\n }\n try { metrics.recordExecution(labelFor(ctx), outcome, elapsed); } catch { /* noop */ }\n };\n\n try {\n // 2. Fire-and-forget for declarative async after* hooks\n if (fireAndForget) {\n try { metrics.recordSkip(labelFor(ctx), 'fire_and_forget'); } catch { /* noop */ }\n // For fire-and-forget we can't keep ctx.input swapped while the\n // engine moves on — copy what we need, restore, and run async.\n void runWithErrorPolicy(ctx)\n .then(() => recordOutcome())\n .catch((err) => {\n recordOutcome(err);\n logger.error('[hook] async handler error (fire-and-forget)', {\n hook: meta.name,\n error: (err as any)?.message,\n });\n });\n return;\n }\n\n try {\n await runWithErrorPolicy(ctx);\n recordOutcome();\n } catch (err) {\n recordOutcome(err);\n throw err;\n }\n } finally {\n restore();\n }\n };\n}\n\n/**\n * Swap `ctx.input` in place for a Proxy that exposes a flat record view\n * over the engine's `{ data, options, id? }` wrapper. Returns a function\n * that restores the original `ctx.input` reference. Reads of\n * `id` / `options` / `ast` / `data` fall through to the wrapper; reads\n * of any other key fall through to `data`. Writes always go to `data`\n * (creating it if missing) so the engine's downstream `input.data`\n * read picks up mutations made by user code as `input.field = value`.\n */\nfunction installFlatInput(ctx: HookContext): () => void {\n const raw: any = ctx.input ?? {};\n const looksWrapped =\n raw && typeof raw === 'object' &&\n ('data' in raw || 'options' in raw || 'id' in raw || 'ast' in raw);\n if (!looksWrapped) return () => {};\n\n const ensureData = (): Record<string, unknown> => {\n if (!raw.data || typeof raw.data !== 'object') {\n raw.data = {};\n }\n return raw.data as Record<string, unknown>;\n };\n\n const proxy = new Proxy(raw, {\n get(target, prop, receiver) {\n if (prop === 'id' || prop === 'options' || prop === 'ast' || prop === 'data') {\n return Reflect.get(target, prop, receiver);\n }\n const data = target.data;\n if (data && typeof data === 'object' && prop in data) {\n return (data as any)[prop];\n }\n return Reflect.get(target, prop, receiver);\n },\n set(target, prop, value) {\n if (prop === 'id' || prop === 'options' || prop === 'ast' || prop === 'data') {\n (target as any)[prop] = value;\n return true;\n }\n ensureData()[prop as string] = value;\n return true;\n },\n has(target, prop) {\n if (prop === 'id' || prop === 'options' || prop === 'ast' || prop === 'data') {\n return prop in target;\n }\n const data = target.data;\n if (data && typeof data === 'object' && prop in data) return true;\n return prop in target;\n },\n ownKeys(target) {\n // Only enumerate the flat record fields. Wrapper keys\n // (id/options/ast/data) remain accessible via dot/bracket notation\n // but are hidden from Object.keys/for-in so user code that does\n // `Object.keys(input).filter(k => input[k] !== previous[k])` only\n // sees actual record fields.\n const dataKeys = target.data && typeof target.data === 'object'\n ? Object.keys(target.data)\n : [];\n return Array.from(new Set(dataKeys));\n },\n getOwnPropertyDescriptor(target, prop) {\n const data = target.data;\n if (data && typeof data === 'object' && prop in data) {\n return { configurable: true, enumerable: true, writable: true, value: (data as any)[prop] };\n }\n // Wrapper keys: still descriptors so `prop in input` works, but\n // marked non-enumerable so they don't appear in Object.keys().\n if (prop === 'id' || prop === 'options' || prop === 'ast' || prop === 'data') {\n const desc = Object.getOwnPropertyDescriptor(target, prop);\n return desc ? { ...desc, enumerable: false } : undefined;\n }\n return Object.getOwnPropertyDescriptor(target, prop);\n },\n });\n\n (ctx as any).input = proxy;\n return () => {\n (ctx as any).input = raw;\n };\n}\n\n/**\n * Choose the record-shaped object the condition formula should evaluate\n * against. Order:\n * 1. ctx.input.data — write operations carry the new record here\n * 2. ctx.previous — update/delete carry pre-image here\n * 3. ctx.input — fall back to flat input bag (read ops, custom shapes)\n */\nfunction pickRecordPayload(ctx: HookContext): any {\n const input: any = ctx.input ?? {};\n if (input && typeof input === 'object' && input.data && typeof input.data === 'object') {\n return input.data;\n }\n if (ctx.previous && typeof ctx.previous === 'object') {\n return ctx.previous;\n }\n return input;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Hook Execution Metrics\n *\n * Lightweight, transport-agnostic recorder interface for per-hook execution\n * counters and latencies. The default implementation is a no-op so the\n * engine pays zero cost when nobody is observing.\n *\n * Wire a real recorder by calling `engine.setHookMetricsRecorder(recorder)`.\n * The runtime / kernel can adapt this to Otel, Prometheus, StatsD, or\n * whatever telemetry pipeline ships with the deployment.\n *\n * Recorded events:\n * - `recordExecution(label, outcome, durationMs)`\n * outcome ∈ 'success' | 'error' | 'timeout' | 'capability_rejected'\n * - `recordSkip(label, reason)`\n * reason ∈ 'condition' | 'fire_and_forget'\n * - `recordRetry(label, attempt)`\n */\n\nexport type HookMetricOutcome =\n | 'success'\n | 'error'\n | 'timeout'\n | 'capability_rejected';\n\nexport type HookSkipReason = 'condition' | 'fire_and_forget';\n\nexport interface HookMetricLabel {\n /** Hook name (stable id from metadata). */\n hook: string;\n /** Object name the hook is bound to. May be undefined for global hooks. */\n object?: string;\n /** Lifecycle event (`beforeInsert`, `afterUpdate`, etc.). */\n event?: string;\n /** True when the handler comes from a metadata `body` (sandboxed JS). */\n body?: boolean;\n}\n\nexport interface HookMetricsRecorder {\n recordExecution(label: HookMetricLabel, outcome: HookMetricOutcome, durationMs: number): void;\n recordSkip(label: HookMetricLabel, reason: HookSkipReason): void;\n recordRetry(label: HookMetricLabel, attempt: number): void;\n}\n\nexport const noopHookMetricsRecorder: HookMetricsRecorder = {\n recordExecution: () => {},\n recordSkip: () => {},\n recordRetry: () => {},\n};\n\n/**\n * In-memory recorder useful for tests, dev-mode dashboards, and as a\n * starting point for adapter implementations. Aggregates counts + a\n * rolling sum of latency per (hook, outcome).\n */\nexport class InMemoryHookMetricsRecorder implements HookMetricsRecorder {\n private executions = new Map<string, { count: number; totalMs: number }>();\n private skips = new Map<string, number>();\n private retries = new Map<string, number>();\n\n recordExecution(label: HookMetricLabel, outcome: HookMetricOutcome, durationMs: number): void {\n const key = `${label.hook}|${outcome}`;\n const cur = this.executions.get(key) ?? { count: 0, totalMs: 0 };\n cur.count += 1;\n cur.totalMs += Math.max(0, durationMs);\n this.executions.set(key, cur);\n }\n\n recordSkip(label: HookMetricLabel, reason: HookSkipReason): void {\n const key = `${label.hook}|${reason}`;\n this.skips.set(key, (this.skips.get(key) ?? 0) + 1);\n }\n\n recordRetry(label: HookMetricLabel, _attempt: number): void {\n this.retries.set(label.hook, (this.retries.get(label.hook) ?? 0) + 1);\n }\n\n snapshot(): {\n executions: Array<{ hook: string; outcome: HookMetricOutcome; count: number; totalMs: number }>;\n skips: Array<{ hook: string; reason: HookSkipReason; count: number }>;\n retries: Array<{ hook: string; count: number }>;\n } {\n return {\n executions: Array.from(this.executions, ([key, v]) => {\n const [hook, outcome] = key.split('|');\n return { hook, outcome: outcome as HookMetricOutcome, count: v.count, totalMs: v.totalMs };\n }),\n skips: Array.from(this.skips, ([key, count]) => {\n const [hook, reason] = key.split('|');\n return { hook, reason: reason as HookSkipReason, count };\n }),\n retries: Array.from(this.retries, ([hook, count]) => ({ hook, count })),\n };\n }\n\n reset(): void {\n this.executions.clear();\n this.skips.clear();\n this.retries.clear();\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Hook Binder\n *\n * Single, canonical entry point that turns declarative `Hook` metadata into\n * runtime registrations on the `ObjectQL` engine. Every metadata source —\n * `defineStack({ hooks })` (consumed by `AppPlugin`), the per-project\n * template seeder (`MultiProjectPlugin`), and the metadata service\n * (`ObjectQLPlugin.loadMetadataFromService`) — funnels through here so\n * that:\n *\n * - Inline function handlers and string-named handlers share one resolver.\n * - Declarative fields (`condition`, `async`, `retryPolicy`, `timeout`,\n * `onError`) are honoured uniformly via `wrapDeclarativeHook`.\n * - Hooks can be unregistered as a unit via `packageId`, enabling clean\n * hot-reload and app uninstall.\n *\n * The ObjectQL engine itself stays simple — it knows how to store and\n * trigger handlers, but knows nothing about declarative semantics. All\n * metadata-aware behaviour lives in this binder + the wrapper module.\n */\n\nimport type { Hook } from '@objectstack/spec/data';\nimport type { ObjectQL, HookHandler } from './engine.js';\nimport { wrapDeclarativeHook } from './hook-wrappers.js';\nimport type { HookMetricsRecorder } from './hook-metrics.js';\n\nexport interface BindHooksOptions {\n /** Owning package / app id — used for `unregisterHooksByPackage`. */\n packageId?: string;\n\n /**\n * Optional name → function map for resolving string `handler` references.\n * Typically supplied by `defineStack({ functions })` and merged with any\n * functions previously registered on the engine.\n */\n functions?: Record<string, HookHandler>;\n\n /**\n * Optional factory that converts a metadata-only `Hook.body` (L1 expression\n * or L2 sandboxed JS source) into an executable `HookHandler`. The runtime\n * package wires this up using `QuickJSScriptRunner`; objectql itself stays\n * sandbox-free so it can run in lightweight environments.\n *\n * If `hook.body` is set and this factory is missing, the hook is skipped\n * with a clear error.\n */\n bodyRunner?: (hook: Hook) => HookHandler | undefined;\n\n /**\n * When true, treat unresolved hooks (body present but no runner, or handler\n * string with no implementation) as fatal errors instead of warnings. Used\n * by production runtimes to fail fast on misconfiguration. Defaults false.\n */\n strict?: boolean;\n\n /**\n * When true, emit a deprecation warning for every hook that still relies\n * on a `handler` ref string instead of the metadata-only `body`. Used by\n * the CLI (compile time) and runtime (boot time) to nudge users away from\n * the legacy `.mjs` runtime bundle path. Defaults false.\n */\n warnLegacyHandler?: boolean;\n\n /** Per-hook execution metrics sink. Defaults to no-op. */\n metrics?: HookMetricsRecorder;\n\n /** Logger; defaults to a silent no-op. */\n logger?: {\n debug: (msg: string, meta?: any) => void;\n info: (msg: string, meta?: any) => void;\n warn: (msg: string, meta?: any) => void;\n error: (msg: string, meta?: any) => void;\n };\n}\n\nconst noopLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/** Counter for stats. */\nexport interface BindHooksResult {\n registered: number;\n skipped: number;\n errors: Array<{ hook: string; reason: string }>;\n}\n\n/**\n * Bind a list of declarative `Hook` definitions to a running ObjectQL engine.\n *\n * Idempotent on `(packageId, hook.name, event, object)`: re-binding the\n * same set after a hot reload first calls `unregisterHooksByPackage`\n * (when `packageId` is provided).\n */\nexport function bindHooksToEngine(\n engine: ObjectQL,\n hooks: Hook[] | undefined,\n opts: BindHooksOptions = {},\n): BindHooksResult {\n const logger = opts.logger ?? noopLogger;\n const result: BindHooksResult = { registered: 0, skipped: 0, errors: [] };\n\n if (!Array.isArray(hooks) || hooks.length === 0) {\n return result;\n }\n\n // Hot-reload friendly: drop anything we previously bound under this\n // packageId so the new set fully replaces the old.\n if (opts.packageId && typeof (engine as any).unregisterHooksByPackage === 'function') {\n try {\n (engine as any).unregisterHooksByPackage(opts.packageId);\n } catch (err: any) {\n logger.warn('[hook-binder] unregister-by-package failed; continuing', {\n packageId: opts.packageId,\n error: err?.message,\n });\n }\n }\n\n // Pre-load any inline functions supplied via `bundle.functions` so\n // string-handler resolution works.\n if (opts.functions && typeof (engine as any).registerFunction === 'function') {\n for (const [name, fn] of Object.entries(opts.functions)) {\n try {\n (engine as any).registerFunction(name, fn, opts.packageId);\n } catch (err: any) {\n logger.warn('[hook-binder] failed to register function', {\n name,\n error: err?.message,\n });\n }\n }\n }\n\n for (const hook of hooks) {\n try {\n const resolved = resolveHandler(engine, hook, opts);\n if (!resolved) {\n result.skipped += 1;\n const reason = (hook as any).body\n ? `hook body present but no bodyRunner supplied to bindHooksToEngine (runtime must wire QuickJSScriptRunner)`\n : typeof hook.handler === 'string'\n ? `unknown function '${hook.handler}'`\n : 'no handler';\n result.errors.push({ hook: hook.name, reason });\n if (opts.strict) {\n throw new Error(`[hook-binder] strict: cannot bind hook '${hook.name}': ${reason}`);\n }\n logger.warn('[hook-binder] skipping hook with unresolved handler', {\n hook: hook.name,\n handler: hook.handler,\n hasBody: Boolean((hook as any).body),\n });\n continue;\n }\n\n if (opts.warnLegacyHandler && !(hook as any).body && typeof hook.handler === 'string') {\n logger.warn('[hook-binder] DEPRECATED: hook uses legacy handler ref without body', {\n hook: hook.name,\n handler: hook.handler,\n hint: 'Move the handler source into Hook.body so the artifact stays metadata-only and the .mjs runtime bundle can be dropped.',\n });\n }\n\n const wrapped = wrapDeclarativeHook(hook, resolved, { logger, metrics: opts.metrics });\n const objects = normalizeObjects(hook.object);\n const events = Array.isArray(hook.events) ? hook.events : [];\n\n for (const event of events) {\n for (const object of objects) {\n engine.registerHook(event, wrapped, {\n object,\n priority: typeof hook.priority === 'number' ? hook.priority : 100,\n packageId: opts.packageId,\n // Reflect metadata so future tooling can introspect / unregister\n // and so we can detect duplicate name collisions.\n // The engine ignores unknown options today; this is forward-only.\n ...({ meta: hook, hookName: hook.name } as any),\n } as any);\n result.registered += 1;\n }\n }\n } catch (err: any) {\n result.errors.push({ hook: hook.name, reason: err?.message ?? String(err) });\n logger.error('[hook-binder] failed to bind hook', {\n hook: hook.name,\n error: err?.message,\n });\n }\n }\n\n if (result.registered > 0) {\n logger.debug('[hook-binder] hooks bound', {\n packageId: opts.packageId,\n registered: result.registered,\n skipped: result.skipped,\n });\n }\n\n return result;\n}\n\nfunction normalizeObjects(target: Hook['object']): string[] {\n if (Array.isArray(target)) return target.length > 0 ? target : ['*'];\n if (typeof target === 'string' && target.length > 0) return [target];\n return ['*'];\n}\n\nfunction resolveHandler(\n engine: ObjectQL,\n hook: Hook,\n opts: BindHooksOptions,\n): HookHandler | undefined {\n // Metadata-only body (L1 expression or L2 sandboxed JS) takes precedence\n // over the legacy `handler` field. This is the cloud-deployable path —\n // the body string ships inside the artifact JSON and runs under a\n // capability-gated sandbox supplied by the runtime.\n const body = (hook as any).body;\n if (body && typeof body === 'object') {\n let runner = opts.bodyRunner;\n if (typeof runner !== 'function') {\n const fallback = (engine as any)?._defaultBodyRunner;\n if (typeof fallback === 'function') runner = fallback;\n }\n if (typeof runner !== 'function') {\n return undefined;\n }\n const fn = runner(hook);\n if (typeof fn === 'function') return fn;\n return undefined;\n }\n\n const h = hook.handler;\n if (typeof h === 'function') return h as HookHandler;\n if (typeof h === 'string' && h.length > 0) {\n // Try the per-bundle map first (hot path during initial bind),\n // then fall back to whatever the engine already knows.\n const fromBundle = opts.functions?.[h];\n if (typeof fromBundle === 'function') return fromBundle;\n if (typeof (engine as any).resolveFunction === 'function') {\n const fn = (engine as any).resolveFunction(h);\n if (typeof fn === 'function') return fn as HookHandler;\n }\n }\n return undefined;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Record Validator\n *\n * Validates an incoming insert/update payload against the canonical\n * `Field` metadata of an `ObjectSchema`. Implements ROADMAP §M10.4 —\n * \"Zod-at-rest\" — but does not require constructing a Zod schema:\n * we walk the field map directly, which is both faster and lets us\n * produce per-field error envelopes shaped for REST consumption.\n *\n * Rules applied (in order, stop at first error per field):\n *\n * - `required` missing/null/empty-string is rejected (insert only;\n * PATCH validates only fields actually supplied)\n * - `maxLength` / `minLength` (text/textarea/email/url/phone/password)\n * - `min` / `max` (number/currency/percent/rating/slider)\n * - format email / url / phone (lightweight RFC-aware regex)\n * - select / multiselect: value must appear in `options`\n * - boolean / toggle: must coerce to boolean\n * - date / datetime: must be ISO-parsable\n *\n * System-injected fields (`id`, `created_at`, `created_by`,\n * `updated_at`, `updated_by`, `organization_id`) are never validated\n * here — the engine and the audit plugin manage them.\n *\n * On failure, a `ValidationError` is thrown with `.fields[]` holding\n * one entry per offending field. REST translates this into a\n * `400 { code: 'VALIDATION_FAILED', message, fields }` envelope so\n * the UI can highlight the specific input.\n */\n\nconst SKIP_FIELDS = new Set<string>([\n 'id', 'created_at', 'created_by', 'updated_at', 'updated_by',\n 'organization_id', 'tenant_id',\n]);\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n// Permissive URL pattern: accept any scheme:// + non-empty body so that\n// non-HTTP URIs used by drivers (libsql://, postgres://, mysql://, file://, s3://, …)\n// pass field-level validation. Stricter per-field checks can be enforced\n// via custom validators where needed.\nconst URL_RE = /^[a-z][a-z0-9+.\\-]*:\\/\\/[^\\s]+$/i;\nconst PHONE_RE = /^[+()\\-\\s\\d.]{5,}$/;\n\nexport interface FieldValidationError {\n field: string;\n code:\n | 'required'\n | 'min_length'\n | 'max_length'\n | 'min_value'\n | 'max_value'\n | 'invalid_email'\n | 'invalid_url'\n | 'invalid_phone'\n | 'invalid_number'\n | 'invalid_boolean'\n | 'invalid_date'\n | 'invalid_option';\n message: string;\n /** Allowed values for select/multiselect, when applicable. */\n options?: string[];\n}\n\nexport class ValidationError extends Error {\n readonly code = 'VALIDATION_FAILED';\n readonly fields: FieldValidationError[];\n constructor(fields: FieldValidationError[]) {\n super(\n `Validation failed for ${fields.length} field(s): ` +\n fields.map((f) => `${f.field} (${f.code})`).join(', '),\n );\n this.name = 'ValidationError';\n this.fields = fields;\n }\n}\n\ntype Mode = 'insert' | 'update';\n\ninterface FieldDef {\n name?: string;\n type: string;\n required?: boolean;\n readonly?: boolean;\n system?: boolean;\n multiple?: boolean;\n maxLength?: number;\n minLength?: number;\n min?: number;\n max?: number;\n options?: Array<{ value: string | number; label?: string } | string | number>;\n}\n\nfunction isMissing(v: unknown): boolean {\n return v === undefined || v === null || (typeof v === 'string' && v.trim() === '');\n}\n\nfunction optionValues(options: FieldDef['options']): string[] {\n if (!Array.isArray(options)) return [];\n return options.map((o) =>\n typeof o === 'object' && o !== null ? String((o as any).value) : String(o),\n );\n}\n\nfunction validateOne(name: string, def: FieldDef, value: unknown): FieldValidationError | null {\n // ── required ────────────────────────────────────────────────────\n if (def.required && isMissing(value)) {\n return { field: name, code: 'required', message: `${name} is required` };\n }\n if (isMissing(value)) return null; // nothing else to check\n\n const t = def.type;\n\n // ── string types ────────────────────────────────────────────────\n if (t === 'text' || t === 'textarea' || t === 'email' || t === 'url' || t === 'phone' || t === 'password' || t === 'markdown' || t === 'html' || t === 'richtext' || t === 'code') {\n const s = typeof value === 'string' ? value : String(value);\n if (def.maxLength !== undefined && s.length > def.maxLength) {\n return { field: name, code: 'max_length', message: `${name} must be ≤ ${def.maxLength} characters (got ${s.length})` };\n }\n if (def.minLength !== undefined && s.length < def.minLength) {\n return { field: name, code: 'min_length', message: `${name} must be ≥ ${def.minLength} characters (got ${s.length})` };\n }\n if (t === 'email' && !EMAIL_RE.test(s)) {\n return { field: name, code: 'invalid_email', message: `${name} must be a valid email address` };\n }\n if (t === 'url' && !URL_RE.test(s)) {\n return { field: name, code: 'invalid_url', message: `${name} must be a valid URL (scheme://...)` };\n }\n if (t === 'phone' && !PHONE_RE.test(s)) {\n return { field: name, code: 'invalid_phone', message: `${name} must be a valid phone number` };\n }\n return null;\n }\n\n // ── number types ────────────────────────────────────────────────\n if (t === 'number' || t === 'currency' || t === 'percent' || t === 'rating' || t === 'slider') {\n const n = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(n)) {\n return { field: name, code: 'invalid_number', message: `${name} must be a number` };\n }\n if (def.min !== undefined && n < def.min) {\n return { field: name, code: 'min_value', message: `${name} must be ≥ ${def.min}` };\n }\n if (def.max !== undefined && n > def.max) {\n return { field: name, code: 'max_value', message: `${name} must be ≤ ${def.max}` };\n }\n return null;\n }\n\n // ── boolean ────────────────────────────────────────────────────\n if (t === 'boolean' || t === 'toggle') {\n if (typeof value === 'boolean') return null;\n if (value === 0 || value === 1 || value === '0' || value === '1' || value === 'true' || value === 'false') return null;\n return { field: name, code: 'invalid_boolean', message: `${name} must be true or false` };\n }\n\n // ── date/datetime ───────────────────────────────────────────────\n if (t === 'date' || t === 'datetime' || t === 'time') {\n if (value instanceof Date) return null;\n if (typeof value === 'string' && !Number.isNaN(Date.parse(value))) return null;\n return { field: name, code: 'invalid_date', message: `${name} must be a valid ${t} (ISO-8601)` };\n }\n\n // ── select / multiselect / radio ────────────────────────────────\n if (t === 'select' || t === 'radio') {\n const allowed = optionValues(def.options);\n if (allowed.length > 0 && !allowed.includes(String(value))) {\n return { field: name, code: 'invalid_option', message: `${name} must be one of: ${allowed.join(', ')}`, options: allowed };\n }\n return null;\n }\n if (t === 'multiselect' || t === 'checkboxes' || t === 'tags') {\n const allowed = optionValues(def.options);\n if (allowed.length === 0) return null;\n const arr = Array.isArray(value) ? value : [value];\n for (const v of arr) {\n if (!allowed.includes(String(v))) {\n return { field: name, code: 'invalid_option', message: `${name}: \"${v}\" is not one of: ${allowed.join(', ')}`, options: allowed };\n }\n }\n return null;\n }\n\n // Other types (lookup, file, formula, json, location, etc.) — no\n // strict shape check at this layer; reference integrity is handled\n // elsewhere (lookup) and the rest are opaque payloads.\n return null;\n}\n\n/**\n * Validate a payload against a list of declared fields. `objectSchema`\n * comes from `ObjectQL.getRegistry().getObject(name)` and exposes a\n * `fields` map of `{ [fieldName]: FieldDef }`.\n *\n * Returns void on success; throws `ValidationError` on failure.\n */\nexport function validateRecord(\n objectSchema: { fields?: Record<string, FieldDef> } | undefined | null,\n data: Record<string, unknown> | undefined | null,\n mode: Mode,\n): void {\n if (!objectSchema?.fields || !data) return;\n\n const errors: FieldValidationError[] = [];\n const fields = objectSchema.fields;\n\n if (mode === 'insert') {\n // Walk all declared fields — required check applies even when\n // the caller didn't supply the field at all.\n for (const [name, def] of Object.entries(fields)) {\n if (SKIP_FIELDS.has(name)) continue;\n if (def.system || def.readonly) continue;\n const err = validateOne(name, def, data[name]);\n if (err) errors.push(err);\n }\n } else {\n // Update — validate only supplied fields, skip required check.\n for (const [name, value] of Object.entries(data)) {\n if (SKIP_FIELDS.has(name)) continue;\n const def = fields[name];\n if (!def) continue;\n if (def.system || def.readonly) continue;\n // Clone def with required=false so PATCH-omitted-fields don't 400.\n const err = validateOne(name, { ...def, required: false }, value);\n if (err) errors.push(err);\n }\n }\n\n if (errors.length > 0) throw new ValidationError(errors);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n//\n// In-memory implementation of the QueryAST aggregation contract.\n//\n// This module is the engine's last-resort path: when the underlying driver\n// returned raw rows but the caller asked for `groupBy` / `aggregations`, the\n// engine pipes the rows through here so the abstract contract is always\n// honoured even on drivers without native aggregation (driver-rest, partial\n// SQL drivers, mock drivers in tests).\n//\n// Capabilities:\n// * Flat groupBy strings: `['region']`\n// * Structured groupBy with date bucketing: `[{ field: 'closed_at',\n// dateGranularity: 'quarter' }]`\n// * Aggregation functions: count, count_distinct, sum, avg, min, max,\n// array_agg, string_agg\n// * `distinct: true` on aggregations (collapse duplicates before applying\n// the function)\n// * `filter: FilterCondition` on aggregations is **not** evaluated here —\n// the engine routes filtered aggregations through the driver where\n// possible; the in-memory fallback ignores the per-aggregation filter and\n// logs a warning if one is present.\n//\n// Date bucketing uses ISO-8601 conventions (weeks start Monday). Null /\n// invalid values bucket as the literal string `'(null)'` to remain\n// consistent with the client `useReportData` hook.\n\nimport type { QueryAST, GroupByNode, AggregationNode, DateGranularityValue } from '@objectstack/spec/data';\n\n/**\n * Group + aggregate raw rows according to the AST's `groupBy` /\n * `aggregations`. When neither is present, returns the rows unchanged.\n */\nexport function applyInMemoryAggregation(\n rows: any[],\n ast: Pick<QueryAST, 'groupBy' | 'aggregations'>,\n): any[] {\n const groupBy = (ast.groupBy ?? []) as GroupByNode[];\n const aggregations = (ast.aggregations ?? []) as AggregationNode[];\n if (groupBy.length === 0 && aggregations.length === 0) return rows;\n\n if (groupBy.length === 0) {\n // Pure aggregation — single result row.\n return [aggregateBucket(rows, aggregations)];\n }\n\n const buckets = new Map<string, { key: Record<string, any>; rows: any[] }>();\n for (const row of rows) {\n const key: Record<string, any> = {};\n const parts: string[] = [];\n for (const g of groupBy) {\n const fieldName = typeof g === 'string' ? g : (g.alias ?? g.field);\n const value = projectGroupValue(row, g);\n key[fieldName] = value;\n parts.push(`${fieldName}=${value}`);\n }\n const id = parts.join('\\u0001');\n let bucket = buckets.get(id);\n if (!bucket) {\n bucket = { key, rows: [] };\n buckets.set(id, bucket);\n }\n bucket.rows.push(row);\n }\n\n const out: any[] = [];\n for (const { key, rows: bucketRows } of buckets.values()) {\n const aggValues = aggregateBucket(bucketRows, aggregations);\n out.push({ ...key, ...aggValues });\n }\n return out;\n}\n\nfunction projectGroupValue(row: any, g: GroupByNode): string {\n const field = typeof g === 'string' ? g : g.field;\n const v = row?.[field];\n if (typeof g !== 'string' && g.dateGranularity) {\n return bucketDateValue(v, g.dateGranularity);\n }\n return v == null ? '(null)' : String(v);\n}\n\nfunction aggregateBucket(rows: any[], aggregations: AggregationNode[]): Record<string, any> {\n const out: Record<string, any> = {};\n for (const agg of aggregations) {\n const alias = agg.alias;\n const fn = agg.function;\n if (fn === 'count') {\n if (!agg.field) {\n out[alias] = rows.length;\n } else {\n out[alias] = rows.reduce(\n (acc, r) => (r[agg.field as string] != null ? acc + 1 : acc),\n 0,\n );\n }\n continue;\n }\n const field = agg.field;\n if (!field) {\n out[alias] = null;\n continue;\n }\n const values = collectValues(rows, field, !!agg.distinct);\n\n switch (fn) {\n case 'count_distinct':\n out[alias] = new Set(values.filter((v) => v != null)).size;\n break;\n case 'sum':\n out[alias] = values.reduce((a, b) => a + toNumber(b), 0);\n break;\n case 'avg': {\n const nums = values.filter((v) => v != null).map(toNumber);\n out[alias] = nums.length === 0 ? null : nums.reduce((a, b) => a + b, 0) / nums.length;\n break;\n }\n case 'min': {\n const defined = values.filter((v) => v != null);\n out[alias] = defined.length === 0 ? null : defined.reduce((a, b) => (a < b ? a : b));\n break;\n }\n case 'max': {\n const defined = values.filter((v) => v != null);\n out[alias] = defined.length === 0 ? null : defined.reduce((a, b) => (a > b ? a : b));\n break;\n }\n case 'array_agg':\n out[alias] = values.slice();\n break;\n case 'string_agg':\n out[alias] = values.filter((v) => v != null).map(String).join(',');\n break;\n default:\n out[alias] = null;\n }\n }\n return out;\n}\n\nfunction collectValues(rows: any[], field: string, distinct: boolean): any[] {\n if (!distinct) return rows.map((r) => r?.[field]);\n const seen = new Set<unknown>();\n const out: any[] = [];\n for (const r of rows) {\n const v = r?.[field];\n if (seen.has(v)) continue;\n seen.add(v);\n out.push(v);\n }\n return out;\n}\n\nfunction toNumber(v: any): number {\n if (typeof v === 'number') return v;\n if (v == null) return 0;\n const n = Number(v);\n return Number.isFinite(n) ? n : 0;\n}\n\n/**\n * Bucket a date-like value into an ISO-formatted period label. Weeks start\n * Monday and use ISO week numbering.\n */\nexport function bucketDateValue(value: unknown, granularity: DateGranularityValue): string {\n if (value == null) return '(null)';\n const d = value instanceof Date ? value : new Date(String(value));\n if (Number.isNaN(d.getTime())) return '(null)';\n const y = d.getUTCFullYear();\n const m = d.getUTCMonth() + 1;\n switch (granularity) {\n case 'year':\n return String(y);\n case 'quarter':\n return `${y}-Q${Math.floor((m - 1) / 3) + 1}`;\n case 'month':\n return `${y}-${String(m).padStart(2, '0')}`;\n case 'day':\n return `${y}-${String(m).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n case 'week': {\n // ISO-8601 week date: week 1 contains the first Thursday of the year.\n const target = new Date(Date.UTC(y, d.getUTCMonth(), d.getUTCDate()));\n const dayNum = (target.getUTCDay() + 6) % 7; // Mon=0..Sun=6\n target.setUTCDate(target.getUTCDate() - dayNum + 3);\n const firstThursday = new Date(Date.UTC(target.getUTCFullYear(), 0, 4));\n const weekNo = 1 + Math.round(\n ((target.getTime() - firstThursday.getTime()) / 86400000 - 3 + ((firstThursday.getUTCDay() + 6) % 7)) / 7,\n );\n return `${target.getUTCFullYear()}-W${String(weekNo).padStart(2, '0')}`;\n }\n default:\n return String(value);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { SchemaRegistry } from './registry.js';\n\n/**\n * MetadataFacade\n *\n * Provides a clean, injectable interface over SchemaRegistry.\n * Registered as the 'metadata' kernel service to eliminate\n * downstream packages needing to manually wrap SchemaRegistry.\n *\n * Implements the async IMetadataService interface.\n * Internally delegates to SchemaRegistry (in-memory) with Promise wrappers.\n *\n * Each facade is bound to a specific SchemaRegistry instance — passed in the\n * constructor — so that multi-kernel servers can give every kernel its own\n * metadata surface without leaking state across tenants.\n */\nexport class MetadataFacade {\n constructor(private registry: SchemaRegistry) {}\n\n /**\n * Register a metadata item\n */\n async register(type: string, name: string, data: any): Promise<void> {\n const definition = typeof data === 'object' && data !== null\n ? { ...data, name: data.name ?? name }\n : data;\n if (type === 'object') {\n this.registry.registerItem(type, definition, 'name' as any);\n } else {\n this.registry.registerItem(type, definition, definition.id ? 'id' as any : 'name' as any);\n }\n }\n\n /**\n * Get a metadata item by type and name\n */\n async get(type: string, name: string): Promise<any> {\n const item = this.registry.getItem(type, name) as any;\n return item?.content ?? item;\n }\n\n /**\n * Get the raw entry (with metadata wrapper)\n */\n getEntry(type: string, name: string): any {\n return this.registry.getItem(type, name);\n }\n\n /**\n * List all items of a type\n */\n async list(type: string): Promise<any[]> {\n const items = this.registry.listItems(type);\n return items.map((item: any) => item?.content ?? item);\n }\n\n /**\n * Unregister a metadata item\n */\n async unregister(type: string, name: string): Promise<void> {\n this.registry.unregisterItem(type, name);\n }\n\n /**\n * Check if a metadata item exists\n */\n async exists(type: string, name: string): Promise<boolean> {\n const item = this.registry.getItem(type, name);\n return item !== undefined && item !== null;\n }\n\n /**\n * List all names of metadata items of a given type\n */\n async listNames(type: string): Promise<string[]> {\n const items = this.registry.listItems(type);\n return items.map((item: any) => item?.name ?? item?.content?.name ?? '').filter(Boolean);\n }\n\n /**\n * Unregister all metadata from a package\n */\n async unregisterPackage(packageName: string): Promise<void> {\n this.registry.unregisterObjectsByPackage(packageName);\n }\n\n /**\n * Convenience: get object definition\n */\n async getObject(name: string): Promise<any> {\n return this.registry.getObject(name);\n }\n\n /**\n * Convenience: list all objects\n */\n async listObjects(): Promise<any[]> {\n return this.registry.getAllObjects();\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectQL } from './engine.js';\nimport { ObjectStackProtocolImplementation } from './protocol.js';\nimport { Plugin, PluginContext } from '@objectstack/core';\nimport { StorageNameMapping } from '@objectstack/spec/system';\n\nexport type { Plugin, PluginContext };\n\n/**\n * Protocol extension for DB-based metadata hydration.\n * `loadMetaFromDb` is implemented by ObjectStackProtocolImplementation but\n * is NOT (yet) part of the canonical ObjectStackProtocol wire-contract in\n * `@objectstack/spec`, since it is a server-side bootstrap concern only.\n */\ninterface ProtocolWithDbRestore {\n loadMetaFromDb(): Promise<{ loaded: number; errors: number }>;\n}\n\n/** Type guard — checks whether the service exposes `loadMetaFromDb`. */\nfunction hasLoadMetaFromDb(service: unknown): service is ProtocolWithDbRestore {\n return (\n typeof service === 'object' &&\n service !== null &&\n typeof (service as Record<string, unknown>)['loadMetaFromDb'] === 'function'\n );\n}\n\n/**\n * Options for ObjectQLPlugin.\n *\n * `projectId` scopes all metadata writes + reads to a specific project.\n * When set, `protocol.saveMetaItem` stamps `project_id = <projectId>` on\n * new sys_metadata rows, and `protocol.loadMetaFromDb` filters by the same\n * column. Leave undefined in single-kernel / self-hosted mode — rows land\n * in the platform-global scope (project_id IS NULL).\n */\nexport interface ObjectQLPluginOptions {\n /** Optional pre-built engine. When absent, one is lazily created in init. */\n ql?: ObjectQL;\n /** Passed to `new ObjectQL(...)` when `ql` is not supplied. */\n hostContext?: Record<string, any>;\n /** Scope sys_metadata reads/writes to this project. */\n projectId?: string;\n /**\n * Override the kernel's default plugin-start timeout for this plugin.\n * Defaults to 120000 (120s). Schema sync to a remote SQL backend\n * (Neon/Postgres/Turso) is latency-bound — the SQL driver currently\n * does NOT support `batchSchemaSync`, so it issues one round-trip per\n * registered object × twice (Phase 1 + Phase 3 in `start()`). On a\n * cold remote DB with N tables this can blow past the kernel's\n * default 30s easily, even though everything is healthy.\n */\n startupTimeout?: number;\n /**\n * Skip both `syncRegisteredSchemas()` calls inside `start()` and\n * assume DDL is managed out-of-band (e.g. an `apps/cloud/scripts/migrate.ts`\n * run before deploy that connects directly to the database and creates\n * all `sys_*` + custom tables once).\n *\n * Use this on cold-start-sensitive runtimes (Cloudflare Containers,\n * Lambda) where the platform's inbound-request budget is shorter than\n * a fresh remote-DB schema sync. The plugin still hydrates the\n * SchemaRegistry from `sys_metadata` (Phase 2), so custom user\n * objects come up — they just aren't re-DDL'd on every cold boot.\n *\n * Falls back to `process.env.OS_SKIP_SCHEMA_SYNC === '1'` when the\n * option is unset, so containers can flip it via their env without a\n * code change.\n */\n skipSchemaSync?: boolean;\n}\n\nexport class ObjectQLPlugin implements Plugin {\n name = 'com.objectstack.engine.objectql';\n type = 'objectql';\n version = '1.0.0';\n /**\n * Schema sync to remote SQL DBs is latency-bound (one round-trip per\n * table × 2 phases). Default to 120s instead of the kernel's 30s so\n * cold Neon/Turso starts don't get killed mid-sync.\n */\n startupTimeout = 120_000;\n\n private ql: ObjectQL | undefined;\n private hostContext?: Record<string, any>;\n private projectId?: string;\n private skipSchemaSync = false;\n /** Unsubscribe handles for metadata-event subscriptions (ADR-0008 PR-7). */\n private metadataUnsubscribes: Array<() => void> = [];\n\n constructor(qlOrOptions?: ObjectQL | ObjectQLPluginOptions, hostContext?: Record<string, any>) {\n // Back-compat: legacy callers passed `(ObjectQL, hostContext)` positionally.\n if (qlOrOptions instanceof ObjectQL) {\n this.ql = qlOrOptions;\n this.hostContext = hostContext;\n return;\n }\n // New signature: options bag.\n const opts = (qlOrOptions as ObjectQLPluginOptions | undefined) ?? {};\n if (opts.ql) {\n this.ql = opts.ql;\n }\n this.hostContext = opts.hostContext ?? hostContext;\n this.projectId = opts.projectId;\n if (typeof opts.startupTimeout === 'number' && opts.startupTimeout > 0) {\n this.startupTimeout = opts.startupTimeout;\n }\n this.skipSchemaSync =\n typeof opts.skipSchemaSync === 'boolean'\n ? opts.skipSchemaSync\n : process.env.OS_SKIP_SCHEMA_SYNC === '1';\n }\n\n init = async (ctx: PluginContext) => {\n if (!this.ql) {\n // Pass kernel logger to engine to avoid creating a separate logger instance\n const hostCtx = { ...this.hostContext, logger: ctx.logger };\n this.ql = new ObjectQL(hostCtx);\n }\n \n // Register as provider for Core Kernel Services\n ctx.registerService('objectql', this.ql);\n\n ctx.registerService('data', this.ql); // ObjectQL implements IDataEngine\n\n // Register manifest service for direct app/package registration.\n // Plugins call ctx.getService('manifest').register(manifestData)\n // instead of the legacy ctx.registerService('app.<id>', manifestData) convention.\n const ql = this.ql;\n ctx.registerService('manifest', {\n register: (manifest: any) => {\n ql.registerApp(manifest);\n ctx.logger.debug('Manifest registered via manifest service', {\n id: manifest.id || manifest.name\n });\n }\n });\n\n ctx.logger.info('ObjectQL engine registered', {\n services: ['objectql', 'data', 'manifest'],\n });\n\n // Register Protocol Implementation\n const protocolShim = new ObjectStackProtocolImplementation(\n this.ql,\n () => ctx.getServices ? ctx.getServices() : new Map(),\n undefined,\n this.projectId,\n );\n\n ctx.registerService('protocol', protocolShim);\n ctx.logger.info('Protocol service registered');\n\n // Register an `analytics` service adapter that maps the dispatcher's\n // expected interface (query / getMeta / generateSql) onto the\n // protocol shim's `analyticsQuery`. Without this, HttpDispatcher's\n // `handleAnalytics` cannot resolve a service and `/api/v1/analytics/*`\n // returns ROUTE_NOT_FOUND, even though discovery advertises the route\n // (objectql's getDiscovery hardcodes `analytics: enabled:true`). The\n // adapter delegates `query` to the cube → engine.aggregate translator\n // already implemented in protocol.ts; getMeta/generateSql return a\n // structured \"not implemented\" payload so callers see something\n // useful instead of a 500.\n ctx.registerService('analytics', {\n query: (body: any) => protocolShim.analyticsQuery(body),\n getMeta: async () => ({\n cubes: [],\n message: 'Analytics meta endpoint not implemented by ObjectQL adapter',\n }),\n generateSql: async (_body: any) => ({\n sql: null,\n message: 'Analytics SQL generation not implemented by ObjectQL adapter',\n }),\n });\n }\n\n start = async (ctx: PluginContext) => {\n ctx.logger.info('ObjectQL engine starting...');\n\n // Sync from external metadata service (e.g. MetadataPlugin) if available\n try {\n const metadataService = ctx.getService('metadata') as any;\n if (metadataService && typeof metadataService.loadMany === 'function' && this.ql) {\n await this.loadMetadataFromService(metadataService, ctx);\n }\n // ── ADR-0008 PR-7: subscribe to object metadata events so the\n // SchemaRegistry cache is invalidated on edits (Studio HMR).\n // The metadata service bubbles repo events through its own\n // `subscribe(type, cb)` API (PR-6 bridge), so we don't talk\n // to the repo directly here — this keeps ObjectQL decoupled\n // from the storage backend.\n if (metadataService && typeof metadataService.subscribe === 'function' && this.ql) {\n this.subscribeToMetadataEvents(metadataService, ctx);\n }\n } catch (e: any) {\n ctx.logger.debug('No external metadata service to sync from');\n }\n \n // Discover features from Kernel Services\n if (ctx.getServices && this.ql) {\n const services = ctx.getServices();\n for (const [name, service] of services.entries()) {\n if (name.startsWith('driver.')) {\n // Register Driver\n this.ql.registerDriver(service);\n ctx.logger.debug('Discovered and registered driver service', { serviceName: name });\n }\n if (name.startsWith('app.')) {\n // Legacy fallback: discover app.* services (DEPRECATED)\n ctx.logger.warn(\n `[DEPRECATED] Service \"${name}\" uses legacy app.* convention. ` +\n `Migrate to ctx.getService('manifest').register(data).`\n );\n this.ql.registerApp(service); // service is Manifest\n ctx.logger.debug('Discovered and registered app service (legacy)', { serviceName: name });\n }\n }\n\n // Bridge realtime service from kernel service registry to ObjectQL.\n // RealtimeServicePlugin registers as 'realtime' service during init().\n // This enables ObjectQL to publish data change events.\n try {\n const realtimeService = ctx.getService('realtime');\n if (realtimeService && typeof realtimeService === 'object' && 'publish' in realtimeService) {\n ctx.logger.info('[ObjectQLPlugin] Bridging realtime service to ObjectQL for event publishing');\n this.ql.setRealtimeService(realtimeService as any);\n }\n } catch (e: any) {\n ctx.logger.debug('[ObjectQLPlugin] No realtime service found — data events will not be published', {\n error: e.message,\n });\n }\n }\n\n // Initialize drivers (calls driver.connect() which sets up persistence)\n await this.ql?.init();\n\n // Phase 1: Sync built-in schemas so sys_metadata table exists before reading it.\n //\n // Cold-start-sensitive runtimes (Cloudflare Containers, Lambda) can\n // opt out via `skipSchemaSync` / `OS_SKIP_SCHEMA_SYNC=1`. In that\n // mode an out-of-band migration must have already created every\n // table; we only assume the DDL is in place and skip straight to\n // hydration. This avoids one round-trip per table × N objects on\n // every cold boot.\n if (this.skipSchemaSync) {\n ctx.logger.info('Skipping schema sync (OS_SKIP_SCHEMA_SYNC=1) — assuming DDL is managed out-of-band');\n } else {\n await this.syncRegisteredSchemas(ctx);\n }\n\n // Phase 2: Hydrate SchemaRegistry from sys_metadata (loads custom/template objects).\n // Project kernels (projectId set) never persist sys_metadata locally —\n // metadata is sourced from the artifact (MetadataPlugin) or routed to the\n // control plane via ControlPlaneProxyDriver. Skip to avoid querying a table\n // that does not exist on local project DBs.\n if (this.projectId === undefined) {\n await this.restoreMetadataFromDb(ctx);\n } else {\n ctx.logger.info('Project kernel — skipping sys_metadata hydration (metadata sourced from artifact)');\n }\n\n // Phase 3: Sync any new schemas that were just hydrated from the DB\n // (e.g. CRM objects seeded via template — they must have tables before use).\n if (!this.skipSchemaSync) {\n await this.syncRegisteredSchemas(ctx);\n }\n\n // Bridge all SchemaRegistry objects to metadata service.\n //\n // `SchemaRegistry` is a process-wide singleton, so project kernels in a\n // multi-project server would otherwise inherit every object ever\n // registered by any sibling project. When this plugin was constructed\n // with a `projectId`, the kernel is project-scoped — its\n // metadata comes from the artifact (MetadataPlugin) or the\n // control-plane proxy, not from local sys_metadata. The bridge would\n // only pollute its metadata service with cross-project leakage, so\n // skip it in that case.\n if (this.projectId === undefined) {\n await this.bridgeObjectsToMetadataService(ctx);\n }\n\n // Register built-in audit hooks\n this.registerAuditHooks(ctx);\n\n // Tenant isolation is now handled by `@objectstack/plugin-security`\n // via the `member_default` permission set's RLS rule\n // (`organization_id = current_user.organization_id`, with\n // field-existence guards). The legacy hard-coded `tenant_id` filter\n // middleware was removed because it (a) collided with the\n // SecurityPlugin RLS pipeline and (b) blindly filtered tables that\n // don't have a `tenant_id` column (e.g. `sys_organization`),\n // returning 0 rows instead of all rows.\n\n ctx.logger.info('ObjectQL engine started', {\n driversRegistered: this.ql?.['drivers']?.size || 0,\n objectsRegistered: this.ql?.registry?.getAllObjects?.()?.length || 0\n });\n }\n\n stop = async (ctx: PluginContext) => {\n // ADR-0008 PR-7: tear down metadata subscriptions on plugin stop so\n // tests don't leak watchers and reloaded plugins don't double-subscribe.\n for (const unsub of this.metadataUnsubscribes) {\n try { unsub(); } catch (e: any) {\n ctx.logger.debug('[ObjectQLPlugin] metadata-event unsubscribe failed', { error: e?.message });\n }\n }\n this.metadataUnsubscribes = [];\n }\n\n /**\n * Subscribe to `object` metadata events from the metadata service and\n * invalidate the SchemaRegistry merge cache on each event (ADR-0008\n * PR-7). For create/update we also re-load the affected object from\n * the metadata service so subsequent reads see the new definition;\n * for delete we unregister it from every contributing package.\n *\n * Events are filtered to the canonical `object` type — view/dashboard\n * /flow edits go through their own consumers (Studio SSE, REST cache).\n *\n * Stored unsubscribe handle is invoked from {@link stop}.\n */\n private subscribeToMetadataEvents(metadataService: any, ctx: PluginContext) {\n const handler = async (evt: any) => {\n if (!this.ql) return;\n const name: string = evt?.name ?? '';\n if (!name) return;\n const eventType: 'added' | 'changed' | 'deleted' =\n evt?.type === 'added' || evt?.type === 'changed' || evt?.type === 'deleted'\n ? evt.type\n : 'changed';\n\n try {\n // Drop the merged-schema cache entry first so any in-flight\n // resolveObject() races recompute against the new state.\n this.ql.registry.invalidate(name);\n\n if (eventType === 'deleted') {\n ctx.logger.info('[ObjectQLPlugin] object metadata deleted — registry invalidated', { name });\n return;\n }\n\n // Re-fetch the canonical definition from the metadata service.\n // The metadata service goes through its loader chain (FS, DB,\n // attached repository), so this picks up edits from any source.\n const fresh = typeof metadataService.get === 'function'\n ? await metadataService.get('object', name)\n : undefined;\n if (fresh && typeof fresh === 'object') {\n // Re-register with the original contributor metadata. We use\n // 'metadata-service' as packageId to match how the initial\n // load enrolls these objects (see `loadMetadataFromService`).\n const packageId = (fresh as any)._packageId ?? 'metadata-service';\n const namespace = (fresh as any).namespace;\n this.ql.registry.registerObject(\n fresh as any,\n packageId,\n namespace,\n 'own',\n );\n ctx.logger.info('[ObjectQLPlugin] object metadata updated — registry refreshed', {\n name,\n packageId,\n });\n } else {\n ctx.logger.debug('[ObjectQLPlugin] object event received but metadata service has no fresh body', { name });\n }\n } catch (e: any) {\n ctx.logger.warn('[ObjectQLPlugin] metadata event handler failed', {\n name,\n error: e?.message,\n });\n }\n };\n\n const unsub = metadataService.subscribe('object', handler);\n if (typeof unsub === 'function') {\n this.metadataUnsubscribes.push(unsub);\n } else if (unsub && typeof unsub.unsubscribe === 'function') {\n // Support `MetadataWatchHandle` style return shape.\n this.metadataUnsubscribes.push(() => unsub.unsubscribe());\n }\n ctx.logger.info('[ObjectQLPlugin] subscribed to object metadata events (ADR-0008 PR-7)');\n }\n\n /**\n * Register built-in audit hooks for auto-stamping created_by/updated_by\n * and fetching previousData for update/delete operations. These are\n * declared as canonical `Hook` metadata and bound through the same\n * `bindHooksToEngine` path used by `defineStack({ hooks })`, so the\n * engine's built-ins flow through the same rails as user code\n * (dogfooding the protocol).\n */\n private registerAuditHooks(ctx: PluginContext) {\n if (!this.ql) return;\n\n const stamp = () => new Date().toISOString();\n\n /**\n * Returns true when the resolved object schema declares a field with the\n * given name. Audit fields (`created_by`, `updated_by`, `tenant_id`) are\n * NOT auto-injected by the SQL driver, so we must only stamp values for\n * fields the user has explicitly declared on the object — otherwise the\n * driver will issue an INSERT against a column that does not exist in\n * the physical table (e.g. `table lead has no column named created_by`).\n *\n * `created_at`/`updated_at` are unconditional because driver-sql creates\n * them as built-in columns on every table.\n */\n const hasField = (objectName: string, field: string): boolean => {\n try {\n const schema: any = this.ql?.getSchema?.(objectName);\n if (!schema || typeof schema !== 'object') return false;\n const fields = schema.fields;\n if (!fields || typeof fields !== 'object') return false;\n return Object.prototype.hasOwnProperty.call(fields, field);\n } catch {\n return false;\n }\n };\n\n const applyToRecord = (\n record: Record<string, any>,\n objectName: string,\n session: any,\n isInsert: boolean,\n ) => {\n const now = stamp();\n if (isInsert) {\n record.created_at = record.created_at ?? now;\n }\n record.updated_at = now;\n if (session?.userId) {\n if (isInsert && hasField(objectName, 'created_by')) {\n record.created_by = record.created_by ?? session.userId;\n }\n if (hasField(objectName, 'updated_by')) {\n record.updated_by = session.userId;\n }\n }\n if (isInsert && session?.tenantId && hasField(objectName, 'tenant_id')) {\n record.tenant_id = record.tenant_id ?? session.tenantId;\n }\n };\n\n const stampData = (\n data: unknown,\n objectName: string,\n session: any,\n isInsert: boolean,\n ) => {\n if (Array.isArray(data)) {\n for (const row of data) {\n if (row && typeof row === 'object') {\n applyToRecord(row as Record<string, any>, objectName, session, isInsert);\n }\n }\n } else if (data && typeof data === 'object') {\n applyToRecord(data as Record<string, any>, objectName, session, isInsert);\n }\n };\n\n const builtinHooks: any[] = [\n {\n name: 'sys_stamp_audit_insert',\n object: '*',\n events: ['beforeInsert'],\n priority: 10,\n description: 'Auto-stamp created_by / updated_by / created_at / updated_at / tenant_id on insert (only when the field exists on the object schema)',\n handler: async (hookCtx: any) => {\n if (hookCtx.input?.data) {\n stampData(hookCtx.input.data, hookCtx.object, hookCtx.session, true);\n }\n },\n },\n {\n name: 'sys_stamp_audit_update',\n object: '*',\n events: ['beforeUpdate'],\n priority: 10,\n description: 'Auto-stamp updated_by / updated_at on update (only when the field exists on the object schema)',\n handler: async (hookCtx: any) => {\n if (hookCtx.input?.data) {\n stampData(hookCtx.input.data, hookCtx.object, hookCtx.session, false);\n }\n },\n },\n {\n name: 'sys_fetch_previous_update',\n object: '*',\n events: ['beforeUpdate'],\n priority: 5,\n description: 'Auto-fetch the previous record for update hooks',\n handler: async (hookCtx: any) => {\n if (hookCtx.input?.id && !hookCtx.previous) {\n try {\n const existing = await this.ql!.findOne(hookCtx.object, {\n where: { id: hookCtx.input.id },\n context: {\n roles: [],\n permissions: [],\n isSystem: true,\n ...(hookCtx.transaction ? { transaction: hookCtx.transaction } : {}),\n } as any,\n });\n if (existing) hookCtx.previous = existing;\n } catch (_e) {\n // Non-fatal: some objects may not support findOne\n }\n }\n },\n },\n {\n name: 'sys_fetch_previous_delete',\n object: '*',\n events: ['beforeDelete'],\n priority: 5,\n description: 'Auto-fetch the previous record for delete hooks',\n handler: async (hookCtx: any) => {\n if (hookCtx.input?.id && !hookCtx.previous) {\n try {\n const existing = await this.ql!.findOne(hookCtx.object, {\n where: { id: hookCtx.input.id },\n context: {\n roles: [],\n permissions: [],\n isSystem: true,\n ...(hookCtx.transaction ? { transaction: hookCtx.transaction } : {}),\n } as any,\n });\n if (existing) hookCtx.previous = existing;\n } catch (_e) {\n // Non-fatal\n }\n }\n },\n },\n ];\n\n if (typeof (this.ql as any).bindHooks === 'function') {\n (this.ql as any).bindHooks(builtinHooks, { packageId: 'sys:audit' });\n } else {\n // Defensive fallback if binder isn't available (older builds).\n for (const h of builtinHooks) {\n for (const event of h.events) {\n this.ql.registerHook(event, h.handler, {\n object: h.object,\n priority: h.priority,\n packageId: 'sys:audit',\n });\n }\n }\n }\n\n ctx.logger.debug('Audit hooks registered via binder (created_by/updated_by, previousData)');\n }\n\n /**\n * Tenant isolation moved to `@objectstack/plugin-security`'s\n * `member_default` permission set RLS\n * (`organization_id = current_user.organization_id`, with\n * field-existence guards). The legacy `registerTenantMiddleware`\n * method was removed because it (a) collided with SecurityPlugin's\n * RLS pipeline and (b) blindly filtered tables that don't have a\n * `tenant_id` column (e.g. `sys_organization`), returning 0 rows\n * instead of all rows.\n */\n\n /**\n * Synchronize all registered object schemas to the database.\n *\n * Groups objects by their responsible driver, then:\n * - If the driver advertises `supports.batchSchemaSync` and implements\n * `syncSchemasBatch()`, submits all schemas in a single call (reducing\n * network round-trips for remote drivers like Turso).\n * - Otherwise falls back to sequential `syncSchema()` per object.\n *\n * This is idempotent — drivers must tolerate repeated calls without\n * duplicating tables or erroring out.\n *\n * Drivers that do not implement `syncSchema` are silently skipped.\n */\n private async syncRegisteredSchemas(ctx: PluginContext) {\n if (!this.ql) return;\n\n const allObjects = this.ql.registry?.getAllObjects?.() ?? [];\n if (allObjects.length === 0) return;\n\n let synced = 0;\n let skipped = 0;\n\n // Group objects by driver for potential batch optimization\n const driverGroups = new Map<any, Array<{ obj: any; tableName: string }>>();\n\n for (const obj of allObjects) {\n const driver = this.ql.getDriverForObject(obj.name);\n if (!driver) {\n ctx.logger.debug('No driver available for object, skipping schema sync', {\n object: obj.name,\n });\n skipped++;\n continue;\n }\n\n if (typeof driver.syncSchema !== 'function') {\n ctx.logger.debug('Driver does not support syncSchema, skipping', {\n object: obj.name,\n driver: driver.name,\n });\n skipped++;\n continue;\n }\n\n const tableName = StorageNameMapping.resolveTableName(obj);\n\n let group = driverGroups.get(driver);\n if (!group) {\n group = [];\n driverGroups.set(driver, group);\n }\n group.push({ obj, tableName });\n }\n\n // Process each driver group\n for (const [driver, entries] of driverGroups) {\n // Batch path: driver supports batch schema sync\n if (\n driver.supports?.batchSchemaSync &&\n typeof driver.syncSchemasBatch === 'function'\n ) {\n const batchPayload = entries.map((e) => ({\n object: e.tableName,\n schema: e.obj,\n }));\n try {\n await driver.syncSchemasBatch(batchPayload);\n synced += entries.length;\n ctx.logger.debug('Batch schema sync succeeded', {\n driver: driver.name,\n count: entries.length,\n });\n } catch (e: unknown) {\n ctx.logger.warn('Batch schema sync failed, falling back to sequential', {\n driver: driver.name,\n error: e instanceof Error ? e.message : String(e),\n });\n // Fallback: sequential sync for this driver's objects\n for (const { obj, tableName } of entries) {\n try {\n await driver.syncSchema(tableName, obj);\n synced++;\n } catch (seqErr: unknown) {\n ctx.logger.warn('Failed to sync schema for object', {\n object: obj.name,\n tableName,\n driver: driver.name,\n error: seqErr instanceof Error ? seqErr.message : String(seqErr),\n });\n }\n }\n }\n } else {\n // Sequential path: no batch support\n for (const { obj, tableName } of entries) {\n try {\n await driver.syncSchema(tableName, obj);\n synced++;\n } catch (e: unknown) {\n ctx.logger.warn('Failed to sync schema for object', {\n object: obj.name,\n tableName,\n driver: driver.name,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n }\n }\n\n if (synced > 0 || skipped > 0) {\n ctx.logger.info('Schema sync complete', { synced, skipped, total: allObjects.length });\n }\n }\n\n /**\n * Restore persisted metadata from the database (sys_metadata) on startup.\n *\n * Calls `protocol.loadMetaFromDb()` to bulk-load all active metadata\n * records (objects, views, apps, etc.) into the in-memory SchemaRegistry.\n * This closes the persistence loop so that user-created schemas survive\n * kernel cold starts and redeployments.\n *\n * Gracefully degrades when:\n * - The protocol service is unavailable (e.g., in-memory-only mode).\n * - `loadMetaFromDb` is not implemented by the protocol shim.\n * - The underlying driver/table does not exist yet (first-run scenario).\n */\n private async restoreMetadataFromDb(ctx: PluginContext): Promise<void> {\n // Phase 1: Resolve protocol service (separate from DB I/O for clearer diagnostics)\n let protocol: ProtocolWithDbRestore;\n try {\n const service = ctx.getService('protocol');\n if (!service || !hasLoadMetaFromDb(service)) {\n ctx.logger.debug('Protocol service does not support loadMetaFromDb, skipping DB restore');\n return;\n }\n protocol = service;\n } catch (e: unknown) {\n ctx.logger.debug('Protocol service unavailable, skipping DB restore', {\n error: e instanceof Error ? e.message : String(e),\n });\n return;\n }\n\n // Phase 2: DB hydration (loads into SchemaRegistry)\n try {\n const { loaded, errors } = await protocol.loadMetaFromDb();\n\n if (loaded > 0 || errors > 0) {\n ctx.logger.info('Metadata restored from database to SchemaRegistry', { loaded, errors });\n } else {\n ctx.logger.debug('No persisted metadata found in database');\n }\n } catch (e: unknown) {\n // Non-fatal: first-run or in-memory driver may not have sys_metadata yet\n ctx.logger.debug('DB metadata restore failed (non-fatal)', {\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n\n /**\n * Bridge all SchemaRegistry objects to the metadata service.\n *\n * This ensures objects registered by plugins and loaded from sys_metadata\n * are visible to AI tools and other consumers that query IMetadataService.\n *\n * Runs after both restoreMetadataFromDb() and syncRegisteredSchemas() to\n * catch all objects in the SchemaRegistry regardless of their source.\n */\n private async bridgeObjectsToMetadataService(ctx: PluginContext): Promise<void> {\n try {\n const metadataService = ctx.getService<any>('metadata');\n if (!metadataService || typeof metadataService.register !== 'function') {\n ctx.logger.debug('Metadata service unavailable for bridging, skipping');\n return;\n }\n\n if (!this.ql?.registry) {\n ctx.logger.debug('SchemaRegistry unavailable for bridging, skipping');\n return;\n }\n\n const objects = this.ql.registry.getAllObjects();\n let bridged = 0;\n\n for (const obj of objects) {\n try {\n // Check if object is already in metadata service to avoid duplicates\n const existing = await metadataService.getObject(obj.name);\n if (!existing) {\n // Register object that exists in SchemaRegistry but not in metadata service\n await metadataService.register('object', obj.name, obj);\n bridged++;\n }\n } catch (e: unknown) {\n ctx.logger.debug('Failed to bridge object to metadata service', {\n object: obj.name,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n\n if (bridged > 0) {\n ctx.logger.info('Bridged objects from SchemaRegistry to metadata service', {\n count: bridged,\n total: objects.length\n });\n } else {\n ctx.logger.debug('No objects needed bridging (all already in metadata service)');\n }\n } catch (e: unknown) {\n ctx.logger.debug('Failed to bridge objects to metadata service', {\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n\n /**\n * Load metadata from external metadata service into ObjectQL registry\n * This enables ObjectQL to use file-based or remote metadata\n */\n private async loadMetadataFromService(metadataService: any, ctx: PluginContext) {\n ctx.logger.info('Syncing metadata from external service into ObjectQL registry...');\n \n // Metadata types to sync\n const metadataTypes = ['object', 'view', 'app', 'flow', 'workflow', 'function', 'hook'];\n let totalLoaded = 0;\n \n for (const type of metadataTypes) {\n try {\n // Check if service has loadMany method\n if (typeof metadataService.loadMany === 'function') {\n const items = await metadataService.loadMany(type);\n\n if (items && items.length > 0) {\n // Functions arrive as JSON-safe records ({name, handler})\n // where `handler` is a function reference or compiled code\n // already attached by the metadata pipeline. Register them\n // BEFORE binding hooks so string-named hook handlers can\n // resolve.\n if (type === 'function' && this.ql && typeof (this.ql as any).registerFunction === 'function') {\n for (const item of items) {\n if (item?.name && typeof item.handler === 'function') {\n (this.ql as any).registerFunction(item.name, item.handler, 'metadata-service');\n }\n }\n }\n\n items.forEach((item: any) => {\n // Determine key field (usually 'name' or 'id')\n const keyField = item.id ? 'id' : 'name';\n \n // For objects, use the ownership-aware registration\n if (type === 'object' && this.ql) {\n // Objects are registered differently (ownership model)\n // Skip for now - handled by app registration\n return;\n }\n \n // Register other types in the registry\n if (this.ql?.registry?.registerItem) {\n this.ql.registry.registerItem(type, item, keyField);\n }\n });\n\n // Hooks need to be wired into the execution pipeline,\n // not just stored in the registry. Funnel through the\n // canonical binder so declarative semantics (condition,\n // retry, timeout, async, onError, priority, packageId)\n // are honoured uniformly with the AppPlugin path.\n if (type === 'hook' && this.ql && typeof (this.ql as any).bindHooks === 'function') {\n (this.ql as any).bindHooks(items, {\n packageId: 'metadata-service',\n });\n }\n\n totalLoaded += items.length;\n ctx.logger.info(`Synced ${items.length} ${type}(s) from metadata service`);\n }\n }\n } catch (e: any) {\n // Type might not exist in metadata service - that's ok\n ctx.logger.debug(`No ${type} metadata found or error loading`, { \n error: e.message \n });\n }\n }\n \n if (totalLoaded > 0) {\n ctx.logger.info(`Metadata sync complete: ${totalLoaded} items loaded into ObjectQL registry`);\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectKernel } from '@objectstack/core';\nimport { ObjectQLPlugin } from './plugin.js';\nimport type { Plugin } from '@objectstack/core';\n\n/**\n * Options for creating an ObjectQL Kernel.\n */\nexport interface ObjectQLKernelOptions {\n /**\n * Additional plugins to register with the kernel.\n */\n plugins?: Plugin[];\n}\n\n/**\n * Convenience factory for creating an ObjectQL-ready kernel.\n *\n * Creates an ObjectKernel pre-configured with the ObjectQLPlugin\n * (data engine, schema registry, protocol implementation) plus any\n * additional plugins provided.\n *\n * @example\n * ```typescript\n * import { createObjectQLKernel } from '@objectstack/objectql';\n *\n * const kernel = createObjectQLKernel({\n * plugins: [myDriverPlugin, myAuthPlugin],\n * });\n * await kernel.bootstrap();\n * ```\n */\nexport async function createObjectQLKernel(options: ObjectQLKernelOptions = {}): Promise<ObjectKernel> {\n const kernel = new ObjectKernel();\n\n // Register the core ObjectQLPlugin first\n await kernel.use(new ObjectQLPlugin());\n\n // Register any additional plugins\n if (options.plugins) {\n for (const plugin of options.plugins) {\n await kernel.use(plugin);\n }\n }\n\n return kernel;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { ServiceObject } from '@objectstack/spec/data';\n\n// ── Introspection Types ──────────────────────────────────────────────────────\n\n/**\n * Column metadata from database introspection.\n */\nexport interface IntrospectedColumn {\n /** Column name */\n name: string;\n /** Native database type (e.g., 'varchar', 'integer', 'timestamp') */\n type: string;\n /** Whether the column is nullable */\n nullable: boolean;\n /** Default value if any */\n defaultValue?: unknown;\n /** Whether this is a primary key */\n isPrimary?: boolean;\n /** Whether this column has a unique constraint */\n isUnique?: boolean;\n /** Maximum length for string types */\n maxLength?: number;\n}\n\n/**\n * Foreign key relationship metadata.\n */\nexport interface IntrospectedForeignKey {\n /** Column name in the source table */\n columnName: string;\n /** Referenced table name */\n referencedTable: string;\n /** Referenced column name */\n referencedColumn: string;\n /** Constraint name */\n constraintName?: string;\n}\n\n/**\n * Table metadata from database introspection.\n */\nexport interface IntrospectedTable {\n /** Table name */\n name: string;\n /** List of columns */\n columns: IntrospectedColumn[];\n /** List of foreign key relationships */\n foreignKeys: IntrospectedForeignKey[];\n /** Primary key columns */\n primaryKeys: string[];\n}\n\n/**\n * Complete database schema introspection result.\n */\nexport interface IntrospectedSchema {\n /** Map of table name to table metadata */\n tables: Record<string, IntrospectedTable>;\n}\n\n// ── Utility Functions ────────────────────────────────────────────────────────\n\n/**\n * Convert a snake_case or plain string to Title Case.\n *\n * @example\n * toTitleCase('first_name') // => 'First Name'\n * toTitleCase('project_task') // => 'Project Task'\n */\nexport function toTitleCase(str: string): string {\n return str\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\n/**\n * Map a native database column type to an ObjectStack FieldType.\n */\nfunction mapDatabaseTypeToFieldType(\n dbType: string\n): 'text' | 'textarea' | 'number' | 'boolean' | 'datetime' | 'date' | 'time' | 'json' {\n const type = dbType.toLowerCase();\n\n // Text types\n if (type.includes('char') || type.includes('varchar') || type.includes('text')) {\n if (type.includes('text')) return 'textarea';\n return 'text';\n }\n\n // Numeric types\n if (\n type.includes('int') || type === 'integer' || type === 'bigint' || type === 'smallint'\n ) {\n return 'number';\n }\n if (\n type.includes('float') || type.includes('double') || type.includes('decimal') ||\n type.includes('numeric') || type === 'real'\n ) {\n return 'number';\n }\n\n // Boolean\n if (type.includes('bool')) {\n return 'boolean';\n }\n\n // Date / Time types\n if (type.includes('timestamp') || type === 'datetime') {\n return 'datetime';\n }\n if (type === 'date') {\n return 'date';\n }\n if (type === 'time') {\n return 'time';\n }\n\n // JSON types\n if (type === 'json' || type === 'jsonb') {\n return 'json';\n }\n\n // Default to text\n return 'text';\n}\n\n/**\n * Convert an introspected database schema to ObjectStack object definitions.\n *\n * This allows using existing database tables without manually defining metadata.\n *\n * @param introspectedSchema - The schema returned from driver.introspectSchema()\n * @param options - Optional filtering / conversion settings\n * @returns Array of ServiceObject definitions that can be registered with ObjectQL\n *\n * @example\n * ```typescript\n * const schema = await driver.introspectSchema();\n * const objects = convertIntrospectedSchemaToObjects(schema);\n * for (const obj of objects) {\n * engine.registerObject(obj);\n * }\n * ```\n */\nexport function convertIntrospectedSchemaToObjects(\n introspectedSchema: IntrospectedSchema,\n options?: {\n /** Tables to exclude from conversion */\n excludeTables?: string[];\n /** Tables to include (if specified, only these will be converted) */\n includeTables?: string[];\n /** Whether to skip system columns like id, created_at, updated_at (default: true) */\n skipSystemColumns?: boolean;\n }\n): ServiceObject[] {\n const objects: ServiceObject[] = [];\n const excludeTables = options?.excludeTables || [];\n const includeTables = options?.includeTables;\n const skipSystemColumns = options?.skipSystemColumns !== false;\n\n for (const [tableName, table] of Object.entries(introspectedSchema.tables)) {\n if (excludeTables.includes(tableName)) continue;\n if (includeTables && !includeTables.includes(tableName)) continue;\n\n const fields: Record<string, any> = {};\n\n for (const column of table.columns) {\n // Skip system columns if requested\n if (skipSystemColumns && ['id', 'created_at', 'updated_at'].includes(column.name)) {\n continue;\n }\n\n // Check for foreign key → lookup field\n const foreignKey = table.foreignKeys.find((fk) => fk.columnName === column.name);\n\n if (foreignKey) {\n fields[column.name] = {\n name: column.name,\n type: 'lookup' as const,\n reference: foreignKey.referencedTable,\n label: toTitleCase(column.name),\n required: !column.nullable,\n };\n } else {\n const fieldType = mapDatabaseTypeToFieldType(column.type);\n\n const field: Record<string, any> = {\n name: column.name,\n type: fieldType,\n label: toTitleCase(column.name),\n required: !column.nullable,\n };\n\n if (column.isUnique) {\n field.unique = true;\n }\n if (column.maxLength && (fieldType === 'text' || fieldType === 'textarea')) {\n field.maxLength = column.maxLength;\n }\n if (column.defaultValue != null) {\n field.defaultValue = column.defaultValue;\n }\n\n fields[column.name] = field;\n }\n }\n\n objects.push({\n name: tableName,\n label: toTitleCase(tableName),\n fields,\n } as ServiceObject);\n }\n\n return objects;\n}\n"],"mappings":"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","names":["item","ConflictError","DEFAULT_METADATA_TYPE_REGISTRY","records","ExpressionEngine","noopLogger","ExpressionEngine","StorageNameMapping"]}