From 93c19fec23dd25adff99abb30e98284f6c158f99 Mon Sep 17 00:00:00 2001 From: Philippe Serhal Date: Sun, 23 Aug 2026 10:51:47 -0400 Subject: [PATCH] refactor: make browser/node/deno seams still more explicit --- .oxlintrc.json | 24 ++++++++++++++ AGENTS.md | 31 ++++++++++++++----- CONTRIBUTING.md | 2 +- db/seed-local.ts | 2 +- import_map.json | 19 ++++++++++-- netlify/_shared/audit-jobs.ts | 4 +-- netlify/_shared/report-persistence.ts | 6 ++-- netlify/edge-functions/audit-stream.ts | 16 +++++----- .../edge-functions/user-publishes-stream.ts | 8 ++--- netlify/functions/_shared/report-schedules.ts | 15 +++++---- .../audit-jobs-cleanup-background.ts | 2 +- netlify/functions/reports.ts | 14 +++------ netlify/functions/trust-reruns-background.ts | 2 +- .../tests/edge-functions/audit-stream.test.ts | 19 ++++++------ .../user-publishes-stream.test.ts | 4 +-- netlify/tests/functions/audit-jobs.test.ts | 6 ++-- netlify/tests/functions/local-seed.test.ts | 6 ++-- .../functions/report-persistence.test.ts | 10 +++--- netlify/tests/functions/reports.test.ts | 4 +-- netlify/tests/functions/trust-reruns.test.ts | 14 ++++----- package.json | 8 +++++ src/App.svelte | 11 +++---- src/App.test.ts | 14 ++++----- src/AppRouter.test.ts | 2 +- src/SharedReport.svelte | 8 ++--- src/SharedReport.test.ts | 2 +- src/{lib => audit}/concurrency.test.ts | 0 src/{lib => audit}/concurrency.ts | 0 src/{lib => audit}/discovery.test.ts | 0 src/{lib => audit}/discovery.ts | 6 ++-- src/{lib => audit}/downloads.test.ts | 0 src/{lib => audit}/downloads.ts | 4 +-- src/{lib => audit}/npmClient.test.ts | 0 src/{lib => audit}/npmClient.ts | 2 +- src/{lib => audit}/reports.test.ts | 2 +- src/{lib => audit}/reports.ts | 12 +++---- src/{lib => audit}/runAudit.test.ts | 2 +- src/{lib => audit}/runAudit.ts | 20 ++---------- src/{lib => audit}/trust.test.ts | 0 src/{lib => audit}/trust.ts | 2 +- src/{lib => client}/auditStream.test.ts | 0 src/{lib => client}/auditStream.ts | 7 ++--- src/{lib => client}/dateFormatting.test.ts | 0 src/{lib => client}/dateFormatting.ts | 0 src/{lib => client}/export.test.ts | 0 src/{lib => client}/export.ts | 0 src/{lib => client}/historyGroups.test.ts | 4 +-- src/{lib => client}/historyGroups.ts | 2 +- src/{lib => client}/members.test.ts | 0 src/{lib => client}/members.ts | 0 src/{lib => client}/sseStream.ts | 0 src/{lib => client}/theme.svelte.ts | 0 src/{lib => client}/theme.test.ts | 0 src/{lib => client}/trustTrend.test.ts | 2 +- src/{lib => client}/trustTrend.ts | 2 +- src/{lib => client}/userPublishStream.test.ts | 0 src/{lib => client}/userPublishStream.ts | 6 ++-- src/components/DailyTrackingButton.svelte | 6 ++-- src/components/DailyTrackingButton.test.ts | 2 +- src/components/ExportButtons.svelte | 2 +- src/components/ExternalView.svelte | 2 +- src/components/HistoryPanel.svelte | 8 ++--- src/components/HistoryPanel.test.ts | 4 +-- src/components/HistoryStack.svelte | 6 ++-- src/components/HistoryStack.test.ts | 4 +-- src/components/ManualView.svelte | 4 +-- src/components/RecentReports.svelte | 6 ++-- src/components/RecentReports.test.ts | 4 +-- src/components/ResultsView.svelte | 3 +- src/components/ResultsView.test.ts | 2 +- src/components/SamplePreview.svelte | 8 ++--- src/components/ThemeToggle.svelte | 2 +- src/components/ThemeToggle.test.ts | 2 +- src/components/TrustTrend.svelte | 6 ++-- src/components/TrustTrend.test.ts | 4 +-- src/components/TrustView.svelte | 4 +-- src/components/UserPublishView.svelte | 4 +-- src/components/UserPublishView.test.ts | 2 +- src/components/reportFormatting.ts | 2 +- src/{lib => shared}/auditDefaults.ts | 0 src/{lib => shared}/exampleTrustHistory.ts | 2 +- src/{lib => shared}/reportHistory.test.ts | 0 src/{lib => shared}/reportHistory.ts | 4 +-- src/{lib => shared}/schemas.ts | 2 +- src/{lib => shared}/types.ts | 7 +++++ src/test/fixtures.ts | 3 +- src/test/setup.ts | 2 +- tsconfig.json | 5 +-- vite.config.ts | 2 +- 89 files changed, 241 insertions(+), 199 deletions(-) rename src/{lib => audit}/concurrency.test.ts (100%) rename src/{lib => audit}/concurrency.ts (100%) rename src/{lib => audit}/discovery.test.ts (100%) rename src/{lib => audit}/discovery.ts (95%) rename src/{lib => audit}/downloads.test.ts (100%) rename src/{lib => audit}/downloads.ts (96%) rename src/{lib => audit}/npmClient.test.ts (100%) rename src/{lib => audit}/npmClient.ts (99%) rename src/{lib => audit}/reports.test.ts (99%) rename src/{lib => audit}/reports.ts (97%) rename src/{lib => audit}/runAudit.test.ts (98%) rename src/{lib => audit}/runAudit.ts (82%) rename src/{lib => audit}/trust.test.ts (100%) rename src/{lib => audit}/trust.ts (95%) rename src/{lib => client}/auditStream.test.ts (100%) rename src/{lib => client}/auditStream.ts (95%) rename src/{lib => client}/dateFormatting.test.ts (100%) rename src/{lib => client}/dateFormatting.ts (100%) rename src/{lib => client}/export.test.ts (100%) rename src/{lib => client}/export.ts (100%) rename src/{lib => client}/historyGroups.test.ts (95%) rename src/{lib => client}/historyGroups.ts (96%) rename src/{lib => client}/members.test.ts (100%) rename src/{lib => client}/members.ts (100%) rename src/{lib => client}/sseStream.ts (100%) rename src/{lib => client}/theme.svelte.ts (100%) rename src/{lib => client}/theme.test.ts (100%) rename src/{lib => client}/trustTrend.test.ts (96%) rename src/{lib => client}/trustTrend.ts (98%) rename src/{lib => client}/userPublishStream.test.ts (100%) rename src/{lib => client}/userPublishStream.ts (87%) rename src/{lib => shared}/auditDefaults.ts (100%) rename src/{lib => shared}/exampleTrustHistory.ts (95%) rename src/{lib => shared}/reportHistory.test.ts (100%) rename src/{lib => shared}/reportHistory.ts (96%) rename src/{lib => shared}/schemas.ts (99%) rename src/{lib => shared}/types.ts (94%) diff --git a/.oxlintrc.json b/.oxlintrc.json index abc2e07..9e9e855 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -34,6 +34,30 @@ "builtin": true }, "overrides": [ + { + // Deno resolves relative specifiers literally in deployed edge bundles. + "files": [ + "src/{audit,shared}/**/*.ts", + "netlify/edge-functions/**/*.ts", + "netlify/_shared/**/*.ts", + "db/{index,schema}.ts" + ], + "excludeFiles": ["**/*.test.ts"], + "rules": { + "import/no-nodejs-modules": "error", + "no-restricted-imports": [ + "error", + { + "patterns": [ + { + "group": ["./**", "../**", "!./**/*.ts", "!../**/*.ts"], + "message": "Edge-reachable relative imports must use a literal .ts specifier." + } + ] + } + ] + } + }, // Don't enable e18e perf rules in test files { "files": ["**/*.{js,jsx,ts,tsx}"], diff --git a/AGENTS.md b/AGENTS.md index 5e46711..641de70 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,20 +27,35 @@ snapshots render through `SharedReport.svelte` and reuse ## Runtime boundaries -The server-side audit graph under `src/lib/` runs in both Deno edge functions -and Node scheduled functions. Anything reachable from `runAudit` or -`runUserPublishes` must use APIs available in both runtimes: no `node:` builtins -and no browser-only globals. Use Web Crypto, not `node:crypto`. +Runtime ownership is explicit in the source tree: + +- `src/client/` is browser-only. +- `src/shared/` contains contracts and utilities usable in the browser, Deno, + and Node. +- `src/audit/` is the server-side audit graph shared by Deno edge functions and + Node scheduled functions. + +Anything in `src/shared/` or `src/audit/` must use APIs available in every +declared runtime: no `node:` builtins or browser-only globals. Use Web Crypto, +not `node:crypto`. Cross-runtime Netlify helpers live in `netlify/_shared/`; `netlify/functions/_shared/` is reserved for Node-only function helpers. +Internal modules use the `package.json#imports` namespaces `#client/*`, +`#shared/*`, `#audit/*`, `#server/*`, `#node/*`, and `#db/*`. Prefer these over +cross-directory relative imports; the namespace makes runtime ownership visible. +Every edge-reachable alias must also have an exact `.ts` mapping in +`import_map.json`: Netlify's deploy-time Deno bundler does not resolve the +`package.json` wildcard mappings. + Netlify edge bundling has stricter rules than Vite or local development: - Edge-reachable relative imports require explicit `.ts` extensions. Node-only serverless files use `.js` and must not enter an edge bundle. -- `valibot` and `packumeta` are mapped to pinned esm.sh builds in - `import_map.json`. A new edge-reachable dependency may need the same treatment. +- Edge-reachable internal aliases, `valibot`, and `packumeta` are mapped in + `import_map.json`. Keep internal mappings synchronized with their + `package.json#imports` targets and pin third-party esm.sh builds. - `@netlify/database` is Netlify-first-party and deliberately not mapped. Use its native tagged-SQL client; validate returned rows with `db/schema.ts`. - Never put tests in `netlify/edge-functions/`: Netlify treats every `.ts` or @@ -51,7 +66,7 @@ Netlify edge bundling has stricter rules than Vite or local development: ### npm access and failure handling -Fetch npm directly through `src/lib/npmClient.ts`: +Fetch npm directly through `src/audit/npmClient.ts`: - `registry.npmjs.org`: packuments and per-version manifests. - `api.npmjs.org`: weekly downloads. @@ -142,7 +157,7 @@ Clipboard and Web Crypto APIs, `matchMedia`, semantic live regions, by default and progressive enhancement for newer ones; do not add JS polyfills for CSS anchor positioning. -Human-facing dates and times go through `src/lib/dateFormatting.ts` and follow +Human-facing dates and times go through `src/client/dateFormatting.ts` and follow the viewer's locale and timezone. Persistence, APIs, sorting, report ids, exports, and `