From 9928b2ab050a84935951adac6eee805103897cee Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:51:15 +0000 Subject: [PATCH 1/3] feat: create independent server app for Vercel deployment - Create apps/server package with all necessary files - Add package.json with ObjectStack dependencies - Create objectstack.config.ts with plugin configuration - Add server/index.ts entrypoint with Hono adapter - Create API handler (api/[[...route]].js) for Vercel - Add build scripts (build-vercel.sh, bundle-api.mjs) - Configure Vercel deployment (vercel.json) - Add environment config (.env.example) - Create .gitignore and .vercelignore - Add tsconfig.json for TypeScript compilation - Write comprehensive README.md - Write detailed DEPLOYMENT.md guide Agent-Logs-Url: https://github.com/objectstack-ai/objectui/sessions/1401bb2d-d094-4280-a66d-bee5388fc83a Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> --- apps/server/.env.example | 16 ++ apps/server/.gitignore | 33 +++ apps/server/.vercelignore | 29 +++ apps/server/DEPLOYMENT.md | 349 ++++++++++++++++++++++++++++ apps/server/README.md | 197 ++++++++++++++++ apps/server/api/[[...route]].js | 11 + apps/server/objectstack.config.ts | 152 ++++++++++++ apps/server/package.json | 38 +++ apps/server/scripts/build-vercel.sh | 41 ++++ apps/server/scripts/bundle-api.mjs | 61 +++++ apps/server/server/index.ts | 73 ++++++ apps/server/tsconfig.json | 27 +++ apps/server/vercel.json | 31 +++ 13 files changed, 1058 insertions(+) create mode 100644 apps/server/.env.example create mode 100644 apps/server/.gitignore create mode 100644 apps/server/.vercelignore create mode 100644 apps/server/DEPLOYMENT.md create mode 100644 apps/server/README.md create mode 100644 apps/server/api/[[...route]].js create mode 100644 apps/server/objectstack.config.ts create mode 100644 apps/server/package.json create mode 100755 apps/server/scripts/build-vercel.sh create mode 100644 apps/server/scripts/bundle-api.mjs create mode 100644 apps/server/server/index.ts create mode 100644 apps/server/tsconfig.json create mode 100644 apps/server/vercel.json diff --git a/apps/server/.env.example b/apps/server/.env.example new file mode 100644 index 00000000..73c5534f --- /dev/null +++ b/apps/server/.env.example @@ -0,0 +1,16 @@ +# Environment Variables for ObjectUI Server + +# Authentication Secret (REQUIRED in production) +# Must be at least 32 characters +AUTH_SECRET=dev-secret-please-change-in-production-min-32-chars + +# Base URL for the application +# Leave empty to auto-detect from VERCEL_URL on Vercel +# Set explicitly for custom domains +# NEXT_PUBLIC_BASE_URL=https://your-domain.com + +# Runtime Mode (automatically set during build) +# VITE_RUNTIME_MODE=server + +# Server URL (automatically set during build) +# VITE_SERVER_URL= diff --git a/apps/server/.gitignore b/apps/server/.gitignore new file mode 100644 index 00000000..260d7048 --- /dev/null +++ b/apps/server/.gitignore @@ -0,0 +1,33 @@ +# Dependencies +node_modules/ +.pnpm-store/ + +# Build outputs +dist/ +api/_handler.js +api/_handler.js.map +public/ + +# Environment +.env +.env.local +.env.*.local + +# Logs +*.log +npm-debug.log* +pnpm-debug.log* + +# OS +.DS_Store +Thumbs.db + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Vercel +.vercel diff --git a/apps/server/.vercelignore b/apps/server/.vercelignore new file mode 100644 index 00000000..b0144f9a --- /dev/null +++ b/apps/server/.vercelignore @@ -0,0 +1,29 @@ +# Vercel build artifacts +node_modules/ +.pnpm-store/ +dist/ + +# Test files +*.test.ts +*.spec.ts +__tests__/ +test/ + +# Source files (only need compiled output) +*.ts +!api/**/*.js +!scripts/**/*.mjs + +# Config files +tsconfig.json +vitest.config.ts +postcss.config.js +tailwind.config.js + +# Documentation +*.md +!README.md + +# Git +.git/ +.gitignore diff --git a/apps/server/DEPLOYMENT.md b/apps/server/DEPLOYMENT.md new file mode 100644 index 00000000..3dd1f9f5 --- /dev/null +++ b/apps/server/DEPLOYMENT.md @@ -0,0 +1,349 @@ +# Deploying ObjectUI Server to Vercel + +This guide demonstrates how to deploy the ObjectUI production server to Vercel using Hono. + +## Prerequisites + +1. A Vercel account +2. Vercel CLI installed (optional): `npm i -g vercel` + +## Environment Variables + +Set the following environment variables in your Vercel project: + +### Required + +- **`AUTH_SECRET`**: A secure random string (minimum 32 characters) for authentication + - Generate with: `openssl rand -base64 32` + - Example: `AUTH_SECRET=abc123def456...` (min 32 chars) + +### Optional + +- **`NEXT_PUBLIC_BASE_URL`**: Your application's base URL (auto-detected from `VERCEL_URL` if not set) + - Example: `NEXT_PUBLIC_BASE_URL=https://objectui.example.com` + +## Deployment Steps + +### Option 1: Using Vercel Dashboard (Recommended) + +1. **Import Repository** + - Go to [vercel.com/new](https://vercel.com/new) + - Import your fork of `objectstack-ai/objectui` + +2. **Configure Project** + - Framework Preset: **Other** (vercel.json handles configuration) + - Root Directory: `apps/server` + - Build Command: (leave default - uses vercel.json) + - Output Directory: (leave default - uses vercel.json) + +3. **Set Environment Variables** + - Go to Project Settings → Environment Variables + - Add `AUTH_SECRET` with a secure 32+ character string + - Optionally add `NEXT_PUBLIC_BASE_URL` for custom domains + +4. **Deploy** + - Click "Deploy" + - Wait for build to complete (~3-5 minutes) + +### Option 2: Using Vercel CLI + +1. **Install Vercel CLI** + ```bash + npm i -g vercel + ``` + +2. **Navigate to Server Directory** + ```bash + cd apps/server + ``` + +3. **Login to Vercel** + ```bash + vercel login + ``` + +4. **Deploy** + ```bash + # Preview deployment + vercel + + # Production deployment + vercel --prod + ``` + +5. **Set Environment Variables** + ```bash + vercel env add AUTH_SECRET production + # Enter your secret when prompted (min 32 chars) + + # Optional: set base URL for custom domain + vercel env add NEXT_PUBLIC_BASE_URL production + ``` + +6. **Redeploy with Environment Variables** + ```bash + vercel --prod + ``` + +## Build Configuration + +The build is configured in `vercel.json`: + +- **Install Command**: `cd ../.. && pnpm install --frozen-lockfile` + - Installs monorepo dependencies from root +- **Build Command**: `bash scripts/build-vercel.sh` + - Builds Console in server mode + - Bundles API serverless function + - Copies Console assets to public/ +- **Framework**: `null` (custom serverless function) +- **Build Environment Variables**: + - `VITE_RUNTIME_MODE=server`: Console connects to API + - `VITE_SERVER_URL=""`: Same-origin API requests + - `VITE_USE_MOCK_SERVER=false`: Disable MSW + +## How It Works + +### 1. Build Process (`scripts/build-vercel.sh`) + +1. **Build Console**: + - Runs `pnpm --filter @object-ui/console run build` + - Console is built with `VITE_RUNTIME_MODE=server` (set in vercel.json) + - Produces static assets in `apps/console/dist/` + +2. **Bundle API**: + - Runs `node scripts/bundle-api.mjs` + - Uses esbuild to bundle `server/index.ts` → `api/_handler.js` + - All dependencies are inlined (self-contained bundle) + +3. **Copy Assets**: + - Copies `apps/console/dist/*` to `apps/server/public/` + - Console UI is served as static files + +### 2. API Handler (`api/[[...route]].js`) + +- Committed catch-all route handler +- Delegates to bundled handler (`api/_handler.js`) +- Vercel detects this file pre-build and creates a serverless function + +### 3. Server Entrypoint (`server/index.ts`) + +- Boots ObjectStack kernel with all plugins +- Creates Hono app using `@objectstack/hono` adapter +- Uses `@hono/node-server`'s `getRequestListener()` for Vercel compatibility +- Handles initialization once on cold start, reuses kernel for subsequent requests + +### 4. Console UI (Frontend SPA) + +- Built with Vite in server mode (not MSW mode) +- Served as static files from `public/` directory +- All API requests go to `/api/v1/*` endpoints +- SPA fallback via Vercel rewrite rules + +## Deployment Architecture + +``` +Vercel Deployment +├── Serverless Function (Node.js) +│ ├── api/[[...route]].js → api/_handler.js +│ ├── ObjectStack Kernel (runtime) +│ ├── Hono HTTP Server +│ └── API Routes (/api/v1/*) +│ +└── Static Files (CDN) + ├── public/index.html + ├── public/assets/* + └── SPA Routing (fallback to index.html) +``` + +### Request Flow + +1. **Browser → `/` or `/apps/*`** + - Vercel CDN serves static files + - SPA router handles client-side navigation + +2. **Browser → `/api/v1/*`** + - Routed to serverless function + - Kernel processes request via Hono + - Returns JSON response + +## Testing Locally + +Before deploying, test locally: + +```bash +# Install dependencies +pnpm install + +# Build the application +cd apps/server +bash scripts/build-vercel.sh + +# Start local server +pnpm dev + +# Test endpoints +curl http://localhost:3000/api/v1/discovery +curl http://localhost:3000/api/v1/meta/objects +``` + +## Accessing the Application + +After deployment, your application will be available at: + +- **Console UI**: `https://your-app.vercel.app/` +- **API Discovery**: `https://your-app.vercel.app/api/v1/discovery` +- **Metadata API**: `https://your-app.vercel.app/api/v1/meta/objects` +- **Data API**: `https://your-app.vercel.app/api/v1/data/:object` + +## Custom Domains + +### Add Custom Domain + +1. Go to Project Settings → Domains +2. Add your domain (e.g., `objectui.example.com`) +3. Configure DNS as instructed by Vercel +4. Update `NEXT_PUBLIC_BASE_URL` environment variable +5. Redeploy: `vercel --prod` + +## Troubleshooting + +### Build Fails + +**Symptoms**: Build fails with dependency errors + +**Solutions**: +- Ensure `pnpm-lock.yaml` is committed +- Check build logs for specific error messages +- Verify all workspace dependencies are available +- Try: `pnpm install --frozen-lockfile` locally first + +### Runtime Errors + +**Symptoms**: 500 errors, function timeouts + +**Solutions**: +- Check function logs in Vercel dashboard +- Verify `AUTH_SECRET` is set correctly +- Ensure `AUTH_SECRET` is at least 32 characters +- Check cold start time (increase `maxDuration` if needed) + +### Console Still in MSW Mode + +**Symptoms**: Console shows "Using Mock Service Worker" instead of connecting to API + +**Solutions**: +- Verify `vercel.json` includes `build.env` with `VITE_RUNTIME_MODE=server` +- Check build logs show "VITE_RUNTIME_MODE=server" during Console build +- Open browser DevTools Console and look for `[Console Config]` log +- Clear Vercel build cache: `vercel --force` + +### Authentication Issues + +**Symptoms**: Login fails, session not persisted + +**Solutions**: +- Verify `AUTH_SECRET` is set and is at least 32 characters +- Check `NEXT_PUBLIC_BASE_URL` matches your actual domain +- Ensure cookies are not blocked by browser +- Check if HTTPS is enabled (required for secure cookies) + +### API 404 Errors + +**Symptoms**: API requests return 404 + +**Solutions**: +- Verify `api/[[...route]].js` is committed +- Check `vercel.json` rewrites configuration +- Ensure serverless function deployed correctly +- Test API endpoint directly: `/api/v1/discovery` + +### Memory/Timeout Issues + +**Symptoms**: Function runs out of memory or times out + +**Solutions**: +- Increase `memory` in `vercel.json` (default: 1024MB) +- Increase `maxDuration` in `vercel.json` (default: 60s) +- Check for memory leaks in custom code +- Consider using a database instead of in-memory driver + +## Production Considerations + +### Database + +The server uses an in-memory database by default. For production: + +1. **Add a Database Driver**: + ```bash + pnpm add @objectstack/driver-turso + # or @objectstack/driver-postgres, etc. + ``` + +2. **Update `objectstack.config.ts`**: + ```typescript + import { TursoDriver } from '@objectstack/driver-turso'; + + const plugins = [ + // Replace InMemoryDriver + new DriverPlugin(new TursoDriver({ + url: process.env.TURSO_DATABASE_URL, + authToken: process.env.TURSO_AUTH_TOKEN, + }), 'turso'), + // ... rest + ]; + ``` + +3. **Set Environment Variables**: + ```bash + vercel env add TURSO_DATABASE_URL production + vercel env add TURSO_AUTH_TOKEN production + ``` + +### Monitoring + +- Enable Vercel Analytics for performance monitoring +- Set up log drains for centralized logging +- Monitor function execution time and memory usage +- Set up alerts for errors and timeouts + +### Security + +- **Always** use a strong `AUTH_SECRET` (32+ random characters) +- Enable HTTPS (automatic on Vercel) +- Set up rate limiting if needed +- Review and audit authentication logic +- Keep dependencies up to date + +## Advanced Configuration + +### Changing Serverless Function Settings + +Edit `vercel.json`: + +```json +{ + "functions": { + "api/**/*.js": { + "memory": 2048, // Increase memory + "maxDuration": 120, // Increase timeout + "runtime": "nodejs20.x" // Specify Node.js version + } + } +} +``` + +### Adding Environment-Specific Configs + +Use Vercel environment variables with different values for preview/production: + +```bash +vercel env add MY_CONFIG production +vercel env add MY_CONFIG preview +``` + +## References + +- [Vercel Hono Documentation](https://vercel.com/docs/frameworks/backend/hono) +- [ObjectUI Documentation](https://www.objectui.org) +- [ObjectStack Framework](https://github.com/objectstack-ai/framework) +- [Vercel Serverless Functions](https://vercel.com/docs/functions/serverless-functions) diff --git a/apps/server/README.md b/apps/server/README.md new file mode 100644 index 00000000..14fbb357 --- /dev/null +++ b/apps/server/README.md @@ -0,0 +1,197 @@ +# ObjectUI Production Server + +This is the production backend server for ObjectUI that serves the Console frontend and provides REST APIs for ObjectStack applications. + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/objectstack-ai/objectui/tree/main/apps/server&project-name=objectui-server&repository-name=objectui-server) + +## Features + +- **Dynamic Schema Loading**: Loads CRM, Todo, and Kitchen Sink apps as plugins +- **Unified Metadata API**: `/api/v1/meta/objects` +- **Unified Data API**: `/api/v1/data/:object` (CRUD operations) +- **Console UI**: Serves the ObjectUI Console frontend at `/` +- **Zero-Code Backend**: No need to create routes or controllers per object +- **Vercel Deployment**: Ready-to-deploy to Vercel with Hono adapter +- **In-Memory Database**: Uses ObjectStack's in-memory driver (configurable for production databases) + +## Architecture + +``` +apps/server/ +├── api/ +│ ├── [[...route]].js # Committed entry point for Vercel +│ └── _handler.js # Generated bundle (not committed) +├── server/ +│ └── index.ts # Server implementation +├── scripts/ +│ ├── build-vercel.sh # Vercel build script +│ └── bundle-api.mjs # API bundler configuration +├── objectstack.config.ts # Server configuration +├── package.json +├── vercel.json # Vercel deployment config +└── tsconfig.json +``` + +## Setup + +### Prerequisites + +- Node.js 18+ and pnpm 8+ +- All dependencies installed in the workspace root + +### Install & Run Locally + +1. Install dependencies from workspace root: + ```bash + corepack enable && pnpm install + ``` + +2. Run the development server: + ```bash + cd apps/server + pnpm dev + ``` + + Server starts at http://localhost:3000 + - Console UI: http://localhost:3000/ + - API Discovery: http://localhost:3000/api/v1/discovery + - Metadata API: http://localhost:3000/api/v1/meta/objects + +3. Build for production: + ```bash + pnpm build + ``` + +## Deployment + +See [DEPLOYMENT.md](./DEPLOYMENT.md) for detailed deployment instructions. + +### Quick Deploy to Vercel + +1. Click the "Deploy with Vercel" button above, or: + ```bash + npm i -g vercel + cd apps/server + vercel + ``` + +2. Set environment variables in Vercel dashboard: + - `AUTH_SECRET`: A secure random string (minimum 32 characters) + - Optional: `NEXT_PUBLIC_BASE_URL` for custom domains + +3. Deploy: + ```bash + vercel --prod + ``` + +## API Usage Examples + +### 1. Get All Objects +```bash +curl http://localhost:3000/api/v1/meta/objects +``` + +Returns JSON array of loaded object definitions from all apps. + +### 2. Create a Todo +```bash +curl -X POST http://localhost:3000/api/v1/data/todo_task \ + -H "Content-Type: application/json" \ + -d '{"title": "Buy Milk", "priority": "high"}' +``` + +### 3. List Todos +```bash +curl http://localhost:3000/api/v1/data/todo_task +``` + +### 4. Get Object Metadata +```bash +curl http://localhost:3000/api/v1/meta/objects/todo_task +``` + +## Configuration + +### Environment Variables + +Create a `.env` file (see `.env.example`): + +```bash +# Required in production +AUTH_SECRET=your-secret-key-min-32-characters + +# Optional - auto-detected on Vercel +NEXT_PUBLIC_BASE_URL=https://your-domain.com +``` + +### Adding More Apps + +Edit `objectstack.config.ts` and add more AppPlugin instances: + +```typescript +import myAppConfig from '@my-org/my-app/objectstack.config'; + +const plugins = [ + // ... existing plugins + new AppPlugin(prepareConfig(resolveDefault(myAppConfig))), +]; +``` + +## How It Works + +### Build Process + +1. **Console Build**: Console is built with `VITE_RUNTIME_MODE=server` (connects to API instead of MSW) +2. **API Bundle**: `server/index.ts` is bundled into `api/_handler.js` with all dependencies inlined +3. **Static Assets**: Console dist files are copied to `public/` directory + +### Runtime + +1. **Serverless Function**: Vercel calls `api/[[...route]].js` which delegates to `api/_handler.js` +2. **Kernel Boot**: ObjectStack kernel boots with all plugins on cold start +3. **Hono App**: Creates HTTP app using `@objectstack/hono` adapter +4. **Request Handling**: All `/api/*` requests go to serverless function, others serve static files + +### Plugin Loading Order + +Order is critical for proper initialization: + +1. **MemoryI18nPlugin**: Registers i18n service before AppPlugin needs it +2. **ObjectQLPlugin**: Provides ObjectQL query engine +3. **DriverPlugin**: Registers in-memory database driver +4. **AppPlugins**: Load example apps (CRM, Todo, Kitchen Sink) +5. **SetupPlugin**: Must load before AuthPlugin (provides setupNav service) +6. **AuthPlugin**: Handles authentication (uses setupNav service) +7. **ConsolePlugin**: Serves the frontend UI + +## Troubleshooting + +### Build Fails + +- Ensure all dependencies are installed: `pnpm install` from workspace root +- Check build logs in Vercel dashboard +- Verify `build-vercel.sh` is executable + +### Runtime Errors + +- Check function logs in Vercel dashboard +- Verify `AUTH_SECRET` is set and is at least 32 characters +- Test locally with `pnpm dev` first + +### Console Shows MSW Mode + +If the Console loads in Mock Service Worker mode instead of connecting to the API: + +- Verify `vercel.json` includes `VITE_RUNTIME_MODE=server` in `build.env` +- Clear Vercel build cache: `vercel --force` +- Check browser DevTools Console for `[Console Config]` log + +## License + +MIT + +## Links + +- [ObjectUI Documentation](https://www.objectui.org) +- [ObjectStack Framework](https://github.com/objectstack-ai/framework) +- [Deployment Guide](./DEPLOYMENT.md) diff --git a/apps/server/api/[[...route]].js b/apps/server/api/[[...route]].js new file mode 100644 index 00000000..f83b5c06 --- /dev/null +++ b/apps/server/api/[[...route]].js @@ -0,0 +1,11 @@ +/** + * Vercel Serverless Function Wrapper + * + * This file is committed to the repo and detected by Vercel pre-build. + * It delegates to the bundled handler (_handler.js) generated during the build. + * + * The catch-all route [[...route]] captures all API requests and forwards them + * to the ObjectStack kernel via Hono. + */ + +export { default } from './_handler.js'; diff --git a/apps/server/objectstack.config.ts b/apps/server/objectstack.config.ts new file mode 100644 index 00000000..769c7ff3 --- /dev/null +++ b/apps/server/objectstack.config.ts @@ -0,0 +1,152 @@ +// Copyright (c) 2025 ObjectUI. Licensed under the MIT license. + +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); +// @ts-ignore +globalThis.require = require; + +import { defineStack } from '@objectstack/spec'; +import { AppPlugin, DriverPlugin } from '@objectstack/runtime'; +import { ObjectQLPlugin } from '@objectstack/objectql'; +import { InMemoryDriver } from '@objectstack/driver-memory'; +import { AuthPlugin } from '@objectstack/plugin-auth'; +import { SetupPlugin } from '@objectstack/plugin-setup'; +import { ConsolePlugin } from '@object-ui/console'; +// @ts-ignore +import * as CorePkg from '@objectstack/core'; + +const createMemoryI18n = CorePkg.createMemoryI18n || (CorePkg as any).default?.createMemoryI18n; + +// Import example apps +// @ts-ignore +import crmConfigImport from '@object-ui/example-crm/objectstack.config'; +// @ts-ignore +import todoConfigImport from '@object-ui/example-todo/objectstack.config'; +// @ts-ignore +import kitchenSinkConfigImport from '@object-ui/example-kitchen-sink/objectstack.config'; + +/** Resolve ESM default-export interop */ +type MaybeDefault = T | { default: T }; +function resolveDefault(mod: MaybeDefault): T { + if (mod && typeof mod === 'object' && 'default' in mod) { + return (mod as { default: T }).default; + } + return mod as T; +} + +/** + * Adapter: prepare a stack config for AppPlugin. + * - Merges stack-level views into object definitions + * - Converts i18n translations to the spec format AppPlugin expects + */ +function prepareConfig(config: any) { + const result = { ...config }; + if (result.i18n?.namespace && result.i18n?.translations) { + const ns = result.i18n.namespace; + const converted: Record = {}; + for (const [locale, data] of Object.entries(result.i18n.translations)) { + converted[locale] = { [ns]: data }; + } + result.translations = [converted]; + } + return result; +} + +const crmConfig = prepareConfig(resolveDefault(crmConfigImport)); +const todoConfig = prepareConfig(resolveDefault(todoConfigImport)); +const kitchenSinkConfig = prepareConfig(resolveDefault(kitchenSinkConfigImport)); + +const appConfigs = [crmConfig, todoConfig, kitchenSinkConfig]; + +/** + * Lightweight plugin that registers the in-memory i18n service during the + * init phase. This is critical for server mode because: + * + * 1. AppPlugin.start() → loadTranslations() needs an i18n service. + * 2. The kernel's own memory i18n fallback is auto-registered in + * validateSystemRequirements() — which runs AFTER all plugin starts. + * 3. Without an early-registered i18n service, loadTranslations() finds + * nothing and silently skips — translations never get loaded. + */ +class MemoryI18nPlugin { + readonly name = 'com.objectstack.service.i18n'; + readonly version = '1.0.0'; + readonly type = 'service' as const; + + init(ctx: any) { + const svc = createMemoryI18n(); + ctx.registerService('i18n', svc); + } +} + +/** + * Shared authentication plugin — reads secrets from environment variables + * so the same config works both locally and on Vercel (where VERCEL_URL is injected). + */ +const authPlugin = new AuthPlugin({ + secret: process.env.AUTH_SECRET ?? 'dev-secret-please-change-in-production-min-32-chars', + baseUrl: process.env.NEXT_PUBLIC_BASE_URL ?? (process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}` + : 'http://localhost:3000'), +}); + +/** + * Plugin ordering matters: + * + * - MemoryI18nPlugin MUST come before AppPlugin so that the i18n service + * exists when AppPlugin.start() → loadTranslations() runs. + * - SetupPlugin MUST load before AuthPlugin so that the setupNav service + * is registered and available when AuthPlugin.init() tries to contribute menu items. + */ +const plugins: any[] = [ + new MemoryI18nPlugin(), + new ObjectQLPlugin(), + new DriverPlugin(new InMemoryDriver(), 'memory'), + // Each example app loaded as an independent AppPlugin + ...appConfigs.map((config: any) => new AppPlugin(config)), + // SetupPlugin must come before AuthPlugin (setupNav service dependency) + new SetupPlugin(), + // AuthPlugin contributes to setupNav during init, so it must come AFTER SetupPlugin + authPlugin, + // Console UI plugin - serves the frontend SPA + new ConsolePlugin(), +]; + +export default defineStack({ + manifest: { + id: 'com.objectui.server', + namespace: 'server', + name: 'ObjectUI Server', + version: '3.3.0', + description: 'Production server with Console UI and example apps (CRM, Todo, Kitchen Sink)', + type: 'app', + }, + + // Explicitly Load Plugins and Apps + plugins, + + build: { + outDir: './dist', + sourcemap: true, + minify: true, + target: 'node18', + }, + + datasources: { + default: { + driver: 'memory', + }, + }, + + dev: { + port: 3000, + host: '0.0.0.0', + watch: true, + hotReload: true, + }, + + deploy: { + target: 'serverless', + region: 'us-east-1', + }, +}); diff --git a/apps/server/package.json b/apps/server/package.json new file mode 100644 index 00000000..01f44ceb --- /dev/null +++ b/apps/server/package.json @@ -0,0 +1,38 @@ +{ + "name": "@object-ui/server", + "version": "3.3.0", + "license": "MIT", + "type": "module", + "private": true, + "description": "ObjectUI Production Server - Backend API server for ObjectStack applications", + "scripts": { + "dev": "objectstack serve --dev", + "start": "objectstack serve", + "build": "objectstack compile", + "typecheck": "tsc --noEmit", + "clean": "rm -rf dist node_modules api/_handler.js public" + }, + "dependencies": { + "@hono/node-server": "^1.19.14", + "@object-ui/console": "workspace:*", + "@object-ui/example-crm": "workspace:*", + "@object-ui/example-kitchen-sink": "workspace:*", + "@object-ui/example-todo": "workspace:*", + "@objectstack/cli": "^4.0.3", + "@objectstack/core": "^4.0.3", + "@objectstack/driver-memory": "^4.0.3", + "@objectstack/hono": "^4.0.3", + "@objectstack/objectql": "^4.0.3", + "@objectstack/plugin-auth": "^4.0.3", + "@objectstack/plugin-hono-server": "^4.0.3", + "@objectstack/plugin-setup": "^4.0.3", + "@objectstack/runtime": "^4.0.3", + "@objectstack/spec": "^4.0.3", + "hono": "^4.12.12" + }, + "devDependencies": { + "esbuild": "^0.24.2", + "tsx": "^4.21.0", + "typescript": "^6.0.2" + } +} diff --git a/apps/server/scripts/build-vercel.sh b/apps/server/scripts/build-vercel.sh new file mode 100755 index 00000000..60f3beee --- /dev/null +++ b/apps/server/scripts/build-vercel.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Build script for Vercel deployment of @object-ui/server. +# +# Follows the Vercel deployment pattern: +# - api/[[...route]].js is committed to the repo (Vercel detects it pre-build) +# - esbuild bundles server/index.ts → api/_handler.js (self-contained bundle) +# - The committed .js wrapper re-exports from _handler.js at runtime +# - Console SPA is built and copied to public/ for serving the UI +# +# Steps: +# 1. Build the project with pnpm (includes console) +# 2. Bundle the API serverless function (→ api/_handler.js) +# 3. Copy console dist files to public/ for UI serving + +echo "[build-vercel] Starting server build..." + +# 1. Build the project with pnpm (from monorepo root) +# This builds both server and console +cd ../.. +echo "[build-vercel] Building console with server mode..." +pnpm --filter @object-ui/console run build +cd apps/server + +# 2. Bundle API serverless function +echo "[build-vercel] Bundling API serverless function..." +node scripts/bundle-api.mjs + +# 3. Copy console dist files to public/ for UI serving +echo "[build-vercel] Copying console dist to public/..." +rm -rf public +mkdir -p public +if [ -d "../console/dist" ]; then + cp -r ../console/dist/* public/ + echo "[build-vercel] ✓ Copied console dist to public/" +else + echo "[build-vercel] ⚠ Console dist not found (skipped)" +fi + +echo "[build-vercel] Done. Static files in public/, serverless function in api/[[...route]].js → api/_handler.js" diff --git a/apps/server/scripts/bundle-api.mjs b/apps/server/scripts/bundle-api.mjs new file mode 100644 index 00000000..90d67c1d --- /dev/null +++ b/apps/server/scripts/bundle-api.mjs @@ -0,0 +1,61 @@ +/** + * Pre-bundles the Vercel serverless API function. + * + * Vercel's @vercel/node builder resolves pnpm workspace packages via symlinks, + * which can cause esbuild to resolve to TypeScript source files rather than + * compiled dist output — producing ERR_MODULE_NOT_FOUND at runtime. + * + * This script bundles server/index.ts with ALL dependencies inlined (including + * npm packages), so the deployed function is self-contained. Only packages + * with native bindings are kept external. + * + * Run from the apps/server directory during the Vercel build step. + */ + +import { build } from 'esbuild'; + +// Packages that cannot be bundled (native bindings / optional drivers) +const EXTERNAL = [ + // Optional knex database drivers — never used at runtime, but knex requires() them + 'pg', + 'pg-native', + 'pg-query-stream', + 'mysql', + 'mysql2', + 'sqlite3', + 'oracledb', + 'tedious', + // macOS-only native file watcher + 'fsevents', +]; + +await build({ + entryPoints: ['server/index.ts'], + bundle: true, + platform: 'node', + format: 'esm', + target: 'es2020', + outfile: 'api/_handler.js', + sourcemap: true, + external: EXTERNAL, + // Silence warnings about optional/unused require() calls in knex drivers + logOverride: { 'require-resolve-not-external': 'silent' }, + // Vercel resolves ESM .js files correctly when "type": "module" is set. + // CJS format would conflict with the project's "type": "module" setting, + // causing Node.js to fail parsing require()/module.exports as ESM syntax. + // + // The createRequire banner provides a real `require` function in the ESM + // scope. esbuild's __require shim (generated for CJS→ESM conversion) + // checks `typeof require !== "undefined"` and uses it when available, + // which fixes "Dynamic require of is not supported" errors + // from CJS dependencies like knex/tarn that require() Node.js built-ins. + banner: { + js: [ + '// Bundled by esbuild — see scripts/bundle-api.mjs', + 'import { createRequire } from "module";', + 'const require = createRequire(import.meta.url);', + ].join('\n'), + }, +}); + +console.log('[bundle-api] Bundled server/index.ts → api/_handler.js'); diff --git a/apps/server/server/index.ts b/apps/server/server/index.ts new file mode 100644 index 00000000..9ec03efb --- /dev/null +++ b/apps/server/server/index.ts @@ -0,0 +1,73 @@ +// Copyright (c) 2025 ObjectUI. Licensed under the MIT license. + +/** + * Vercel Serverless Function Entrypoint + * + * Boots the ObjectStack kernel with Hono adapter and exports a Vercel-compatible + * handler using @hono/node-server's getRequestListener(). + * + * This file is bundled by scripts/bundle-api.mjs during the Vercel build step + * and becomes the self-contained API handler at api/_handler.js. + */ + +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); +// @ts-ignore +globalThis.require = require; + +import { Kernel } from '@objectstack/runtime'; +import { createHonoApp } from '@objectstack/hono'; +import { getRequestListener } from '@hono/node-server'; +import config from '../objectstack.config'; + +let kernel: Kernel | null = null; +let app: any = null; + +/** + * Initialize the kernel and Hono app (happens once on cold start) + */ +async function initializeApp() { + if (app) return app; + + console.log('[server] Initializing ObjectStack kernel...'); + + // Boot the kernel with all plugins + kernel = new Kernel(); + await kernel.boot(config); + + console.log('[server] Creating Hono app...'); + + // Create Hono app from kernel + app = createHonoApp(kernel); + + console.log('[server] Server initialized successfully'); + + return app; +} + +/** + * Vercel serverless function handler + * + * Vercel calls this function for each request. We initialize once on cold start + * and reuse the kernel/app for subsequent requests in the same container. + */ +export default async function handler(req: any, res: any) { + try { + // Initialize on first request (cold start) + const honoApp = await initializeApp(); + + // Convert Vercel request to Node.js request listener format + const requestListener = getRequestListener(honoApp.fetch); + + // Handle the request + return requestListener(req, res); + } catch (error) { + console.error('[server] Fatal error:', error); + res.statusCode = 500; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ + error: 'Internal Server Error', + message: error instanceof Error ? error.message : 'Unknown error' + })); + } +} diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json new file mode 100644 index 00000000..9089303a --- /dev/null +++ b/apps/server/tsconfig.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": ".", + "module": "ESNext", + "target": "ES2020", + "lib": ["ES2020"], + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "isolatedModules": true + }, + "include": [ + "server/**/*", + "objectstack.config.ts", + "scripts/**/*" + ], + "exclude": [ + "node_modules", + "dist", + "api/_handler.js" + ] +} diff --git a/apps/server/vercel.json b/apps/server/vercel.json new file mode 100644 index 00000000..322a4c83 --- /dev/null +++ b/apps/server/vercel.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "framework": null, + "installCommand": "cd ../.. && pnpm install --frozen-lockfile", + "buildCommand": "bash scripts/build-vercel.sh", + "build": { + "env": { + "VITE_RUNTIME_MODE": "server", + "VITE_SERVER_URL": "", + "VITE_USE_MOCK_SERVER": "false" + } + }, + "functions": { + "api/**/*.js": { + "memory": 1024, + "maxDuration": 60 + } + }, + "headers": [ + { + "source": "/assets/(.*)", + "headers": [ + { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" } + ] + } + ], + "rewrites": [ + { "source": "/api/:path*", "destination": "/api/[[...route]]" }, + { "source": "/((?!api/).*)", "destination": "/index.html" } + ] +} From 294093306979a2e035101841c91451a15afd5053 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:53:01 +0000 Subject: [PATCH 2/3] fix: update tsconfig and fix type errors in server - Add @types/node to tsconfig types - Remove rootDir to allow importing from parent dirs - Fix datasources config format (add required config field) - Add @ts-ignore for missing type exports in runtime packages Agent-Logs-Url: https://github.com/objectstack-ai/objectui/sessions/1401bb2d-d094-4280-a66d-bee5388fc83a Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> --- apps/server/objectstack.config.ts | 1 + apps/server/server/index.ts | 5 +- apps/server/tsconfig.json | 2 +- pnpm-lock.yaml | 448 +++++++++++++++++------------- 4 files changed, 259 insertions(+), 197 deletions(-) diff --git a/apps/server/objectstack.config.ts b/apps/server/objectstack.config.ts index 769c7ff3..6ec5a8a7 100644 --- a/apps/server/objectstack.config.ts +++ b/apps/server/objectstack.config.ts @@ -135,6 +135,7 @@ export default defineStack({ datasources: { default: { driver: 'memory', + config: {}, }, }, diff --git a/apps/server/server/index.ts b/apps/server/server/index.ts index 9ec03efb..426f8b5f 100644 --- a/apps/server/server/index.ts +++ b/apps/server/server/index.ts @@ -15,12 +15,15 @@ const require = createRequire(import.meta.url); // @ts-ignore globalThis.require = require; +// @ts-ignore import { Kernel } from '@objectstack/runtime'; +// @ts-ignore import { createHonoApp } from '@objectstack/hono'; import { getRequestListener } from '@hono/node-server'; +// @ts-ignore import config from '../objectstack.config'; -let kernel: Kernel | null = null; +let kernel: any = null; let app: any = null; /** diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json index 9089303a..30fdbf39 100644 --- a/apps/server/tsconfig.json +++ b/apps/server/tsconfig.json @@ -2,10 +2,10 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "./dist", - "rootDir": ".", "module": "ESNext", "target": "ES2020", "lib": ["ES2020"], + "types": ["node"], "moduleResolution": "bundler", "jsx": "react-jsx", "strict": true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce1e0c1b..b5998c43 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -409,6 +409,67 @@ importers: specifier: ^4.1.4 version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + apps/server: + dependencies: + '@hono/node-server': + specifier: ^1.19.14 + version: 1.19.14(hono@4.12.12) + '@object-ui/console': + specifier: workspace:* + version: link:../console + '@object-ui/example-crm': + specifier: workspace:* + version: link:../../examples/crm + '@object-ui/example-kitchen-sink': + specifier: workspace:* + version: link:../../examples/kitchen-sink + '@object-ui/example-todo': + specifier: workspace:* + version: link:../../examples/todo + '@objectstack/cli': + specifier: ^4.0.3 + version: 4.0.3(@ai-sdk/anthropic@3.0.69(zod@4.3.6))(@ai-sdk/google@3.0.63(zod@4.3.6))(@ai-sdk/openai@3.0.52(zod@4.3.6))(@objectstack/core@4.0.3(pino@8.21.0))(esbuild@0.24.2)(pino@8.21.0) + '@objectstack/core': + specifier: ^4.0.3 + version: 4.0.3(pino@8.21.0) + '@objectstack/driver-memory': + specifier: ^4.0.3 + version: 4.0.3(pino@8.21.0) + '@objectstack/hono': + specifier: ^4.0.3 + version: 4.0.3(@objectstack/runtime@4.0.3(pino@8.21.0))(hono@4.12.12) + '@objectstack/objectql': + specifier: ^4.0.3 + version: 4.0.3(pino@8.21.0) + '@objectstack/plugin-auth': + specifier: ^4.0.3 + version: 4.0.3(@opentelemetry/api@1.9.0)(better-sqlite3@12.9.0)(next@16.2.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pino@8.21.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.4) + '@objectstack/plugin-hono-server': + specifier: ^4.0.3 + version: 4.0.3(pino@8.21.0) + '@objectstack/plugin-setup': + specifier: ^4.0.3 + version: 4.0.3(pino@8.21.0) + '@objectstack/runtime': + specifier: ^4.0.3 + version: 4.0.3(pino@8.21.0) + '@objectstack/spec': + specifier: ^4.0.3 + version: 4.0.3 + hono: + specifier: ^4.12.12 + version: 4.12.12 + devDependencies: + esbuild: + specifier: ^0.24.2 + version: 0.24.2 + tsx: + specifier: ^4.21.0 + version: 4.21.0 + typescript: + specifier: ^6.0.2 + version: 6.0.2 + apps/site: dependencies: '@monaco-editor/react': @@ -817,7 +878,7 @@ importers: version: 9.0.0 '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 6.0.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) chalk: specifier: ^5.6.2 version: 5.6.2 @@ -838,7 +899,7 @@ importers: version: 4.1.1 vite: specifier: ^8.0.8 - version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + version: 8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) devDependencies: '@types/express': specifier: ^4.17.25 @@ -857,7 +918,7 @@ importers: version: 6.0.2 vitest: specifier: ^4.1.4 - version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/collaboration: dependencies: @@ -1045,7 +1106,7 @@ importers: version: 8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.6.18(prettier@3.8.2))(typescript@6.0.2) '@storybook/react-vite': specifier: ^8.6.18 - version: 8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(rollup@4.60.1)(storybook@8.6.18(prettier@3.8.2))(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(rollup@4.60.1)(storybook@8.6.18(prettier@3.8.2))(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 @@ -1057,7 +1118,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 6.0.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) autoprefixer: specifier: ^10.5.0 version: 10.5.0(postcss@8.5.9) @@ -1078,10 +1139,10 @@ importers: version: 6.0.2 vite: specifier: ^8.0.8 - version: 8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + version: 8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) vite-plugin-dts: specifier: ^4.5.4 - version: 4.5.4(@types/node@25.6.0)(rollup@4.60.1)(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.5.4(@types/node@25.6.0)(rollup@4.60.1)(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/core: dependencies: @@ -1137,7 +1198,7 @@ importers: version: 6.0.2 vitest: specifier: ^4.1.4 - version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/data-objectstack: dependencies: @@ -3111,8 +3172,8 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + '@esbuild/aix-ppc64@0.24.2': + resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -3129,8 +3190,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + '@esbuild/android-arm64@0.24.2': + resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -3147,8 +3208,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + '@esbuild/android-arm@0.24.2': + resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -3165,8 +3226,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + '@esbuild/android-x64@0.24.2': + resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -3183,8 +3244,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + '@esbuild/darwin-arm64@0.24.2': + resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -3201,8 +3262,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + '@esbuild/darwin-x64@0.24.2': + resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -3219,8 +3280,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + '@esbuild/freebsd-arm64@0.24.2': + resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -3237,8 +3298,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + '@esbuild/freebsd-x64@0.24.2': + resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -3255,8 +3316,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + '@esbuild/linux-arm64@0.24.2': + resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -3273,8 +3334,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + '@esbuild/linux-arm@0.24.2': + resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -3291,8 +3352,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + '@esbuild/linux-ia32@0.24.2': + resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -3309,8 +3370,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + '@esbuild/linux-loong64@0.24.2': + resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -3327,8 +3388,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + '@esbuild/linux-mips64el@0.24.2': + resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -3345,8 +3406,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + '@esbuild/linux-ppc64@0.24.2': + resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -3363,8 +3424,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + '@esbuild/linux-riscv64@0.24.2': + resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -3381,8 +3442,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + '@esbuild/linux-s390x@0.24.2': + resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -3399,8 +3460,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + '@esbuild/linux-x64@0.24.2': + resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -3417,8 +3478,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + '@esbuild/netbsd-arm64@0.24.2': + resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -3435,8 +3496,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + '@esbuild/netbsd-x64@0.24.2': + resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -3453,8 +3514,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + '@esbuild/openbsd-arm64@0.24.2': + resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -3471,8 +3532,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + '@esbuild/openbsd-x64@0.24.2': + resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -3489,12 +3550,6 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.27.7': resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} @@ -3507,8 +3562,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + '@esbuild/sunos-x64@0.24.2': + resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -3525,8 +3580,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + '@esbuild/win32-arm64@0.24.2': + resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -3543,8 +3598,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + '@esbuild/win32-ia32@0.24.2': + resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -3561,8 +3616,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + '@esbuild/win32-x64@0.24.2': + resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -7768,8 +7823,8 @@ packages: peerDependencies: esbuild: '>=0.12 <1' - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + esbuild@0.24.2: + resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} engines: {node: '>=18'} hasBin: true @@ -12756,7 +12811,7 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.12': + '@esbuild/aix-ppc64@0.24.2': optional: true '@esbuild/aix-ppc64@0.27.7': @@ -12765,7 +12820,7 @@ snapshots: '@esbuild/aix-ppc64@0.28.0': optional: true - '@esbuild/android-arm64@0.25.12': + '@esbuild/android-arm64@0.24.2': optional: true '@esbuild/android-arm64@0.27.7': @@ -12774,7 +12829,7 @@ snapshots: '@esbuild/android-arm64@0.28.0': optional: true - '@esbuild/android-arm@0.25.12': + '@esbuild/android-arm@0.24.2': optional: true '@esbuild/android-arm@0.27.7': @@ -12783,7 +12838,7 @@ snapshots: '@esbuild/android-arm@0.28.0': optional: true - '@esbuild/android-x64@0.25.12': + '@esbuild/android-x64@0.24.2': optional: true '@esbuild/android-x64@0.27.7': @@ -12792,7 +12847,7 @@ snapshots: '@esbuild/android-x64@0.28.0': optional: true - '@esbuild/darwin-arm64@0.25.12': + '@esbuild/darwin-arm64@0.24.2': optional: true '@esbuild/darwin-arm64@0.27.7': @@ -12801,7 +12856,7 @@ snapshots: '@esbuild/darwin-arm64@0.28.0': optional: true - '@esbuild/darwin-x64@0.25.12': + '@esbuild/darwin-x64@0.24.2': optional: true '@esbuild/darwin-x64@0.27.7': @@ -12810,7 +12865,7 @@ snapshots: '@esbuild/darwin-x64@0.28.0': optional: true - '@esbuild/freebsd-arm64@0.25.12': + '@esbuild/freebsd-arm64@0.24.2': optional: true '@esbuild/freebsd-arm64@0.27.7': @@ -12819,7 +12874,7 @@ snapshots: '@esbuild/freebsd-arm64@0.28.0': optional: true - '@esbuild/freebsd-x64@0.25.12': + '@esbuild/freebsd-x64@0.24.2': optional: true '@esbuild/freebsd-x64@0.27.7': @@ -12828,7 +12883,7 @@ snapshots: '@esbuild/freebsd-x64@0.28.0': optional: true - '@esbuild/linux-arm64@0.25.12': + '@esbuild/linux-arm64@0.24.2': optional: true '@esbuild/linux-arm64@0.27.7': @@ -12837,7 +12892,7 @@ snapshots: '@esbuild/linux-arm64@0.28.0': optional: true - '@esbuild/linux-arm@0.25.12': + '@esbuild/linux-arm@0.24.2': optional: true '@esbuild/linux-arm@0.27.7': @@ -12846,7 +12901,7 @@ snapshots: '@esbuild/linux-arm@0.28.0': optional: true - '@esbuild/linux-ia32@0.25.12': + '@esbuild/linux-ia32@0.24.2': optional: true '@esbuild/linux-ia32@0.27.7': @@ -12855,7 +12910,7 @@ snapshots: '@esbuild/linux-ia32@0.28.0': optional: true - '@esbuild/linux-loong64@0.25.12': + '@esbuild/linux-loong64@0.24.2': optional: true '@esbuild/linux-loong64@0.27.7': @@ -12864,7 +12919,7 @@ snapshots: '@esbuild/linux-loong64@0.28.0': optional: true - '@esbuild/linux-mips64el@0.25.12': + '@esbuild/linux-mips64el@0.24.2': optional: true '@esbuild/linux-mips64el@0.27.7': @@ -12873,7 +12928,7 @@ snapshots: '@esbuild/linux-mips64el@0.28.0': optional: true - '@esbuild/linux-ppc64@0.25.12': + '@esbuild/linux-ppc64@0.24.2': optional: true '@esbuild/linux-ppc64@0.27.7': @@ -12882,7 +12937,7 @@ snapshots: '@esbuild/linux-ppc64@0.28.0': optional: true - '@esbuild/linux-riscv64@0.25.12': + '@esbuild/linux-riscv64@0.24.2': optional: true '@esbuild/linux-riscv64@0.27.7': @@ -12891,7 +12946,7 @@ snapshots: '@esbuild/linux-riscv64@0.28.0': optional: true - '@esbuild/linux-s390x@0.25.12': + '@esbuild/linux-s390x@0.24.2': optional: true '@esbuild/linux-s390x@0.27.7': @@ -12900,7 +12955,7 @@ snapshots: '@esbuild/linux-s390x@0.28.0': optional: true - '@esbuild/linux-x64@0.25.12': + '@esbuild/linux-x64@0.24.2': optional: true '@esbuild/linux-x64@0.27.7': @@ -12909,7 +12964,7 @@ snapshots: '@esbuild/linux-x64@0.28.0': optional: true - '@esbuild/netbsd-arm64@0.25.12': + '@esbuild/netbsd-arm64@0.24.2': optional: true '@esbuild/netbsd-arm64@0.27.7': @@ -12918,7 +12973,7 @@ snapshots: '@esbuild/netbsd-arm64@0.28.0': optional: true - '@esbuild/netbsd-x64@0.25.12': + '@esbuild/netbsd-x64@0.24.2': optional: true '@esbuild/netbsd-x64@0.27.7': @@ -12927,7 +12982,7 @@ snapshots: '@esbuild/netbsd-x64@0.28.0': optional: true - '@esbuild/openbsd-arm64@0.25.12': + '@esbuild/openbsd-arm64@0.24.2': optional: true '@esbuild/openbsd-arm64@0.27.7': @@ -12936,7 +12991,7 @@ snapshots: '@esbuild/openbsd-arm64@0.28.0': optional: true - '@esbuild/openbsd-x64@0.25.12': + '@esbuild/openbsd-x64@0.24.2': optional: true '@esbuild/openbsd-x64@0.27.7': @@ -12945,16 +13000,13 @@ snapshots: '@esbuild/openbsd-x64@0.28.0': optional: true - '@esbuild/openharmony-arm64@0.25.12': - optional: true - '@esbuild/openharmony-arm64@0.27.7': optional: true '@esbuild/openharmony-arm64@0.28.0': optional: true - '@esbuild/sunos-x64@0.25.12': + '@esbuild/sunos-x64@0.24.2': optional: true '@esbuild/sunos-x64@0.27.7': @@ -12963,7 +13015,7 @@ snapshots: '@esbuild/sunos-x64@0.28.0': optional: true - '@esbuild/win32-arm64@0.25.12': + '@esbuild/win32-arm64@0.24.2': optional: true '@esbuild/win32-arm64@0.27.7': @@ -12972,7 +13024,7 @@ snapshots: '@esbuild/win32-arm64@0.28.0': optional: true - '@esbuild/win32-ia32@0.25.12': + '@esbuild/win32-ia32@0.24.2': optional: true '@esbuild/win32-ia32@0.27.7': @@ -12981,7 +13033,7 @@ snapshots: '@esbuild/win32-ia32@0.28.0': optional: true - '@esbuild/win32-x64@0.25.12': + '@esbuild/win32-x64@0.24.2': optional: true '@esbuild/win32-x64@0.27.7': @@ -13441,15 +13493,6 @@ snapshots: '@types/yargs': 17.0.35 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - glob: 10.5.0 - magic-string: 0.27.0 - react-docgen-typescript: 2.4.0(typescript@6.0.2) - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) - optionalDependencies: - typescript: 6.0.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: glob: 10.5.0 @@ -13826,6 +13869,33 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@objectstack/cli@4.0.3(@ai-sdk/anthropic@3.0.69(zod@4.3.6))(@ai-sdk/google@3.0.63(zod@4.3.6))(@ai-sdk/openai@3.0.52(zod@4.3.6))(@objectstack/core@4.0.3(pino@8.21.0))(esbuild@0.24.2)(pino@8.21.0)': + dependencies: + '@ai-sdk/gateway': 3.0.96(zod@4.3.6) + '@objectstack/client': 4.0.3(pino@8.21.0) + '@objectstack/core': 4.0.3(pino@8.21.0) + '@objectstack/driver-memory': 4.0.3(pino@8.21.0) + '@objectstack/objectql': 4.0.3(pino@8.21.0) + '@objectstack/plugin-hono-server': 4.0.3(pino@8.21.0) + '@objectstack/plugin-setup': 4.0.3(pino@8.21.0) + '@objectstack/rest': 4.0.3(pino@8.21.0) + '@objectstack/runtime': 4.0.3(pino@8.21.0) + '@objectstack/service-ai': 4.0.3(@ai-sdk/anthropic@3.0.69(zod@4.3.6))(@ai-sdk/gateway@3.0.96(zod@4.3.6))(@ai-sdk/google@3.0.63(zod@4.3.6))(@ai-sdk/openai@3.0.52(zod@4.3.6))(pino@8.21.0)(zod@4.3.6) + '@objectstack/spec': 4.0.3 + '@oclif/core': 4.10.5 + bundle-require: 5.1.0(esbuild@0.24.2) + chalk: 5.6.2 + dotenv-flow: 4.1.0 + tsx: 4.21.0 + yaml: 2.8.3 + zod: 4.3.6 + transitivePeerDependencies: + - '@ai-sdk/anthropic' + - '@ai-sdk/google' + - '@ai-sdk/openai' + - esbuild + - pino + '@objectstack/cli@4.0.3(@ai-sdk/anthropic@3.0.69(zod@4.3.6))(@ai-sdk/google@3.0.63(zod@4.3.6))(@ai-sdk/openai@3.0.52(zod@4.3.6))(@objectstack/core@4.0.3(pino@8.21.0))(esbuild@0.28.0)(pino@8.21.0)': dependencies: '@ai-sdk/gateway': 3.0.96(zod@4.3.6) @@ -15412,14 +15482,6 @@ snapshots: react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - '@storybook/builder-vite@8.6.18(storybook@8.6.18(prettier@3.8.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - '@storybook/csf-plugin': 8.6.18(storybook@8.6.18(prettier@3.8.2)) - browser-assert: 1.2.1 - storybook: 8.6.18(prettier@3.8.2) - ts-dedent: 2.2.0 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) - '@storybook/builder-vite@8.6.18(storybook@8.6.18(prettier@3.8.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@storybook/csf-plugin': 8.6.18(storybook@8.6.18(prettier@3.8.2)) @@ -15437,8 +15499,8 @@ snapshots: '@storybook/theming': 8.6.18(storybook@8.6.18(prettier@3.8.2)) better-opn: 3.0.2 browser-assert: 1.2.1 - esbuild: 0.25.12 - esbuild-register: 3.6.0(esbuild@0.25.12) + esbuild: 0.24.2 + esbuild-register: 3.6.0(esbuild@0.24.2) jsdoc-type-pratt-parser: 4.8.0 process: 0.11.10 recast: 0.23.11 @@ -15496,26 +15558,6 @@ snapshots: react-dom: 19.2.5(react@19.2.5) storybook: 8.6.18(prettier@3.8.2) - '@storybook/react-vite@8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(rollup@4.60.1)(storybook@8.6.18(prettier@3.8.2))(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) - '@rollup/pluginutils': 5.3.0(rollup@4.60.1) - '@storybook/builder-vite': 8.6.18(storybook@8.6.18(prettier@3.8.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) - '@storybook/react': 8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.6.18(prettier@3.8.2))(typescript@6.0.2) - find-up: 5.0.0 - magic-string: 0.30.21 - react: 19.2.5 - react-docgen: 7.1.1 - react-dom: 19.2.5(react@19.2.5) - resolve: 1.22.12 - storybook: 8.6.18(prettier@3.8.2) - tsconfig-paths: 4.2.0 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - rollup - - supports-color - - typescript - '@storybook/react-vite@8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(rollup@4.60.1)(storybook@8.6.18(prettier@3.8.2))(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) @@ -16273,16 +16315,6 @@ snapshots: optionalDependencies: maplibre-gl: 5.23.0 - '@vitejs/plugin-react@6.0.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - '@rolldown/pluginutils': 1.0.0-rc.7 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) - - '@vitejs/plugin-react@6.0.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - '@rolldown/pluginutils': 1.0.0-rc.7 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitejs/plugin-react@6.0.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 @@ -16300,7 +16332,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.24.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/expect@2.0.5': dependencies: @@ -16318,6 +16350,15 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 + '@vitest/mocker@4.1.4(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.24.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + '@vitest/spy': 4.1.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + msw: 2.13.3(@types/node@25.6.0)(typescript@6.0.2) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.24.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + '@vitest/mocker@4.1.4(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.4 @@ -16375,7 +16416,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vitest: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.24.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/utils@2.0.5': dependencies: @@ -16954,6 +16995,11 @@ snapshots: dependencies: run-applescript: 7.1.0 + bundle-require@5.1.0(esbuild@0.24.2): + dependencies: + esbuild: 0.24.2 + load-tsconfig: 0.2.5 + bundle-require@5.1.0(esbuild@0.27.7): dependencies: esbuild: 0.27.7 @@ -17617,10 +17663,10 @@ snapshots: esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 - esbuild-register@3.6.0(esbuild@0.25.12): + esbuild-register@3.6.0(esbuild@0.24.2): dependencies: debug: 4.4.3(supports-color@8.1.1) - esbuild: 0.25.12 + esbuild: 0.24.2 transitivePeerDependencies: - supports-color @@ -17632,34 +17678,33 @@ snapshots: - supports-color optional: true - esbuild@0.25.12: + esbuild@0.24.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 + '@esbuild/aix-ppc64': 0.24.2 + '@esbuild/android-arm': 0.24.2 + '@esbuild/android-arm64': 0.24.2 + '@esbuild/android-x64': 0.24.2 + '@esbuild/darwin-arm64': 0.24.2 + '@esbuild/darwin-x64': 0.24.2 + '@esbuild/freebsd-arm64': 0.24.2 + '@esbuild/freebsd-x64': 0.24.2 + '@esbuild/linux-arm': 0.24.2 + '@esbuild/linux-arm64': 0.24.2 + '@esbuild/linux-ia32': 0.24.2 + '@esbuild/linux-loong64': 0.24.2 + '@esbuild/linux-mips64el': 0.24.2 + '@esbuild/linux-ppc64': 0.24.2 + '@esbuild/linux-riscv64': 0.24.2 + '@esbuild/linux-s390x': 0.24.2 + '@esbuild/linux-x64': 0.24.2 + '@esbuild/netbsd-arm64': 0.24.2 + '@esbuild/netbsd-x64': 0.24.2 + '@esbuild/openbsd-arm64': 0.24.2 + '@esbuild/openbsd-x64': 0.24.2 + '@esbuild/sunos-x64': 0.24.2 + '@esbuild/win32-arm64': 0.24.2 + '@esbuild/win32-ia32': 0.24.2 + '@esbuild/win32-x64': 0.24.2 esbuild@0.27.7: optionalDependencies: @@ -22488,25 +22533,6 @@ snapshots: - rollup - supports-color - vite-plugin-dts@4.5.4(@types/node@25.6.0)(rollup@4.60.1)(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - '@microsoft/api-extractor': 7.58.2(@types/node@25.6.0) - '@rollup/pluginutils': 5.3.0(rollup@4.60.1) - '@volar/typescript': 2.4.28 - '@vue/language-core': 2.2.0(typescript@6.0.2) - compare-versions: 6.1.1 - debug: 4.4.3(supports-color@8.1.1) - kolorist: 1.8.0 - local-pkg: 1.1.2 - magic-string: 0.30.21 - typescript: 6.0.2 - optionalDependencies: - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - '@types/node' - - rollup - - supports-color - vite-plugin-dts@4.5.4(@types/node@25.6.0)(rollup@4.60.1)(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@microsoft/api-extractor': 7.58.2(@types/node@25.6.0) @@ -22526,7 +22552,7 @@ snapshots: - rollup - supports-color - vite@8.0.8(@types/node@25.6.0)(esbuild@0.25.12)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3): + vite@8.0.8(@types/node@25.6.0)(esbuild@0.24.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -22535,7 +22561,7 @@ snapshots: tinyglobby: 0.2.16 optionalDependencies: '@types/node': 25.6.0 - esbuild: 0.25.12 + esbuild: 0.24.2 fsevents: 2.3.3 jiti: 2.6.1 tsx: 4.21.0 @@ -22581,6 +22607,38 @@ snapshots: redent: 3.0.0 vitest: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest@4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.24.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@vitest/expect': 4.1.4 + '@vitest/mocker': 4.1.4(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.24.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.4 + '@vitest/runner': 4.1.4 + '@vitest/snapshot': 4.1.4 + '@vitest/spy': 4.1.4 + '@vitest/utils': 4.1.4 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.1.1 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.24.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@types/node': 25.6.0 + '@vitest/coverage-v8': 4.1.4(vitest@4.1.4) + '@vitest/ui': 4.1.4(vitest@4.1.4) + happy-dom: 20.9.0 + jsdom: 29.0.2(@noble/hashes@2.2.0) + transitivePeerDependencies: + - msw + vitest@4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@vitest/ui@4.1.4)(happy-dom@20.9.0)(jsdom@29.0.2(@noble/hashes@2.2.0))(msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.4 From 6578cee7bef0ac9839a906e20cc26094d69551e0 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:53:35 +0000 Subject: [PATCH 3/3] docs: add implementation summary for server app Add IMPLEMENTATION.md documenting the complete server app structure, architecture, deployment process, and key decisions Agent-Logs-Url: https://github.com/objectstack-ai/objectui/sessions/1401bb2d-d094-4280-a66d-bee5388fc83a Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> --- apps/server/IMPLEMENTATION.md | 155 ++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 apps/server/IMPLEMENTATION.md diff --git a/apps/server/IMPLEMENTATION.md b/apps/server/IMPLEMENTATION.md new file mode 100644 index 00000000..ffa4f938 --- /dev/null +++ b/apps/server/IMPLEMENTATION.md @@ -0,0 +1,155 @@ +# Independent Vercel Server Implementation + +## Summary + +Successfully created an independent `apps/server` package that separates the Vercel backend deployment from the console frontend, following the pattern from `objectstack-ai/framework/apps/server`. + +## What Was Created + +### Core Files + +1. **package.json** - Dependencies and scripts for the server +2. **objectstack.config.ts** - Server configuration with plugin loading +3. **server/index.ts** - Serverless function entrypoint with Hono adapter +4. **api/[[...route]].js** - Vercel catch-all API handler + +### Build Infrastructure + +5. **scripts/build-vercel.sh** - Build script for Vercel deployment +6. **scripts/bundle-api.mjs** - ESBuild bundler configuration +7. **vercel.json** - Vercel deployment configuration +8. **tsconfig.json** - TypeScript configuration + +### Supporting Files + +9. **.env.example** - Environment variable template +10. **.gitignore** - Git ignore rules +11. **.vercelignore** - Vercel ignore rules +12. **README.md** - Usage and API documentation +13. **DEPLOYMENT.md** - Detailed deployment guide + +## Architecture + +``` +apps/server/ +├── api/ +│ ├── [[...route]].js # Vercel entry (committed) +│ └── _handler.js # Bundled handler (generated) +├── server/ +│ └── index.ts # Server implementation +├── scripts/ +│ ├── build-vercel.sh # Build orchestration +│ └── bundle-api.mjs # API bundler +├── objectstack.config.ts # Kernel configuration +└── vercel.json # Vercel config +``` + +## Key Features + +### Plugin Loading Order + +Critical for proper initialization: + +1. **MemoryI18nPlugin** - Registers i18n service early +2. **ObjectQLPlugin** - Provides query engine +3. **DriverPlugin** (InMemoryDriver) - Database driver +4. **AppPlugins** - CRM, Todo, Kitchen Sink examples +5. **SetupPlugin** - Must precede AuthPlugin +6. **AuthPlugin** - Authentication (uses setupNav) +7. **ConsolePlugin** - Serves frontend UI + +### Build Process + +1. Builds console with `VITE_RUNTIME_MODE=server` +2. Bundles `server/index.ts` → `api/_handler.js` with esbuild +3. Copies console dist to `public/` for static serving + +### Runtime Flow + +1. Vercel calls `api/[[...route]].js` +2. Delegates to bundled `api/_handler.js` +3. Kernel boots on cold start (cached for warm requests) +4. Hono app handles `/api/v1/*` requests +5. Static files served from `public/` + +## Environment Variables + +**Required:** +- `AUTH_SECRET` - Min 32 characters for production + +**Optional:** +- `NEXT_PUBLIC_BASE_URL` - Auto-detected from VERCEL_URL + +## Deployment + +### Quick Deploy + +```bash +cd apps/server +vercel +``` + +### Set Environment Variables + +```bash +vercel env add AUTH_SECRET production +``` + +### Production Deploy + +```bash +vercel --prod +``` + +## API Endpoints + +- **Discovery:** `/api/v1/discovery` +- **Metadata:** `/api/v1/meta/objects` +- **Data CRUD:** `/api/v1/data/:object` +- **Console UI:** `/` (root) + +## Testing Locally + +```bash +# Install dependencies +pnpm install + +# Run dev server +cd apps/server +pnpm dev + +# Test API +curl http://localhost:3000/api/v1/discovery +``` + +## Differences from Framework Reference + +1. Serves ObjectUI Console (not separate Studio app) +2. Console built from `apps/console` with server mode +3. Uses `@object-ui/*` example apps instead of `@example/*` +4. Imports ConsolePlugin from `@object-ui/console` package +5. Same in-memory driver pattern for development + +## Next Steps + +For production deployment: + +1. Replace InMemoryDriver with persistent database (Turso, PostgreSQL) +2. Configure environment variables in Vercel +3. Set up monitoring and logging +4. Enable Vercel Analytics +5. Configure custom domain + +## Files Changed + +- Created `apps/server/` directory with 13 files +- Updated `pnpm-lock.yaml` for new dependencies + +## Commit History + +1. `9928b2a` - Initial server app creation +2. `2940933` - Fix TypeScript configuration and type errors + +## Status + +✅ **Complete** - Server app is ready for deployment to Vercel