fix(mcp): use local sqlite scene storage

This commit is contained in:
Aymeric Rabot
2026-04-24 13:32:04 -07:00
parent 06d00566f0
commit b3d1f663f6
119 changed files with 1086 additions and 23694 deletions
+1 -1
View File
@@ -73,7 +73,7 @@ export async function PUT(request: NextRequest, { params }: RouteParams) {
graph: parsed.data.graph as never,
thumbnailUrl:
parsed.data.thumbnailUrl === undefined ? existing.thumbnailUrl : parsed.data.thumbnailUrl,
expectedVersion,
expectedVersion: expectedVersion ?? existing.version,
})
return NextResponse.json(meta, {
headers: { ETag: `"${meta.version}"` },
+1 -1
View File
@@ -8,7 +8,7 @@ describe('getSceneStore', () => {
createSceneStore: async (_env?: NodeJS.ProcessEnv) => {
callCount++
return {
backend: 'filesystem' as const,
backend: 'sqlite' as const,
__instanceNumber: callCount,
save: async () => ({}) as never,
load: async () => null,
+4 -62
View File
@@ -1,67 +1,9 @@
// TODO: auth — every call in this module currently runs unauthenticated.
// v0.1 skips auth; the factory should eventually receive a user context from
// middleware / a request-scoped session and propagate it into SceneStore.
// Only import this module from server code (route handlers, server components,
// server actions). Importing from client code will leak the Supabase service
// role key into the browser bundle.
// v0.1 is scoped to local-first use on a developer machine. A hosted editor
// should pass request-scoped user context through this factory before exposing
// these routes publicly.
import type { SceneGraph } from '@pascal-app/core/clone-scene-graph'
/**
* Inlined copies of the shared storage contract. The canonical source lives in
* `packages/mcp/src/storage/types.ts`; re-declared here so the editor only
* needs the runtime factory from `@pascal-app/mcp/storage` and type-checks
* without a hard compile-time dependency on the MCP package's source tree.
*
* Keep this file in sync whenever the MCP storage types change.
*/
export type SceneId = string
export interface SceneMeta {
id: SceneId
name: string
projectId: string | null
thumbnailUrl: string | null
version: number
createdAt: string
updatedAt: string
ownerId: string | null
sizeBytes: number
nodeCount: number
}
export interface SceneWithGraph extends SceneMeta {
graph: SceneGraph
}
export interface SceneSaveOptions {
id?: SceneId
name: string
projectId?: string | null
ownerId?: string | null
graph: SceneGraph
thumbnailUrl?: string | null
expectedVersion?: number
}
export interface SceneListOptions {
projectId?: string
ownerId?: string
limit?: number
}
export interface SceneMutateOptions {
expectedVersion?: number
}
export interface SceneStore {
readonly backend: 'filesystem' | 'supabase'
save(opts: SceneSaveOptions): Promise<SceneMeta>
load(id: SceneId): Promise<SceneWithGraph | null>
list(opts?: SceneListOptions): Promise<SceneMeta[]>
delete(id: SceneId, opts?: SceneMutateOptions): Promise<boolean>
rename(id: SceneId, newName: string, opts?: SceneMutateOptions): Promise<SceneMeta>
}
import type { SceneStore } from '@pascal-app/mcp/storage'
/**
* Per-process singleton. The factory is async because backend modules are
+7 -1
View File
@@ -4,7 +4,13 @@ const nextConfig: NextConfig = {
typescript: {
ignoreBuildErrors: true,
},
transpilePackages: ['three', '@pascal-app/viewer', '@pascal-app/core', '@pascal-app/editor'],
transpilePackages: [
'three',
'@pascal-app/viewer',
'@pascal-app/core',
'@pascal-app/editor',
'@pascal-app/mcp',
],
turbopack: {
resolveAlias: {
react: './node_modules/react',
+1 -1
View File
@@ -17,7 +17,7 @@
"next.config.js",
".next/types/**/*.ts"
],
"exclude": ["node_modules"],
"exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx"],
"references": [
{ "path": "../../packages/core" },
{ "path": "../../packages/viewer" }