Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/27678-objectui-skill-msw-removed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@objectstack/skills': patch
'@object-ui/console': patch
---

docs(skills): the objectui data-integration guide stops teaching the MSW plugin removed in 12.0

Clause-②: no
Metadata-protocol: none

- **Before.** `skills/objectui/guides/data-integration.md` taught a frontend-first setup built on the MSW plugin package, removed in 12.0 (its last npm release is 11.0.0, so the install still succeeds and pulls an 11.x plugin into the current stack), and eval 2 of `evals/data-integration.json` rewarded that answer.
- **Now.** The section "Frontend-first development" names the two supported paths: a static scope with no backend, or the real server run locally with `os dev` behind a Vite `/api` proxy. It states that `os dev` persists to SQLite, that `--fresh` gives a throwaway database, and that the retired in-memory driver is refused. Eval 2 grades `os dev`, `proxy` and `objectstack.config`, and refuses the MSW setup. Net -35 lines in the guide.
- **Console.** `VITE_USE_MOCK_SERVER`, which no source reads, leaves `.env.development`, `.env.production` and the Vercel build command. The `mockServiceWorker.js` rewrite exclusion and the `vendor-msw` chunk row in `docs/deployment.md` go too. No runtime behaviour changes.
12 changes: 6 additions & 6 deletions skills/objectui/evals/data-integration.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@
},
{
"id": 2,
"prompt": "Set up MSW mock data for my ObjectUI app so I can develop the frontend without a running backend. I have a Todo object with title, completed, and dueDate fields.",
"expected_output": "Provides MSW browser setup using ObjectKernel + InMemoryDriver + MSWPlugin, objectstack.config with the Todo schema, and main.tsx bootstrap pattern.",
"prompt": "I want to build my ObjectUI frontend before the backend is deployed. I have a Todo object with title, completed, and dueDate fields. How do I get a working API locally?",
"expected_output": "Runs the real server locally with os dev (the Todo object in objectstack.config) and proxies /api to it from the Vite dev server; no MSW plugin.",
"files": [],
"assertions": {
"must_contain": [
"ObjectKernel",
"InMemoryDriver",
"MSWPlugin",
"os dev",
"proxy",
"objectstack.config"
],
"must_not_contain": [
"msw rest.get('/api/todos'"
"enableBrowser",
"setupWorker"
]
}
},
Expand Down
72 changes: 19 additions & 53 deletions skills/objectui/guides/data-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,65 +351,33 @@ function MyPlugin() {
}
```

## MSW mock setup (frontend-first development)
## Frontend-first development

For developing the UI without a running backend, use Mock Service Worker with ObjectStack's in-browser kernel.
There is no mock-server plugin: the MSW plugin was removed in 12.0, and npm
still serves its stale 11.x build — ⛔ do not install it. Two supported paths:

### Browser mock server
- **No backend:** publish static values as a scope ("Static data (no backend)" above).
- **Real API, locally:** run `os dev` in the ObjectStack app whose
`objectstack.config.ts` declares your objects. In a project that runs Vite
itself (not `objectui dev`), proxy `/api` to it so page and API share one origin:

```typescript
// src/mocks/browser.ts
import { ObjectKernel, DriverPlugin, AppPlugin } from '@objectstack/runtime';
import { ObjectQLPlugin } from '@objectstack/objectql';
import { InMemoryDriver } from '@objectstack/driver-memory';
import { MSWPlugin } from '@objectstack/plugin-msw';

export async function startMockServer(appConfig: any) {
const kernel = new ObjectKernel({ skipSystemValidation: true });

await kernel.use(new ObjectQLPlugin());

const driver = new InMemoryDriver();
await kernel.use(new DriverPlugin(driver, 'memory'));
await kernel.use(new AppPlugin(appConfig));
await kernel.use(new MSWPlugin({
enableBrowser: true,
baseUrl: '/api/v1',
logRequests: true,
}));

await kernel.bootstrap();

// Seed initial data
if (appConfig.manifest?.data) {
for (const dataset of appConfig.manifest.data) {
for (const record of dataset.records) {
await driver.create(dataset.object, record);
}
}
}
}
```bash
os dev # http://localhost:3000; if busy, the banner names the port taken
os dev --fresh # throwaway database, deleted on exit
```

### App entry with MSW

```typescript
// src/main.tsx
import { startMockServer } from './mocks/browser';
import appConfig from '../objectstack.config';

async function bootstrap() {
if (import.meta.env.DEV) {
await startMockServer(appConfig);
}

const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(<App />);
}

bootstrap();
// vite.config.ts
export default defineConfig({
server: { proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } } },
});
```

By default `os dev` persists to a SQLite file and seeds a dev admin
(`admin@objectos.ai` / `admin123`) on an empty database. It has no in-memory
driver (`--database-driver memory` is refused); `--database :memory:` is
SQLite's in-memory database. Commands and flags: the `objectstack-platform` skill.

### Test DataSource helper

<!-- os:check -->
Expand Down Expand Up @@ -507,8 +475,6 @@ unsubscribe?.();

- Spelling `QueryParams` options without the `$` prefix (`limit`, `filter`, `sort`): the index signature accepts them, nothing reads them, and a dropped `$top` fetches the whole table.
- Importing `fetch` directly in components instead of using DataSource from context.
- Forgetting to await `startMockServer()` before rendering — MSW intercepts aren't ready.
- Mismatched `baseUrl` between MSW plugin and ObjectStackAdapter — requests bypass mocks.
- Not providing `getObjectSchema()` — plugins that need field metadata will fail.
- Passing a DataSource adapter instance where a static object is expected (or vice versa).
- Not handling loading/error states in components that fetch data.
1 change: 0 additions & 1 deletion ui/apps/console/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@
# Setting VITE_SERVER_URL to an absolute origin still works, but it opts this
# app back out of same-origin and into CORS + the 401 above.
VITE_SERVER_URL=
VITE_USE_MOCK_SERVER=false
1 change: 0 additions & 1 deletion ui/apps/console/.env.production
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# (e.g. demo.objectstack.ai on Vercel) inject VITE_SERVER_URL at
# build time via their deploy environment.
VITE_SERVER_URL=
VITE_USE_MOCK_SERVER=false

# ── Sentry error tracking: CONFIGURED ON THE SERVER, never here ─────────────
#
Expand Down
1 change: 0 additions & 1 deletion ui/apps/console/docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ The console build produces 17+ named chunks via `manualChunks`:
| `vendor-ui-utils` | cva, clsx, tailwind-merge | Rare |
| `vendor-objectstack` | @objectstack/spec, client | Moderate |
| `vendor-zod` | Zod validation | Rare |
| `vendor-msw` | MSW (demo mode only) | Rare |
| `vendor-charts` | Recharts, D3 | Rare |
| `vendor-dndkit` | @dnd-kit | Rare |
| `vendor-i18n` | i18next | Rare |
Expand Down
4 changes: 2 additions & 2 deletions ui/apps/console/vercel.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"installCommand": "cd ../.. && pnpm install --frozen-lockfile",
"buildCommand": "cd ../.. && pnpm --filter @object-ui/app-shell... build && cd apps/console && NODE_OPTIONS=--max-old-space-size=4096 VITE_USE_MOCK_SERVER=false VITE_BASE_PATH=/ vite build",
"buildCommand": "cd ../.. && pnpm --filter @object-ui/app-shell... build && cd apps/console && NODE_OPTIONS=--max-old-space-size=4096 VITE_BASE_PATH=/ vite build",
"outputDirectory": "dist",
"framework": "vite",
"rewrites": [
{ "source": "/((?!assets|mockServiceWorker\\.js).*)", "destination": "/index.html" }
{ "source": "/((?!assets).*)", "destination": "/index.html" }
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe('committed .env files carry no third-party telemetry endpoint', () => {
it('parses real assignments out of the console production env', () => {
const parsed = parseEnv(readFileSync(path.join(repoRoot, 'apps/console/.env.production'), 'utf8'));
expect(parsed.map((entry) => entry.key)).toContain('VITE_SERVER_URL');
expect(parsed.find((entry) => entry.key === 'VITE_USE_MOCK_SERVER')?.value).toBe('false');
expect(parsed.find((entry) => entry.key === 'VITE_SERVER_URL')?.value).toBe('');
});

it('flags an offending file — proving the rules can actually fire', () => {
Expand All @@ -133,7 +133,7 @@ describe('committed .env files carry no third-party telemetry endpoint', () => {
expect(violationsIn('OS_TELEMETRY_CLIENT_ERROR_REPORTING_SEND_DEFAULT_PII=true')).not.toEqual([]);
// …and does not fire on the commentary that documents the recipe.
expect(violationsIn('# VITE_SENTRY_DSN=https://<key>@<org>.ingest.sentry.io/<p>')).toEqual([]);
expect(violationsIn('VITE_SERVER_URL=\nVITE_USE_MOCK_SERVER=false')).toEqual([]);
expect(violationsIn('VITE_SERVER_URL=\nVITE_BASE_PATH=/')).toEqual([]);
});

it.each(envFiles)('%s', (file) => {
Expand Down
Loading