# Migration Guide — Adopting `@bytelyst/*` Packages Step-by-step guide for integrating `@bytelyst/*` shared packages into a new product or dashboard. --- ## Prerequisites 1. Clone both repos side-by-side: ``` code/ ├── learning_ai_common_plat/ # shared packages + services └── your-product/ # your product repo ``` 2. Build all packages: ```bash cd learning_ai_common_plat pnpm install pnpm build ``` --- ## Step 1: Add Package Dependencies In your product's `package.json`, add `file:` references to the packages you need: ```json { "dependencies": { "@bytelyst/errors": "file:../learning_ai_common_plat/packages/errors", "@bytelyst/cosmos": "file:../learning_ai_common_plat/packages/cosmos", "@bytelyst/config": "file:../learning_ai_common_plat/packages/config", "@bytelyst/auth": "file:../learning_ai_common_plat/packages/auth", "@bytelyst/api-client": "file:../learning_ai_common_plat/packages/api-client", "@bytelyst/logger": "file:../learning_ai_common_plat/packages/logger" } } ``` Adjust the `../` path depth based on your directory structure. Then run `npm install`. > **Important:** Run `pnpm build` in `learning_ai_common_plat` before `npm install` in your product. The `file:` refs need compiled `dist/` directories. --- ## Step 2: Wire Up Cosmos DB Create `src/lib/cosmos.ts`: ```typescript import { getCosmosClient, getDatabase, registerContainers, getRegisteredContainer, } from '@bytelyst/cosmos'; // Define your containers const CONTAINERS = [ 'users', 'settings', 'audit_log', // ... your containers ]; let initialized = false; export async function initializeAllContainers() { if (initialized) return; await registerContainers(CONTAINERS); initialized = true; } export function getContainer(name: string) { return getRegisteredContainer(name); } export { getCosmosClient, getDatabase, initializeAllContainers }; ``` Required env vars: `COSMOS_ENDPOINT`, `COSMOS_KEY`, `COSMOS_DATABASE` --- ## Step 3: Wire Up Auth (Server-Side) Create `src/lib/auth-server.ts`: ```typescript import { createJwtUtils, hashPassword, verifyPassword } from '@bytelyst/auth'; const jwt = createJwtUtils({ issuer: 'your-product-name', accessTokenExpiry: '1h', refreshTokenExpiry: '30d', }); export { jwt, hashPassword, verifyPassword }; ``` Required env var: `JWT_SECRET` (min 32 chars) --- ## Step 4: Wire Up Product Identity Create `src/lib/product-config.ts`: ```typescript import { loadProductIdentity } from '@bytelyst/config'; const identity = loadProductIdentity(); export const PRODUCT_ID = identity.productId; export const PRODUCT_NAME = identity.productName; ``` Required env vars: `DEFAULT_PRODUCT_ID` (or set in `shared/product.json`) > **Rule:** Every Cosmos document MUST include a `productId` field using this value. --- ## Step 5: Wire Up Service Clients (If Using Microservices) Create `src/lib/billing-client.ts` (example): ```typescript import { createApiClient } from '@bytelyst/api-client'; const billingApi = createApiClient({ baseUrl: process.env.PLATFORM_SERVICE_URL || 'http://localhost:4003', getToken: () => { // Return the current user's JWT token return localStorage.getItem('access_token'); }, }); export async function getSubscription(userId: string) { return billingApi.fetch(`/api/subscriptions/${userId}`); } ``` --- ## Step 6: Wire Up Error Handling Import typed errors for consistent HTTP error responses: ```typescript import { BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, } from '@bytelyst/errors'; // In your API routes: if (!user) throw new NotFoundError('User not found'); if (!isAdmin) throw new ForbiddenError('Admin access required'); ``` --- ## Step 7: Wire Up Auth Context (React Dashboards) For admin-style dashboards, use the factory: ```typescript import { createAuthProvider } from '@bytelyst/react-auth'; interface MyUser { id: string; email: string; role: string; } const { AuthProvider, useAuth } = createAuthProvider({ storagePrefix: 'myapp', onLoginFallback: async (email, password) => { const res = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); if (!res.ok) return null; const data = await res.json(); return { user: data.user, token: data.accessToken }; }, }); export { AuthProvider, useAuth }; ``` > **Note:** If your auth flow needs SSO cookies, registration, or session restore via API calls, keep a custom auth context instead. --- ## Docker Builds ### Fastify Services (in `learning_ai_common_plat`) Services use pnpm monorepo builds with repo root as context. See any service's `Dockerfile` for the pattern: - Multi-stage: `pnpm install` → build packages + service → `pnpm deploy` - `docker-compose.yml` sets `context: .` with `dockerfile: services//Dockerfile` ### Next.js Dashboards (in your product repo) Dashboards need pre-built packages copied into the build context: 1. Run `./scripts/docker-prep-dashboards.sh` to copy `@bytelyst/*` into `.docker-deps/` 2. Dockerfile copies `.docker-deps/@bytelyst/` to `/learning_ai_common_plat/packages/` so `file:` refs resolve --- ## Checklist - [ ] `pnpm build` in `learning_ai_common_plat` runs clean - [ ] `npm install` in your product resolves all `@bytelyst/*` deps - [ ] `tsc --noEmit` passes in your product - [ ] Every Cosmos document includes `productId` field - [ ] `JWT_SECRET` is set and shared across all services - [ ] No `console.log` in production code (use `req.log` or `@bytelyst/logger`) - [ ] Commit: `feat(integration): wire @bytelyst/* shared packages`