Skip to content

refactor: replace non-null assertions / unsafe casts with helpers#353

Merged
HugoRCD merged 5 commits into
mainfrom
refactor/typescript-cleanup
May 24, 2026
Merged

refactor: replace non-null assertions / unsafe casts with helpers#353
HugoRCD merged 5 commits into
mainfrom
refactor/typescript-cleanup

Conversation

@HugoRCD
Copy link
Copy Markdown
Owner

@HugoRCD HugoRCD commented May 24, 2026

🔗 Linked issue

📚 Description

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Summary by CodeRabbit

  • Bug Fixes
    • Improved null-safety and error handling across apps and server routes; various UI null/undefined issues fixed.
  • Content & SEO
    • More robust SEO metadata and Open Graph image generation; sitemap path/lastmod normalization.
  • UI / Docs
    • Safer docs navigation rendering and improved demo/terminal behavior; stream/playground and chat UIs render more reliably.
  • Tests & Tooling
    • Extensive test hardening and new helpers for more reliable assertions.
  • Performance
    • Benchmark baselines updated to reflect measured size changes.

@HugoRCD HugoRCD self-assigned this May 24, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
evlog-docs Ready Ready Preview, Comment, Open in v0 May 24, 2026 5:31pm
just-use-evlog Ready Ready Preview, Comment May 24, 2026 5:31pm

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 24, 2026

Thank you for following the naming conventions! 🙏

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 24, 2026

📝 Walkthrough

Walkthrough

Widespread runtime and test hardening: added runtime type guards, safer DOM/context access, deterministic stringify guard, logger/AI formatting hardening, updated framework integrations (Fastify, SvelteKit, ingest), and added test helpers plus mass test migrations to use them.

Changes

Safety + test harness migration

Layer / File(s) Summary
Small app/component runtime guards
apps/docs/..., apps/just-use-evlog/..., apps/nuxthub-playground/..., apps/playground/..., examples/...
UI components and app pages now use runtime guards for templates/DOM/props and safer computed logic; small fixes to interval cleanup and SEO field extraction.
Examples and utilities runtime guards
examples/..., examples/tanstack-start/..., examples/workers/...
Added requireRequestLogger utility; require-based DOM helpers; normalized catch/error handling to wrap non-Error throwables; updated example routes to use runtime-checked logger retrieval.
Ingest / server runtime guards and waitUntil handling
packages/evlog/src/runtime/server/routes/_evlog/ingest.post.ts
Stricter request body validation, timestamp normalization, explicit log level validation, and cross-platform safe discovery/use of event waitUntil for background drain work.
Core library: audit, logger, Fastify, SvelteKit hardening
packages/evlog/src/audit.ts, packages/evlog/src/logger.ts, packages/evlog/src/fastify/index.ts, packages/evlog/src/sveltekit/index.ts
stableStringify now guards plain objects; logger pretty/A I formatting hardened with plain-object checks and safe coercions; Fastify integration normalizes errors and attaches plugin metadata via Object.assign; SvelteKit integration adds EvlogError guards and normalizes thrown values before finishing.
Test helpers: defined/getDrainCallArg & test migration
packages/evlog/test/helpers/defined.ts, many packages/evlog/test/*
New defined/getDrainCallArg helpers and broad test-suite migration to use them (safer unwrapping of mock/drain call args, switch tests to drain-based assertions, useLogger() usage).
Test harness: Vite helpers & plugin test refactors
packages/evlog/test/helpers/vite.ts, packages/evlog/test/vite/*
Introduced shared Vite test utilities (getPluginHook, runPluginTransform, etc.) and updated multiple plugin tests to use the shared harness for consistent invocation and assertions.

Estimated code review effort:
🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs:

  • HugoRCD/evlog#335: Related docs-site sidebar/navigation rendering and type-safety updates.
  • HugoRCD/evlog#338: Related test-system refactors and shared helper additions.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/typescript-cleanup

@HugoRCD HugoRCD changed the title chore(bench): update size baseline refactor: replace non-null assertions / unsafe casts with helpers May 24, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 24, 2026

Benchmark report

Bundle size

Threshold: 5% · 🔴 larger · 🟡 warning · 🟢 smaller · ⚪ unchanged · 🆕 new

Status Entry Base (gzip) Current (gzip) Change Raw delta
🆕 adapter/memory 2.04 kB new +5.13 kB
🔴 framework/sveltekit 1.59 kB 1.96 kB +23.5% +1.33 kB
🔴 utils 1.58 kB 1.78 kB +12.6% +449 B
🔴 logger 229 B 255 B +11.4% +51 B
🔴 framework/fastify 1.02 kB 1.08 kB +6.3% +61 B
🟡 toolkit 781 B 798 B +2.2% +40 B
framework/express 727 B 741 B +1.9% +49 B
adapter/hyperdx 1.18 kB 1.19 kB +1.3% +41 B
adapter/better-stack 1.26 kB 1.27 kB +1.2% +41 B
framework/nitro 7.16 kB 7.23 kB +0.9% +196 B
adapter/posthog 1.47 kB 1.48 kB +0.9% +41 B
adapter/axiom 1.50 kB 1.51 kB +0.8% +41 B
adapter/datadog 2.48 kB 2.50 kB +0.6% +41 B
adapter/otlp 2.14 kB 2.15 kB +0.5% +41 B
adapter/sentry 2.40 kB 2.42 kB +0.4% +41 B
adapter/fs 3.35 kB 3.36 kB +0.4% +41 B
framework/nestjs 1.25 kB 1.26 kB +0.4% +41 B
framework/hono 615 B 616 B +0.2% 0 B
framework/ai 4.67 kB 4.67 kB 0.0% 0 B
framework/vite 2.40 kB 2.40 kB 0.0% 0 B
core (index) 2.15 kB 2.15 kB 0.0% 0 B
enrichers 1.99 kB 1.99 kB 0.0% 0 B
error 1.57 kB 1.57 kB 0.0% 0 B
pipeline 1.35 kB 1.35 kB 0.0% 0 B
workers 1.30 kB 1.30 kB 0.0% 0 B
http 1.24 kB 1.24 kB 0.0% 0 B
browser 289 B 289 B 0.0% 0 B
client 128 B 128 B 0.0% 0 B
types 31 B 31 B 0.0% 0 B
framework/next 5.20 kB 5.20 kB -0.0% 0 B
framework/elysia 1.33 kB 1.33 kB -0.1% 0 B
🔴 Total 54.33 kB 57.23 kB +5.3% +7.65 kB

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 24, 2026

npm i https://pkg.pr.new/evlog@353
npm i https://pkg.pr.new/@evlog/nuxthub@353

commit: ec9042d

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/evlog/test/ai/ai.test.ts (1)

16-35: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Replace local merge re-implementation with the real source helper.

Line 16 through Line 35 re-implement production merge behavior in tests (isPlainObject/mergeInto). This can drift from runtime behavior and weaken test fidelity; import the real helper (or expose a test-safe entrypoint) instead.

As per coding guidelines, "packages/evlog/test/**/*.{ts,tsx}: Always import real source helpers in tests, never re-implement them in tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/evlog/test/ai/ai.test.ts` around lines 16 - 35, Replace the local
re-implementation of isPlainObject and mergeInto in the test with the canonical
helper from the production source: remove the local isPlainObject and mergeInto
definitions and import the shared merge helper (the exported function that
provides the same merge behavior) into packages/evlog/test/ai/ai.test.ts; if the
helper is not exported for tests, add a test-safe export or entrypoint in the
production module and import that instead so the test uses the real
implementation rather than duplicating logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/evlog/src/audit.ts`:
- Around line 35-37: isPlainObject is currently treating any non-null, non-array
object (Dates, Maps, class instances) as plain, which breaks canonical hashing
used by stableStringify and signed; change isPlainObject to only return true for
true plain objects (i.e., objects whose [[Class]] is "Object" and whose
prototype is Object.prototype). Specifically, update isPlainObject(value) to
check Object.prototype.toString.call(value) === '[object Object]' and
(Object.getPrototypeOf(value) === Object.prototype || value.constructor ===
Object), so Dates/Maps/instances are not treated as plain and will not be
enumerated by stableStringify/signed({ strategy: ... }). Ensure the function
name isPlainObject remains the same so callers (e.g., stableStringify and
signed) continue to use it.

In `@packages/evlog/src/logger.ts`:
- Around line 440-444: The code assumes JSON.stringify(tc.input) returns a
string and calls .length, which can throw if it returns undefined; update the
logic in the block that builds the truncated input (the variables tc, inputStr,
truncated, hasInputs, toolCallEntries, idx) to safely coerce or guard the
serialized input before checking length—e.g., compute inputStr as a guaranteed
string (use a fallback like '' or String(JSON.stringify(tc.input) || '')) or
check for undefined before accessing .length, then perform the truncation only
when inputStr is a string; apply the same guard to the other similar snippet
around lines referencing inputStr/truncated.

In `@packages/evlog/test/helpers/vite.ts`:
- Around line 28-36: The callConfigResolved helper calls plugin.configResolved
or hook.handler synchronously and doesn't await possible Promises, so change
callConfigResolved to handle async returns: make it async (or return a Promise)
and await the result of invoking plugin.configResolved (for function hooks) or
hook.handler (for object-form hooks) so the plugin's async setup completes
before tests call transform; refer to the callConfigResolved function,
plugin.configResolved, and hook.handler when making this change.

In `@packages/nuxthub/src/module.ts`:
- Around line 37-39: The code assumes config.crons is an array when creating the
crons variable and mutating it; guard it by checking Array.isArray(config.crons)
and default to an empty array if not, e.g. initialize crons only from
config.crons when it's an array so subsequent operations (findIndex on crons and
any mutation) are safe; update the initialization that defines crons and keep
the rest of the logic that computes existing (findIndex for path
'/api/_cron/evlog-cleanup') unchanged.

---

Outside diff comments:
In `@packages/evlog/test/ai/ai.test.ts`:
- Around line 16-35: Replace the local re-implementation of isPlainObject and
mergeInto in the test with the canonical helper from the production source:
remove the local isPlainObject and mergeInto definitions and import the shared
merge helper (the exported function that provides the same merge behavior) into
packages/evlog/test/ai/ai.test.ts; if the helper is not exported for tests, add
a test-safe export or entrypoint in the production module and import that
instead so the test uses the real implementation rather than duplicating logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fde77243-2338-47ec-962e-b6d9ea7e1cb3

📥 Commits

Reviewing files that changed from the base of the PR and between ee997b3 and 07b655d.

📒 Files selected for processing (65)
  • apps/docs/app/components/HeroTerminalDemo.vue
  • apps/docs/app/components/docs/DocsAsideLeftBody.vue
  • apps/docs/app/components/docs/DocsAsideLeftBodyItem.vue
  • apps/docs/app/components/og-image/OgImageDocs.satori.vue
  • apps/docs/server/routes/sitemap.xml.ts
  • apps/just-use-evlog/app/pages/index.vue
  • apps/nuxthub-playground/app/components/AiChat.vue
  • apps/nuxthub-playground/server/api/logs.get.ts
  • apps/playground/app/pages/stream.vue
  • apps/playground/server/api/audit/with-audit.post.ts
  • apps/playground/server/api/test/better-auth/whoami.get.ts
  • examples/browser/src/client.ts
  • examples/community-adapter-skeleton/test/acme.test.ts
  • examples/community-framework-skeleton/src/index.ts
  • examples/solidstart/src/entry-client.tsx
  • examples/tanstack-start/src/routes/api/admin.ts
  • examples/tanstack-start/src/routes/api/checkout.ts
  • examples/tanstack-start/src/routes/api/hello.ts
  • examples/tanstack-start/src/routes/api/order.ts
  • examples/tanstack-start/src/utils/require-request-logger.ts
  • examples/workers/src/index.ts
  • packages/evlog/bench/baseline/size.json
  • packages/evlog/src/audit.ts
  • packages/evlog/src/fastify/index.ts
  • packages/evlog/src/logger.ts
  • packages/evlog/src/runtime/server/routes/_evlog/ingest.post.ts
  • packages/evlog/src/shared/define.ts
  • packages/evlog/src/shared/storage.ts
  • packages/evlog/src/sveltekit/index.ts
  • packages/evlog/test/README.md
  • packages/evlog/test/adapters/fs.test.ts
  • packages/evlog/test/ai/ai.test.ts
  • packages/evlog/test/core/audit.test.ts
  • packages/evlog/test/core/logger-request-logger.test.ts
  • packages/evlog/test/core/logger.test.ts
  • packages/evlog/test/core/middleware.test.ts
  • packages/evlog/test/core/pipeline.test.ts
  • packages/evlog/test/core/redact-integration.test.ts
  • packages/evlog/test/core/redact.test.ts
  • packages/evlog/test/frameworks/elysia.test.ts
  • packages/evlog/test/frameworks/express.test.ts
  • packages/evlog/test/frameworks/fastify.test.ts
  • packages/evlog/test/frameworks/hono.test.ts
  • packages/evlog/test/frameworks/nestjs-real-runtime.test.ts
  • packages/evlog/test/frameworks/nestjs.test.ts
  • packages/evlog/test/frameworks/react-router.test.ts
  • packages/evlog/test/frameworks/sveltekit.test.ts
  • packages/evlog/test/helpers/defined.ts
  • packages/evlog/test/helpers/framework.ts
  • packages/evlog/test/helpers/frameworkMatrix.ts
  • packages/evlog/test/helpers/vite.ts
  • packages/evlog/test/http/stream-server.test.ts
  • packages/evlog/test/next/middleware.test.ts
  • packages/evlog/test/next/storage.test.ts
  • packages/evlog/test/nitro/errorHandler.test.ts
  • packages/evlog/test/nitro/plugin-enrichment.test.ts
  • packages/evlog/test/nitro/plugin.test.ts
  • packages/evlog/test/vite/auto-imports.test.ts
  • packages/evlog/test/vite/client-inject.test.ts
  • packages/evlog/test/vite/source-location.test.ts
  • packages/evlog/test/vite/strip.test.ts
  • packages/nuxthub/src/config.ts
  • packages/nuxthub/src/module.ts
  • packages/nuxthub/src/runtime/drain.ts
  • packages/nuxthub/src/runtime/tasks/evlog-cleanup.ts

Comment thread packages/evlog/src/audit.ts
Comment thread packages/evlog/src/logger.ts
Comment thread packages/evlog/test/helpers/vite.ts Outdated
Comment thread packages/nuxthub/src/module.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/evlog/src/logger.ts`:
- Around line 367-370: The serializeToolInput function currently calls
JSON.stringify which can throw on circular structures or unsupported types
(e.g., BigInt); wrap the JSON.stringify call in a try/catch and provide a safe
fallback (for example, use a replacer to convert BigInt to strings and
detect/replace circular refs, or on error return a deterministic fallback like
util.inspect(input) or String(input) with an explanatory marker). Update
serializeToolInput to attempt JSON.stringify(input) inside try, handle known
edge cases (BigInt -> toString) or catch exceptions and return a safe string so
serialization never throws.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ae31550d-0ed4-489d-9d09-a995877b0d1f

📥 Commits

Reviewing files that changed from the base of the PR and between 07b655d and b9921cc.

📒 Files selected for processing (10)
  • packages/evlog/src/audit.ts
  • packages/evlog/src/logger.ts
  • packages/evlog/test/ai/ai.test.ts
  • packages/evlog/test/core/audit.test.ts
  • packages/evlog/test/helpers/vite.ts
  • packages/evlog/test/vite/auto-imports.test.ts
  • packages/evlog/test/vite/client-inject.test.ts
  • packages/evlog/test/vite/source-location.test.ts
  • packages/evlog/test/vite/strip.test.ts
  • packages/nuxthub/src/module.ts

Comment thread packages/evlog/src/logger.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/evlog/test/core/logger.test.ts`:
- Around line 1160-1162: Add a logger reset to the existing afterEach block:
call initLogger({ pretty: false }) in the afterEach alongside
vi.restoreAllMocks() so the global logger state is returned to defaults after
each test; reference the existing afterEach and the initLogger function to
locate where to add the call.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6f337a1c-8201-4a1e-96a2-e11f78dddcfd

📥 Commits

Reviewing files that changed from the base of the PR and between b9921cc and ec9042d.

📒 Files selected for processing (2)
  • packages/evlog/src/logger.ts
  • packages/evlog/test/core/logger.test.ts

Comment on lines +1160 to +1162
afterEach(() => {
vi.restoreAllMocks()
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider resetting logger state in afterEach for consistency.

Other test suites in this file (e.g., enabled option, silent option) call initLogger({ pretty: false }) in afterEach to reset global logger state. While this test suite is currently last in the file, adding the reset would be more robust against future test additions or reordering.

Suggested change
   afterEach(() => {
     vi.restoreAllMocks()
+    initLogger({ pretty: false })
   })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
afterEach(() => {
vi.restoreAllMocks()
})
afterEach(() => {
vi.restoreAllMocks()
initLogger({ pretty: false })
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/evlog/test/core/logger.test.ts` around lines 1160 - 1162, Add a
logger reset to the existing afterEach block: call initLogger({ pretty: false })
in the afterEach alongside vi.restoreAllMocks() so the global logger state is
returned to defaults after each test; reference the existing afterEach and the
initLogger function to locate where to add the call.

@HugoRCD HugoRCD merged commit 354275f into main May 24, 2026
20 checks passed
@HugoRCD HugoRCD deleted the refactor/typescript-cleanup branch May 24, 2026 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant