Skip to content

v0.7.5

Choose a tag to compare

@github-actions github-actions released this 19 Sep 07:12
· 43 commits to main since this release

ExisJS Release v0.7.5

Release Date: 2026-09-19
Type: Minor Resilience, Modern Web Standards & Developer Experience
Affected Packages: exisjs, @exisjs/rs, create-exisjs


Highlights

  • Centralized Exception Handler (src/http/error.ts): Auto-discovered by the framework without manual registration in server.ts. New scaffolding command exis g error.
  • Boundary Lifecycle Hooks: Granular beforeHandle(req, res) (route guarding) and afterHandle(req, res, data) (payload transformation / auditing) across functional and OOP paradigms.
  • Modern Web Standards:
    • req.signal: Standard Web API AbortSignal for in-flight request cancellation.
    • Dual-stack IPv6-mapped IPv4 normalization (::ffff:x.x.x.x $\to$ x.x.x.x and ::1 $\to$ 127.0.0.1).
    • CHIPS Partitioned cookies (partitioned: true) and storage retention priority: 'low' | 'medium' | 'high'.
    • Automatic secure: true enforcement on sameSite: 'None'.
    • Domain/path-scoped res.clearCookie(name, { path, domain }).
  • Leak-Safe Streaming (res.sendStream): Automatically destroys source streams (stream.destroy()) on client disconnect to prevent socket and file descriptor leaks.
  • Schema & Query String Coercion:
    • tex.date({ coerce: true, minDate, maxDate }): Parses ISO 8601 strings into native JavaScript Date instances.
    • tex.array(schema, { coerce: true }): Automatically coerces single strings and comma-separated query parameters (e.g. ?tags=node,rust) into typed arrays.
  • IETF Rate Limit Headers: Standard RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, and RFC 6585 Retry-After on HTTP 429.
  • Zero-Delay Graceful Shutdown: server.closeIdleConnections() terminates idle keep-alive sockets immediately, cutting server teardown and reload delay to < 10ms.
  • CI/CD Build Resilience: Added --skip-env-check and mock schema resolution for headless container production builds.

Detailed Changes

Added

Centralized Exception Handler

// src/http/error.ts
import type { ExisRequest, ExisResponse } from 'exisjs'

export default function onError(err: any, req: ExisRequest, res: ExisResponse) {
  const statusCode = err.statusCode || 500
  res.status(statusCode).json({
    success: false,
    error: err.name || 'InternalServerError',
    message: err.message || 'An unexpected error occurred',
    path: req.path
  })
}

Boundary Lifecycle Hooks

// src/http/api/boundary.ts
import { defineBoundary } from 'exisjs/router'

export const config = defineBoundary({
  async beforeHandle(req, res) {
    if (!req.headers['x-api-key']) {
      res.status(401).json({ error: 'Unauthorized' })
      return false
    }
  },
  afterHandle(req, res, data) {
    return { ...data, processedAt: Date.now() }
  }
})

Request Cancellation (req.signal)

// src/http/search/route.ts
import { controller, route } from 'exisjs/router'

export default controller({
  query: route.get('/search', {
    async handle({ req, query }) {
      // Abort downstream fetch if client closes connection
      const response = await fetch(`https://api.external.com?q=${query.q}`, {
        signal: req.signal
      })
      return response.json()
    }
  })
})

Query Coercion

// src/http/events/route.ts
const FilterSchema = tex.object({
  from: tex.date({ coerce: true, optional: true }),
  tags: tex.array(tex.string(), { coerce: true, optional: true })
})
// Handles: ?from=2026-09-01T00:00:00Z&tags=tech,ai

Fixed

  • Sanitizer & Validator Null Handling:
    • Prevented TypeError: Cannot read properties of null (reading 'trim') across top-level fields, nested array items, and post-validation refinements on nullable schemas.
    • Updated native Rust engine (validate_field) to accept null for nullable fields and inner array elements.
  • Dev Watcher Windows File Lock Crash:
    • Intercepted non-fatal EBUSY, EPERM, and UNKNOWN file lock exceptions on Chokidar watchers on Windows.
    • Expanded watcher ignore rules for compressed archives (.rar, .zip, .tar.gz, etc.), lock files, logs, and database files.
  • Root Tool Configuration Isolation:
    • Fixed exis build attempting to compile external root configs (drizzle.config.ts, vite.config.ts, tailwind.config.ts).
    • Added skipLibCheck: true during programmatic TypeScript builds to protect against uninstalled dev-tool type definitions.
    • Promoted @types/node and core HTTP types to dependencies so production installations (--omit=dev) preserve complete types.

Full Changelog: v0.7.4...v0.7.5