diff --git a/packages/matrix/helpers/index.ts b/packages/matrix/helpers/index.ts index 01b32c84cf..0996602148 100644 --- a/packages/matrix/helpers/index.ts +++ b/packages/matrix/helpers/index.ts @@ -12,10 +12,11 @@ import { } from '../docker/synapse'; import { realmPassword } from './realm-credentials'; import { appURL, BasicSQLExecutor, SQLExecutor } from './isolated-realm-server'; +import { isEnvironmentMode, getEnvironmentSlug } from './environment-config'; import { APP_BOXEL_MESSAGE_MSGTYPE } from './matrix-constants'; import { randomUUID } from 'crypto'; -export const testHost = 'http://localhost:4205/test'; +export const testHost = appURL; export const mailHost = 'http://localhost:5001'; export const initialRoomName = 'New AI Assistant Chat'; export const REGISTRATION_TOKEN = 'abc123'; @@ -107,15 +108,27 @@ async function registerRealmRedirect( } export async function setRealmRedirects(page: Page) { + let baseServerUrl: string; + let isolatedServerUrl: string; + + if (isEnvironmentMode()) { + let slug = getEnvironmentSlug(); + baseServerUrl = `http://realm-server.${slug}.localhost`; + isolatedServerUrl = `http://realm-matrix-test.${slug}.localhost`; + } else { + baseServerUrl = 'http://localhost:4201'; + isolatedServerUrl = 'http://localhost:4205'; + } + await registerRealmRedirect( page, - 'http://localhost:4201/skills/', - 'http://localhost:4205/skills/', + `${baseServerUrl}/skills/`, + `${isolatedServerUrl}/skills/`, ); await registerRealmRedirect( page, - 'http://localhost:4201/base/', - 'http://localhost:4205/base/', + `${baseServerUrl}/base/`, + `${isolatedServerUrl}/base/`, ); } diff --git a/packages/matrix/helpers/isolated-realm-server.ts b/packages/matrix/helpers/isolated-realm-server.ts index 4db80a5c25..8acc50308e 100644 --- a/packages/matrix/helpers/isolated-realm-server.ts +++ b/packages/matrix/helpers/isolated-realm-server.ts @@ -6,6 +6,7 @@ import { ensureDirSync, copySync, readFileSync } from 'fs-extra'; import { Pool } from 'pg'; import { createServer as createNetServer, type AddressInfo } from 'net'; import type { SynapseInstance } from '../docker/synapse'; +import { isEnvironmentMode, getEnvironmentSlug } from './environment-config'; setGracefulCleanup(); @@ -18,7 +19,23 @@ const skillsRealmDir = resolve( ); const baseRealmDir = resolve(join(__dirname, '..', '..', 'base')); const matrixDir = resolve(join(__dirname, '..')); -export const appURL = 'http://localhost:4205/test'; + +const ISOLATED_REALM_SERVICE = 'realm-matrix-test'; +const ISOLATED_WORKER_SERVICE = 'worker-matrix-test'; +const DEFAULT_REALM_PORT = 4205; + +function getRealmBaseURL(): string { + if (isEnvironmentMode()) { + return `http://${ISOLATED_REALM_SERVICE}.${getEnvironmentSlug()}.localhost`; + } + return `http://localhost:${DEFAULT_REALM_PORT}`; +} + +export const realmDomain = isEnvironmentMode() + ? `${ISOLATED_REALM_SERVICE}.${getEnvironmentSlug()}.localhost` + : `localhost:${DEFAULT_REALM_PORT}`; + +export const appURL = `${getRealmBaseURL()}/test`; const DEFAULT_PRERENDER_PORT = 4231; @@ -142,7 +159,11 @@ export async function startPrerenderServer( ...process.env, NODE_ENV: process.env.NODE_ENV ?? 'development', NODE_NO_WARNINGS: '1', - BOXEL_HOST_URL: process.env.HOST_URL ?? 'http://localhost:4200', + BOXEL_HOST_URL: + process.env.HOST_URL ?? + (isEnvironmentMode() + ? `http://host.${getEnvironmentSlug()}.localhost` + : 'http://localhost:4200'), }; let prerenderArgs = [ '--transpileOnly', @@ -216,6 +237,13 @@ export async function startServer({ let testDBName = `test_db_${Math.floor(10000000 * Math.random())}`; let workerManagerPort = await findAvailablePort(4232); + let envMode = isEnvironmentMode(); + let realmBaseURL = getRealmBaseURL(); + let realmPort = envMode ? 0 : DEFAULT_REALM_PORT; + let realmDomain = envMode + ? `${ISOLATED_REALM_SERVICE}.${getEnvironmentSlug()}.localhost` + : `localhost:${DEFAULT_REALM_PORT}`; + process.env.PGPORT = '5435'; process.env.PGDATABASE = testDBName; process.env.NODE_NO_WARNINGS = '1'; @@ -236,13 +264,16 @@ export async function startServer({ `--prerendererUrl='${prerenderURL}'`, `--migrateDB`, - `--fromUrl='http://localhost:4205/test/'`, - `--toUrl='http://localhost:4205/test/'`, + `--fromUrl='${realmBaseURL}/test/'`, + `--toUrl='${realmBaseURL}/test/'`, ]; workerArgs = workerArgs.concat([ `--fromUrl='https://cardstack.com/base/'`, - `--toUrl='http://localhost:4205/base/'`, + `--toUrl='${realmBaseURL}/base/'`, ]); + if (envMode) { + workerArgs.push(`--serviceName=${ISOLATED_WORKER_SERVICE}`); + } let workerManager = spawn('ts-node', workerArgs, { cwd: realmServerDir, @@ -262,7 +293,7 @@ export async function startServer({ let serverArgs = [ `--transpileOnly`, 'main', - `--port=4205`, + `--port=${realmPort}`, `--matrixURL='${matrixURL}'`, `--realmsRootPath='${dir.name}'`, `--workerManagerPort=${workerManagerPort}`, @@ -271,21 +302,24 @@ export async function startServer({ `--path='${testRealmDir}'`, `--username='test_realm'`, - `--fromUrl='http://localhost:4205/test/'`, - `--toUrl='http://localhost:4205/test/'`, + `--fromUrl='${realmBaseURL}/test/'`, + `--toUrl='${realmBaseURL}/test/'`, ]; serverArgs = serverArgs.concat([ `--username='skills_realm'`, `--path='${skillsRealmDir}'`, - `--fromUrl='http://localhost:4205/skills/'`, - `--toUrl='http://localhost:4205/skills/'`, + `--fromUrl='${realmBaseURL}/skills/'`, + `--toUrl='${realmBaseURL}/skills/'`, ]); serverArgs = serverArgs.concat([ `--username='base_realm'`, `--path='${baseRealmDir}'`, `--fromUrl='https://cardstack.com/base/'`, - `--toUrl='http://localhost:4205/base/'`, + `--toUrl='${realmBaseURL}/base/'`, ]); + if (envMode) { + serverArgs.push(`--serviceName=${ISOLATED_REALM_SERVICE}`); + } console.log(`realm server database: ${testDBName}`); @@ -294,8 +328,8 @@ export async function startServer({ stdio: ['pipe', 'pipe', 'pipe', 'ipc'], env: { ...process.env, - PUBLISHED_REALM_BOXEL_SPACE_DOMAIN: 'localhost:4205', - PUBLISHED_REALM_BOXEL_SITE_DOMAIN: 'localhost:4205', + PUBLISHED_REALM_BOXEL_SPACE_DOMAIN: realmDomain, + PUBLISHED_REALM_BOXEL_SITE_DOMAIN: realmDomain, }, }); realmServer.unref(); diff --git a/packages/matrix/playwright.config.ts b/packages/matrix/playwright.config.ts index adb4530187..a807d90c0e 100644 --- a/packages/matrix/playwright.config.ts +++ b/packages/matrix/playwright.config.ts @@ -1,4 +1,13 @@ import { defineConfig, devices } from '@playwright/test'; +import { appURL } from './helpers/isolated-realm-server'; +import { + isEnvironmentMode, + getEnvironmentSlug, +} from './helpers/environment-config'; + +// In environment mode, the isolated realm server is behind Traefik on port 80. +// In non-env mode, it listens directly on port 4205. +let realmPort = isEnvironmentMode() ? 80 : 4205; /** * See https://playwright.dev/docs/test-configuration. @@ -14,7 +23,7 @@ export default defineConfig({ reporter: process.env.CI ? 'blob' : 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { - baseURL: 'http://localhost:4205/test', + baseURL: appURL, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'retry-with-trace', @@ -35,7 +44,7 @@ export default defineConfig({ launchOptions: { args: [ // Simulate resolving a custom workspace domain to a realm server - '--host-resolver-rules=MAP published.realm 127.0.0.1:4205', + `--host-resolver-rules=MAP published.realm 127.0.0.1:${realmPort}`, // Allow iframe to request storage access depsite being considered insecure '--unsafely-treat-insecure-origin-as-secure=http://published.realm', ], diff --git a/packages/matrix/tests/head-tags.spec.ts b/packages/matrix/tests/head-tags.spec.ts index 391e9537aa..c05bc0a1de 100644 --- a/packages/matrix/tests/head-tags.spec.ts +++ b/packages/matrix/tests/head-tags.spec.ts @@ -1,7 +1,7 @@ import { test, expect } from './fixtures'; import type { Page } from '@playwright/test'; import { randomUUID } from 'crypto'; -import { appURL } from '../helpers/isolated-realm-server'; +import { appURL, realmDomain } from '../helpers/isolated-realm-server'; import { clearLocalStorage, createRealm, @@ -82,7 +82,7 @@ test.describe('Head tags', () => { }) => { await publishDefaultRealm(page); - let publishedRealmURLString = `http://${user.username}.localhost:4205/new-workspace/index`; + let publishedRealmURLString = `http://${user.username}.${realmDomain}/new-workspace/index`; await page.goto(publishedRealmURLString); @@ -270,7 +270,7 @@ test.describe('Head tags', () => { await page.locator('[data-test-publish-button]').click(); await page.waitForSelector('[data-test-unpublish-button]'); - let publishedRealmURL = `http://${user.username}.localhost:4205/${realmName}/`; + let publishedRealmURL = `http://${user.username}.${realmDomain}/${realmName}/`; let defaultCardURL = `${publishedRealmURL}default-head-card.json`; await page.goto(defaultCardURL); diff --git a/packages/matrix/tests/host-mode.spec.ts b/packages/matrix/tests/host-mode.spec.ts index 00c5316a63..15fcb79f72 100644 --- a/packages/matrix/tests/host-mode.spec.ts +++ b/packages/matrix/tests/host-mode.spec.ts @@ -6,7 +6,7 @@ import { postCardSource, waitUntil, } from '../helpers'; -import { appURL } from '../helpers/isolated-realm-server'; +import { appURL, realmDomain } from '../helpers/isolated-realm-server'; import { randomUUID } from 'crypto'; test.describe('Host mode', () => { @@ -185,10 +185,10 @@ test.describe('Host mode', () => { await page.reload(); await page.locator('[data-test-host-mode-isolated]').waitFor(); - publishedRealmURL = `http://published.localhost:4205/${username}/${realmName}/`; + publishedRealmURL = `http://published.${realmDomain}/${username}/${realmName}/`; await page.evaluate( - async ({ realmURL, publishedRealmURL }) => { + async ({ realmURL, publishedRealmURL, serverOrigin }) => { let sessions = JSON.parse( window.localStorage.getItem('boxel-session') ?? '{}', ); @@ -197,7 +197,7 @@ test.describe('Host mode', () => { throw new Error(`No session token found for ${realmURL}`); } - let response = await fetch('http://localhost:4205/_publish-realm', { + let response = await fetch(`${serverOrigin}/_publish-realm`, { method: 'POST', headers: { Accept: 'application/json', @@ -216,13 +216,13 @@ test.describe('Host mode', () => { return response.json(); }, - { realmURL, publishedRealmURL }, + { realmURL, publishedRealmURL, serverOrigin: serverIndexUrl }, ); publishedCardURL = `${publishedRealmURL}index.json`; publishedWhitePaperCardURL = `${publishedRealmURL}white-paper.json`; publishedMyCardURL = `${publishedRealmURL}my-card.json`; - connectRouteURL = `http://localhost:4205/connect/${encodeURIComponent( + connectRouteURL = `${serverIndexUrl}/connect/${encodeURIComponent( publishedRealmURL, )}`; @@ -322,7 +322,7 @@ test.describe('Host mode', () => { page, }) => { let response = await page.goto( - 'http://localhost:4205/connect/http%3A%2F%2Fexample.com', + `${serverIndexUrl}/connect/http%3A%2F%2Fexample.com`, ); expect(response?.status()).toBe(404); diff --git a/packages/matrix/tests/publish-realm.spec.ts b/packages/matrix/tests/publish-realm.spec.ts index 2d5e1eeed7..d1e63302ba 100644 --- a/packages/matrix/tests/publish-realm.spec.ts +++ b/packages/matrix/tests/publish-realm.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from './fixtures'; import type { Page } from '@playwright/test'; -import { appURL } from '../helpers/isolated-realm-server'; +import { appURL, realmDomain } from '../helpers/isolated-realm-server'; import { clearLocalStorage, createRealm, @@ -60,11 +60,11 @@ test.describe('Publish realm', () => { await newTab.waitForLoadState(); await expect(newTab).toHaveURL( - `http://${user.username}.localhost:4205/new-workspace/`, + `http://${user.username}.${realmDomain}/new-workspace/`, ); await expect( newTab.locator( - `[data-test-card="http://${user.username}.localhost:4205/new-workspace/index"]`, + `[data-test-card="http://${user.username}.${realmDomain}/new-workspace/index"]`, ), ).toBeVisible(); await newTab.close(); @@ -119,11 +119,11 @@ test.describe('Publish realm', () => { await newTab.waitForLoadState(); await expect(newTab).toHaveURL( - 'http://acceptable-subdomain.localhost:4205/', + `http://acceptable-subdomain.${realmDomain}/`, ); await expect( newTab.locator( - '[data-test-card="http://acceptable-subdomain.localhost:4205/index"]', + `[data-test-card="http://acceptable-subdomain.${realmDomain}/index"]`, ), ).toBeVisible(); await newTab.close(); @@ -251,7 +251,7 @@ test.describe('Publish realm', () => { await newTab.waitForLoadState(); await expect(newTab).toHaveURL( - `http://${user.username}.localhost:4205/new-workspace/`, + `http://${user.username}.${realmDomain}/new-workspace/`, ); await newTab.close(); await page.bringToFront(); @@ -281,7 +281,7 @@ test.describe('Publish realm', () => { await newTab.waitForLoadState(); await expect(newTab).toHaveURL( - `http://${user.username}.localhost:4205/new-workspace/`, + `http://${user.username}.${realmDomain}/new-workspace/`, ); await newTab.close(); await page.bringToFront(); diff --git a/packages/matrix/tests/registration-with-token.spec.ts b/packages/matrix/tests/registration-with-token.spec.ts index 498b60faa3..0f6afc8831 100644 --- a/packages/matrix/tests/registration-with-token.spec.ts +++ b/packages/matrix/tests/registration-with-token.spec.ts @@ -253,7 +253,7 @@ test.describe('User Registration w/ Token', () => { APP_BOXEL_REALMS_EVENT_TYPE, ); expect(realms).toEqual({ - realms: [`http://localhost:4205/${firstUser.username}/personal/`], + realms: [`${serverIndexUrl}/${firstUser.username}/personal/`], }); }); diff --git a/packages/matrix/tests/skills.spec.ts b/packages/matrix/tests/skills.spec.ts index 629d521d22..bac4349aed 100644 --- a/packages/matrix/tests/skills.spec.ts +++ b/packages/matrix/tests/skills.spec.ts @@ -50,15 +50,15 @@ test.describe('Skills', () => { ).toContainClass('checked'); } - const environmentSkillCardId = `http://localhost:4205/skills/Skill/boxel-environment`; + const serverIndexUrl = new URL(appURL).origin; + const environmentSkillCardId = `${serverIndexUrl}/skills/Skill/boxel-environment`; const defaultSkillCardsForCodeMode = [ - `http://localhost:4205/skills/Skill/boxel-development`, + `${serverIndexUrl}/skills/Skill/boxel-development`, environmentSkillCardId, ]; const skillCard1 = `${appURL}/skill-pirate-speak`; const skillCard2 = `${appURL}/skill-seo`; const skillCard3 = `${appURL}/skill-card-title-editing`; - const serverIndexUrl = new URL(appURL).origin; test(`it can attach skill cards and toggle activation`, async ({ page }) => { await login(page, firstUser.username, firstUser.password, { url: appURL }); diff --git a/packages/realm-server/scripts/start-base.sh b/packages/realm-server/scripts/start-base.sh index 034133a85e..2f9a73ee0b 100755 --- a/packages/realm-server/scripts/start-base.sh +++ b/packages/realm-server/scripts/start-base.sh @@ -1,7 +1,9 @@ #! /bin/sh SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)" . "$SCRIPTS_DIR/wait-for-pg.sh" +. "$SCRIPTS_DIR/ensure-traefik.sh" +ensure_traefik wait_for_postgres if [ -z "$MATRIX_REGISTRATION_SHARED_SECRET" ]; then @@ -9,27 +11,47 @@ if [ -z "$MATRIX_REGISTRATION_SHARED_SECRET" ]; then export MATRIX_REGISTRATION_SHARED_SECRET fi -PRERENDER_URL="${PRERENDER_URL:-http://localhost:4221}" +# Environment-mode configuration +if [ -n "$BOXEL_ENVIRONMENT" ]; then + ENV_SLUG=$(echo "$BOXEL_ENVIRONMENT" | tr '[:upper:]' '[:lower:]' | sed 's|/|-|g; s|[^a-z0-9-]||g; s|-\+|-|g; s|^-\|-$||g') + REALM_BASE_URL="http://realm-server.${ENV_SLUG}.localhost" + REALM_PORT=0 + REALMS_ROOT="./realms/${ENV_SLUG}" + PGDATABASE_VAL="boxel_${ENV_SLUG}" + MATRIX_URL_VAL="http://matrix.${ENV_SLUG}.localhost" + PRERENDER_URL="${PRERENDER_URL:-http://prerender.${ENV_SLUG}.localhost}" + WORKER_MANAGER_ARG="--workerManagerUrl=http://worker.${ENV_SLUG}.localhost" + # Ensure per-environment database exists + sh "$SCRIPTS_DIR/../../../scripts/ensure-branch-db.sh" "$ENV_SLUG" +else + REALM_BASE_URL="http://localhost:4201" + REALM_PORT=4201 + REALMS_ROOT="./realms/localhost_4201_base" + PGDATABASE_VAL="boxel_base" + MATRIX_URL_VAL="http://localhost:8008" + PRERENDER_URL="${PRERENDER_URL:-http://localhost:4221}" + WORKER_MANAGER_ARG="$1" +fi NODE_ENV=development \ NODE_NO_WARNINGS=1 \ PGPORT=5435 \ - PGDATABASE=boxel_base \ + PGDATABASE="${PGDATABASE_VAL}" \ REALM_SERVER_SECRET_SEED="mum's the word" \ REALM_SECRET_SEED="shhh! it's a secret" \ GRAFANA_SECRET="shhh! it's a secret" \ - MATRIX_URL=http://localhost:8008 \ + MATRIX_URL="${MATRIX_URL_VAL}" \ REALM_SERVER_MATRIX_USERNAME=realm_server \ ts-node \ --transpileOnly main \ - --port=4201 \ - --matrixURL='http://localhost:8008' \ - --realmsRootPath='./realms/localhost_4201_base' \ + --port="${REALM_PORT}" \ + --matrixURL="${MATRIX_URL_VAL}" \ + --realmsRootPath="${REALMS_ROOT}" \ --prerendererUrl="${PRERENDER_URL}" \ --migrateDB \ - $1 \ + $WORKER_MANAGER_ARG \ \ --path='../base' \ --username='base_realm' \ --fromUrl='https://cardstack.com/base/' \ - --toUrl='http://localhost:4201/base/' + --toUrl="${REALM_BASE_URL}/base/" diff --git a/packages/realm-server/scripts/start-services-for-host-tests.sh b/packages/realm-server/scripts/start-services-for-host-tests.sh index 6b734859b7..7368744a7f 100755 --- a/packages/realm-server/scripts/start-services-for-host-tests.sh +++ b/packages/realm-server/scripts/start-services-for-host-tests.sh @@ -46,6 +46,37 @@ done export CATALOG_REALM_PATH="$CATALOG_TEMP_PATH" +# Environment-mode configuration +if [ -n "$BOXEL_ENVIRONMENT" ]; then + . "$SCRIPTS_DIR/ensure-traefik.sh" + ensure_traefik + + ENV_SLUG=$(echo "$BOXEL_ENVIRONMENT" | tr '[:upper:]' '[:lower:]' | sed 's|/|-|g; s|[^a-z0-9-]||g; s|-\+|-|g; s|^-\|-$||g') + REALM_HOST="realm-server.${ENV_SLUG}.localhost" + REALM_TEST_HOST="realm-test.${ENV_SLUG}.localhost" + READY_PATH="_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson" + + PHASE1_URLS="http-get://${REALM_HOST}/base/${READY_PATH}|http://matrix.${ENV_SLUG}.localhost|http://localhost:5001|http://icons.${ENV_SLUG}.localhost" + PHASE2_URLS="http-get://${REALM_TEST_HOST}/node-test/${READY_PATH}" + + # Pre-setup: ensure Postgres, database, and migrations are ready before + # starting the realm server (follows the same pattern as start-all.sh). + REPO_ROOT="$(cd "$SCRIPTS_DIR/../../.." && pwd)" + export PGPORT="${PGPORT:-5435}" + export PGDATABASE="${PGDATABASE:-boxel_${ENV_SLUG}}" + + ./scripts/start-pg.sh + echo "Waiting for Postgres to accept connections..." + until docker exec boxel-pg pg_isready -U postgres >/dev/null 2>&1; do sleep 1; done + "$REPO_ROOT/scripts/ensure-branch-db.sh" "$ENV_SLUG" + echo "Running database migrations..." + pnpm migrate + ./scripts/start-matrix.sh +else + PHASE1_URLS="http-get://localhost:4201/base/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson|http://localhost:8008|http://localhost:5001|http://localhost:4206" + PHASE2_URLS="http-get://localhost:4202/node-test/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson" +fi + # Make host-test startup logs focus on indexing progress rather than per-request noise. HOST_TEST_LOG_LEVELS="${HOST_TEST_LOG_LEVELS:-*=info,realm:requests=warn,realm-index-updater=debug,index-runner=debug,index-perf=debug,index-writer=debug,worker=debug,worker-manager=debug}" SKIP_CATALOG="${SKIP_CATALOG:-}" @@ -63,7 +94,7 @@ WAIT_ON_TIMEOUT=900000 \ NODE_NO_WARNINGS=1 \ start-server-and-test \ 'run-p -ln start:pg start:prerender-dev start:prerender-manager-dev start:matrix start:smtp start:worker-development start:development' \ - 'http-get://localhost:4201/base/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson|http://localhost:8008|http://localhost:5001|http://localhost:4206' \ + "$PHASE1_URLS" \ 'run-p -ln start:worker-test start:test-realms' \ - 'http-get://localhost:4202/node-test/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson' \ + "$PHASE2_URLS" \ 'wait' diff --git a/packages/realm-server/scripts/start-services-for-matrix-tests.sh b/packages/realm-server/scripts/start-services-for-matrix-tests.sh index 914abe5553..f0d817c044 100755 --- a/packages/realm-server/scripts/start-services-for-matrix-tests.sh +++ b/packages/realm-server/scripts/start-services-for-matrix-tests.sh @@ -1,13 +1,56 @@ #! /bin/sh +SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)" + pnpm --dir=../skills-realm skills:setup + # There is a race condition starting up the servers that setting up the # submission realm triggers which triggers the start-development.sh script to # SIGTERM. currently we don't need the submission realm for host tests to -# skipping that. but this issue needs to be fixed. +# skipping that. but this issue needs to be fixed. # ALSO i really think if we want a submission realm in our matrix tests then # we probably need to add that via the isolated realm server--not here... + +# Environment-mode configuration +if [ -n "$BOXEL_ENVIRONMENT" ]; then + . "$SCRIPTS_DIR/ensure-traefik.sh" + ensure_traefik + + ENV_SLUG=$(echo "$BOXEL_ENVIRONMENT" | tr '[:upper:]' '[:lower:]' | sed 's|/|-|g; s|[^a-z0-9-]||g; s|-\+|-|g; s|^-\|-$||g') + REALM_HOST="realm-server.${ENV_SLUG}.localhost" + READINESS_URL="http-get://${REALM_HOST}/base/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson" + ICONS_URL="http://icons.${ENV_SLUG}.localhost" + + # Pre-setup: ensure Postgres, database, and migrations are ready before + # starting the realm server (follows the same pattern as start-all.sh). + REPO_ROOT="$(cd "$SCRIPTS_DIR/../../.." && pwd)" + export PGPORT="${PGPORT:-5435}" + export PGDATABASE="${PGDATABASE:-boxel_${ENV_SLUG}}" + + ./scripts/start-pg.sh + echo "Waiting for Postgres to accept connections..." + until docker exec boxel-pg pg_isready -U postgres >/dev/null 2>&1; do sleep 1; done + "$REPO_ROOT/scripts/ensure-branch-db.sh" "$ENV_SLUG" + echo "Running database migrations..." + pnpm migrate + ./scripts/start-matrix.sh + + # Start icons server in background (env-aware: dynamic port + Traefik registration). + # In non-env mode, icons is expected to be started externally (e.g. CI does this). + sh "$SCRIPTS_DIR/start-icons.sh" & + ICONS_PID=$! + cleanup_icons_server() { + if [ -n "$ICONS_PID" ]; then + kill "$ICONS_PID" >/dev/null 2>&1 || true + fi + } + trap cleanup_icons_server EXIT INT TERM +else + READINESS_URL="http-get://localhost:4201/base/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson" + ICONS_URL="http://localhost:4206" +fi + WAIT_ON_TIMEOUT=600000 NODE_NO_WARNINGS=1 SKIP_SUBMISSION=true \ start-server-and-test \ 'run-p -ln start:pg start:prerender-dev start:prerender-manager-dev start:worker-base start:base' \ - 'http-get://localhost:4201/base/_readiness-check?acceptHeader=application%2Fvnd.api%2Bjson|http://localhost:4206' \ + "${READINESS_URL}|${ICONS_URL}" \ 'wait' diff --git a/packages/realm-server/scripts/start-worker-base.sh b/packages/realm-server/scripts/start-worker-base.sh index abe5b3a27e..188e520a60 100755 --- a/packages/realm-server/scripts/start-worker-base.sh +++ b/packages/realm-server/scripts/start-worker-base.sh @@ -2,24 +2,42 @@ SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)" . "$SCRIPTS_DIR/wait-for-pg.sh" . "$SCRIPTS_DIR/wait-for-prerender.sh" +. "$SCRIPTS_DIR/ensure-traefik.sh" +ensure_traefik wait_for_postgres -PRERENDER_URL="${PRERENDER_URL:-http://localhost:4222}" + +# Environment-mode configuration +if [ -n "$BOXEL_ENVIRONMENT" ]; then + ENV_SLUG=$(echo "$BOXEL_ENVIRONMENT" | tr '[:upper:]' '[:lower:]' | sed 's|/|-|g; s|[^a-z0-9-]||g; s|-\+|-|g; s|^-\|-$||g') + REALM_BASE_URL="http://realm-server.${ENV_SLUG}.localhost" + WORKER_PORT=0 + PGDATABASE_VAL="boxel_${ENV_SLUG}" + PRERENDER_URL="${PRERENDER_URL:-http://prerender-mgr.${ENV_SLUG}.localhost}" + MATRIX_URL_VAL="http://matrix.${ENV_SLUG}.localhost" +else + REALM_BASE_URL="http://localhost:4201" + WORKER_PORT=4213 + PGDATABASE_VAL="boxel_base" + PRERENDER_URL="${PRERENDER_URL:-http://localhost:4222}" + MATRIX_URL_VAL="http://localhost:8008" +fi + wait_for_prerender "$PRERENDER_URL" NODE_ENV=development \ NODE_NO_WARNINGS=1 \ NODE_OPTIONS="${NODE_OPTIONS:---max-old-space-size=4096}" \ PGPORT=5435 \ - PGDATABASE=boxel_base \ + PGDATABASE="${PGDATABASE_VAL}" \ REALM_SECRET_SEED="shhh! it's a secret" \ REALM_SERVER_MATRIX_USERNAME=realm_server \ LOW_CREDIT_THRESHOLD=2000 \ ts-node \ --transpileOnly worker-manager \ - --port=4213 \ - --matrixURL='http://localhost:8008' \ + --port="${WORKER_PORT}" \ + --matrixURL="${MATRIX_URL_VAL}" \ --prerendererUrl="${PRERENDER_URL}" \ \ --fromUrl='https://cardstack.com/base/' \ - --toUrl='http://localhost:4201/base/' + --toUrl="${REALM_BASE_URL}/base/"