diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 46d92188f..f049e32f6 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -27,11 +27,6 @@ jobs: node-version: 26.8.1 cache: "pnpm" - - name: πŸ¦• Setup Deno - uses: denoland/setup-deno@v2 - with: - deno-version: 2.9.7 - - name: πŸ“₯ Download deps run: pnpm install diff --git a/.github/workflows/dx.yml b/.github/workflows/dx.yml index 1d5b0bcec..b197ba43d 100644 --- a/.github/workflows/dx.yml +++ b/.github/workflows/dx.yml @@ -41,10 +41,5 @@ jobs: - name: πŸ“₯ Download deps run: pnpm install - - name: πŸ¦• Setup Deno - uses: denoland/setup-deno@v2 - with: - deno-version: 2.9.7 - - name: πŸ”₯ DX task run: pnpm dx diff --git a/.github/workflows/migrate.yml b/.github/workflows/migrate.yml index e2dcffc93..2bb1ce170 100644 --- a/.github/workflows/migrate.yml +++ b/.github/workflows/migrate.yml @@ -26,11 +26,6 @@ jobs: node-version: 26.8.1 cache: "pnpm" - - name: πŸ¦• Install deno - uses: denoland/setup-deno@v2 - with: - deno-version: 2.9.7 - - name: πŸ“₯ Download deps run: pnpm install diff --git a/.github/workflows/proto-check.yml b/.github/workflows/proto-check.yml index 39e5072ac..cfe2183a4 100644 --- a/.github/workflows/proto-check.yml +++ b/.github/workflows/proto-check.yml @@ -35,11 +35,6 @@ jobs: node-version: 26.8.1 cache: "pnpm" - - name: πŸ¦• Setup Deno - uses: denoland/setup-deno@v2 - with: - deno-version: 2.9.7 - - name: 🐹 Setup Go uses: actions/setup-go@v5 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3bf2506b8..13ff630a5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -69,11 +69,6 @@ jobs: node-version: 26.8.1 cache: "pnpm" - - name: πŸ¦• Setup Deno - uses: denoland/setup-deno@v2 - with: - deno-version: 2.9.7 - - name: πŸ“₯ Download deps run: pnpm install diff --git a/AGENTS.md b/AGENTS.md index 85176e90a..1576d1d90 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,9 +17,9 @@ are in `apps/dashboard/README.md`. ## Toolchain -`devbox.json` pins exact node, deno, bun, turso-cli and sqld versions; the CI -workflows pin the same node and deno. Never float one back to `@latest` or -`v2.x` β€” `tsc` and test results differ by version, so a drifting pin makes +`devbox.json` pins exact node, bun, turso-cli and sqld versions; the CI +workflows pin the same node. Never float one back to `@latest` or +`v26.x` β€” `tsc` and test results differ by version, so a drifting pin makes `pnpm verify` disagree with CI for reasons unrelated to your change. ## Architecture diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b59f41ec8..df9eb12da 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,7 +34,7 @@ To contribute code changes, follow these steps: packages your diff touches; those do need a local libSQL server. See the [Requirements](./README.md#requirements) list in the README for the - full toolchain (Node.js, pnpm, Bun, Deno, Turso CLI). + full toolchain (Node.js, pnpm, Bun, Turso CLI). 4. Make commits with clear and descriptive messages. Each commit should have a single logical purpose. 5. Push your branch to your forked repository. 6. Open a pull request (PR) from your branch to the original repository's `main` branch. diff --git a/README.md b/README.md index 8362d6d10..c39167777 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,6 @@ The template source and the setup instructions are in [ephraimduncan/openstatus- - [Node.js](https://nodejs.org/en/) - [pnpm](https://pnpm.io/) -- [Deno](https://deno.com/) - [Turso CLI](https://docs.turso.tech/quickstart). #### Dashboard diff --git a/apps/dashboard/README.md b/apps/dashboard/README.md index 73c8ea9a2..f691c6482 100644 --- a/apps/dashboard/README.md +++ b/apps/dashboard/README.md @@ -4,7 +4,7 @@ ### Requirements -- [Node.js](https://nodejs.org/en/) >= 20.0.0 β€” runtime +- [Node.js](https://nodejs.org/en/) >= 26.2 β€” runtime (`devbox.json` pins the exact version) - [pnpm](https://pnpm.io/) >= 8 β€” monorepo package manager (see root `package.json` for pinned version) - [Bun](https://bun.sh/) β€” optional, used by the utility scripts in `src/scripts` - [Turso CLI](https://docs.turso.tech/quickstart) β€” starts the local libSQL server via `pnpm --filter '@openstatus/db' dev` diff --git a/apps/server/.gitignore b/apps/server/.gitignore index 12a21cd50..27ec8abbf 100644 --- a/apps/server/.gitignore +++ b/apps/server/.gitignore @@ -1,6 +1,2 @@ node_modules -app -src/_serve.bundle.mjs -.deno_compile_bundle_*.mjs -app.tmp-* slack-manifest.dev.json diff --git a/apps/server/deno.jsonc b/apps/server/deno.jsonc deleted file mode 100644 index d3de83dde..000000000 --- a/apps/server/deno.jsonc +++ /dev/null @@ -1,6 +0,0 @@ -/* Needed to fix the import aliases */ -{ - "imports": { - "@/": "./src/", - }, -} diff --git a/apps/web/deno.jsonc b/apps/web/deno.jsonc deleted file mode 100644 index 5ae72d87e..000000000 --- a/apps/web/deno.jsonc +++ /dev/null @@ -1,10 +0,0 @@ -/* Needed to fix the import aliases, and to render components in `deno test` */ -{ - "compilerOptions": { - "jsx": "react-jsx", - "jsxImportSource": "react", - }, - "imports": { - "@/": "./src/", - }, -} diff --git a/apps/workflows/.gitignore b/apps/workflows/.gitignore index e4037038c..47d38dfda 100644 --- a/apps/workflows/.gitignore +++ b/apps/workflows/.gitignore @@ -1,6 +1,5 @@ # deps node_modules/ -# build artifacts / local dev db -app +# local dev db dev.db* diff --git a/apps/workflows/deno-migration-plan.md b/apps/workflows/deno-migration-plan.md deleted file mode 100644 index 2b7b2f0f9..000000000 --- a/apps/workflows/deno-migration-plan.md +++ /dev/null @@ -1,437 +0,0 @@ -# Plan: migrate `apps/server` + `apps/workflows` from bun to Deno 2.9 - -Goal: remove **bun** from the project. Three pillars, shipped as **one big-bang PR**: - -1. **Build** β€” `bun build --compile` β†’ `deno compile` (server + workflows). -2. **Install** β€” the Docker `pnpm install` stage β†’ `deno install` (server + workflows). -3. **Tests** β€” `bun:test` β†’ **`node:test` runner + `@std/expect`**, run via **`deno test`**, - across **all ~270 test files** (12 packages + apps server, workflows, web, status-page). - -The other apps (`web`, `dashboard`, `status-page`, `docs`, `screenshot-service`) keep -**pnpm** for install + their existing builds; their only bun usage was `bun test`, removed by -pillar 3. `pnpm` remains the local-dev + non-migrated-app package manager. - ---- - -## Agreed decisions (the design) - -| # | Area | Decision | -|---|------|----------| -| 1 | Test scope | All ~270 `bun:test` files (12 packages + server/workflows/web/status-page) | -| 2 | Rollout | One big-bang PR, guarded by a baseline test-count parity gate (#16) | -| 3 | Entrypoint | **Split**: `index.ts` exports `app`; new `serve.ts` calls `Deno.serve`, is the compile target | -| 4 | Assertions | Keep Jest-style `expect` via **`@std/expect`** | -| 5 | Mocks | **`@std/testing/mock`** (`spy`/`stub`, `using`) + **`@std/testing/time`** (`FakeTime`) | -| 6 | `mock.module` | **Hybrid**: `stub` the reachable seams; **default-param DI** for the rest; delete dead ones | -| 7 | Test infra | New **`@openstatus/test-utils`** package: matchers (`expect.extend`), setup, shared fakes | -| 8 | DI style | **Default-parameter injection** for `dispatch*` / `getChannel` | -| 9 | Snapshots / type tests | `@std/testing/snapshot` / `expect-type` | -| 10 | Typecheck | Replace `tsc` with **`deno check`**, scoped to `apps/server` + `apps/workflows` (src + tests) | -| 11 | Permissions | `-A` for `deno test` and `deno compile` now; tighten the binary in a follow-up | -| 12 | Docker install | `deno install --prod --frozen --allow-scripts`, hoisted node_modules; `pnpm-workspace.yaml` stays authoritative; commit `deno.lock` only | -| 13 | CI install | CI test/migrate jobs **keep `pnpm install`**; `deno install` is exercised by the docker-publish build | -| 14 | CI test orchestration | Keep **turbo**; each package `"test": "deno test -A"`; swap `setup-bun` β†’ `setup-deno` | -| 15 | Integration tests | Stay in the same `deno test -A` run, against the CI libsql service (as today) | -| 16 | Safety net | Record base-commit `bun test` pass count; assert `deno test` count β‰₯ it (fail CI on drop) | -| 17 | Other apps | Stay on pnpm install + existing build | -| 18 | Codemod | `ts-morph`/`jscodeshift` for the mechanical rewrite; hand-fix the ~60-file residue | - ---- - -## Resolved by codebase exploration (facts, not assumptions) - -- **Entrypoint must split** β€” tests do `import { app } from "@/index"`; a top-level - `Deno.serve` in `index.ts` would boot a server on every test import. -- **Server needs no libsql side-car** β€” `packages/db` uses `drizzle-orm/libsql/http` (pure - HTTP). Only `apps/workflows/src/lib/db.ts` uses the native `@libsql/client` embedded replica - β†’ native-addon compile risk is **workflows-only**. -- **Tests are integration tests against a real libSQL DB** β€” CI runs a `libsql-server` - service + migrate + seed. The preload mocks only Tinybird/Redis/subscriptions; DB is real. -- **Step D seams are mixed**: `@/libs/clients` (`tb`/`redis` singletons) + `Redis.fromEnv` - are stub-able; `@openstatus/subscriptions` `dispatch*` + `getChannel` are destructured live - bindings called directly β†’ need DI. -- **`node-fetch` mock is dead** β€” the SUT uses **global `fetch`**; tests set - `global.fetch = mockFetch` (the effective line) plus a redundant `mock.module("node-fetch")` - (not a dependency). β†’ `stub(globalThis, "fetch", …)` and delete the `mock.module` line. -- **`start.sh` is unused by Fly** (entrypoint is the binary; compose `command` commented) β€” - prod migrations run via CI `migrate.yml`. We keep `start.sh` anyway and port its command. -- **migrate/seed have no `Bun.*`** β€” `packages/db/src/migrate.mts` + `seed.mts` use only - `@libsql/client`/drizzle/`process` β†’ run under `deno run -A` unchanged. -- **`Bun.*` lives only in dev/build scripts** β€” `packages/db/env.ts`, `apps/server/env.ts`, - `apps/workflows/src/build-docker.ts` (`Bun.file`/`Bun.write`). -- **web/status-page tests are pure logic/util** β€” no DOM/`@testing-library`/React rendering; - run under `deno test` with no jsdom. -- **Only `apps/server` runs `tsc`** today (`tsc --noEmit`, `types: ["bun-types"]`). - ---- - -## Phase 0 β€” Spikes (gate the big-bang) β€” βœ… DONE (1,2) / deferred (3,4) - -Toolchain confirmed: **deno 2.9.0**, bun 1.3.11, pnpm 11.2.1, node 24, dofigen 2.8.0. - -1. βœ… **`Deno.serve` + Hono compile/serve.** Compiled, served, `/ping`β†’200, embedded asset - read via `Deno.readTextFile(new URL(...))`. **Correction: the flag is `--include`, not - `--include-as-is`** (the latter does not exist in 2.9). -2. βœ… **libSQL native addon under `deno compile` β€” make-or-break, PASSED with a bonus.** - `deno compile` **embeds the native addon into the binary** (10.7MB) and the binary runs from - a clean dir with **no node_modules**. **Consequence: the workflows `docker` + `libsql` - side-car stages are no longer needed** (they existed only because `bun build --compile` - could not embed native addons). One caveat for the real monorepo build: `--node-modules-dir=manual` - against the giant shared `node_modules` hangs (tries to embed everything) β€” use deno's - managed npm resolution / `--exclude-unused-npm` so only reachable packages embed. Final flag - combo to be settled in Phase 5 against the real Docker build. -3. ⏳ **Test stack interop** β€” validated at the start of Phase 2 by migrating one real route - test (faster than a synthetic spike): `@std/expect` matchers, `toHaveBeenCalled*` vs - `@std/testing/mock` spies (else `assertSpyCalls`), `expect.extend`, `stub` on `tb` getters + - `globalThis.fetch`, `FakeTime`. -4. ⏳ **`deno install` on the repo** β€” done carefully in Phase 3 (it may rewrite manifests and - re-layout `node_modules`, which would disrupt the in-progress pnpm-based work), in an - isolated copy first. - ---- - -## βœ… RESOLVED β€” deep workspace imports: exports maps + sloppy (no deno.json) - -**Solution (verified under `deno run` + `deno compile` + bun):** add an `exports` map to the -4 deep-imported packages (`@openstatus/db`, `@openstatus/api`, `@openstatus/emails`, -`@openstatus/tracker`) and pass `--unstable-sloppy-imports` on every deno command. The exports -map crosses the package boundary (sloppy can't); sloppy resolves the relative extensionless -imports inside packages. **No deno.json. 4 package.json touched, not 512 imports.** - -Exports map shape (per package), covering the 36 distinct targets (29 files, 7 dirs all in db): - -```jsonc -"exports": { - ".": "./src/index.ts", - "./env.mjs": "./env.mjs", // db only (non-src deep import) - "./src/schema": "./src/schema/index.ts", // + the 6 other directory targets - "./src/client": "./src/client.tsx", // .tsx files need explicit entries - "./src/*": "./src/*.ts" // wildcard handles the .ts files -} -``` - -Every deno invocation (`test`/`compile`/`check`/`run`) must include `--unstable-sloppy-imports`. - -### Original investigation (kept for context) - -The codebase has **512 bare deep-subpath imports across 400 files** of the form -`@openstatus/db/src/schema/constants` (also `@openstatus/api/src/*`, `@openstatus/emails/src/*`, -`@openstatus/tracker/src/*`). Targets are a **mix of `.ts` files, `.tsx` files, and directories** -(`@openstatus/db/src/schema` is a dir with `index.ts`). Verified facts (Deno 2.9.0 experiments): - -- **`--unstable-sloppy-imports` resolves *relative* extensionless imports** (incl. dir-index and - `.tsx`) for `deno run`/`compile`/`test`. βœ… -- It does **NOT** resolve **bare cross-package** deep subpaths β€” those go through node_modules - package resolution where sloppy does not apply. Fails for run/compile/test (works only for the - lenient `deno check` TS resolver). ❌ β€” true even in Deno workspace mode (`deno install`). -- **Explicit extension** (`@openstatus/db/src/schema/constants.ts`) resolves under both Deno and - bun β€” but directory imports still need `/index.ts`, and it risks the Next.js apps (turbopack/tsc). -- **`exports` map** with a `./src/*` wildcard handles `.ts` files but **not** the mixed - dir/`.tsx` cases reliably (Deno does not fall through exports fallback arrays on a missing file). -- **deno.json import map** prefix (`"@openstatus/db/src/": "./packages/db/src/"`) + sloppy - **resolves ALL cases** (file `.ts`/`.tsx` + dir-index) for run **and** compile. βœ… β€” but it is a - `deno.json`, which the user asked to avoid. - -**This is a hard fork:** the only clean, complete fix is a 4-entry `deno.json` import map, which -collides with the "no deno.json" preference ([[feedback-no-deno-json]]). Awaiting a decision (see -chat) before proceeding with Phase 2+. Everything below assumes that decision is made. - -## Implementation findings (verified during execution) - -- **`@/*` tsconfig path alias** β€” Deno doesn't read tsconfig `paths`. 153 `@/…` imports across - 113 files in `apps/server` rewritten to **relative paths** (codemod). workflows uses none. βœ… -- **`deno install` foundation** β€” works, with one workaround: it **crashes seeding `deno.lock` - from `pnpm-lock.yaml`** on a pnpm alias (`string-width-cjs@string-width@4.2.3`). Fix: move - `pnpm-lock.yaml` aside during `deno install` so Deno resolves fresh, then restore it. Deno - migrates the **catalog into root `package.json`** (not deno.json) and writes `deno.lock`. - After install, the full server graph resolves (deep imports + `zod` + `hono`). βœ… -- **`@std/expect` `toHaveBeenCalled*` does NOT accept `@std/testing/mock` spies** (verified: - "Received function must be a mock or spy function"). β†’ the ~187 `toHaveBeenCalled*` sites must - use **`assertSpyCalls`/`assertSpyCall`** instead. Basic `expect`, `expect.extend` custom - matchers, and `FakeTime` all work. ⚠ (more test rework than planned) -- **βœ… `deno compile` of `apps/server` WORKS in a clean Docker container** β€” the local 12-min - hang was the **polluted local node_modules** (Deno-managed mix + broken `.next` symlinks + - every app's deps). In Docker with a **scoped `pnpm install --filter @openstatus/server...`** - (20.8s) then `deno compile --node-modules-dir=manual`, the binary builds fast and **runs**: - `/ping`β†’200, `/openapi.yaml`β†’embedded asset, full app graph boots ("Listening on :3000"). - - **Winning build recipe** (`apps/server/Dockerfile.deno-test`): node:24-slim β†’ `pnpm install - --prod --frozen-lockfile --filter @openstatus/server...` β†’ denoland/deno:2.9.0 β†’ `deno - compile -A --no-check --unstable-sloppy-imports --node-modules-dir=manual --include - static/openapi.yaml --include static/openapi-v1.json --output app src/serve.ts` β†’ debian - runtime with just the binary. - - **No `deno install`** in the build β€” pnpm install (scoped) is what produces node_modules; - Deno reads the catalog from root `package.json` (migrated once) + consumes pnpm's layout. - This sidesteps `deno install`'s whole-monorepo install + the pnpm-alias lockfile crash. - - Catalog must be present in root `package.json` for Deno to resolve `catalog:` specifiers. - - Sandbox note: needed `docker build --network=host` here (flaky build-network); normal CI ok. - - Image 495MB (debian + binary). Could slim further later. -- **βœ… `apps/workflows` also builds in Docker** (same recipe, `--filter @openstatus/workflows...`, - 465MB) and **embeds the libSQL native addon** (no side-car). Verified the binary executes (it - reaches the embedded-replica `createClient` and opens the sync connection). Full boot needs a - real Turso `DATABASE_URL` β€” in the sandbox it blocks in SYN_SENT to an unreachable sync URL at - module load (the `createClient` runs before logging, so no logs appear). Not a build defect. -- **⚠ `@sentry/bun` β†’ `@sentry/deno`** β€” workflows used `@sentry/bun` (bun-only; hangs under - Deno) in `index.ts`, `lib/sentry.ts`, `cron/index.ts`. Swapped all three to `@sentry/deno` - (`10.61.0`, API-compatible: `init`/`captureException`/`captureMessage`/`captureCheckIn`/`flush`), - updated `package.json` + `pnpm-lock.yaml`. The server uses `@hono/sentry` (unaffected). -- **⚠ embedded-replica `createClient` blocks at module load** until the sync URL connects β€” so - the workflows process won't serve `/ping` until the DB is reachable. Pre-existing behavior - (bun did the same); flagged for prod startup robustness. - -## Phase 2 β€” Test migration β€” πŸ”Ά IN PROGRESS - -- βœ… `@openstatus/test-utils` package built + validated: re-exports `node:test` runner with a - Bun-compat **`.each`** shim, `@std/expect` `expect` extended with the ~12 **bun-only matchers** - (`toBeNumber`, `toContainValue`, …), and `@std/testing/mock` (`spy`/`stub`/`assertSpyCalls`) + - `@std/testing/time` (`FakeTime`). Uses `jsr:@std/*` so only Deno needs them. -- βœ… Codemod swapped `bun:test` β†’ `@openstatus/test-utils` in **194 files**; updated 21+ - `package.json` (`deno test` script, test-utils devDep, dropped `@types/bun`/`bun-types`); - removed `bunfig.toml`. -- βœ… **`@/*` alias β†’ relative** rewrite: server (153), status-page (211), web (332). Deno - ignores tsconfig paths. -- βœ… **Import-only suites PASS under `deno test`**: header-analysis (7), status-page (51), web - (23). Mock pattern validated: discord + 5 more notifications PASS. -- πŸ”Ά **Remaining mock work (~47 files)**: `@std/expect` `toHaveBeenCalled*` does NOT accept std - spies β†’ use `assertSpyCalls`. Per-file quirks remain: 6 notifications (webhook double-stub, - bird-whatsapp `jest`, slack/grafana call-count-after-restub), importers clients, status-fetcher, - tracker (`FakeTime`), subscriptions/api/server (**`mock.module` β†’ stub + default-param DI**, - and these are **DB-integration tests needing a running libSQL to verify**). -- ⏳ snapshots (`toMatchSnapshot` β†’ `@std/testing/snapshot`) + type tests (`expectTypeOf` β†’ - `expect-type`) not started. - -## Phase 1 β€” Source changes β€” βœ… DONE - -- βœ… split `index.ts`/`serve.ts` (both apps); server static asset β†’ `Deno.readTextFile`. -- βœ… `Bun.*` β†’ `Deno.copyFile` in `apps/server/env.ts`, `packages/db/env.ts`. -- βœ… `migrate`/`seed`/`env` scripts + `start.sh` β†’ `deno run -A`; app `dev`/`start`/`test` β†’ deno. - -(Detail of the changes below.) - -### Entrypoint split (both apps) - -`index.ts`: keep `export const app = new Hono(...)`, **remove** `const server = {...}` + -`export default server`. New `serve.ts`: - -```ts -import { app } from "./index"; -import { env } from "./env"; -Deno.serve({ port: env.PORT ?? 3000 }, app.fetch); -``` - -`serve.ts` is the `deno compile` target. Tests still import `app` with no server side-effect. - -### Server static asset (`apps/server/src/index.ts:22`) - -Drop `import openapiYaml … with { type: "text" }`. Embed via `--include-as-is` (Phase 4) and -read at startup: - -```ts -const openapiYaml = await Deno.readTextFile(new URL("../static/openapi.yaml", import.meta.url)); -``` - -JSON imports (`with { type: "json" }`) stay β€” Deno supports them. - -### `Bun.*` β†’ Deno APIs (dev/build scripts) - -`packages/db/env.ts`, `apps/server/env.ts`: `Bun.file(p).text()/.json()` β†’ -`Deno.readTextFile(p)` (+ `JSON.parse`); `Bun.write(p, s)` β†’ `Deno.writeTextFile(p, s)`. -(`apps/workflows/src/build-docker.ts` is deleted in Phase 5 β€” no port needed.) - -### migrate / `start.sh` - -`packages/db/package.json`: `"migrate": "deno run -A src/migrate.mts"`, -`"seed": "deno run -A src/seed.mts"`, `"env": "deno run -A env.ts"`. Keep `start.sh`; change -`bun src/migrate.mts` β†’ `deno run -A src/migrate.mts`. - ---- - -## Phase 2 β€” Test migration (`bun:test` β†’ `node:test` + `@std/expect`, `deno test`) - -Surface: **~270 files**, ~2920 `expect` assertions, ~150 bun-only matchers, 47 `mock` / -21 `spyOn` / 10 `setSystemTime` / 6 `jest.*`, 4 `mock.module` seams (+ dead `node-fetch`), -12 snapshot files, 10 type-test files. - -### Step 0 β€” `@openstatus/test-utils` package (Decision 7) - -``` -packages/test-utils/ - src/setup.ts # registers expect.extend matchers; installs the global fetch stub helper - src/matchers.ts # the ~150 bun-only matchers (toBeNumber, toContainValue, toBeString, …) - src/fakes/ # tinybird.ts, redis.ts, subscriptions.ts β€” shared test doubles -``` - -Each tester adds `@openstatus/test-utils` as a devDependency; every test file imports -`@openstatus/test-utils/setup` **first** (codemod injects). - -### Step A β€” codemod (`ts-morph`/`jscodeshift`, ~270 files) - -Per file: replace the `bun:test` import with `node:test` + `@std/expect`, alias -`beforeAllβ†’before`/`afterAllβ†’after`, and inject `import "@openstatus/test-utils/setup";` as -the first import. `expect(...)` bodies untouched. - -### Step B β€” bun-only matchers - -Implemented once in `@openstatus/test-utils` via `expect.extend` (verified in Phase 0 spike 3). -`pass()`/`fail()` helpers β†’ explicit `expect(...)` assertions in the few sites that use them. - -### Step C β€” mocks (`@std/testing/mock` + `@std/testing/time`) - -`mock(fn)`β†’`spy(fn)`; `spyOn(o,"m")`β†’`using s = spy(o,"m")` / `stub(o,"m",impl)`; sequential -returnsβ†’`returnsNext`; `setSystemTime`β†’`using t = new FakeTime(date)` + `t.tick`. Prefer -`using` (auto-restore) β€” deletes most `afterEach` teardown. Keep `toHaveBeenCalled*` if Phase-0 -interop holds, else `assertSpyCalls`/`assertSpyCall`. - -### Step D β€” module mocks (hybrid; Decisions 6 + 8) - -- **stub-able** β†’ `@std/testing/mock` `stub`, fakes from `@openstatus/test-utils/fakes`: - `tb`/`redis` (`@/libs/clients` singletons), `Redis.fromEnv` (`@openstatus/upstash`). -- **global fetch** β†’ `stub(globalThis, "fetch", …)`; **delete** every `mock.module("node-fetch")`. -- **DI (default-param)** β†’ `dispatchMaintenanceUpdate`, `dispatchStatusReportUpdate` - (`maintenances/post.ts`, `statusReports/post.ts`), `getChannel` - (`rpc/handlers/status-page/index.ts`): add `deps = { … }` last param; tests pass fakes. -- The old global `preload.ts` is deleted; its four mocks move to the above mechanisms. - -### Step E β€” preload replacement - -`bunfig.toml` preload is gone; the `@openstatus/test-utils/setup` import (Step A) replaces it. -Import ordering: setup first, then the SUT. - -### Step F β€” snapshots + type tests - -Snapshots β†’ `@std/testing/snapshot` `assertSnapshot(t, value)` (regenerate + diff the 12 -files). Type tests β†’ `expect-type` (`expectTypeOf().toEqualTypeOf()`), validated by -`deno check` where in scope (the two apps). - -### Step G β€” invocation - -Each package/app `"test": "deno test -A"`. Pull `@std/expect`, `@std/testing`, `expect-type` -via `jsr add`/devDeps so pnpm install resolves them. Remove `bunfig.toml`, `bun-types`, -`@types/bun`. - ---- - -## Phase 3 β€” Install via `deno install` (Docker, server + workflows) - -Deno 2.9 reads `pnpm-workspace.yaml` catalogs (482 `catalog:` refs) + workspace globs -(244 `workspace:*`) and seeds `deno.lock` from `pnpm-lock.yaml`. dofigen `install` stage: - -```yaml - install: - fromImage: denoland/deno:2.9.0 - workdir: /app/ - env: - DENO_NODE_MODULES_DIR: auto # hoisted layout for compile + libsql side-car - bind: - - pnpm-workspace.yaml # catalog + workspace source of truth - - pnpm-lock.yaml - - deno.lock - - package.json - - …all workspace package.json (same bind list as today)… - run: deno install --prod --frozen --allow-scripts - cache: - - /deno-dir -``` - -`pnpm-workspace.yaml` stays authoritative (Decision 12); commit `deno.lock`; do **not** commit -any catalog/`deno.json` that 2.9 may emit. Verify (Phase 0 spike 4) the migration write stays -additive so pnpm keeps working for the other apps. - ---- - -## Phase 4 β€” `apps/server/dofigen.yml` (build) - -`build` stage β†’ Deno + `deno compile` (target `serve.ts`). No libsql side-car (HTTP driver). - -```yaml - build: - fromImage: denoland/deno:2.9.0 - workdir: /app/apps/server - env: { NODE_ENV: production } - copy: - - . /app/ - - { fromBuilder: install, source: /app/node_modules, target: /app/node_modules } - - { fromBuilder: install, source: /app/apps/server/node_modules, target: /app/apps/server/node_modules } - - { fromBuilder: install, source: /app/packages, target: /app/packages } - run: >- - deno compile -A --no-check --node-modules-dir - --include static/openapi.yaml --include static/openapi-v1.json - --output app serve.ts -``` - -`--no-check` keeps compile fast (`deno check` is the typecheck gate, Decision 10). Optionally -benchmark experimental `--bundle` for a smaller binary. Runtime copy `/app/apps/server/app` β†’ -`/bin/app` unchanged. - ---- - -## Phase 5 β€” `apps/workflows/dofigen.yml` (build) β€” side-car DROPPED - -Spike 2 proved `deno compile` **embeds** the libSQL native addon into the binary, so the whole -side-car apparatus goes away: - -1. **`build`** β†’ `deno compile -A --no-check --output app serve.ts`. Settle the npm-embed flags - here (`--exclude-unused-npm` / managed npm) so it embeds reachable packages, not the whole - `node_modules` (spike 2 caveat). -2. **DELETE the `docker` stage** (`build-docker.ts` existed only to generate the side-car - `package.json`) and **DELETE the `libsql` stage**. -3. **`build-docker.ts`** itself becomes dead code β†’ remove (its sole purpose was the side-car). -4. **runtime copy** β†’ just the self-contained `app` binary. No `node_modules` copied at all. - -This makes the workflows runtime image dramatically simpler (binary only, like server). - ---- - -## Phase 6 β€” CI - -- `test.yml` + `migrate.yml`: replace `oven-sh/setup-bun` with `denoland/setup-deno@v2` - (Deno 2.9). **Keep `pnpm install`** (Decision 13), the libsql service, migrate, seed. - `pnpm test` β†’ turbo β†’ per-package `deno test -A` (Decision 14). -- Add a **`deno check`** step for `apps/server` + `apps/workflows` (src + tests) replacing the - server `tsc` step (Decision 10). -- **Parity gate** (Decision 16): a CI step records the base-commit `bun test` total pass count - (artifact / committed baseline number), then asserts `deno test`'s pass count β‰₯ baseline. -- docker-publish workflows exercise `deno install` + `deno compile` via the Dockerfiles. - ---- - -## Phase 7 β€” Verify & ship - -Per app: `dofigen generate`; `docker buildx build -f apps//Dockerfile .` from repo root; -run, `GET /ping` β†’ 200; server `GET /openapi.yaml` β†’ body; workflows embedded replica syncs + -a cron endpoint responds. Locally: `pnpm install && pnpm migrate && pnpm seed && pnpm test` -green; parity count β‰₯ baseline; `deno check` clean for the two apps. Watch Fly RSS/OOM on -workflows after deploy (Deno V8 heap defaults differ from bun β€” see `research.md`). - ---- - -## Risks - -| Risk | Mitigation | -|------|-----------| -| ~~libSQL native addon won't `deno compile`~~ | βœ… RESOLVED (spike 2): deno embeds the addon; side-car dropped | -| Big-bang PR hides a regression / silent skip | Parity gate (16); split into logical commits within the one PR for bisect | -| `@std/expect` `toHaveBeenCalled*` βœ— interop with `@std/testing/mock` spies | Phase-0 spike 3; fallback `assertSpyCalls`/`assertSpyCall` | -| `deno install` rewrites manifests / breaks pnpm for other apps | Phase-0 spike 4; keep `pnpm-workspace.yaml` authoritative, don't commit deno catalog | -| `deno check` surfaces new diagnostics vs `tsc` | Scoped to two apps (10); fix as part of the PR | -| ~270-file codemod churn | AST codemod (18) + parity gate; hand-fix the ~60-file residue | -| `stub` can't reach `tb` getter methods | Phase-0 spike 3; fallback = make `tb`/`redis` injectable like the dispatch seams | - ---- - -## TODO - -- [ ] **Phase 0** spikes: serve+compile Β· libsql-compile (workflows) Β· test-stack interop Β· `deno install` -- [ ] Phase 1: split `index.ts`/`serve.ts` (both) Β· server static asset Β· `Bun.*`β†’Deno Β· migrate/seed/`start.sh`β†’deno -- [ ] Phase 2.0: create `@openstatus/test-utils` (matchers, setup, fakes) -- [ ] Phase 2.A: codemod imports + lifecycle + setup-inject (~270 files) -- [ ] Phase 2.B–C: matchers via `expect.extend`; mocks β†’ `@std/testing/mock`/`time` -- [ ] Phase 2.D: hybrid module mocks β€” stub `tb`/`redis`/`Redis.fromEnv` + `globalThis.fetch`; DI `dispatch*`/`getChannel`; delete `node-fetch` mocks + `preload.ts` -- [ ] Phase 2.F: snapshots β†’ `@std/testing/snapshot`; type tests β†’ `expect-type` -- [ ] Phase 2.G: `"test": "deno test -A"` everywhere; add JSR devDeps; remove `bunfig.toml`/`bun-types` -- [ ] Phase 3: `deno install` stage (both dofigen); commit `deno.lock` -- [ ] Phase 4: `apps/server` build β†’ `deno compile` (serve.ts, `--include-as-is`) -- [ ] Phase 5: `apps/workflows` build β†’ `deno compile`; `build-docker.ts`β†’deno; `libsql` stageβ†’npm -- [ ] Phase 6: CI `setup-deno`, keep `pnpm install`, `deno check` (2 apps), parity gate -- [ ] Phase 7: `dofigen generate` + docker build + verify each app; ship; watch Fly RSS -- [ ] Update CLAUDE.md memory note "use bun test directly" β†’ `deno test` - diff --git a/deno.lock b/deno.lock deleted file mode 100644 index a0899fd5e..000000000 --- a/deno.lock +++ /dev/null @@ -1,330 +0,0 @@ -{ - "version": "5", - "specifiers": { - "jsr:@std/assert@^1.0.19": "1.0.19", - "jsr:@std/async@^1.4.0": "1.4.0", - "jsr:@std/data-structures@^1.1.0": "1.1.0", - "jsr:@std/expect@*": "1.0.19", - "jsr:@std/internal@^1.0.12": "1.0.14", - "jsr:@std/internal@^1.0.13": "1.0.14", - "jsr:@std/path@^1.1.4": "1.1.4", - "jsr:@std/testing@*": "1.0.19", - "jsr:@std/yaml@^1.0.9": "1.2.0" - }, - "jsr": { - "@std/assert@1.0.19": { - "integrity": "eaada96ee120cb980bc47e040f82814d786fe8162ecc53c91d8df60b8755991e", - "dependencies": [ - "jsr:@std/internal@^1.0.12" - ] - }, - "@std/async@1.4.0": { - "integrity": "4d70b008634f571cff9b554090d628c76141c32613aae0ff283fd5fa23d0c379" - }, - "@std/data-structures@1.1.0": { - "integrity": "c35ae4ad5d8e41a38573c2fe3e19b18ea2505f63cfea201edcb8720aca1f7f58" - }, - "@std/expect@1.0.19": { - "integrity": "25271785688c7ff902fa54875d6aa4001f552c5578f7f0fefb5b5aac1fc2ed8a", - "dependencies": [ - "jsr:@std/assert", - "jsr:@std/internal@^1.0.13", - "jsr:@std/path" - ] - }, - "@std/internal@1.0.14": { - "integrity": "291516b3d4c35024d6ffbc0a9df5bf4c64116e05b50012cf846710152d2ffdf7" - }, - "@std/path@1.1.4": { - "integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5", - "dependencies": [ - "jsr:@std/internal@^1.0.12" - ] - }, - "@std/testing@1.0.19": { - "integrity": "f4236172365b216728dc3cc8b5e80a9f4c33083d1e4ede7613d5b25b4014898e", - "dependencies": [ - "jsr:@std/assert", - "jsr:@std/async", - "jsr:@std/data-structures" - ] - }, - "@std/yaml@1.2.0": { - "integrity": "20beb41e4983ba3437dbefac62b14061ab058e8a187596f19d28ff9035f6e6cf" - } - }, - "workspace": { - "packageJson": { - "dependencies": [ - "npm:turbo@2.11.2" - ] - }, - "members": { - "apps/dashboard": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "apps/server": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19", - "npm:@jsr/std__yaml@^1.0.9" - ] - } - }, - "apps/status-page": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "apps/web": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/ai": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/api": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/assertions": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/db": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/emails": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/header-analysis": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/importers": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/base": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/bird-whatsapp": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/discord": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/google-chat": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/grafana-oncall": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/ms-teams": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/ntfy": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/opsgenie": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/pagerduty": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/slack": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/telegram": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/twillio-sms": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/notifications/webhook": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/services": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/status-fetcher": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/subscriptions": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/test-utils": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/theme-store": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/tinybird": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/tracker": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/upstash": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - }, - "packages/utils": { - "packageJson": { - "dependencies": [ - "npm:@jsr/std__expect@^1.0.19", - "npm:@jsr/std__testing@^1.0.19" - ] - } - } - } - } -} diff --git a/devbox.json b/devbox.json index 78ea1f227..841fffa6c 100644 --- a/devbox.json +++ b/devbox.json @@ -3,7 +3,6 @@ "packages": [ "turso-cli@1.0.15", "nodejs@26.8.1", - "deno@2.9.5", "bun@1.3.13", "sqld@0.24.32" ], diff --git a/devbox.lock b/devbox.lock index 3c276e53d..0a109169a 100644 --- a/devbox.lock +++ b/devbox.lock @@ -49,68 +49,6 @@ } } }, - "deno@2.9.5": { - "last_modified": "2026-08-27T07:16:00Z", - "resolved": "github:NixOS/nixpkgs/c27cdad491a991b11ed731760aa2ef8db0cb0410#deno", - "source": "devbox-search", - "version": "2.9.5", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/94pdxnq7cfdymzmr19144spl0rp34mjg-deno-2.9.5", - "default": true - }, - { - "name": "denort", - "path": "/nix/store/ci5jh3b5yr2dz36q8qb9qs4za2nkkgz3-deno-2.9.5-denort" - }, - { - "name": "libdenort", - "path": "/nix/store/lcxc1mm8hz5i9jhdpv0cb233nxf9r64g-deno-2.9.5-libdenort" - } - ], - "store_path": "/nix/store/94pdxnq7cfdymzmr19144spl0rp34mjg-deno-2.9.5" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8rzh2fpa3lwqzx9iiz07qbk3b7lsjniw-deno-2.9.5", - "default": true - }, - { - "name": "denort", - "path": "/nix/store/2h16nirjr5ddd2bz7vxd19q0lawl5cd3-deno-2.9.5-denort" - }, - { - "name": "libdenort", - "path": "/nix/store/8hn63ayil0mk81a7mim21qh4155n3r6j-deno-2.9.5-libdenort" - } - ], - "store_path": "/nix/store/8rzh2fpa3lwqzx9iiz07qbk3b7lsjniw-deno-2.9.5" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7hk2ax3hgs4152cdqsqcq4lfq1a2kla6-deno-2.9.5", - "default": true - }, - { - "name": "libdenort", - "path": "/nix/store/3m3rdq6vl231165fycmk5rjc48anrzxi-deno-2.9.5-libdenort" - }, - { - "name": "denort", - "path": "/nix/store/180ds5dqaynm1k7c1j6s5lwlak943z9k-deno-2.9.5-denort" - } - ], - "store_path": "/nix/store/7hk2ax3hgs4152cdqsqcq4lfq1a2kla6-deno-2.9.5" - } - } - }, "github:NixOS/nixpkgs/nixpkgs-unstable": { "last_modified": "2025-11-05T16:44:39Z", "resolved": "github:NixOS/nixpkgs/ffcdcf99d65c61956d882df249a9be53e5902ea5?lastModified=1762361079&narHash=sha256-lz718rr1BDpZBYk7%2BG8cE6wee3PiBUpn8aomG%2FvLLiY%3D" diff --git a/oxlint.config.ts b/oxlint.config.ts index 03fc287cc..c7d9adc1a 100644 --- a/oxlint.config.ts +++ b/oxlint.config.ts @@ -126,7 +126,7 @@ export default defineConfig({ excludeFiles: ["**/__tests__/**", "**/*.test.ts"], rules: { "openstatus/services-mutation-guards": "error", - // apps/workflows runs this on Deno, and it stays Edge-safe by design. + // The package stays Edge-safe by design. "no-restricted-imports": [ "error", { diff --git a/packages/analytics/env.ts b/packages/analytics/env.ts index 4611ed752..15132ee96 100644 --- a/packages/analytics/env.ts +++ b/packages/analytics/env.ts @@ -3,11 +3,9 @@ import { z } from "zod"; /** * `NODE_ENV` is read through this alias rather than as a literal - * `process.env.NODE_ENV` member access: `deno bundle` (esbuild) constant-folds - * that exact expression into a string at build time β€” `"development"` unless - * `--minify` is passed β€” which left `setupAnalytics` permanently no-op inside - * the compiled `apps/server` binary. The other keys stay as literal member - * accesses because Next.js needs them that way to inline `NEXT_PUBLIC_*`. + * `process.env.NODE_ENV` member access, which some bundlers fold into a + * build-time string. The other keys stay as literal member accesses because + * Next.js needs them that way to inline `NEXT_PUBLIC_*`. */ const processEnv: Record = process.env; diff --git a/packages/emails/src/env.ts b/packages/emails/src/env.ts index d378e5e88..6c4942ac3 100644 --- a/packages/emails/src/env.ts +++ b/packages/emails/src/env.ts @@ -3,11 +3,8 @@ import { z } from "zod"; /** * `NODE_ENV` is read through this alias rather than as a literal - * `process.env.NODE_ENV` member access: `deno bundle` (esbuild) constant-folds - * that exact expression into a string at build time β€” `"development"` unless - * `--minify` is passed β€” which silently disabled every production guard in - * this package inside the compiled `apps/server` binary. Aliasing the object - * defeats the fold, so the value is read from the real environment at runtime. + * `process.env.NODE_ENV` member access, which some bundlers fold into a + * build-time string; the alias keeps it a runtime value. */ const processEnv: Record = process.env; diff --git a/packages/services/src/env.ts b/packages/services/src/env.ts index 201dc8061..a57868cfb 100644 --- a/packages/services/src/env.ts +++ b/packages/services/src/env.ts @@ -1,11 +1,7 @@ /** - * `NODE_ENV`, read so that bundlers cannot fold it away. - * - * `deno bundle` (esbuild) rewrites the exact expression `process.env.NODE_ENV` - * to a string literal at build time β€” `"development"` unless `--minify` is - * passed, and `apps/server` bundles without it (see `apps/server/dofigen.yml`). - * Reading through an aliased object defeats that substitution, so the value - * comes from the real environment at runtime. + * `NODE_ENV`, read so that bundlers cannot fold it away: some replace the + * exact expression `process.env.NODE_ENV` with a build-time literal. Reading + * through an aliased object keeps it a runtime value. */ export const env = { get NODE_ENV(): string { diff --git a/packages/services/src/oauth/crypto.ts b/packages/services/src/oauth/crypto.ts index e098e0cf5..787f43a37 100644 --- a/packages/services/src/oauth/crypto.ts +++ b/packages/services/src/oauth/crypto.ts @@ -1,4 +1,4 @@ -// Web Crypto only: this package runs on Deno and stays Edge-safe. +// Web Crypto only: this package stays Edge-safe. const encoder = new TextEncoder(); diff --git a/packages/test-utils/src/vitest.ts b/packages/test-utils/src/vitest.ts index c0a0f1611..c8793ce86 100644 --- a/packages/test-utils/src/vitest.ts +++ b/packages/test-utils/src/vitest.ts @@ -6,7 +6,7 @@ import type { Plugin } from "vite"; import { defineConfig } from "vitest/config"; type Options = { - /** Test-double swaps, in Deno import-map format, relative to the package. */ + /** Test-double swaps, in import-map format, relative to the package. */ importMap?: string; /** Loaded into `process.env` for every test file, relative to the package. */ envFile?: string; @@ -14,7 +14,7 @@ type Options = { }; /** - * Applies a Deno-style import map: exact bare keys, `/`-suffixed prefix keys, + * Applies an import map: exact bare keys, `/`-suffixed prefix keys, * and relative keys matched against the importer-resolved path without * extension probing β€” so `./page-urls` is swapped but `./page-urls.ts` is not. */ diff --git a/packages/tinybird/src/env.ts b/packages/tinybird/src/env.ts index 201dc8061..a57868cfb 100644 --- a/packages/tinybird/src/env.ts +++ b/packages/tinybird/src/env.ts @@ -1,11 +1,7 @@ /** - * `NODE_ENV`, read so that bundlers cannot fold it away. - * - * `deno bundle` (esbuild) rewrites the exact expression `process.env.NODE_ENV` - * to a string literal at build time β€” `"development"` unless `--minify` is - * passed, and `apps/server` bundles without it (see `apps/server/dofigen.yml`). - * Reading through an aliased object defeats that substitution, so the value - * comes from the real environment at runtime. + * `NODE_ENV`, read so that bundlers cannot fold it away: some replace the + * exact expression `process.env.NODE_ENV` with a build-time literal. Reading + * through an aliased object keeps it a runtime value. */ export const env = { get NODE_ENV(): string {