3232 */
3333
3434import { resolve as resolvePath } from 'node:path' ;
35+ import { readFile } from 'node:fs/promises' ;
3536import type * as Contracts from '@objectstack/spec/contracts' ;
3637import {
3738 type BasePluginsFactory ,
3839 type AppBundleResolver ,
40+ AppPlugin ,
3941} from '@objectstack/runtime' ;
4042import { createControlPlanePlugins } from './server/control-plane-preset.js' ;
4143import { templateRegistry } from './server/templates/registry.js' ;
@@ -59,38 +61,47 @@ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL
5961// ── LOCAL MODE ────────────────────────────────────────────────────────────────
6062
6163const localProjectId = process . env . OBJECTSTACK_PROJECT_ID ?? 'proj_local' ;
62- const localDatabaseUrl = process . env . OBJECTSTACK_DATABASE_URL
63- ?? `file:${ resolvePath ( process . cwd ( ) , '.objectstack/data/local.db' ) } ` ;
64- const localDatabaseDriver = process . env . OBJECTSTACK_DATABASE_DRIVER ?? 'sqlite' ;
6564const localArtifactPath = process . env . OBJECTSTACK_ARTIFACT_PATH
6665 ?? resolvePath ( process . cwd ( ) , 'dist/objectstack.json' ) ;
6766
68- // Lazy-loading proxy for local boot: registers ObjectQL + MetadataPlugin(local-file) + Auth
69- // on the kernel. No control-plane, no MultiProjectPlugin.
70- const localBootPluginProxy : any = {
71- name : 'com.objectstack.local-boot' ,
72- version : '0.0.0' ,
73- async init ( ctx : any ) {
74- const { ObjectQLPlugin } = await import ( '@objectstack/objectql' ) ;
75- const { MetadataPlugin } = await import ( '@objectstack/metadata' ) ;
76- const { AuthPlugin } = await import ( '@objectstack/plugin-auth' ) ;
67+ async function buildLocalPlugins ( ) {
68+ const { ObjectQLPlugin } = await import ( '@objectstack/objectql' ) ;
69+ const { MetadataPlugin } = await import ( '@objectstack/metadata' ) ;
70+ const { AuthPlugin } = await import ( '@objectstack/plugin-auth' ) ;
7771
78- await ctx . kernel . use ( new ObjectQLPlugin ( { environmentId : localProjectId } ) ) ;
79- await ctx . kernel . use ( new MetadataPlugin ( {
72+ // Load artifact JSON to register app bundle (objects, views, etc.) via AppPlugin.
73+ // AppPlugin.init() calls manifest.register() → ql.registerApp() which is the
74+ // correct pathway for objects to enter the ObjectQL schema registry.
75+ let artifactBundle : any = null ;
76+ try {
77+ const raw = await readFile ( localArtifactPath , 'utf8' ) ;
78+ const parsed = JSON . parse ( raw ) ;
79+ // Detect envelope vs bare ObjectStackDefinition
80+ artifactBundle = ( parsed ?. schemaVersion && parsed ?. metadata !== undefined )
81+ ? parsed . metadata
82+ : parsed ;
83+ } catch {
84+ // Artifact not available yet (e.g. first run before compile) — AppPlugin skipped.
85+ }
86+
87+ // MetadataPlugin must start before ObjectQLPlugin so that when ObjectQL's
88+ // start() calls loadMetadataFromService(), the artifact is already loaded.
89+ const plugins : any [ ] = [
90+ new MetadataPlugin ( {
8091 watch : false ,
8192 environmentId : localProjectId ,
8293 artifactSource : { mode : 'local-file' , path : localArtifactPath } ,
83- } ) ) ;
84- await ctx . kernel . use ( new AuthPlugin ( { secret : authSecret , baseUrl } ) ) ;
85-
86- ctx . logger ?. info ?. ( '[LocalBoot] plugins registered' , {
87- projectId : localProjectId ,
88- databaseUrl : localDatabaseUrl ,
89- databaseDriver : localDatabaseDriver ,
90- artifactPath : localArtifactPath ,
91- } ) ;
92- } ,
93- } ;
94+ } ) ,
95+ new ObjectQLPlugin ( { environmentId : localProjectId } ) ,
96+ new AuthPlugin ( { secret : authSecret , baseUrl } ) ,
97+ ] ;
98+
99+ if ( artifactBundle ) {
100+ plugins . push ( new AppPlugin ( artifactBundle ) ) ;
101+ }
102+
103+ return plugins ;
104+ }
94105
95106// ── CLOUD MODE ────────────────────────────────────────────────────────────────
96107
@@ -171,9 +182,9 @@ const multiProjectPluginProxy: any = {
171182
172183// ── Export ────────────────────────────────────────────────────────────────────
173184
174- export default isLocalMode
185+ const config = isLocalMode
175186 ? {
176- plugins : [ localBootPluginProxy ] ,
187+ plugins : await buildLocalPlugins ( ) ,
177188 api : {
178189 enableProjectScoping : false ,
179190 projectResolution : 'none' as const ,
@@ -193,3 +204,5 @@ export default isLocalMode
193204 projectResolution : 'auto' as const ,
194205 } ,
195206 } ;
207+
208+ export default config ;
0 commit comments