From 3b0c796ec7ee996089afc691cb8891b19bca4882 Mon Sep 17 00:00:00 2001 From: dirtydishes Date: Mon, 27 Apr 2026 04:13:47 -0400 Subject: [PATCH] refactor docker deployment build contexts --- deployment/docker/.env.example | 2 + deployment/docker/Dockerfile.ingest-options | 7 +- deployment/docker/Dockerfile.service | 7 +- deployment/docker/Dockerfile.web | 7 +- deployment/docker/README.md | 35 ++- deployment/docker/docker-compose.yml | 20 +- deployment/docker/workspace-root/bun.lock | 276 ++++++++++++++++++ deployment/docker/workspace-root/package.json | 20 ++ .../docker/workspace-root/tsconfig.base.json | 13 + 9 files changed, 365 insertions(+), 22 deletions(-) create mode 100644 deployment/docker/workspace-root/bun.lock create mode 100644 deployment/docker/workspace-root/package.json create mode 100644 deployment/docker/workspace-root/tsconfig.base.json diff --git a/deployment/docker/.env.example b/deployment/docker/.env.example index 3d305fe..58b5986 100644 --- a/deployment/docker/.env.example +++ b/deployment/docker/.env.example @@ -11,6 +11,8 @@ NPM_SHARED_NETWORK=npm-shared # Recommended with NPM on the same Docker network: # app. -> web:3000 # api. -> api:4000 +# Leave NEXT_PUBLIC_API_URL empty to use same-origin mode +# (app. serves UI and proxies API paths to api:4000). NEXT_PUBLIC_API_URL=https://api.example.com NEXT_PUBLIC_NBBO_MAX_AGE_MS=1000 diff --git a/deployment/docker/Dockerfile.ingest-options b/deployment/docker/Dockerfile.ingest-options index 0a231cd..156dc1d 100644 --- a/deployment/docker/Dockerfile.ingest-options +++ b/deployment/docker/Dockerfile.ingest-options @@ -6,7 +6,12 @@ ENV NODE_ENV=production ENV VIRTUAL_ENV=/opt/ingest-options-venv ENV PATH="${VIRTUAL_ENV}/bin:${PATH}" -COPY . . +COPY --from=workspace package.json ./package.json +COPY --from=workspace bun.lock ./bun.lock +COPY --from=workspace tsconfig.base.json ./tsconfig.base.json +COPY --from=services . ./services +COPY --from=packages . ./packages +COPY --from=apps . ./apps RUN apt-get update \ && apt-get install -y --no-install-recommends python3 python3-pip python3-venv \ diff --git a/deployment/docker/Dockerfile.service b/deployment/docker/Dockerfile.service index 4c32bbe..bc48d2d 100644 --- a/deployment/docker/Dockerfile.service +++ b/deployment/docker/Dockerfile.service @@ -4,7 +4,12 @@ WORKDIR /app ENV NODE_ENV=production -COPY . . +COPY --from=workspace package.json ./package.json +COPY --from=workspace bun.lock ./bun.lock +COPY --from=workspace tsconfig.base.json ./tsconfig.base.json +COPY --from=services . ./services +COPY --from=packages . ./packages +COPY --from=apps . ./apps RUN bun install --frozen-lockfile diff --git a/deployment/docker/Dockerfile.web b/deployment/docker/Dockerfile.web index 038e0a4..6956335 100644 --- a/deployment/docker/Dockerfile.web +++ b/deployment/docker/Dockerfile.web @@ -10,7 +10,12 @@ ENV NEXT_TELEMETRY_DISABLED=1 ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} ENV NEXT_PUBLIC_NBBO_MAX_AGE_MS=${NEXT_PUBLIC_NBBO_MAX_AGE_MS} -COPY . . +COPY --from=workspace package.json ./package.json +COPY --from=workspace bun.lock ./bun.lock +COPY --from=workspace tsconfig.base.json ./tsconfig.base.json +COPY --from=services . ./services +COPY --from=packages . ./packages +COPY --from=apps . ./apps RUN bun install --frozen-lockfile RUN bun run --cwd apps/web build diff --git a/deployment/docker/README.md b/deployment/docker/README.md index 7df8dd6..de7c805 100644 --- a/deployment/docker/README.md +++ b/deployment/docker/README.md @@ -52,7 +52,8 @@ Important defaults: - `NATS_URL`, `CLICKHOUSE_URL`, and `REDIS_URL` should stay on the internal container hostnames unless you intentionally split infra out. - `OPTIONS_INGEST_ADAPTER=synthetic` and `EQUITIES_INGEST_ADAPTER=synthetic` are the safest first boot settings. - `NPM_SHARED_NETWORK=npm-shared` is the recommended external Docker network name for NPM and this stack. -- `NEXT_PUBLIC_API_URL=https://api.example.com` is the recommended production shape when using NPM with two subdomains. +- `NEXT_PUBLIC_API_URL=https://api.example.com` uses a two-subdomain setup (`app` + `api`). +- `NEXT_PUBLIC_API_URL=` (empty) uses same-origin mode where the app host also proxies API paths to `api:4000`. 3. Build and start the stack: @@ -98,11 +99,13 @@ If you want to use a different network name, set `NPM_SHARED_NETWORK` in `.env` 6. Create these NPM proxy hosts: -- `app.example.com` -> forward to `web`, port `3000` -- `api.example.com` -> forward to `api`, port `4000` +- `app.example.com` -> forward to `web` (or `islandflow-vps-web-1`), port `3000` +- `api.example.com` -> forward to `api` (or `islandflow-vps-api-1`), port `4000` For the API host, enable websocket support. +If NPM is attached to multiple Docker networks and another stack also has an `api` container alias, prefer the explicit container name (`islandflow-vps-api-1`) to avoid DNS collisions. + 7. Open the app: - `https://app.example.com/` @@ -161,19 +164,24 @@ If IBKR is running somewhere else, change: ## NPM routing -Recommended proxy hosts: +The Islandflow stack expects an external NPM instance on the shared Docker network. The dedicated NPM stack now lives in `../npm`. -- `app.` -> `web:3000` -- `api.` -> `api:4000` +Supported routing modes: -The web app should be built with `NEXT_PUBLIC_API_URL=https://api.` so browser REST and websocket traffic goes straight to the API host through NPM. +1. Two-subdomain mode + - `app.` -> `web:3000` + - `api.` -> `api:4000` + - Build web with `NEXT_PUBLIC_API_URL=https://api.`. -The API host needs websocket support enabled because the app uses `/ws/*` endpoints for live streams. +2. Same-origin fallback mode + - Build web with `NEXT_PUBLIC_API_URL=` (empty). + - Keep `app.` -> web. + - Add path-based proxy rules on `app.` for API routes to `api:4000`: + - `/ws/*`, `/replay/*`, `/prints/*`, `/joins/*`, `/nbbo/*`, `/dark/*`, `/flow/*`, `/candles/*` -Because `web` and `api` are both attached to the shared user-defined network, NPM can target them directly by container DNS name: +Use websocket support on whichever host serves `/ws/*`. -- `web` -- `api` +If NPM is on multiple networks and names collide (for example another stack also exposes `api`), target explicit container names (`islandflow-vps-api-1`, `islandflow-vps-web-1`) instead of generic aliases. ## Updating the deployment @@ -227,6 +235,7 @@ Only use `-v` if you intentionally want to wipe ClickHouse, Redis, and JetStream - The root `.env.example` still contains a `REPLAY_ENABLED` comment, but the current replay service does not read that variable. Use the Compose replay profile instead. - This stack does not publish `web` or `api` to host ports. NPM must be able to resolve `web` and `api` over the shared user-defined network from `NPM_SHARED_NETWORK`. +- If NPM is attached to more than one application network, generic upstream aliases like `api` can resolve to the wrong stack. Prefer explicit container names in NPM upstream settings. - Some hosts disable IPv6 inside containers; the bundled ClickHouse config pins `listen_host` to `0.0.0.0` so the API can reach ClickHouse reliably over Docker networking. - The stack assumes a single-node VPS deployment. If you later split infra or add external managed services, update the three core connection URLs in `.env`. @@ -235,6 +244,6 @@ Only use `-v` if you intentionally want to wipe ClickHouse, Redis, and JetStream After NPM is wired up: - `https://app./` should load the UI. -- Browser network requests from the UI should target `https://api./...`. -- Live feeds should connect over `wss://api./ws/...`. +- In two-subdomain mode, browser requests should target `https://api./...` and live feeds should use `wss://api./ws/...`. +- In same-origin mode, browser requests should target `https://app./...` for API paths and live feeds should use `wss://app./ws/...`. - `docker compose ps` should show no service publishing host port `80`. diff --git a/deployment/docker/docker-compose.yml b/deployment/docker/docker-compose.yml index 08764de..a3ed7a4 100644 --- a/deployment/docker/docker-compose.yml +++ b/deployment/docker/docker-compose.yml @@ -1,9 +1,17 @@ name: islandflow-vps +x-build-contexts: &build-contexts + context: . + additional_contexts: + workspace: ./workspace-root + apps: ../../apps + services: ../../services + packages: ../../packages + x-service-common: &service-common build: - context: ../.. - dockerfile: deployment/docker/Dockerfile.service + <<: *build-contexts + dockerfile: Dockerfile.service env_file: - ./.env restart: unless-stopped @@ -21,8 +29,8 @@ x-service-common: &service-common services: web: build: - context: ../.. - dockerfile: deployment/docker/Dockerfile.web + <<: *build-contexts + dockerfile: Dockerfile.web args: NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-} NEXT_PUBLIC_NBBO_MAX_AGE_MS: ${NEXT_PUBLIC_NBBO_MAX_AGE_MS:-1000} @@ -82,8 +90,8 @@ services: ingest-options: build: - context: ../.. - dockerfile: deployment/docker/Dockerfile.ingest-options + <<: *build-contexts + dockerfile: Dockerfile.ingest-options env_file: - ./.env restart: unless-stopped diff --git a/deployment/docker/workspace-root/bun.lock b/deployment/docker/workspace-root/bun.lock new file mode 100644 index 0000000..d6e99c6 --- /dev/null +++ b/deployment/docker/workspace-root/bun.lock @@ -0,0 +1,276 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "islandflow", + "devDependencies": { + "typescript-language-server": "^5.1.3", + }, + }, + "apps/web": { + "name": "@islandflow/web", + "dependencies": { + "@islandflow/types": "workspace:*", + "lightweight-charts": "^4.2.0", + "next": "^14.2.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + }, + "devDependencies": { + "@types/node": "^20.14.10", + "@types/react": "^18.3.3", + "typescript": "^5.5.4", + }, + }, + "packages/bus": { + "name": "@islandflow/bus", + "dependencies": { + "nats": "^2.24.0", + }, + }, + "packages/config": { + "name": "@islandflow/config", + "dependencies": { + "zod": "^3.23.8", + }, + }, + "packages/observability": { + "name": "@islandflow/observability", + }, + "packages/storage": { + "name": "@islandflow/storage", + "dependencies": { + "@clickhouse/client": "^0.2.6", + "@islandflow/types": "workspace:*", + }, + }, + "packages/types": { + "name": "@islandflow/types", + "dependencies": { + "zod": "^3.23.8", + }, + }, + "services/api": { + "name": "@islandflow/api", + "dependencies": { + "@islandflow/bus": "workspace:*", + "@islandflow/config": "workspace:*", + "@islandflow/observability": "workspace:*", + "@islandflow/storage": "workspace:*", + "@islandflow/types": "workspace:*", + "redis": "^5.10.0", + "zod": "^3.23.8", + }, + }, + "services/candles": { + "name": "@islandflow/candles", + "dependencies": { + "@islandflow/bus": "workspace:*", + "@islandflow/config": "workspace:*", + "@islandflow/observability": "workspace:*", + "@islandflow/storage": "workspace:*", + "@islandflow/types": "workspace:*", + "redis": "^5.10.0", + "zod": "^3.23.8", + }, + }, + "services/compute": { + "name": "@islandflow/compute", + "dependencies": { + "@islandflow/bus": "workspace:*", + "@islandflow/config": "workspace:*", + "@islandflow/observability": "workspace:*", + "@islandflow/storage": "workspace:*", + "@islandflow/types": "workspace:*", + "redis": "^5.10.0", + "zod": "^3.23.8", + }, + }, + "services/eod-enricher": { + "name": "@islandflow/eod-enricher", + "dependencies": { + "@islandflow/config": "workspace:*", + "@islandflow/observability": "workspace:*", + }, + }, + "services/ingest-equities": { + "name": "@islandflow/ingest-equities", + "dependencies": { + "@islandflow/bus": "workspace:*", + "@islandflow/config": "workspace:*", + "@islandflow/observability": "workspace:*", + "@islandflow/storage": "workspace:*", + "@islandflow/types": "workspace:*", + "ws": "^8.18.3", + "zod": "^3.23.8", + }, + }, + "services/ingest-options": { + "name": "@islandflow/ingest-options", + "dependencies": { + "@islandflow/bus": "workspace:*", + "@islandflow/config": "workspace:*", + "@islandflow/observability": "workspace:*", + "@islandflow/storage": "workspace:*", + "@islandflow/types": "workspace:*", + "@msgpack/msgpack": "^3.1.3", + "ws": "^8.18.3", + "zod": "^3.23.8", + }, + }, + "services/refdata": { + "name": "@islandflow/refdata", + "dependencies": { + "@islandflow/config": "workspace:*", + "@islandflow/observability": "workspace:*", + }, + }, + "services/replay": { + "name": "@islandflow/replay", + "dependencies": { + "@islandflow/bus": "workspace:*", + "@islandflow/config": "workspace:*", + "@islandflow/observability": "workspace:*", + "@islandflow/storage": "workspace:*", + "@islandflow/types": "workspace:*", + "zod": "^3.23.8", + }, + }, + }, + "packages": { + "@clickhouse/client": ["@clickhouse/client@0.2.10", "", { "dependencies": { "@clickhouse/client-common": "0.2.10" } }, "sha512-ZwBgzjEAFN/ogS0ym5KHVbR7Hx/oYCX01qGp2baEyfN2HM73kf/7Vp3GvMHWRy+zUXISONEtFv7UTViOXnmFrg=="], + + "@clickhouse/client-common": ["@clickhouse/client-common@0.2.10", "", {}, "sha512-BvTY0IXS96y9RUeNCpKL4HUzHmY80L0lDcGN0lmUD6zjOqYMn78+xyHYJ/AIAX7JQsc+/KwFt2soZutQTKxoGQ=="], + + "@islandflow/api": ["@islandflow/api@workspace:services/api"], + + "@islandflow/bus": ["@islandflow/bus@workspace:packages/bus"], + + "@islandflow/candles": ["@islandflow/candles@workspace:services/candles"], + + "@islandflow/compute": ["@islandflow/compute@workspace:services/compute"], + + "@islandflow/config": ["@islandflow/config@workspace:packages/config"], + + "@islandflow/eod-enricher": ["@islandflow/eod-enricher@workspace:services/eod-enricher"], + + "@islandflow/ingest-equities": ["@islandflow/ingest-equities@workspace:services/ingest-equities"], + + "@islandflow/ingest-options": ["@islandflow/ingest-options@workspace:services/ingest-options"], + + "@islandflow/observability": ["@islandflow/observability@workspace:packages/observability"], + + "@islandflow/refdata": ["@islandflow/refdata@workspace:services/refdata"], + + "@islandflow/replay": ["@islandflow/replay@workspace:services/replay"], + + "@islandflow/storage": ["@islandflow/storage@workspace:packages/storage"], + + "@islandflow/types": ["@islandflow/types@workspace:packages/types"], + + "@islandflow/web": ["@islandflow/web@workspace:apps/web"], + + "@msgpack/msgpack": ["@msgpack/msgpack@3.1.3", "", {}, "sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA=="], + + "@next/env": ["@next/env@14.2.35", "", {}, "sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ=="], + + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@14.2.33", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA=="], + + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@14.2.33", "", { "os": "darwin", "cpu": "x64" }, "sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA=="], + + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@14.2.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw=="], + + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@14.2.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg=="], + + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@14.2.33", "", { "os": "linux", "cpu": "x64" }, "sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg=="], + + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@14.2.33", "", { "os": "linux", "cpu": "x64" }, "sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA=="], + + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@14.2.33", "", { "os": "win32", "cpu": "arm64" }, "sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ=="], + + "@next/swc-win32-ia32-msvc": ["@next/swc-win32-ia32-msvc@14.2.33", "", { "os": "win32", "cpu": "ia32" }, "sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q=="], + + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@14.2.33", "", { "os": "win32", "cpu": "x64" }, "sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg=="], + + "@redis/bloom": ["@redis/bloom@5.10.0", "", { "peerDependencies": { "@redis/client": "^5.10.0" } }, "sha512-doIF37ob+l47n0rkpRNgU8n4iacBlKM9xLiP1LtTZTvz8TloJB8qx/MgvhMhKdYG+CvCY2aPBnN2706izFn/4A=="], + + "@redis/client": ["@redis/client@5.10.0", "", { "dependencies": { "cluster-key-slot": "1.1.2" } }, "sha512-JXmM4XCoso6C75Mr3lhKA3eNxSzkYi3nCzxDIKY+YOszYsJjuKbFgVtguVPbLMOttN4iu2fXoc2BGhdnYhIOxA=="], + + "@redis/json": ["@redis/json@5.10.0", "", { "peerDependencies": { "@redis/client": "^5.10.0" } }, "sha512-B2G8XlOmTPUuZtD44EMGbtoepQG34RCDXLZbjrtON1Djet0t5Ri7/YPXvL9aomXqP8lLTreaprtyLKF4tmXEEA=="], + + "@redis/search": ["@redis/search@5.10.0", "", { "peerDependencies": { "@redis/client": "^5.10.0" } }, "sha512-3SVcPswoSfp2HnmWbAGUzlbUPn7fOohVu2weUQ0S+EMiQi8jwjL+aN2p6V3TI65eNfVsJ8vyPvqWklm6H6esmg=="], + + "@redis/time-series": ["@redis/time-series@5.10.0", "", { "peerDependencies": { "@redis/client": "^5.10.0" } }, "sha512-cPkpddXH5kc/SdRhF0YG0qtjL+noqFT0AcHbQ6axhsPsO7iqPi1cjxgdkE9TNeKiBUUdCaU1DbqkR/LzbzPBhg=="], + + "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], + + "@swc/helpers": ["@swc/helpers@0.5.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "tslib": "^2.4.0" } }, "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A=="], + + "@types/node": ["@types/node@20.19.27", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug=="], + + "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], + + "@types/react": ["@types/react@18.3.27", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w=="], + + "busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001761", "", {}, "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g=="], + + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + + "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "fancy-canvas": ["fancy-canvas@2.1.0", "", {}, "sha512-nifxXJ95JNLFR2NgRV4/MxVP45G9909wJTEKz5fg/TZS20JJZA6hfgRVh/bC9bwl2zBtBNcYPjiBE4njQHVBwQ=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "lightweight-charts": ["lightweight-charts@4.2.3", "", { "dependencies": { "fancy-canvas": "2.1.0" } }, "sha512-5kS/2hY3wNYNzhnS8Gb+GAS07DX8GPF2YVDnd2NMC85gJVQ6RLU6YrXNgNJ6eg0AnWPwCnvaGtYmGky3HiLQEw=="], + + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "nats": ["nats@2.29.3", "", { "dependencies": { "nkeys.js": "1.1.0" } }, "sha512-tOQCRCwC74DgBTk4pWZ9V45sk4d7peoE2njVprMRCBXrhJ5q5cYM7i6W+Uvw2qUrcfOSnuisrX7bEx3b3Wx4QA=="], + + "next": ["next@14.2.35", "", { "dependencies": { "@next/env": "14.2.35", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "graceful-fs": "^4.2.11", "postcss": "8.4.31", "styled-jsx": "5.1.1" }, "optionalDependencies": { "@next/swc-darwin-arm64": "14.2.33", "@next/swc-darwin-x64": "14.2.33", "@next/swc-linux-arm64-gnu": "14.2.33", "@next/swc-linux-arm64-musl": "14.2.33", "@next/swc-linux-x64-gnu": "14.2.33", "@next/swc-linux-x64-musl": "14.2.33", "@next/swc-win32-arm64-msvc": "14.2.33", "@next/swc-win32-ia32-msvc": "14.2.33", "@next/swc-win32-x64-msvc": "14.2.33" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig=="], + + "nkeys.js": ["nkeys.js@1.1.0", "", { "dependencies": { "tweetnacl": "1.0.3" } }, "sha512-tB/a0shZL5UZWSwsoeyqfTszONTt4k2YS0tuQioMOD180+MbombYVgzDUYHlx+gejYK6rgf08n/2Df99WY0Sxg=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + + "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], + + "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], + + "redis": ["redis@5.10.0", "", { "dependencies": { "@redis/bloom": "5.10.0", "@redis/client": "5.10.0", "@redis/json": "5.10.0", "@redis/search": "5.10.0", "@redis/time-series": "5.10.0" } }, "sha512-0/Y+7IEiTgVGPrLFKy8oAEArSyEJkU0zvgV5xyi9NzNQ+SLZmyFbUsWIbgPcd4UdUh00opXGKlXJwMmsis5Byw=="], + + "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="], + + "styled-jsx": ["styled-jsx@5.1.1", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" } }, "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tweetnacl": ["tweetnacl@1.0.3", "", {}, "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "typescript-language-server": ["typescript-language-server@5.1.3", "", { "bin": { "typescript-language-server": "lib/cli.mjs" } }, "sha512-r+pAcYtWdN8tKlYZPwiiHNA2QPjXnI02NrW5Sf2cVM3TRtuQ3V9EKKwOxqwaQ0krsaEXk/CbN90I5erBuf84Vg=="], + + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + + "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + } +} diff --git a/deployment/docker/workspace-root/package.json b/deployment/docker/workspace-root/package.json new file mode 100644 index 0000000..0d570a9 --- /dev/null +++ b/deployment/docker/workspace-root/package.json @@ -0,0 +1,20 @@ +{ + "name": "islandflow", + "private": true, + "type": "module", + "workspaces": [ + "apps/*", + "services/*", + "packages/*" + ], + "scripts": { + "dev": "bun run scripts/dev.ts", + "dev:infra": "docker compose up", + "dev:infra:down": "docker compose down", + "dev:web": "bun --cwd=apps/web run dev", + "dev:services": "bun run scripts/dev-services.ts" + }, + "devDependencies": { + "typescript-language-server": "^5.1.3" + } +} diff --git a/deployment/docker/workspace-root/tsconfig.base.json b/deployment/docker/workspace-root/tsconfig.base.json new file mode 100644 index 0000000..f98f46a --- /dev/null +++ b/deployment/docker/workspace-root/tsconfig.base.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["ES2022"], + "strict": true, + "isolatedModules": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "noEmit": true + } +}