@@ -44,7 +44,7 @@ export interface DevPluginOptions {
4444 * Override which services to enable. By default all core services are enabled.
4545 * Set a service name to `false` to skip it.
4646 *
47- * Available services: 'objectql', 'driver', 'auth', 'server', 'rest'
47+ * Available services: 'objectql', 'driver', 'auth', 'server', 'rest', 'dispatcher'
4848 */
4949 services ?: Partial < Record < string , boolean > > ;
5050
@@ -53,21 +53,44 @@ export interface DevPluginOptions {
5353 * Useful for adding custom project plugins while still getting the dev defaults.
5454 */
5555 extraPlugins ?: Plugin [ ] ;
56+
57+ /**
58+ * Stack definition to load as a project.
59+ * When provided, the DevPlugin wraps it in an AppPlugin so that all
60+ * metadata (objects, views, apps, dashboards, etc.) is registered with
61+ * the kernel and exposed through the REST/metadata APIs.
62+ *
63+ * This is what makes `new DevPlugin({ stack: config })` equivalent to
64+ * a full `os serve --dev` environment: views can be read, modified, and
65+ * saved through the API.
66+ *
67+ * @example
68+ * ```ts
69+ * import config from './objectstack.config';
70+ * plugins: [new DevPlugin({ stack: config })]
71+ * ```
72+ */
73+ stack ?: Record < string , any > ;
5674}
5775
5876/**
5977 * Development Mode Plugin for ObjectStack
6078 *
61- * A convenience plugin that auto-configures the entire platform stack
62- * for local development. Instead of manually wiring:
79+ * A convenience plugin that auto-configures the **entire** platform stack
80+ * for local development, simulating all kernel services so developers
81+ * can work in a full-featured API environment without external dependencies.
82+ *
83+ * Instead of manually wiring:
6384 *
6485 * ```ts
6586 * plugins: [
6687 * new ObjectQLPlugin(),
6788 * new DriverPlugin(new InMemoryDriver()),
6889 * new AuthPlugin({ secret: '...', baseUrl: '...' }),
6990 * new HonoServerPlugin({ port: 3000 }),
70- * // ...
91+ * createRestApiPlugin(),
92+ * createDispatcherPlugin(),
93+ * new AppPlugin(config),
7194 * ]
7295 * ```
7396 *
@@ -77,13 +100,17 @@ export interface DevPluginOptions {
77100 * plugins: [new DevPlugin()]
78101 * ```
79102 *
80- * The DevPlugin will:
81- * 1. Register an ObjectQL engine (data layer)
82- * 2. Register an InMemoryDriver (no database required)
83- * 3. Register an Auth plugin (with dev credentials)
84- * 4. Register a Hono HTTP server
85- * 5. Register REST API endpoints
86- * 6. Optionally seed a default admin user
103+ * ## Services enabled
104+ *
105+ * | Service | Package | Description |
106+ * |--------------|-----------------------------------|-------------------------------------------|
107+ * | ObjectQL | `@objectstack/objectql` | Data engine (query, CRUD, hooks) |
108+ * | Driver | `@objectstack/driver-memory` | In-memory database (no DB install) |
109+ * | Auth | `@objectstack/plugin-auth` | Authentication with dev credentials |
110+ * | HTTP Server | `@objectstack/plugin-hono-server` | HTTP server on configured port |
111+ * | REST API | `@objectstack/rest` | Auto-generated CRUD + metadata endpoints |
112+ * | Dispatcher | `@objectstack/runtime` | Auth, GraphQL, analytics, packages, etc. |
113+ * | App/Metadata | `@objectstack/runtime` | Project metadata (objects, views, apps) |
87114 *
88115 * All services can be individually disabled via `options.services`.
89116 * Peer packages are loaded via dynamic import and silently skipped if missing.
@@ -122,13 +149,13 @@ export class DevPlugin implements Plugin {
122149
123150 const enabled = ( name : string ) => this . options . services ?. [ name ] !== false ;
124151
125- // 1. ObjectQL Engine (data layer)
152+ // 1. ObjectQL Engine (data layer + metadata service )
126153 if ( enabled ( 'objectql' ) ) {
127154 try {
128155 const { ObjectQLPlugin } = await import ( '@objectstack/objectql' ) ;
129156 const qlPlugin = new ObjectQLPlugin ( ) ;
130157 this . childPlugins . push ( qlPlugin ) ;
131- ctx . logger . info ( ' ✔ ObjectQL engine enabled' ) ;
158+ ctx . logger . info ( ' ✔ ObjectQL engine enabled (data + metadata) ' ) ;
132159 } catch {
133160 ctx . logger . warn ( ' ✘ @objectstack/objectql not installed — skipping data engine' ) ;
134161 }
@@ -148,7 +175,21 @@ export class DevPlugin implements Plugin {
148175 }
149176 }
150177
151- // 3. Auth Plugin
178+ // 3. App Plugin — registers project metadata (objects, views, apps, dashboards, etc.)
179+ // This is the key piece that enables full API development:
180+ // once metadata is registered, REST endpoints can read/write views, etc.
181+ if ( this . options . stack ) {
182+ try {
183+ const { AppPlugin } = await import ( '@objectstack/runtime' ) as any ;
184+ const appPlugin = new AppPlugin ( this . options . stack ) ;
185+ this . childPlugins . push ( appPlugin ) ;
186+ ctx . logger . info ( ' ✔ App metadata loaded from stack definition' ) ;
187+ } catch {
188+ ctx . logger . warn ( ' ✘ @objectstack/runtime not installed — skipping app metadata' ) ;
189+ }
190+ }
191+
192+ // 4. Auth Plugin
152193 if ( enabled ( 'auth' ) ) {
153194 try {
154195 const { AuthPlugin } = await import ( '@objectstack/plugin-auth' ) as any ;
@@ -163,7 +204,7 @@ export class DevPlugin implements Plugin {
163204 }
164205 }
165206
166- // 4 . Hono HTTP Server
207+ // 5 . Hono HTTP Server
167208 if ( enabled ( 'server' ) ) {
168209 try {
169210 const { HonoServerPlugin } = await import ( '@objectstack/plugin-hono-server' ) as any ;
@@ -177,28 +218,30 @@ export class DevPlugin implements Plugin {
177218 }
178219 }
179220
180- // 5 . REST API endpoints
221+ // 6 . REST API endpoints (CRUD + metadata read/write)
181222 if ( enabled ( 'rest' ) ) {
182223 try {
183- const restModule = await import ( '@objectstack/rest' ) as any ;
184- // REST may export a plugin class or a factory function
185- const RestPlugin = ( restModule as any ) . RestPlugin
186- ?? ( restModule as any ) . createRestPlugin
187- ?? ( restModule as any ) . default ;
188- if ( typeof RestPlugin === 'function' ) {
189- const restPlugin = RestPlugin . prototype ?. init
190- ? new RestPlugin ( )
191- : RestPlugin ( ) ;
192- if ( restPlugin ) {
193- this . childPlugins . push ( restPlugin ) ;
194- ctx . logger . info ( ' ✔ REST API endpoints enabled' ) ;
195- }
196- }
224+ const { createRestApiPlugin } = await import ( '@objectstack/rest' ) as any ;
225+ const restPlugin = createRestApiPlugin ( ) ;
226+ this . childPlugins . push ( restPlugin ) ;
227+ ctx . logger . info ( ' ✔ REST API endpoints enabled (CRUD + metadata)' ) ;
197228 } catch {
198229 ctx . logger . debug ( ' ℹ @objectstack/rest not installed — skipping REST endpoints' ) ;
199230 }
200231 }
201232
233+ // 7. Dispatcher (auth routes, GraphQL, analytics, packages, storage, automation)
234+ if ( enabled ( 'dispatcher' ) ) {
235+ try {
236+ const { createDispatcherPlugin } = await import ( '@objectstack/runtime' ) as any ;
237+ const dispatcherPlugin = createDispatcherPlugin ( ) ;
238+ this . childPlugins . push ( dispatcherPlugin ) ;
239+ ctx . logger . info ( ' ✔ Dispatcher enabled (auth, GraphQL, analytics, packages, storage)' ) ;
240+ } catch {
241+ ctx . logger . debug ( ' ℹ Dispatcher not available — skipping extended API routes' ) ;
242+ }
243+ }
244+
202245 // Extra user-provided plugins
203246 if ( this . options . extraPlugins ) {
204247 this . childPlugins . push ( ...this . options . extraPlugins ) ;
@@ -241,6 +284,10 @@ export class DevPlugin implements Plugin {
241284 ctx . logger . info ( '─────────────────────────────────────────' ) ;
242285 ctx . logger . info ( '🟢 ObjectStack Dev Server ready' ) ;
243286 ctx . logger . info ( ` http://localhost:${ this . options . port } ` ) ;
287+ ctx . logger . info ( '' ) ;
288+ ctx . logger . info ( ' API: /api/v1/data/:object' ) ;
289+ ctx . logger . info ( ' Metadata: /api/v1/meta/:type/:name' ) ;
290+ ctx . logger . info ( ' Discovery: /.well-known/objectstack' ) ;
244291 ctx . logger . info ( '─────────────────────────────────────────' ) ;
245292 }
246293
0 commit comments