Skip to content

Commit 7e1953b

Browse files
committed
feat: add createStudioRuntimeConfigPlugin to serve runtime config for multi-project mode
1 parent ddd6620 commit 7e1953b

3 files changed

Lines changed: 33 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
- `apps/server`: Multi-project / cloud mode now also serves `GET /api/v1/studio/runtime-config` (returns `{ singleProject: false }`) via a new `createStudioRuntimeConfigPlugin`. Eliminates the 404 the Studio SPA logged on first load when `OBJECTSTACK_MULTI_PROJECT=true` (the default for root `pnpm dev`). Single-project mode is unchanged.
12+
1013
### Added
1114
- **M1 — Project Artifact envelope schema (`@objectstack/spec`)** — Introduced the v0 `ProjectArtifactSchema` in `packages/spec/src/system/project-artifact.zod.ts`, the immutable envelope that `objectstack compile` will produce and ObjectOS will consume at boot. Required fields: `schemaVersion` (literal `'0.1'`), `projectId`, `commitId`, `checksum` (`{ algorithm, value }`), `metadata` (per-category arrays, `passthrough()` for forward compatibility), `functions` (inlined source with optional language/source/hash), and `manifest` (plugin / driver / engine requirements). Optional `builtAt`, `builtWith`, and a reserved `payloadRef` (`{ url, expiresAt, checksum }`) for future S3 indirection without an envelope bump. 14 new tests in `project-artifact.test.ts`. Resolves ROADMAP M1; unblocks M3 (Artifact API) and M4 (ObjectOS artifact loader).
1215

apps/server/objectstack.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import {
4646
AppPlugin,
4747
} from '@objectstack/runtime';
4848
import { createControlPlanePlugins } from './server/control-plane-preset.js';
49-
import { createSingleProjectPlugin } from './server/single-project-plugin.js';
49+
import { createSingleProjectPlugin, createStudioRuntimeConfigPlugin } from './server/single-project-plugin.js';
5050
import { templateRegistry } from './server/templates/registry.js';
5151

5252
type IDataDriver = Contracts.IDataDriver;
@@ -247,6 +247,7 @@ const config = isLocalMode
247247
baseUrl,
248248
}),
249249
multiProjectPluginProxy,
250+
createStudioRuntimeConfigPlugin(),
250251
],
251252
api: {
252253
enableProjectScoping: true,

apps/server/server/single-project-plugin.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,34 @@ export function createSingleProjectPlugin(options: SingleProjectPluginOptions =
141141
};
142142
}
143143

144+
/**
145+
* Multi-project / cloud variant: only registers `/studio/runtime-config`,
146+
* returning `{ singleProject: false }` so the SPA falls through to the
147+
* org/project picker. Avoids a 404 in the Network panel without affecting
148+
* any actual control-plane behaviour.
149+
*/
150+
export function createStudioRuntimeConfigPlugin(options: { apiPrefix?: string } = {}): any {
151+
const prefix = options.apiPrefix ?? '/api/v1';
152+
return {
153+
name: 'com.objectstack.studio.runtime-config',
154+
version: '1.0.0',
155+
init: async (_ctx: AnyContext) => {},
156+
start: async (ctx: AnyContext) => {
157+
let server: IHttpServer | undefined;
158+
try {
159+
server = ctx.getService('http.server') as IHttpServer | undefined;
160+
} catch {
161+
return;
162+
}
163+
if (!server) return;
164+
server.get(`${prefix}/studio/runtime-config`, async (_req: any, res: any) => {
165+
res.json({ singleProject: false });
166+
});
167+
},
168+
stop: async (_ctx: AnyContext) => {},
169+
};
170+
}
171+
144172
function buildLocalProjectRow(orgId: string, projectId: string, userId: string): Record<string, unknown> {
145173
const now = new Date().toISOString();
146174
return {

0 commit comments

Comments
 (0)