All notable changes to the ObjectStack Protocol will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
-
Metadata Versioning & History — Comprehensive version history tracking and rollback capabilities for metadata items. Key features include:
MetadataHistoryRecordSchemadefining structure for historical snapshotssys_metadata_historysystem table for version storage- Automatic history tracking in
DatabaseLoaderwith SHA-256 checksum deduplication getHistory(),rollback(), anddiff()methods inIMetadataService- REST API endpoints:
GET /history,POST /rollback,GET /diff HistoryCleanupManagerwith configurable retention policies (age-based and count-based)- Comprehensive test suite covering all history operations
This aligns ObjectStack with enterprise platforms like Salesforce Setup Audit Trail and ServiceNow Update Sets. See
docs/METADATA_HISTORY.mdfor detailed usage. (Phase 4a: Metadata Versioning & History)
-
i18n:
I18nLabelSchemanow acceptsstringonly —label,description,title, and other display-text fields across all UI schemas (AppSchema,NavigationArea,PageSchema,DashboardWidgetSchema,ReportSchema,ChartSchema,NotificationSchema,AriaPropsSchema, etc.) now accept only plain strings. The previousstring | I18nObjectunion type has been replaced withz.string(). i18n translation keys will be auto-generated by the framework at registration time; developers only need to provide the default-language string value. Translations are managed through translation files, not inline i18n objects. (#1054)Migration: Replace any
label: { key: '...', defaultValue: 'X' }withlabel: 'X'. Existing plain-string labels require no changes.Affected plugins updated:
@objectstack/plugin-setup—setup-app.ts,setup-areas.ts@objectstack/plugin-auth— navigation item labels@objectstack/plugin-security— navigation item labels@objectstack/plugin-audit— navigation item labels
- README rewrite — Rewrote
README.mdto accurately reflect theobjectstack-ai/frameworkrepository. Updates include: corrected title ("ObjectStack Framework"), updated badges (v4.0.1, 6,507 tests passing), fixed stale clone URL (spec.git→framework.git), added all missing packages (driver-sql,driver-turso,plugin-audit,plugin-setup,service-feed,service-automation,service-ai,service-realtime,service-i18n), updated codebase metrics (27 packages, 200 Zod schema files, 1,600+ exported schemas, 8,750+.describe()annotations, 6,507 tests passing), and restructured sections to match the current monorepo layout.
- Studio Vercel API routes returning HTML instead of JSON — Adopted the
same Vercel deployment pattern used by
hotcrm: committedapi/[[...route]].jscatch-all route so Vercel detects it pre-build, switched esbuild output from CJS to ESM (fixes"type": "module"conflict), and changed the bundle output toapi/_handler.js(a separate file that the committed wrapper re-exports). This avoids both Vercel's TS compilation overwriting the bundle (ERR_MODULE_NOT_FOUND) and the "File not found" error from deleting source files during build. AddedcreateRequirebanner to the esbuild config so that CJS dependencies (knex/tarn) canrequire()Node.js built-in modules likeeventswithout the "Dynamic require is not supported" error. Addedfunctions.includeFilesinvercel.jsonto include native addons (better-sqlite3,@libsql/client) that esbuild cannot bundle. Added a build step to copy native external modules from the monorepo rootnode_modules/into the studio's localnode_modules/, since pnpm's strict mode (unlike hotcrm'sshamefully-hoist) doesn't symlink transitive native dependencies into app-levelnode_modules/. Updated rewrites to match:/api/:path*→/api/[[...route]]. - Studio CORS error on Vercel temporary/preview domains — Changed
VITE_SERVER_URLfrom hardcodedhttps://play.objectstack.aito""(empty string / same-origin) invercel.jsonso each deployment — including previews — calls its own serverless function instead of the production API cross-origin. Also added Hono CORS middleware toapps/studio/server/index.tsas a safety net for any remaining cross-origin scenarios; dynamically allows all*.vercel.appsubdomains, explicitly listed Vercel deployment URLs, and localhost. ExtractedgetVercelOrigins()helper to keep CORS and better-authtrustedOriginsallowlists in sync. - Client test aligned with removed
ai.chatmethod — Updated@objectstack/clienttest suite to match the current API surface whereai.chat()was removed in favour of the Vercel AI SDKuseChat()hook. The obsolete test that calledclient.ai.chat()now asserts the method is absent, fixing the CI@objectstack/client#testfailure.
-
Metadata Management Tools (
service-ai) — Added 6 built-in AI tools for metadata CRUD operations, each defined as a first-classToolmetadata file usingdefineTool()from@objectstack/spec/ai:create-object.tool.ts— Creates a new data object with schema validationadd-field.tool.ts— Adds a field to an existing objectmodify-field.tool.ts— Modifies field properties on an objectdelete-field.tool.ts— Removes a field from an objectlist-metadata-objects.tool.ts— Lists all registered metadata objectsdescribe-metadata-object.tool.ts— Returns full schema details of an object
Each
.tool.tsfile is an independent metadata unit withname,label,description,category,builtIn, andparameters— following the same.object.ts/.view.tsmetadata file convention. Handler factories remain inmetadata-tools.tsand bind handlers atai:readytime viaregisterMetadataTools(registry, { metadataService }). 79 unit tests covering tool metadata properties, handler execution, input validation, error handling, dual registration with data tools, and a full lifecycle test. -
Agent Skills —
skills/directory (agentskills.io) — Createdskills/folder at repository root following the agentskills.io specification. Five expert-knowledge skills with hand-writtenSKILL.mdfiles andreferences/quick-lookup tables:skills/schema-design/— Data schema design (Object, Field, Validation, Index)skills/ui-design/— UI protocol (View, App, Dashboard, Report, Action)skills/automation-design/— Automation (Flow, Workflow, Trigger, Approval)skills/ai-agent-design/— AI Agent protocol (Agent, Skill, RAG, Tool)skills/api-design/— API protocol (REST endpoints, Discovery, Datasource) EachSKILL.mdincludes YAML frontmatter (name,description,license,metadata), domain rules, usage guidance, best practices, common pitfalls, and code examples. Zod schema files remain the single source of truth; skills reference them for validation.
-
Discovery Schema —
ServiceStatusenum &handlerReadyfield — Added'registered'status toServiceInfoSchemato distinguish routes that are declared in the dispatcher table but whose HTTP handler has not been verified. Added optionalhandlerReadyboolean field (omitted = unverified/unknown) so clients can filter handler-ready services before displaying endpoints when the value is explicitlytrue. -
Discovery Schema —
RouteHealthReportSchema— New schema for automated route/handler coverage reporting at startup. Includes per-route health entries (pass,fail,missing,skip) and summary counters. -
Dispatcher Schema —
DispatcherErrorCode&DispatcherErrorResponseSchema— Semantic error codes (404/405/501/503) with machine-readabletypefield (ROUTE_NOT_FOUND,METHOD_NOT_ALLOWED,NOT_IMPLEMENTED,SERVICE_UNAVAILABLE) and developer-facinghintstrings. -
Dispatcher Schema —
/healthroute — Added health endpoint toDEFAULT_DISPATCHER_ROUTES. -
REST API Plugin —
handlerStatusfield — AddedhandlerStatus(implemented,stub,planned) toRestApiEndpointSchemato track handler implementation readiness. -
REST API Plugin —
RouteCoverageReportSchema— Schema for adapter-generated coverage reports listing every declared endpoint and its implementation status. -
aiv6 as a dependency of@objectstack/specfor type re-exports
- Removed
valuefield from data API responses — ThefindDataprotocol implementation no longer returns the deprecatedvaluefield alongsiderecords. Onlyrecordsis returned, matching theFindDataResponseSchemaspec. All downstream consumers (Studio, app-host example, tests) updated to userecordsexclusively. OData-specific responses (ODataResponseSchema) retainvalueper the OData v4 standard — protocol-to-OData adaptation is handled in the HTTP dispatch layer.
- AI Chat Protocol Aligned with Vercel AI SDK — Removed custom AI chat protocol
types and Zod schemas (
AIMessage,AIToolCall,AIStreamEvent,AiChatRequestSchema,AiChatResponseSchema) from@objectstack/spec. The canonical message, tool-call, and streaming types are now re-exported from the Vercel AI SDK (aiv6):ModelMessagereplacesAIMessageToolCallPartreplacesAIToolCallToolResultPartreplacesAIToolResultTextStreamPart<ToolSet>replacesAIStreamEventIAIServiceandLLMAdaptermethod signatures now acceptModelMessage[]and returnTextStreamPart<ToolSet>for streaming- Deprecated type aliases preserved for migration convenience
- NLQ, Suggest, and Insights protocols (ObjectStack-specific) are retained
@objectstack/service-aimigrated to Vercel AI SDK types — All source files and tests now use canonical Vercel types (ModelMessage,ToolCallPart,ToolResultPart,TextStreamPart<ToolSet>) instead of deprecated aliases:ToolRegistry.execute()acceptsToolCallPartand returnsToolExecutionResult(extendsToolResultPartwithisError?: boolean)- Tool call loop in
AIService.chatWithTools()constructs properAssistantModelMessageandToolModelMessagewith Vercel-format content arrays MemoryLLMAdapter.streamChat()emits VercelTextStreamPart<ToolSet>events- Conversation services serialize/deserialize
ModelMessageunion to flat DB columns - All 158 service-ai tests updated and passing
- Runtime Dispatcher — semantic error differentiation —
HttpDispatcher.dispatch()now returns typed 404 (ROUTE_NOT_FOUND) with diagnostic info instead of bare{ handled: false }. AddedrouteNotFound()(404) helper method. - Runtime Dispatcher —
/healthhandler — Added health endpoint returningstatus,timestamp,version, anduptime. - Runtime Dispatcher —
handlerReadyin discovery —getDiscoveryInfo()now emitshandlerReady: truefor services with confirmed handlers andhandlerReady: falsefor unavailable services. - Dispatcher Plugin — semantic 404 —
sendResult()now returnsROUTE_NOT_FOUNDerror type with a hint pointing to the discovery endpoint. Added/healthhandler registration. - Studio — handler-ready filtering —
useApiDiscovery()now checks bothenabledandhandlerReady(orstatus === 'available' | 'degraded'for backward compatibility) before displaying service endpoints in the UI.
AiChatRequestSchema/AiChatResponseSchemaZod schemas from@objectstack/spec/api— the AI chat wire protocol now uses Vercel AI SDK's data stream format (toDataStreamResponse())aiChatmethod fromIObjectStackAPIand client SDK — consumers should use@ai-sdk/react/useChatdirectly- AI
/chatendpoint fromDEFAULT_AI_ROUTESplugin REST API definition
aiv6 as a dependency of@objectstack/specfor type re-exports- Vercel AI Data Stream Protocol support on
/api/v1/ai/chat— The chat endpoint now supports dual-mode responses:- Streaming (default): When
streamis notfalse, returns Vercel Data Stream Protocol frames (0:text,9:tool-call,d:finish, etc.), directly consumable by@ai-sdk/react/useChat - JSON (legacy): When
stream: false, returns the original JSON response - Accepts Vercel useChat flat body format (
system,model,temperature,maxTokensas top-level fields) alongside the legacy{ messages, options } systemPrompt/systemfield is prepended as a system message- Message validation now accepts Vercel multi-part array content
RouteResponse.vercelDataStreamflag signals HTTP server layer to encode events using the Vercel Data Stream frame format
- Streaming (default): When
VercelLLMAdapter— Production adapter wrapping Vercel AI SDK'sgenerateText/streamTextfor any compatible model provider (OpenAI, Anthropic, Google, Ollama, etc.)vercel-stream-encoder.ts— Utilities (encodeStreamPart,encodeVercelDataStream) to convertTextStreamPart<ToolSet>events into Vercel Data Stream wire-format frames- 176 service-ai tests passing (18 new tests for stream encoder, route dual-mode, systemPrompt, flat options, array content)
- Version Alignment Patch — Unified all package versions to
4.0.1. Previously,@objectstack/driver-sqland@objectstack/driver-tursowere at3.3.2, example packages were at3.0.26, and the root monorepo was at3.0.8while all other@objectstack/*packages were at4.0.0. All packages now share a single, consistent version number aligned with the changesetfixedgroup configuration.
@objectstack/service-realtime—sys_presenceSystem Object — Registers thesys_presencesystem object in theservice-realtimepackage as the canonical Presence domain object. Fields align with thePresenceStateSchemaprotocol definition (user_id,session_id,status,last_seen,current_location,device,custom_status,metadata).RealtimeServicePluginnow auto-registers the object via theapp.com.objectstack.service.realtimeservice convention. AddedSystemObjectName.PRESENCEconstant ('sys_presence') to@objectstack/spec/system.@objectstack/service-ai— Data Chatbot: Tool Call Loop & Agent Runtime — Implements an Airtable Copilot-style data conversation Chatbot with full-stack support:AIService.chatWithTools()— automatic multi-round LLM ↔ tool call loop withmaxIterationssafety limit, parallel tool execution, and forced final responseAIResult.toolCalls— new field on the AI result contract so adapters can return tool call requests from the LLMChatWithToolsOptions— new contract interface extendingAIRequestOptions- 5 built-in data tools:
list_objects,describe_object,query_records,get_record,aggregate_data— with parameter schemas, limit capping (max 200), and error handling registerDataTools(registry, context)— factory to register all data tools againstIDataEngine+IMetadataServiceAgentRuntime— loads agent metadata, builds system prompts from instructions + UI context (objectName,recordId,viewName), resolves agent tool references against theToolRegistrybuildAgentRoutes()— newPOST /api/v1/ai/agents/:agentName/chatroute with agent lookup, active-check, context injection, andchatWithToolsintegrationDATA_CHAT_AGENT— built-indata_chatagent spec with role, instructions, guardrails, planning config, and tool declarationsAIServicePluginauto-registers data tools anddata_chatagent whenIDataEngine+IMetadataServiceare available in the kernel- 42 new test cases covering tool call loop, data tools, agent runtime, agent routes, and agent spec validation
@objectstack/service-ai— ObjectQL-backed persistent ConversationService — NewObjectQLConversationServiceimplementsIAIConversationServiceusingIDataEnginefor durable conversation and message storage across service restarts:ai_conversationsandai_messagessystem object definitions (namespaceai)- Full CRUD:
create,get,list(with userId/agentId/limit/cursor filters),addMessage(with toolCalls/toolCallId support), anddelete(cascade) AIServicePluginauto-detectsIDataEnginein the kernel service registry and usesObjectQLConversationServicewhen available, falling back toInMemoryConversationServicefor dev/test environmentsAIServicePluginOptions.conversationServiceallows explicit override- Plugin registers AI system objects via
app.com.objectstack.service-aiservice - 16 new test cases covering all five interface methods plus edge cases
- Promoted
LLMAdapterinterface to@objectstack/spec/contracts— Moved theLLMAdapteradapter contract from@objectstack/service-aiinternal types to the canonical protocol layer (packages/spec/src/contracts/llm-adapter.ts). Third-party adapter implementations (OpenAI, Anthropic, Ollama, etc.) can now depend solely on@objectstack/specfor type alignment.service-aire-exports the interface for backward compatibility.
- Changeset fixed versioning — add driver-sql and driver-turso — Added
@objectstack/driver-sqland@objectstack/driver-tursoto the changesetfixedversioning group in.changeset/config.json. These packages were missing from the group, causing them to be published as3.3.2instead of4.0.0during the v4.0.0 release. All future releases will now keep these driver packages in sync with the rest of the ecosystem. - ObjectQL build failure — Fixed TypeScript TS2345 errors in
packages/objectql/src/protocol.tswhereSchemaRegistry.registerItem()calls failed type checking for thekeyFieldparameter. Applied'name' as anycast consistent with the established codebase pattern. - ObjectQL
loadMetaFromDb— Fixed metadata hydration forobjecttype records to useSchemaRegistry.registerObject()instead ofregisterItem(), resolving a mismatch where objects registered viaregisterItemcould not be retrieved viagetItem('object', ...). - Adapter discovery endpoints — Fixed discovery route in Hono, SvelteKit, Nuxt, Next.js,
and Fastify adapters to serve discovery info at the API prefix root (e.g.,
GET /api) instead of a/discoverysubpath. Updated.well-known/objectstackredirects accordingly. - Client feed namespace routing — Fixed
ObjectStackClient.feedmethods to use thedataroute (/api/v1/data/{object}/{recordId}/feed) instead of a separate/api/v1/feedroute, matching the actual server-side routing where feed is a sub-resource of data.
@objectstack/service-ai— Unified AI capability service plugin — New kernel plugin providing standardized AI service integration:- Registers as kernel
'ai'service conforming toIAIServicecontract - LLM adapter layer with provider abstraction (
LLMAdapterinterface) and built-inMemoryLLMAdapterfor testing/development ToolRegistryfor metadata/business tool registration and executionInMemoryConversationServiceimplementingIAIConversationServicefor multi-turn conversation management with message persistence- REST/SSE route self-registration (
/api/v1/ai/chat,/api/v1/ai/chat/stream,/api/v1/ai/complete,/api/v1/ai/models,/api/v1/ai/conversations) - Plugin lifecycle hooks (
ai:ready,ai:routes) for extensibility
- Registers as kernel
- Expanded
IAIServicecontract — Added streaming (streamChat), tool calling protocol (AIToolDefinition,AIToolCall,AIToolResult,AIMessageWithTools,AIRequestOptionsWithTools,AIStreamEvent), and conversation management (IAIConversationService,AIConversation) topackages/spec/src/contracts/ai-service.ts @objectstack/plugin-setup— Platform Setup App plugin — New internal plugin (packages/plugins/plugin-setup) that owns and finalizes the platform Setup App. Ships four built-in Setup Areas (Administration, Platform, System, AI) as empty skeletons. Other plugins contribute navigation items via thesetupNavservice during theirinitphase. Atstart, SetupPlugin merges all contributions, filters out empty areas, and registers the finalized Setup App as an internal platform app. This establishes clear architectural separation: spec = protocol only, objectql = data/query only, plugins = system feature and UI composition.
- Unified API query syntax documentation with Spec canonical format — Rewrote
content/docs/protocol/objectql/query-syntax.mdxandcontent/docs/guides/contracts/data-engine.mdxto align all examples, interface definitions, and field names with the canonicalQuerySchema,FilterConditionSchema, andEngineQueryOptionsSchemafrom@objectstack/spec. All query examples now usewhere+ MongoDB-style$opobject syntax (replacing legacy tuple/filters/三元组 format),orderBy(replacingsort),groupBy(replacinggroup_by), andaggregationsarray (replacingaggregateobject map).IDataEnginecontract documentation updated to reflect the real interface (find/findOne/insert/update/delete/count/aggregate). Added legacy compatibility sections clearly marking tuple/array syntax as UI-builder input only, with migration guidance.
- Studio Vercel deployment — switched from InMemoryDriver to TursoDriver — The Studio serverless
API entrypoint (
apps/studio/api/index.ts) now uses@objectstack/driver-turso(TursoDriver) instead of@objectstack/driver-memory(InMemoryDriver) for Vercel deployments. In production, the driver connects to a Turso cloud database viaTURSO_DATABASE_URLandTURSO_AUTH_TOKENenvironment variables (remote mode). For local development without those variables, it falls back to:memory:(ephemeral SQLite). This ensures data persistence across serverless function invocations on Vercel. The browser MSW mock kernel remains unchanged (InMemoryDriver).
- Metadata DB persistence —
saveMetaItem()now writes to database — The protocol implementation (ObjectStackProtocolImplementation.saveMetaItem()) now persists metadata to thesys_metadatatable viaIDataEnginein addition to the in-memorySchemaRegistry. Previously, metadata saved viaPUT /api/v1/meta/:type/:namewas lost on server restart. AddedloadMetaFromDb()bootstrap method to hydrate the registry from the database on startup.getMetaItem()andgetMetaItems()now fall back to database queries when items are not found in the in-memory registry. Discovery endpoint metadata status upgraded fromdegradedtoavailable. Graceful degradation: if the database is unavailable, operations fall back to memory-only mode with a warning. - Vercel API always returns HTML — serverless function entrypoint not found — The
bundle-api.mjsscript was emittingapi/index.jsat the project root, butvercel.jsonsetsoutputDirectory: "dist", so Vercel could not discover the serverless function and fell back to the SPA HTML route for all/api/*requests. Changed esbuildoutfiletodist/api/index.jsand added explicitfunctionsconfig invercel.jsonwith@vercel/node@3runtime.
- Batch schema sync for remote DDL in kernel bootstrap —
ObjectQLPlugin.syncRegisteredSchemas()now groups objects by driver and usessyncSchemasBatch()when the driver advertisessupports.batchSchemaSync = true. This reduces the number of remote DDL round-trips from roughly N×(2–3) individual calls (introspection + optional PRAGMA + DDL write per object) to a small constant number of batchedclient.batch()calls, cutting cold-start times from 58+ seconds to under 10 seconds for 100+ objects on remote drivers (e.g. Turso cloud). Falls back to sequentialsyncSchema()per object for drivers without batch support or if the batched calls fail at runtime. AddedbatchSchemaSynccapability flag toDriverCapabilitiesSchema, optionalsyncSchemasBatch()toIDataDriver, andRemoteTransport.syncSchemasBatch()using@libsql/client'sbatch()API. @objectstack/driver-turso— dual transport architecture — TursoDriver now supports three transport modes:local,replica, andremote. Remote mode (url: 'libsql://...') enables pure cloud-only queries via@libsql/clientSDK (HTTP/WebSocket) without requiring a local SQLite database or Knex. Transport mode is auto-detected from the URL or can be forced viaconfig.mode. The driver exposestransportModeandisRemoteproperties for runtime introspection. All IDataDriver methods (CRUD, bulk, transactions, schema sync) work identically across all modes. AddedRemoteTransportclass,TursoTransportModetype, and support for injecting a pre-configured@libsql/clientinstance viaconfig.client.
- Vercel deployment —
ERR_MODULE_NOT_FOUNDfor@objectstack/metadata— Fixed incorrectexportspaths in@objectstack/metadatapackage.jsonthat pointed directly to TypeScript source files (src/index.ts,src/node.ts) instead of compiled dist output. Node.js cannot import.tsfiles at runtime, causingERR_MODULE_NOT_FOUNDon Vercel. Updatedmain,types, andexportsto reference dist files (dist/index.js,dist/index.mjs,dist/node.mjs, etc.). Added a localtsup.config.tswith both entry points (src/index.ts,src/node.ts) and afilesfield to the package.json. Follows the same pattern as@objectstack/spec. - Vercel deployment —
ERR_MODULE_NOT_FOUNDfor@objectstack/service-feed— Fixed incorrectexportspaths inpackage.jsonfor all service packages that declare"type": "module". Whentsupbuilds an ESM package ("type": "module"), it outputs.jsfor ESM and.cjsfor CJS. However, the exports maps incorrectly referenced.mjs(ESM) and.js(CJS) — the convention for packages without"type": "module". This caused Node's ESM resolver to fail withERR_MODULE_NOT_FOUNDwhen Vercel tried to importdist/index.mjs(which doesn't exist). Affected packages:service-feed,service-automation,service-cache,service-realtime,service-job,service-queue,service-storage,service-analytics. @objectstack/driver-sqlDTS build failure — knex type resolution — Fixed a TypeScript declaration build failure caused by knex v3.2.3 declaring a non-existent.d.mtstypes file in its package.jsonexportsfield. WithmoduleResolution: "bundler", TypeScript could not resolve knex's type declarations, resulting in TS7016 and TS7006 errors during DTS generation. Added apathsmapping in the driver-sqltsconfig.jsonto direct TypeScript to the correctknex/types/index.d.tsfile. This also fixes cascade build failures in all downstream packages that depend on driver-sql.SqlDriver.syncSchema()— physical table name mismatch — Fixed the root cause of theno such table: sys_usererror:syncSchema()was ignoring theobjectparameter (physical table name likesys_user) and usingschema.name(FQN likesys__user) for DDL operations. The method now correctly passes the physical table name toinitObjects(). Additionally,initObjects()now supports atableNameproperty as defense-in-depth, preferring it overnamewhen both are present.- Login API error — database tables not created — Fixed a critical naming mismatch between
the FQN (Fully Qualified Name) used by SchemaRegistry (e.g.,
sys__userwith double underscore) and the physical table name derived byObjectSchema.create()(e.g.,sys_userwith single underscore).syncRegisteredSchemas()now uses thetableNameproperty from object definitions for DDL operations, ensuring tables are created with the correct physical name that matches what the auth adapter andSystemObjectNameconstants expect. SchemaRegistry.getObject()— protocol name resolution — Added a third fallback that matches objects by theirtableNameproperty (e.g.,getObject('sys_user')now correctly finds the object registered as FQNsys__user). This bridges protocol-layer names (SystemObjectName.USER = 'sys_user') with the registry's FQN naming convention.ObjectQL.resolveObjectName()— physical table name — Now returnsschema.tableName(the physical table/collection name) instead ofschema.name(the FQN) when available, ensuring driver SQL queries target the correct table.SqlDriver.ensureDatabaseExists()— multi-driver support — Extended database auto-creation to support MySQL (error codeER_BAD_DB_ERROR/ errno 1049) alongside PostgreSQL (error code3D000). SQLite is explicitly skipped (auto-creates files).SqlDriver.createDatabase()— MySQL support — Added MySQL-specific logic that connects without a database specified and usesCREATE DATABASE IF NOT EXISTS.
@objectstack/driver-tursoplugin — Migrated and standardized the Turso/libSQL driver from@objectql/driver-tursointopackages/plugins/driver-turso/. The driver extendsSqlDriverfrom@objectstack/driver-sql— all CRUD, schema, filter, aggregation, and introspection logic is inherited with zero code duplication. Turso-specific features include: three connection modes (local file, in-memory, embedded replica),@libsql/clientsync mechanism for embedded replicas, multi-tenant router with TTL-based driver caching, and enhanced capability flags (FTS5, JSON1, CTE, savepoints, indexes). Includes 53 unit tests. Factory functioncreateTursoDriver()and plugin manifest for kernel integration.- Multi-tenant routing (
createMultiTenantRouter) — Database-per-tenant architecture with automatic driver lifecycle management, tenant ID validation, configurable TTL cache, andonTenantCreate/onTenantEvictlifecycle callbacks. Serverless-safe (no global intervals).
@objectstack/driver-sql— Protected extensibility — Changedprivatetoprotectedfor all internal properties and methods (knex,config,jsonFields,booleanFields,tablesWithTimestamps,isSqlite,isPostgres,isMysql,getBuilder,applyFilters,applyFilterCondition,mapSortField,mapAggregateFunc,buildWindowFunction,createColumn,ensureDatabaseExists,createDatabase,isJsonField,formatInput,formatOutput,introspectColumns,introspectForeignKeys,introspectPrimaryKeys,introspectUniqueConstraints). Enables clean subclassing for driver variants (Turso, D1, etc.) without code duplication.
@objectstack/driver-sql—count()returns NaN for zero results — Fixedcount()method using||(logical OR) instead of??(nullish coalescing) to read the count value. When the actual count was0,row.count || row['count(*)']evaluated toNumber(undefined)=NaNbecause0is falsy. Now usesrow.count ?? row['count(*)'] ?? 0for correct zero handling.
- Unified Data Driver Contract (
IDataDriver) — Resolved the split betweenDriverInterface(core, minimal ~13 methods) andIDataDriver(spec, comprehensive 28 methods).IDataDriverfrom@objectstack/spec/contractsis now the single authoritative contract for all database driver implementations.DriverInterfaceis retained as a deprecated type alias for backward compatibility. Both@objectstack/driver-sqland@objectstack/driver-memorynow implementIDataDriverdirectly with fullDriverCapabilitiessupport. @objectstack/driver-sql— Added missingIDataDrivermethods:findStream,upsert,bulkUpdate,bulkDelete,commit,rollback,dropTable,explain. Alignedsupportswith fullDriverCapabilitiesschema.updateMany/deleteManynow returnnumber(count) instead of{ modifiedCount }/{ deletedCount }objects.deletereturnsboolean.@objectstack/driver-memory— Alignedsupportsproperty with fullDriverCapabilitiesschema (addedcreate,read,update,delete,bulkCreate,bulkUpdate,bulkDelete,savepoints,queryCTE,jsonQuery,geospatialQuery,streaming,schemaSync, etc.).
@objectstack/driver-sql— Legacy query key fallbacks — Removed support for deprecated query keysfilters(usewhere),sort(useorderBy),skip(useoffset), andtop(uselimit) fromfind,updateMany,deleteMany, andcountmethods. The SQL driver now strictly follows theIDataDriver/QueryASTprotocol. Allas anycasts for legacy key access have been eliminated. Tests updated to use only standardQueryASTkeys.
DriverInterface— UseIDataDriverfrom@objectstack/spec/contractsinstead.DriverInterfaceremains as a type alias in both@objectstack/spec/contractsand@objectstack/corefor backward compatibility.
@objectstack/driver-sqlplugin — Migrated the Knex-based SQL driver from@objectql/driver-sqlintopackages/plugins/driver-sql/. The driver implements the standardDriverInterfacefrom@objectstack/coreand imports types from@objectstack/spec/data. Supports PostgreSQL, MySQL, and SQLite (viabetter-sqlite3). Includes schema sync, introspection, aggregation, window functions, transactions, and full CRUD with both QueryAST and legacy filter format support. All 72 unit tests pass against in-memory SQLite.
- Migrate API layer to Hono + Vercel Node adapter — Replaced the vestigial Next.js-style
api/[...path].tscatch-all with a properapi/index.tsHono entrypoint usinghandle(app)fromhono/vercel. Vercel routes now use a rewrite rule (/api/*→/api) for native Hono routing, eliminating path-normalisation hacks and catch-all bundling pitfalls. Kernel boot remains lazy (cold-start only) viaensureApp()/ensureKernel()in_kernel.ts.
- Service-analytics build error (TS6133) — Removed unused
measurevariable innative-sql-strategy.tsthat caused the DTS build to fail withnoUnusedLocalsenabled, blocking the entire CI build pipeline. - Next.js adapter test failures — Updated 9 metadata API test assertions to match the
current
dispatch(method, path, body, queryParams, context)call signature used by the implementation. Tests were still expecting the olddispatch(subPath, context, method, body)signature. - Auth plugin test failures — Fixed 2 tests in
auth-plugin.test.tsthat referenced the wrongAuthManagerinstance viaregisterService.mock.calls. AddedmockClear()before local plugin init to ensuremock.calls[0]points to the correct AuthManager for the test's plugin instance. - SvelteKit adapter test failures — Updated test mock to include
dispatch()method and aligned Metadata, Data, Error handling, and toResponse test assertions with the unified catch-all dispatch pattern used by the implementation and all other adapters (e.g. Hono). Removed obsoletehandleMetadata/handleDatareferences from the mock. - Vercel serverless 404 fix — The previous
api/[...path].tspath-normalisation fix is now superseded by the Hono adapter migration above. The newapi/index.tsentrypoint combined with Vercel rewrites (/api/*→/api) eliminates the routing ambiguity that caused 404s. - Kernel cold-start race condition —
api/_kernel.tsuses a shared boot promise so that concurrent cold-start requests wait for the same initialisation rather than launching duplicate boot sequences. Seed-data failures are treated as non-fatal, and the broker shim is validated after bootstrap with automatic reattachment if lost. - Broker-resilient metadata handler —
HttpDispatcher.handleMetadata()no longer requires a broker upfront. It tries the protocol service and ObjectQL registry first, falling back to the broker only when available. Serverless/lightweight setups without a full message broker now return proper metadata responses instead of throwing 500 errors.
@objectstack/service-analytics— New multi-driver analytics service implementingIAnalyticsService. Uses a Strategy Pattern with priority-ordered chain: P1 NativeSQLStrategy (pushes queries as native SQL to Postgres/MySQL drivers), P2 ObjectQLStrategy (translates to ObjectQLaggregate()AST), P3 InMemoryStrategy (delegates to existingMemoryAnalyticsServicefor dev/test). IncludesCubeRegistryfor auto-discovery of cubes from manifest definitions and object schema inference,AnalyticsServicePluginfor kernel plugin lifecycle,generateSql()dry-run capability, andqueryCapabilities()driver probing for dynamic strategy selection. 34 unit tests covering all strategy branches.- Studio system objects visibility — Studio now auto-registers all system objects (sys_user,
sys_role, sys_audit_log, etc.) from plugin-auth, plugin-security, and plugin-audit at kernel
initialization. The sidebar "System" group dynamically lists all
isSystem=trueobjects with a collapsible "System Objects" section. A filter toggle on the Data group allows showing/hiding system objects from the main object list. - ObjectSchema
namespaceproperty — New optionalnamespacefield onObjectSchemafor logical domain classification (e.g.,'sys','crm'). When set,tableNameis auto-derived as{namespace}_{name}byObjectSchema.create()unless an explicittableNameis provided. This decouples the logical object name from the physical table name and enables unified routing, permissions, and discovery by domain. - SystemObjectName constants — Extended with all system objects:
ORGANIZATION,MEMBER,INVITATION,TEAM,TEAM_MEMBER,API_KEY,TWO_FACTOR,ROLE,PERMISSION_SET,AUDIT_LOG(in addition to existingUSER,SESSION,ACCOUNT,VERIFICATION,METADATA). - plugin-auth system objects — Added
SysOrganization,SysMember,SysInvitation,SysTeam,SysTeamMember,SysApiKey,SysTwoFactorobject definitions withnamespace: 'sys'. Existing objects (SysUser,SysSession,SysAccount,SysVerification) migrated to use namespace convention. - plugin-security system objects — Added
SysRoleandSysPermissionSetobject definitions. - plugin-audit — New plugin package with
SysAuditLogimmutable audit trail object definition. - StorageNameMapping.resolveTableName() — Now supports namespace-aware auto-derivation
(
{namespace}_{name}fallback when no explicittableNameis set).
- ObjectFilterSchema
includeSystemdefault — Changed fromfalsetotrue. Studio ObjectManager now includes system objects by default. Users can toggle visibility via the Data group filter control. - System object naming convention — All system objects now use
namespace: 'sys'with shortname(e.g.,name: 'user'instead ofname: 'sys_user'). Thesys_prefix is auto-derived viatableName={namespace}_{name}. File naming followssys-{name}.object.tspattern. - plugin-auth object exports — New canonical exports use
Sys*prefix (e.g.,SysUser,SysSession). LegacyAuth*exports are preserved as deprecated re-exports for backward compatibility. - sys_metadata object — Migrated to
namespace: 'sys',name: 'metadata'convention (tableName auto-derived assys_metadata). - Locale code fallback — New
resolveLocale()helper in@objectstack/corethat resolves locale codes through a 4-step fallback chain: exact match → case-insensitive match (zh-cn→zh-CN) → base language match (zh-CN→zh) → variant expansion (zh→zh-CN). Used bycreateMemoryI18n,HttpDispatcher.handleI18n(), andI18nServicePluginroute handlers. - Auto-detection of I18nServicePlugin — Both
DevPluginand CLIservecommand now automatically detecttranslations/i18nconfig in the stack definition and registerI18nServicePluginfrom@objectstack/service-i18nwhen available. Falls back to the core in-memory i18n (with locale resolution) if the package is not installed. - Enhanced i18n diagnostics —
AppPluginnow emits clear warnings when:- Translations exist but no i18n service is registered (guides user to add the plugin).
- Translations are loaded into a fallback/stub i18n service (recommends production plugin).
- i18n locale fallback in REST routes —
HttpDispatcher.handleI18n()translations and labels endpoints now resolve locale codes via fallback when exact match returns empty translations. The response includesrequestedLocalewhen a fallback was used.
- DevPlugin i18n stub — Replaced the duplicate
createI18nStub()inDevPluginwithcreateMemoryI18nfrom@objectstack/core, ensuring locale fallback works consistently in dev mode. DevPlugin now triesI18nServicePluginbefore the stub when stack has translations. createMemoryI18nnow usesresolveLocale()internally fort()andgetTranslations(), enabling locale fallback (e.g.zh→zh-CN) without any plugin changes.- CLI
servecommand now auto-registersI18nServicePluginwhen config has translations/i18n, mirroring DevPlugin's auto-detection behavior for production environments.
- i18n route self-registration — Moved i18n REST endpoint registration from
RestServertoI18nServicePlugin(and kernel fallback). The i18n plugin now self-registers/api/v1/i18n/*routes via thekernel:readyhook, following the same autonomous plugin pattern used byAuthPlugin,WorkflowPlugin, and other service plugins.RestServerno longer registers or manages any i18n endpoints, keeping it strictly a protocol-driven gateway. - Removed
enableI18nflag fromRestApiConfigschema (rest-server.zod.ts) — i18n endpoints are now controlled by the i18n service plugin's ownregisterRoutesoption (default:true). - Removed
registerI18nEndpoints()method fromRestServerclass. I18nServicePluginnow acceptsregisterRoutesandbasePathoptions for HTTP route control.- i18n endpoints now work independently of
RestServer, enabling MSW/mock test environments to serve i18n routes without any REST API gateway dependency. - Dispatcher i18n bridge routes —
createDispatcherPlugin()now registers i18n HTTP route bridges (GET /i18n/locales,GET /i18n/translations/:locale,GET /i18n/labels/:object/:locale) viaHttpDispatcher.handleI18n(), ensuring i18n endpoints work even when only the kernel's memory fallback i18n is active (no explicitI18nServicePluginloaded). This is consistent with how auth, analytics, packages, storage, and automation services are bridged.
- i18n as core built-in service — The i18n service is now a
corecriticality service with automatic in-memory fallback. When no plugin (e.g.I18nServicePlugin) registers an i18n service, the kernel auto-injectscreateMemoryI18n(in-memory Map-backed II18nService implementation) duringvalidateSystemRequirements(). This ensures/api/v1/i18n/*routes and discovery always report i18n as available, even withoutplugin-i18ninstalled. createMemoryI18nfallback factory in@objectstack/core(packages/core/src/fallbacks/memory-i18n.ts) implementingII18nServicecontract with translation loading, dot-notation key resolution, parameter interpolation, and locale management.
ServiceRequirementDef.i18nupgraded from'optional'to'core'— kernel now warns (instead of silently ignoring) when no i18n service is registered, and auto-injects in-memory fallback.SERVICE_CONFIG['i18n'].plugininprotocol.tscorrected from'plugin-i18n'to'service-i18n'to match the actual@objectstack/service-i18npackage name.- Updated kernel-services.mdx documentation to reflect i18n as core/built-in capability.
- AppPlugin getService crash on missing services —
AppPlugin.start()andloadTranslations()now wrapctx.getService()in try/catch, since the kernel'sgetServicethrows when a service is not registered (rather than returningundefined). This was the direct cause ofplugin.app.com.example.crm failed to start— the i18n service was not registered, sogetService('i18n')threw an unhandled exception. - CLI serve: host config AppPlugin mis-wrap —
serve.tsno longer wraps a host/aggregator config (one that already contains instantiated plugins in itspluginsarray) with an extraAppPlugin. This prevents theplugin.app.dev-workspace failed to starterror and eliminates duplicate plugin registration when runningpnpm dev. - plugin-auth CJS→ESM interop — Added
moduleandexportsfields to@objectstack/plugin-authpackage.json so Node.js resolves the ESM build (.mjs) when using dynamicimport(), eliminating theExperimentalWarning: CommonJS module … is loading ES Modulewarning caused bybetter-authbeing ESM-only. - i18n service registration & state inconsistency — Discovery API (
getDiscoveryInfo) now uses the same asyncresolveService()fallback chain that request handlers (handleI18n) use, ensuring the reported service status is always consistent with actual runtime availability. - Discovery
localefield is now populated from the actual i18n service (getDefaultLocale,getLocales) instead of being hardcoded, so clients get accurate locale information. - Updated all framework adapters (Hono, Express, Fastify, Next.js, NestJS, Nuxt, SvelteKit),
the dispatcher plugin, and the MSW plugin to
awaitthe now-asyncgetDiscoveryInfo().
- AppPlugin i18n auto-loading —
AppPluginnow automatically loads translation bundles from app configs (translationsarray) into the kernel's i18n service during thestartphase, coordinating i18n data loading across server/dev/mock environments. - i18n service registration guide in
content/docs/guides/kernel-services.mdxdocumenting service registration patterns, discovery consistency, and AppPlugin auto-loading behavior.
- Updated ROADMAP.md for v3.0 release preparation with full codebase scan results
- Audited all @deprecated items: 14 in spec, 9 in runtime packages (23 total)
- Identified stale deprecation notices targeting v2.0.0 (current: v2.0.7)
- Updated metrics: 172 schema files, 191 test files, 5,165 tests, 7,095 .describe() annotations
- The following items are scheduled for removal in v3.0.0 (see
packages/spec/V3_MIGRATION_GUIDE.md):Hub.*barrel re-exports fromhub/index.tslocation(singular) onActionSchema— uselocations(array)definePlugin()in spec — will move to@objectstack/corecreateErrorResponse()/getHttpStatusForCategory()in spec — will move to@objectstack/coreRateLimitSchema,RealtimePresenceStatus,RealtimeActionaliases- Event bus helper functions (
createDefaultEventBusConfig,createDefaultDLQConfig,createDefaultEventHandlerConfig) HttpDispatcherclass in@objectstack/runtimecreateHonoApp()in@objectstack/hono
2.0.7 - 2026-02-11
- Modularized
kernel/events.zod.ts(765 lines) into 6 focused sub-modules for better tree-shaking:events/core.zod.ts: Priority, metadata, type definition, base eventevents/handlers.zod.ts: Event handlers, routes, persistenceevents/queue.zod.ts: Queue config, replay, sourcingevents/dlq.zod.ts: Dead letter queue, event log entriesevents/integrations.zod.ts: Webhooks, message queues, notificationsevents/bus.zod.ts: Complete event bus config and helpers
- Created v3.0 migration guide (
packages/spec/V3_MIGRATION_GUIDE.md)
kernel/events.zod.tsnow re-exports from sub-modules (backward compatible)- Updated all packages to version 2.0.7 with unified versioning
2.0.6 - 2026-02-11
- Patch release for maintenance and stability improvements
- Updated all packages to version 2.0.6 with unified versioning
2.0.5 - 2026-02-10
- Unified all package versions to 2.0.5
- Added
@objectstack/plugin-authand@objectstack/plugin-securityto the changeset fixed versioning group - All packages now release together under the same version number
2.0.4 - 2026-02-10
- Patch release for maintenance and stability improvements
- Updated all packages to version 2.0.4 with unified versioning
2.0.3 - 2026-02-10
- Patch release for maintenance and stability improvements
- Updated all packages to version 2.0.3 with unified versioning
2.0.2 - 2026-02-10
- Exclude generated JSON schema files from git tracking
- Add
packages/spec/json-schema/to.gitignore(1277 generated files, 5MB) - JSON schema files are still generated during
pnpm buildand included in npm publish - Fix studio module resolution logic for better compatibility
- Updated all packages to version 2.0.2 with unified versioning
2.0.1 - 2026-02-09
- Patch release for maintenance and stability improvements
- Updated all packages to version 2.0.1 with unified versioning
0.9.1 - 2026-02-03
- Patch release for maintenance and stability improvements
- Updated all packages to version 0.9.1 with unified versioning
0.9.0 - 2026-02-03
- Minor version bump for new features and improvements
- All packages updated to version 0.9.0
0.8.2 - 2026-02-02
- BREAKING: Removed
view-storage.zod.tsandViewStoragerelated types from@objectstack/spec - BREAKING: Removed
createView,updateView,deleteView,listViewsfromObjectStackProtocolinterface - BREAKING: Removed in-memory View Storage implementation from
@objectstack/objectql - Updated
@objectstack/plugin-mswto dynamically load@objectstack/objectqlto avoid hard dependencies
0.8.1 - 2026-02-01
- Patch release for maintenance and stability improvements
- Updated all packages to version 0.8.1
0.8.0 - 2026-02-01
- Upgrade to Zod v4 and protocol improvements
- Aligned all protocol definitions with stricter type safety
- Updated all packages to version 0.8.0
0.7.2 - 2026-01-31
- Updated system protocol JSON schemas (events, worker, metadata-loader)
- Enhanced documentation structure for system protocols
- Generated comprehensive JSON schema documentation
0.7.1 - 2026-01-31
- Patch release for maintenance and stability improvements
- Updated all packages to version 0.7.1
0.6.1 - 2026-01-28
- Patch release for maintenance and stability improvements
- Updated all packages to version 0.6.1
0.4.1 - 2026-01-27
- Synchronized plugin-msw version to 0.4.1 (was incorrectly at 0.3.3)
- Updated runtime peer dependency versions to ^0.4.1 across all plugins
- Fixed internal dependency version mismatches
0.4.0 - 2026-01-26
- Updated all core packages to version 0.4.0
0.3.3 - 2026-01-25
- Enhanced GitHub workflows for CI, release, and PR automation
- Added comprehensive prompt templates for different protocol areas
- Improved project documentation and automation guides
- Updated changeset configuration
- Added cursor rules for better development experience
- Updated all packages to version 0.3.3
0.3.2 - 2026-01-24
- Patch release for maintenance and stability improvements
- Updated all packages to version 0.3.2
0.3.1 - 2026-01-23
- Organized zod schema files by folder structure
- Improved project documentation
0.3.0 - 2026-01-22
- Comprehensive documentation structure with CONTRIBUTING.md
- Documentation hub at docs/README.md
- Standards documentation (naming-conventions, api-design, error-handling)
- Architecture deep dives (data-layer, ui-layer, system-layer)
- Code of Conduct
- Changelog template
- Migration guides structure
- Security and performance guides
- Updated README.md with improved documentation navigation
- Enhanced documentation organization following industry best practices
- All packages now use unified versioning (all packages released together with same version number)
0.1.1 - 2026-01-20
- Initial protocol specifications
- Zod schemas for data, UI, system, AI, and API protocols
- JSON schema generation
- Basic documentation site with Fumadocs
- Example implementations (CRM, Todo)
## [X.Y.Z] - YYYY-MM-DD
### Added
- New features or capabilities
### Changed
- Changes to existing functionality
### Deprecated
- Features that will be removed in upcoming releases
### Removed
- Features that have been removed
### Fixed
- Bug fixes
### Security
- Security-related changesWhen making changes:
- Add entries under
[Unreleased]section - Choose the appropriate category: Added, Changed, Deprecated, Removed, Fixed, Security
- Write clear, concise descriptions of your changes
- Link to PRs or issues where applicable:
- Feature description (#PR_NUMBER)
Example:
### Added
- New encrypted field type for sensitive data (#123)
- Support for PostgreSQL window functions in query protocol (#124)
### Fixed
- Validation error when using lookup fields with filters (#125)When releasing a new version:
- Create a new version section from the
[Unreleased]content - Move entries from
[Unreleased]to the new version section - Add release date in YYYY-MM-DD format
- Tag the release in git:
git tag -a v0.2.0 -m "Release v0.2.0" - Update links at the bottom of the file
Following Semantic Versioning:
- MAJOR version (X.0.0): Incompatible API changes
- MINOR version (0.X.0): Add functionality in a backward compatible manner
- PATCH version (0.0.X): Backward compatible bug fixes
- Added: New features, protocols, schemas, or capabilities
- Changed: Changes to existing functionality
- Deprecated: Features marked for removal (but still working)
- Removed: Features that have been removed
- Fixed: Bug fixes
- Security: Security vulnerability fixes or improvements
Mark breaking changes clearly:
### Changed
- **BREAKING**: Renamed `maxLength` to `maxLen` in FieldSchema (#126)
Migration: Update all field definitions to use `maxLen` instead of `maxLength`- Update CHANGELOG.md with release notes
- Update version in package.json files
- Run
pnpm changeset versionto update package versions - Commit changes:
git commit -m "chore: release vX.Y.Z" - Create git tag:
git tag -a vX.Y.Z -m "Release vX.Y.Z" - Push:
git push && git push --tags - Run
pnpm releaseto publish packages