Skip to content

feat(studio): Switch Vercel deployment from MSW to real server mode#929

Merged
hotlong merged 5 commits into
mainfrom
copilot/update-vercel-deployment-mode
Mar 18, 2026
Merged

feat(studio): Switch Vercel deployment from MSW to real server mode#929
hotlong merged 5 commits into
mainfrom
copilot/update-vercel-deployment-mode

Conversation

Copilot AI commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

Studio's Vercel deployment ran the entire ObjectStack kernel in-browser via MSW — no real backend. This converts it to server mode using Hono serverless functions.

Server-side API (api/)

  • api/[...path].ts — Vercel catch-all serverless function, delegates to Hono app via handle()
  • api/_kernel.ts — Lazy-initialized kernel singleton (survives warm invocations), seeds data on cold start, exposes createHonoApp({ kernel, prefix: '/api/v1' })

Broker shim extraction (DRY)

  • src/lib/create-broker-shim.ts — Extracted the ~265-line inline broker shim from createKernel.ts into a shared factory. Both MSW (browser) and Hono (server) modes import it.

Configuration

  • vercel.jsonVITE_RUNTIME_MODE=server, VITE_SERVER_URL="" (same-origin), rewrite excludes /api/
  • package.json — Added hono, @objectstack/hono
┌─── Vercel ──────────────────────────────────────┐
│  Static (Vite SPA)     → /index.html, /assets/* │
│  Serverless Function   → /api/[...path]         │
│    Hono → ObjectKernel → ObjectQL → InMemory    │
└─────────────────────────────────────────────────┘

Docs

  • Updated deployment-vercel.mdx — server mode is now the default; added Hono+Vite SPA example as Option B

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@vercel

vercel Bot commented Mar 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectstack-play Ready Ready Preview, Comment Mar 18, 2026 0:37am
spec Ready Ready Preview, Comment Mar 18, 2026 0:37am

Request Review

Copilot AI and others added 2 commits March 18, 2026 10:47
…ith Hono serverless functions

- Add api/[...path].ts Vercel serverless catch-all using Hono
- Add api/_kernel.ts server-side kernel singleton
- Extract broker shim to src/lib/create-broker-shim.ts (DRY)
- Update vercel.json to VITE_RUNTIME_MODE=server
- Add hono and @objectstack/hono dependencies
- Update deployment docs

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Update Vercel deployment to use real server mode instead of MSW feat(studio): Switch Vercel deployment from MSW to real server mode Mar 18, 2026
Copilot AI requested a review from hotlong March 18, 2026 10:52
@hotlong

hotlong commented Mar 18, 2026

Copy link
Copy Markdown
Collaborator

@copilot 18:58:15.850 @objectstack/spec:build: ✓ data/TenantDatabaseLifecycle.json
18:58:17.870 @objectstack/studio:build: �[31merror during build:
18:58:17.871 @objectstack/studio:build: Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './internal' is not defined by "exports" in /vercel/path0/node_modules/.pnpm/@vitejs+plugin-react@6.0.1_vite@7.3.1_@types+node@25.5.0_jiti@2.6.1_lightningcss@1.31.1_tsx@4.21.0_/node_modules/vite/package.json imported from /vercel/path0/node_modules/.pnpm/@vitejs+plugin-react@6.0.1_vite@7.3.1_@types+node@25.5.0_jiti@2.6.1_lightningcss@1.31.1_tsx@4.21.0_/node_modules/@vitejs/plugin-react/dist/index.js
18:58:17.871 @objectstack/studio:build: at exportsNotFound (node:internal/modules/esm/resolve:313:10)
18:58:17.871 @objectstack/studio:build: at packageExportsResolve (node:internal/modules/esm/resolve:661:9)
18:58:17.872 @objectstack/studio:build: at packageResolve (node:internal/modules/esm/resolve:774:12)
18:58:17.872 @objectstack/studio:build: at moduleResolve (node:internal/modules/esm/resolve:858:18)
18:58:17.872 @objectstack/studio:build: at defaultResolve (node:internal/modules/esm/resolve:990:11)
18:58:17.872 @objectstack/studio:build: at #cachedDefaultResolve (node:internal/modules/esm/loader:718:20)
18:58:17.872 @objectstack/studio:build: at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:735:38)
18:58:17.872 @objectstack/studio:build: at ModuleLoader.resolveSync (node:internal/modules/esm/loader:764:52)
18:58:17.872 @objectstack/studio:build: at #resolve (node:internal/modules/esm/loader:700:17)
18:58:17.872 @objectstack/studio:build: at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:620:35)�[39m
18:58:17.895 @objectstack/studio:build:  ELIFECYCLE  Command failed with exit code 1.
18:58:17.906 @objectstack/studio:build: ERROR: command finished with error: command (/vercel/path0/apps/studio) /vercel/.local/share/pnpm/.tools/pnpm/10.31.0/bin/pnpm run build exited (1)
18:58:17.906 @objectstack/studio#build: command (/vercel/path0/apps/studio) /vercel/.local/share/pnpm/.tools/pnpm/10.31.0/bin/pnpm run build exited (1)
18:58:17.916 ERROR run failed: command exited (1)
18:58:17.935 Error: Command "cd ../.. && pnpm turbo run build --filter=@objectstack/studio" exited with 1

…atibility

@vitejs/plugin-react v6 requires Vite 8+ and fails with ERR_PACKAGE_PATH_NOT_EXPORTED
when paired with Vite 7. v5.2.0 explicitly supports Vite 4–8.

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>

Copilot AI commented Mar 18, 2026

Copy link
Copy Markdown
Contributor Author

@copilot 18:58:15.850 @objectstack/spec:build: ✓ data/TenantDatabaseLifecycle.json
18:58:17.870 @objectstack/studio:build: �[31merror during build:
18:58:17.871 @objectstack/studio:build: Error [E...

The build failure was caused by @vitejs/plugin-react@6.0.1 being incompatible with Vite 7 — v6 requires Vite 8+ and tries to import vite/internal which doesn't exist in Vite 7. Downgraded to @vitejs/plugin-react@^5.2.0 which explicitly supports Vite 4–8. Build now passes. Fixed in 9db6d8d.

@hotlong

hotlong commented Mar 18, 2026

Copy link
Copy Markdown
Collaborator

@copilot 从组分之更新最新代码并解决冲突,测试确认

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates ObjectStack Studio’s Vercel deployment to run in server mode (Hono serverless function) instead of MSW-only mode, aligning Studio’s hosted behavior with real API endpoints and sharing broker-shim logic across runtimes.

Changes:

  • Switch Studio Vercel config to server mode (VITE_RUNTIME_MODE=server, same-origin VITE_SERVER_URL="") and add SPA rewrite that avoids /api/*.
  • Add Vercel serverless API entrypoint (api/[...path].ts) and kernel singleton (api/_kernel.ts) using Hono + @objectstack/hono.
  • Extract the broker shim into src/lib/create-broker-shim.ts and update deps (add hono, @objectstack/hono, and align @vitejs/plugin-react to ^5.2.0).

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds Hono + adapter deps and updates resolved versions (incl. plugin-react downgrade).
content/docs/guides/deployment-vercel.mdx Updates Vercel deployment guide to recommend Server mode and document Hono setup.
apps/studio/vercel.json Switches Studio build env to server mode and adjusts SPA rewrites to avoid /api/*.
apps/studio/src/mocks/createKernel.ts Reuses extracted broker shim instead of inlining broker logic.
apps/studio/src/lib/create-broker-shim.ts New shared broker shim implementation for MSW + server modes.
apps/studio/package.json Adds hono + @objectstack/hono and adjusts @vitejs/plugin-react version.
apps/studio/CHANGELOG.md Notes the server-mode Vercel deployment changes for the release.
apps/studio/api/[...path].ts New Vercel catch-all serverless function that delegates to the inner Hono app.
apps/studio/api/_kernel.ts New server-side kernel singleton + Hono app factory for Vercel warm invocations.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread apps/studio/vercel.json
},
"rewrites": [
{ "source": "/(.*)", "destination": "/index.html" }
{ "source": "/((?!api/).*)", "destination": "/index.html" }
}
},
"rewrites": [
{ "source": "/((?!api/).*)", "destination": "/index.html" }
Comment on lines +23 to +31
// --- Singleton state (persists across warm invocations) ---
let _kernel: ObjectKernel | null = null;
let _app: Hono | null = null;

/**
* Boot the ObjectStack kernel (one-time cold-start cost).
*/
async function bootKernel(): Promise<ObjectKernel> {
if (_kernel) return _kernel;
Comment on lines +46 to +99
// Seed data from config
await seedData(kernel, [studioConfig]);

_kernel = kernel;
console.log('[Vercel] Kernel ready.');
return kernel;
}

/**
* Seed records defined in app configs into the ObjectQL engine.
*/
async function seedData(kernel: ObjectKernel, configs: any[]) {
const ql = (kernel as any).context?.getService('objectql');
if (!ql) return;

// Reserved namespaces ('base', 'system') bypass FQN transformation —
// objects in these namespaces keep their short name as-is.
const RESERVED_NS = new Set(['base', 'system']);
const toFQN = (name: string, namespace?: string) => {
if (name.includes('__') || !namespace || RESERVED_NS.has(namespace)) return name;
return `${namespace}__${name}`;
};

for (const appConfig of configs) {
const namespace = (appConfig.manifest || appConfig)?.namespace as string | undefined;

const seedDatasets: any[] = [];
if (Array.isArray(appConfig.data)) {
seedDatasets.push(...appConfig.data);
}
if (appConfig.manifest && Array.isArray(appConfig.manifest.data)) {
seedDatasets.push(...appConfig.manifest.data);
}

for (const dataset of seedDatasets) {
if (!dataset.records || !dataset.object) continue;

const objectFQN = toFQN(dataset.object, namespace);

// Handle PaginatedResult wrapper — InMemoryDriver may return { value: [...] }
let existing = await ql.find(objectFQN);
if (existing && (existing as any).value) existing = (existing as any).value;

if (!existing || existing.length === 0) {
console.log(`[Vercel] Seeding ${dataset.records.length} records for ${objectFQN}`);
for (const record of dataset.records) {
await ql.insert(objectFQN, record);
}
}
}
}
}

/**
Comment on lines +275 to +290
import { ObjectKernel, DriverPlugin, AppPlugin } from '@objectstack/runtime';
import { ObjectQLPlugin } from '@objectstack/objectql';
import { InMemoryDriver } from '@objectstack/driver-memory';
import { createHonoApp } from '@objectstack/hono';
import { Hono } from 'hono';
import appConfig from '../objectstack.config';

export const config = { runtime: 'edge' };

const app = new Hono().basePath('/api');
let _kernel: ObjectKernel | null = null;
let _app: Hono | null = null;

async function bootKernel(): Promise<ObjectKernel> {
if (_kernel) return _kernel;
_kernel = new ObjectKernel();
await _kernel.use(new ObjectQLPlugin());
await _kernel.use(new DriverPlugin(new InMemoryDriver(), 'memory'));
await _kernel.use(new AppPlugin(appConfig));
Comment on lines +23 to +30
const app = new Hono();

app.all('/*', async (c) => {
const inner = await getApp();
return inner.fetch(c.req.raw);
});

export default handle(app);
@hotlong

hotlong commented Mar 18, 2026

Copy link
Copy Markdown
Collaborator

@copilot 从主分支更新最新代码并解决冲突,测试确认

Merges latest main which bumps vite from 7.3.1 to 8.0.0 and
@vitejs/plugin-react from 5.1.4 to 6.0.1. The previous v5.2.0
downgrade is no longer needed since Vite 8 is now the base.

Resolves lockfile conflicts and confirms build + tests pass.

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>

Copilot AI commented Mar 18, 2026

Copy link
Copy Markdown
Contributor Author

@copilot 从组分之更新最新代码并解决冲突,测试确认

Merged latest main into the branch and resolved lockfile conflicts. Main brought in Vite 8.0.0 + @vitejs/plugin-react 6.0.1 (now a compatible pair), so the previous v5.2.0 downgrade is reverted. Build and all tests (5 files, 13 tests) pass. Fixed in 85f3180e.

@hotlong
hotlong merged commit 878d0ef into main Mar 18, 2026
1 of 4 checks passed
Copilot stopped work on behalf of hotlong due to an error March 18, 2026 12:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants