chore(build): add switchable bytelyst package source

This commit is contained in:
root 2026-05-05 19:47:41 +00:00
parent eac07dc3d9
commit 1bd0297066
14 changed files with 1294 additions and 418 deletions

1
.npmrc
View File

@ -1,4 +1,5 @@
@bytelyst:registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/ @bytelyst:registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/
//gitea.bytelyst.com/api/packages/ByteLyst/npm/:_authToken=${GITEA_NPM_TOKEN} //gitea.bytelyst.com/api/packages/ByteLyst/npm/:_authToken=${GITEA_NPM_TOKEN}
# Used only when BYTELYST_PACKAGE_SOURCE=gitea.
# Gitea returns Docker-internal tarball URLs (172.17.0.1:3300); rewrite host to the public URL # Gitea returns Docker-internal tarball URLs (172.17.0.1:3300); rewrite host to the public URL
replace-registry-host=always replace-registry-host=always

116
.pnpmfile.cjs Normal file
View File

@ -0,0 +1,116 @@
const fs = require('node:fs');
const path = require('node:path');
const PACKAGE_SCOPE = '@bytelyst/';
const PACKAGE_SOURCE = process.env.BYTELYST_PACKAGE_SOURCE || 'vendor';
const COMMON_PLAT_ROOT = process.env.BYTELYST_COMMON_PLAT_ROOT || '/opt/bytelyst/learning_ai_common_plat';
const COMMON_PLAT_PACKAGES_ROOT = path.join(COMMON_PLAT_ROOT, 'packages');
const VENDOR_PACKAGES_ROOT = path.join(__dirname, 'vendor', 'bytelyst');
const VERSION_CACHE = new Map();
let loggedSource = false;
function packageDirFor(name) {
return name.startsWith(PACKAGE_SCOPE) ? name.slice(PACKAGE_SCOPE.length) : null;
}
function pathIfPackageExists(rootDir, name) {
const packageDir = packageDirFor(name);
if (!packageDir) return null;
const candidate = path.join(rootDir, packageDir);
return fs.existsSync(path.join(candidate, 'package.json')) ? candidate : null;
}
function readPackageVersion(packagePath) {
if (VERSION_CACHE.has(packagePath)) {
return VERSION_CACHE.get(packagePath);
}
try {
const packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'), 'utf8'));
const version = packageJson.version || null;
VERSION_CACHE.set(packagePath, version);
return version;
} catch {
VERSION_CACHE.set(packagePath, null);
return null;
}
}
function resolveRegistryVersion(name) {
const commonPlatPath = pathIfPackageExists(COMMON_PLAT_PACKAGES_ROOT, name);
if (commonPlatPath) {
const version = readPackageVersion(commonPlatPath);
if (version) return version;
}
const vendorPath = pathIfPackageExists(VENDOR_PACKAGES_ROOT, name);
if (vendorPath) {
const version = readPackageVersion(vendorPath);
if (version) return version;
}
return null;
}
function resolveSpecifier(name) {
if (!name.startsWith(PACKAGE_SCOPE)) {
return null;
}
if (PACKAGE_SOURCE === 'common-plat') {
const packagePath = pathIfPackageExists(COMMON_PLAT_PACKAGES_ROOT, name);
return packagePath ? `file:${packagePath}` : null;
}
if (PACKAGE_SOURCE === 'gitea') {
const version = resolveRegistryVersion(name);
return version ?? null;
}
const vendorPath = pathIfPackageExists(VENDOR_PACKAGES_ROOT, name);
if (vendorPath) {
return `file:${vendorPath}`;
}
const commonPlatPath = pathIfPackageExists(COMMON_PLAT_PACKAGES_ROOT, name);
if (commonPlatPath) {
return `file:${commonPlatPath}`;
}
const version = resolveRegistryVersion(name);
return version ?? null;
}
function rewriteDependencySet(dependencies = {}) {
for (const dependencyName of Object.keys(dependencies)) {
const rewrittenSpecifier = resolveSpecifier(dependencyName);
if (rewrittenSpecifier) {
dependencies[dependencyName] = rewrittenSpecifier;
}
}
}
function logSourceOnce() {
if (loggedSource) {
return;
}
loggedSource = true;
process.stderr.write(
`[bytelyst] pnpm package source=${PACKAGE_SOURCE} commonPlatRoot=${COMMON_PLAT_ROOT}\n`,
);
}
module.exports = {
hooks: {
readPackage(packageJson) {
logSourceOnce();
rewriteDependencySet(packageJson.dependencies);
rewriteDependencySet(packageJson.devDependencies);
rewriteDependencySet(packageJson.optionalDependencies);
rewriteDependencySet(packageJson.peerDependencies);
return packageJson;
},
},
};

View File

@ -23,7 +23,7 @@ web dashboard, and Expo mobile app under a single pnpm workspace.
## Quick Start ## Quick Start
```bash ```bash
pnpm install pnpm run install:common-plat
cp .env.example .env # root — used by Docker Compose and CI cp .env.example .env # root — used by Docker Compose and CI
cp backend/.env.example backend/.env # backend — fill in Cosmos, exchange, and AI credentials cp backend/.env.example backend/.env # backend — fill in Cosmos, exchange, and AI credentials
cp web/.env.example web/.env.local # web — Vite build-time API URLs cp web/.env.example web/.env.local # web — Vite build-time API URLs
@ -139,8 +139,25 @@ uses redacted URL helpers for any future FMP log output.
## Shared Dependencies ## Shared Dependencies
Common-platform packages are vendored from `../learning_ai_common_plat/packages/*` Package resolution is controlled by `BYTELYST_PACKAGE_SOURCE` through
and linked via `vendor/` at install time. See `pnpm-workspace.yaml` for the link strategy. `.pnpmfile.cjs`.
- `vendor` (default): prefer `vendor/bytelyst/*`, then fall back to a local
`learning_ai_common_plat` checkout if present, then registry versions.
- `common-plat`: resolve `@bytelyst/*` directly from
`/opt/bytelyst/learning_ai_common_plat/packages/*`.
- `gitea`: resolve `@bytelyst/*` from the Gitea npm registry using
`GITEA_NPM_TOKEN`.
Examples:
```bash
pnpm run install:common-plat
pnpm run install:gitea
pnpm run install:vendor
```
Override the sibling repo location with `BYTELYST_COMMON_PLAT_ROOT=/path/to/learning_ai_common_plat`.
## Release Checklist ## Release Checklist

View File

@ -9,7 +9,9 @@ RUN corepack enable && corepack prepare pnpm@10.6.5 --activate
WORKDIR /app WORKDIR /app
ARG GITEA_NPM_TOKEN ARG GITEA_NPM_TOKEN
ARG BYTELYST_PACKAGE_SOURCE=vendor
ENV GITEA_NPM_TOKEN=${GITEA_NPM_TOKEN} ENV GITEA_NPM_TOKEN=${GITEA_NPM_TOKEN}
ENV BYTELYST_PACKAGE_SOURCE=${BYTELYST_PACKAGE_SOURCE}
# Copy workspace root files first (layer cache) # Copy workspace root files first (layer cache)
COPY .npmrc pnpm-workspace.yaml pnpm-lock.yaml* ./ COPY .npmrc pnpm-workspace.yaml pnpm-lock.yaml* ./
@ -36,7 +38,9 @@ RUN corepack enable && corepack prepare pnpm@10.6.5 --activate
WORKDIR /app WORKDIR /app
ARG GITEA_NPM_TOKEN ARG GITEA_NPM_TOKEN
ARG BYTELYST_PACKAGE_SOURCE=vendor
ENV GITEA_NPM_TOKEN=${GITEA_NPM_TOKEN} ENV GITEA_NPM_TOKEN=${GITEA_NPM_TOKEN}
ENV BYTELYST_PACKAGE_SOURCE=${BYTELYST_PACKAGE_SOURCE}
COPY .npmrc pnpm-workspace.yaml pnpm-lock.yaml* ./ COPY .npmrc pnpm-workspace.yaml pnpm-lock.yaml* ./
COPY package.json ./package.json COPY package.json ./package.json

View File

@ -4,7 +4,7 @@
# #
# Both services mount local source directories so edits are reflected immediately # Both services mount local source directories so edits are reflected immediately
# without rebuilding the image. Requires node_modules to exist locally # without rebuilding the image. Requires node_modules to exist locally
# (run `pnpm install` at repo root first). # (run the matching root install first, for example `pnpm run install:common-plat`).
version: '3.9' version: '3.9'

View File

@ -4,7 +4,7 @@
# #
# Requires: # Requires:
# - backend/.env populated (copy from backend/.env.example) # - backend/.env populated (copy from backend/.env.example)
# - GITEA_NPM_TOKEN env var set for private @bytelyst/* registry build args # - GITEA_NPM_TOKEN env var set when BYTELYST_PACKAGE_SOURCE=gitea
# #
# For hot-reload dev mode use: # For hot-reload dev mode use:
# docker compose -f docker-compose.yml -f docker-compose.dev.yml up # docker compose -f docker-compose.yml -f docker-compose.dev.yml up
@ -21,6 +21,7 @@ services:
context: . context: .
dockerfile: backend/Dockerfile dockerfile: backend/Dockerfile
args: args:
BYTELYST_PACKAGE_SOURCE: ${BYTELYST_PACKAGE_SOURCE:-vendor}
GITEA_NPM_TOKEN: ${GITEA_NPM_TOKEN:-} GITEA_NPM_TOKEN: ${GITEA_NPM_TOKEN:-}
container_name: invttrdg-backend container_name: invttrdg-backend
env_file: env_file:
@ -46,6 +47,7 @@ services:
context: . context: .
dockerfile: web/Dockerfile dockerfile: web/Dockerfile
args: args:
BYTELYST_PACKAGE_SOURCE: ${BYTELYST_PACKAGE_SOURCE:-vendor}
GITEA_NPM_TOKEN: ${GITEA_NPM_TOKEN:-} GITEA_NPM_TOKEN: ${GITEA_NPM_TOKEN:-}
VITE_PRODUCT_ID: ${VITE_PRODUCT_ID:-invttrdg} VITE_PRODUCT_ID: ${VITE_PRODUCT_ID:-invttrdg}
VITE_PLATFORM_URL: ${VITE_PLATFORM_URL:-https://api.bytelyst.com/platform/api} VITE_PLATFORM_URL: ${VITE_PLATFORM_URL:-https://api.bytelyst.com/platform/api}

View File

@ -46,16 +46,21 @@ doesn't reflect them yet**. The previous session installed those via
issue, which left stray `web/package-lock.json` etc. — those are now issue, which left stray `web/package-lock.json` etc. — those are now
git-ignored (commit `255bb07`). git-ignored (commit `255bb07`).
**Action required before CI green**: on a workstation with **Action required before CI green**: regenerate the root lockfile from a
`GITEA_NPM_TOKEN` exported, run: consistent package source, then commit the result. For a sibling
`learning_ai_common_plat` checkout on this host, run:
```bash ```bash
pnpm install -r --no-frozen-lockfile pnpm run install:common-plat -- --no-frozen-lockfile
git add pnpm-lock.yaml git add pnpm-lock.yaml
git commit -m "chore(E2): regen root lockfile with new web deps" git commit -m "chore(E2): regen root lockfile with new web deps"
git push git push
``` ```
If you need the registry path instead, run
`BYTELYST_PACKAGE_SOURCE=gitea pnpm install -r --no-frozen-lockfile` with
`GITEA_NPM_TOKEN` exported.
This is **item E2** in `docs/AUDIT_REDESIGN.md`. CI will fail until it lands. This is **item E2** in `docs/AUDIT_REDESIGN.md`. CI will fail until it lands.
### 2. Pre-existing test failures (NOT my regressions) ### 2. Pre-existing test failures (NOT my regressions)

View File

@ -29,11 +29,14 @@ It covers:
### Workspace bootstrap ### Workspace bootstrap
```bash ```bash
pnpm install pnpm run install:common-plat
cp .env.example .env cp .env.example .env
pnpm verify pnpm verify
``` ```
If you need the registry path instead, use `pnpm run install:gitea`. The active
resolver is controlled by `BYTELYST_PACKAGE_SOURCE` in `.pnpmfile.cjs`.
### Core commands ### Core commands
```bash ```bash
@ -60,9 +63,13 @@ pnpm docker:down
Prerequisites for Docker: Prerequisites for Docker:
- `.env` at repo root filled in (copy from `.env.example`) - `.env` at repo root filled in (copy from `.env.example`)
- `GITEA_NPM_TOKEN` set in `.env` for private `@bytelyst/*` registry - `GITEA_NPM_TOKEN` set when `BYTELYST_PACKAGE_SOURCE=gitea`
- `VITE_PLATFORM_URL` and `VITE_TRADING_API_URL` set if not using localhost defaults - `VITE_PLATFORM_URL` and `VITE_TRADING_API_URL` set if not using localhost defaults
- For dev mode: run `pnpm install` locally first (node_modules mounted as volume) - For dev mode: run the matching local install first (for example `pnpm run install:common-plat`)
Docker note: `common-plat` mode targets `/opt/bytelyst/learning_ai_common_plat`
on the host, so container builds should stay on `vendor` or `gitea` unless the
build context is expanded to include the sibling repo.
### Surface-specific commands ### Surface-specific commands

View File

@ -19,7 +19,7 @@ import { chatSuggestions } from '@/constants/mockData';
import PressableScale from '@/components/PressableScale'; import PressableScale from '@/components/PressableScale';
import { useMobileAuth } from '@/providers/MobileAuthProvider'; import { useMobileAuth } from '@/providers/MobileAuthProvider';
import { mobileRuntime } from '@/lib/runtime'; import { mobileRuntime } from '@/lib/runtime';
import { createRequestId } from '../../../shared/request-id.js'; import { createRequestId } from '../../shared/request-id.js';
interface ChatMessage { interface ChatMessage {
id: string; id: string;

View File

@ -10,7 +10,7 @@ import PillBadge from '@/components/PillBadge';
import PressableScale from '@/components/PressableScale'; import PressableScale from '@/components/PressableScale';
import { useMobileAuth } from '@/providers/MobileAuthProvider'; import { useMobileAuth } from '@/providers/MobileAuthProvider';
import { mobileRuntime } from '@/lib/runtime'; import { mobileRuntime } from '@/lib/runtime';
import { createRequestId } from '../../../shared/request-id.js'; import { createRequestId } from '../../shared/request-id.js';
interface MarketplacePreset { interface MarketplacePreset {
id: string; id: string;

View File

@ -52,7 +52,8 @@
"devDependencies": { "devDependencies": {
"@babel/core": "^7.25.2", "@babel/core": "^7.25.2",
"@types/node": "^24.10.1", "@types/node": "^24.10.1",
"@types/react": "~19.1.10", "@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0",
"eslint": "^9.39.1", "eslint": "^9.39.1",
"eslint-config-expo": "~10.0.0", "eslint-config-expo": "~10.0.0",
"typescript": "~5.9.2" "typescript": "~5.9.2"

View File

@ -6,6 +6,9 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "pnpm --filter @bytelyst/trading-backend build && pnpm --filter @bytelyst/trading-web build && pnpm --filter @bytelyst/trading-mobile typecheck", "build": "pnpm --filter @bytelyst/trading-backend build && pnpm --filter @bytelyst/trading-web build && pnpm --filter @bytelyst/trading-mobile typecheck",
"install:common-plat": "BYTELYST_PACKAGE_SOURCE=common-plat pnpm install -r",
"install:gitea": "BYTELYST_PACKAGE_SOURCE=gitea pnpm install -r",
"install:vendor": "BYTELYST_PACKAGE_SOURCE=vendor pnpm install -r",
"lint": "pnpm --filter @bytelyst/trading-backend lint && pnpm --filter @bytelyst/trading-web lint && pnpm --filter @bytelyst/trading-mobile lint", "lint": "pnpm --filter @bytelyst/trading-backend lint && pnpm --filter @bytelyst/trading-web lint && pnpm --filter @bytelyst/trading-mobile lint",
"smoke:release": "sh ./scripts/smoke-release.sh", "smoke:release": "sh ./scripts/smoke-release.sh",
"test": "pnpm --filter @bytelyst/trading-backend test && pnpm --filter @bytelyst/trading-web test", "test": "pnpm --filter @bytelyst/trading-backend test && pnpm --filter @bytelyst/trading-web test",
@ -18,6 +21,7 @@
}, },
"dependencies": { "dependencies": {
"@bytelyst/kill-switch-client": "file:./vendor/bytelyst/kill-switch-client", "@bytelyst/kill-switch-client": "file:./vendor/bytelyst/kill-switch-client",
"@bytelyst/react-native-platform-sdk": "^1.0.0",
"@bytelyst/react-auth": "file:./vendor/bytelyst/react-auth", "@bytelyst/react-auth": "file:./vendor/bytelyst/react-auth",
"@bytelyst/telemetry-client": "file:./vendor/bytelyst/telemetry-client" "@bytelyst/telemetry-client": "file:./vendor/bytelyst/telemetry-client"
}, },

1525
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,9 @@ RUN corepack enable && corepack prepare pnpm@10.6.5 --activate
WORKDIR /app WORKDIR /app
ARG GITEA_NPM_TOKEN ARG GITEA_NPM_TOKEN
ARG BYTELYST_PACKAGE_SOURCE=vendor
ENV GITEA_NPM_TOKEN=${GITEA_NPM_TOKEN} ENV GITEA_NPM_TOKEN=${GITEA_NPM_TOKEN}
ENV BYTELYST_PACKAGE_SOURCE=${BYTELYST_PACKAGE_SOURCE}
COPY .npmrc pnpm-workspace.yaml pnpm-lock.yaml* ./ COPY .npmrc pnpm-workspace.yaml pnpm-lock.yaml* ./
COPY package.json ./package.json COPY package.json ./package.json