diff --git a/.env.example b/.env.example index 6a6f69da10..014f531319 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,8 @@ -# Optional environment variables — the editor works without any of these +# Optional environment variables # Dev server port (default: 3002, set in .env.defaults) # PORT=3002 + +# Public editor origin used by Mint OAuth and same-origin checks. +# Set this when Pascal is hosted outside editor.pascal.app. +# MINT_PASCAL_HOST_ORIGIN=https://pascal.example.com diff --git a/SETUP.md b/SETUP.md index 86cbe34213..a2cf671cd2 100644 --- a/SETUP.md +++ b/SETUP.md @@ -24,8 +24,9 @@ cp .env.example .env | Variable | Required | Description | |----------|----------|-------------| | `PORT` | No | Dev server port (default: 3002) | +| `MINT_PASCAL_HOST_ORIGIN` | No | Public editor origin used by Mint sign-in and request checks. Set it for self-hosted deployments. | -The editor works fully without any environment variables. +Local development and the official hosted editor work without any environment variables. ## Docker @@ -36,6 +37,13 @@ docker compose up -d The editor will be running at **http://localhost:3000**. Saved scenes live in the `pascal-data` volume, so they survive `docker compose down`. +Docker defaults `MINT_PASCAL_HOST_ORIGIN` to `http://localhost:3000`. Override +it when hosting Pascal at another origin: + +```bash +MINT_PASCAL_HOST_ORIGIN=https://pascal.example.com docker compose up -d +``` + Keep the container port at 3000: the `/scenes` page fetches its own API through a base URL that only `NEXT_PUBLIC_APP_URL` can override, and Next inlines that value at build time, so remapping the port to something else makes the page diff --git a/apps/editor/app/api/plugins/mint/[...path]/route.ts b/apps/editor/app/api/plugins/mint/[...path]/route.ts new file mode 100644 index 0000000000..01ad4f07e4 --- /dev/null +++ b/apps/editor/app/api/plugins/mint/[...path]/route.ts @@ -0,0 +1,12 @@ +import { handleMintPascalRequest } from '@mint/pascal-plugin/server' +import { BASE_URL } from '@/lib/utils' + +export const runtime = 'nodejs' +export const dynamic = 'force-dynamic' + +const route = (request: Request) => + handleMintPascalRequest(request, { + origin: process.env.MINT_PASCAL_HOST_ORIGIN ?? BASE_URL, + }) + +export { route as GET, route as POST } diff --git a/apps/editor/app/globals.css b/apps/editor/app/globals.css index ef3a61a715..e8f38d8ff3 100644 --- a/apps/editor/app/globals.css +++ b/apps/editor/app/globals.css @@ -4,6 +4,7 @@ @source "../../../packages/editor/src"; @source "../../../packages/nodes/src"; @source "../../../node_modules/@pascal-app/plugin-trees/src"; +@source "../../../node_modules/@mint/pascal-plugin/src"; @custom-variant dark (&:is(.dark *)); diff --git a/apps/editor/lib/bootstrap.ts b/apps/editor/lib/bootstrap.ts index a24f64cb53..93edd78030 100644 --- a/apps/editor/lib/bootstrap.ts +++ b/apps/editor/lib/bootstrap.ts @@ -1,3 +1,4 @@ +import { mintHostPanel, mintPlugin } from '@mint/pascal-plugin' import { type AnyNodeDefinition, discoverPlugins, @@ -85,6 +86,8 @@ export async function loadExternalPlugins(): Promise { // so it is registered separately from the core plugin manifest. extendPluginDiscovery(async () => [treesPlugin]) registerEditorHostPanel(treesHostPanel) +extendPluginDiscovery(async () => [mintPlugin]) +registerEditorHostPanel(mintHostPanel) loadBuiltinsSync() void loadExternalPlugins() diff --git a/apps/editor/next.config.ts b/apps/editor/next.config.ts index 054ee1b06e..08961a3b3d 100644 --- a/apps/editor/next.config.ts +++ b/apps/editor/next.config.ts @@ -25,6 +25,7 @@ const nextConfig: NextConfig = { '@pascal-app/editor', '@pascal-app/mcp', '@pascal-app/plugin-trees', + '@mint/pascal-plugin', '@dgreenheck/ez-tree', ], turbopack: { diff --git a/apps/editor/package.json b/apps/editor/package.json index c6c369508b..ba2da86503 100644 --- a/apps/editor/package.json +++ b/apps/editor/package.json @@ -13,6 +13,7 @@ }, "dependencies": { "@iconify/react": "^6.0.2", + "@mint/pascal-plugin": "github:mintdotgg/mint-pascal-plugin#902c546dbaece6b31455c0dc394afe6b9cd136fe", "@number-flow/react": "^0.6.0", "@pascal-app/core": "*", "@pascal-app/editor": "*", diff --git a/bun.lock b/bun.lock index ea300a69b8..8a5789266c 100644 --- a/bun.lock +++ b/bun.lock @@ -27,6 +27,7 @@ "version": "0.1.0", "dependencies": { "@iconify/react": "^6.0.2", + "@mint/pascal-plugin": "github:mintdotgg/mint-pascal-plugin#902c546dbaece6b31455c0dc394afe6b9cd136fe", "@number-flow/react": "^0.6.0", "@pascal-app/core": "*", "@pascal-app/editor": "*", @@ -508,6 +509,8 @@ "@mediapipe/tasks-vision": ["@mediapipe/tasks-vision@0.10.17", "", {}, "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg=="], + "@mint/pascal-plugin": ["@mint/pascal-plugin@github:mintdotgg/mint-pascal-plugin#902c546", { "peerDependencies": { "@pascal-app/core": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "@pascal-app/editor": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "@pascal-app/viewer": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "react": "^18 || ^19", "three": "^0.185" } }, "mintdotgg-mint-pascal-plugin-902c546"], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], "@monogrid/gainmap-js": ["@monogrid/gainmap-js@3.4.0", "", { "dependencies": { "promise-worker-transferable": "^1.0.4" }, "peerDependencies": { "three": ">= 0.159.0" } }, "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg=="], diff --git a/docker-compose.yml b/docker-compose.yml index 862452a9fd..55a169220a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,8 @@ services: - "3000:3000" environment: NODE_ENV: production + # Public editor origin used by Mint OAuth and same-origin checks. + MINT_PASCAL_HOST_ORIGIN: ${MINT_PASCAL_HOST_ORIGIN:-http://localhost:3000} # Scene database location. Without the volume below, every saved project is # discarded when the container is recreated. PASCAL_DATA_DIR: /data