Ovineko

website·Indexed 29 days ago

https://ovineko.com

A collection of tools and utility packages for modern web applications, featuring SPA Guard—a family of packages for resilient single-page applications providing automatic retry, cache busting, and error reporting. Includes specialized integrations such as @ovineko/spa-guard-react, @ovineko/spa-guard-vite, @ovineko/spa-guard-fastify, and @ovineko/spa-guard-react-router.

Tokens
12.3K
Snippets
72
Records
90
Agent score
49%

What's inside Ovineko

  1. Overview of SPA Guard and its package family

    SPA Guard is a family of packages that ensures resilient single-page applications by handling JavaScript chunk load failures caused by network issues, deployment cache invalidation, CDN problems, or 404s. It implements a two-level retry strategy: module-level retries for individual import() calls and page-level retries that trigger full page reloads with cache busting.

    Package Ecosystem

    • @ovineko/spa-guard: Core runtime, error handling, schema, and i18n.
    • @ovineko/spa-guard-react: React hooks, components, and error boundaries (Requires react@^19).
    • @ovineko/spa-guard-react-router: Integration for React Router v7 error boundaries (Requires react@^19, react-router@^7).
    • @ovineko/spa-guard-vite: Vite plugin to inject the runtime script at build time (Requires vite@^8 or ^7).
    • @ovineko/spa-guard-node: Server-side HTML cache with ETag/304, pre-compression, and i18n (Requires parse5@^8).
    • @ovineko/spa-guard-fastify: Fastify plugin for beacon endpoints and HTML cache handling (Requires fastify@^5 or ^4).
    • @ovineko/spa-guard-eslint: ESLint rules for enforcing SPA Guard patterns (Requires eslint@^9 or ^10).
  2. Overview of @ovineko utility packages

    The @ovineko organization provides several standalone, independently versioned utility packages for modern web applications:

    • @ovineko/react-router: Type-safe wrapper for React Router v7 with valibot schema validation.
    • @ovineko/clean-pkg-json: Zero-config tool to clean package.json before publishing.
    • @ovineko/fastify-base: Pre-configured Fastify server with observability integrations.
    • @ovineko/datamitsu-config: Internal shared configuration for datamitsu tooling.
  3. Planned features and integrations for @ovineko/clean-pkg-json

    The @ovineko/clean-pkg-json package is currently in development (v0.0.0) and not yet published to npm. It is designed to provide a production-ready Fastify server setup with built-in observability and health monitoring. Planned features include:

    • Sentry Integration: Automatic error tracking, stack traces, and performance monitoring.
    • Prometheus Metrics: Built-in metrics endpoint (default /metrics) for HTTP latency, status codes, and runtime metrics (CPU/Memory).
    • OpenTelemetry: Distributed tracing with automatic span creation and context propagation for microservices.
    • Health Checks: Standardized liveness (/health/live) and readiness (/health/ready) probes, including custom checks for databases and caches.
    • TypeScript Support: Full type-safety and sensible production defaults.
    const server = await createFastifyServer({
      sentry: {
        dsn: process.env.SENTRY_DSN,
        environment: process.env.NODE_ENV,
      },
      prometheus: {
        enabled: true,
        endpoint: "/metrics",
      },
      opentelemetry: {
        enabled: true,
        serviceName: "my-service",
      },
      health: {
        liveness: "/health/live",
        readiness: "/health/ready",
      },
    });
    
    // Add your routes
    server.get("/api/users", async (request, reply) => {
      return { users: [] };
    });
    
    await server.listen({ port: 3000, host: "0.0.0.0" });
  4. Ovineko project requirements and technology stack

    Ovineko is a monorepo of tools built with a specific technology stack. It strictly enforces the use of pnpm as the package manager via a preinstall script.

    System Requirements:

    • Node.js >= 24.11.0
    • pnpm >= 10.25.0

    Core Technologies:

    • TypeScript, React 19, React Router v7, Valibot (runtime validation), and Fastify.

    Development Tooling:

    • Build: tsup (esbuild), turbo (monorepo orchestration).
    • Testing: vitest.
    • Quality: datamitsu (orchestrator for oxlint, ESLint, Prettier, knip, commitlint, syncpack, and gitleaks).
  5. SPA Guard recovery and reporting architecture

    SPA Guard implements a coordinated recovery system:

    • Two-Level Retry: First, lazyWithRetry (from @ovineko/spa-guard-react) attempts to retry the specific import() call. If that fails, the orchestrator triggers a full-page reload with cache-busting parameters.
    • User Feedback: Injects a loading UI into the DOM during the reload process so the user is aware of the recovery attempt.
    • Reliable Reporting: Uses navigator.sendBeacon to send structured error payloads to the server, ensuring errors are reported even if they occur before Sentry initializes or during page unload.
  6. SPA Guard package family overview

    SPA Guard is a suite of packages designed for resilient single-page applications. The family includes:

    • @ovineko/spa-guard: Core runtime, error handling, schema, and i18n.
    • @ovineko/spa-guard-react: React hooks, components, and error boundaries.
    • @ovineko/spa-guard-react-router: Integration for React Router v7 error boundaries.
    • @ovineko/spa-guard-vite: Vite plugin and inline scripts.
    • @ovineko/spa-guard-node: Server-side HTML cache with ETag/304, pre-compression, and i18n (using parse5).
    • @ovineko/spa-guard-fastify: Fastify plugin for beacon endpoints and HTML cache handling.
    • @ovineko/spa-guard-eslint: ESLint rules (e.g., no-direct-lazy, no-direct-error-boundary).
  7. Understand how SPA Guard handles chunk load errors

    SPA Guard addresses five critical failure modes that standard error boundaries (like React's) or error trackers (like Sentry) often miss because they require the main JS bundle to have already loaded:

    1. Post-deployment Chunk 404s: When a user has an old tab open and navigates to a lazy route after a new deployment. Solution: Page reload.
    2. Lazy Module Initialization Errors: Errors thrown during the execution of a successfully loaded lazy module.
    3. Main Chunk Failure: When the primary bundle fails to load (CDN/Network error). Since Sentry/Error listeners are usually inside the bundle, they never run. Solution: An inline script in <head> that runs before any chunks are requested.
    4. CSS Preload Failures: When CSS chunks are blocked or 404. Solution: Capturing 'error' events and unhandledrejection.
    5. CSP Violations: When the browser blocks a script via Content-Security-Policy. Solution: Listening for securitypolicyviolation events.
  8. Initialize SPA Guard with recommendedSetup

    Call recommendedSetup() immediately after the React render() call. This ensures the SPA Guard loading overlay is dismissed only after React has taken over the DOM and prevents the healthy boot grace timer from starting too early. The function is idempotent and returns a cleanup function to tear down version checking and the boot timer.
    import { recommendedSetup } from '@ovineko/spa-guard-react';
    
    createRoot(document.getElementById("root")!).render(
      <StrictMode>
        <ErrorBoundary>
          <App />
        </ErrorBoundary>
      </StrictMode>,
    );
    
    // Dismisses loading spinner and starts healthy boot grace timer
    const cleanup = recommendedSetup();
  9. Install @ovineko/spa-guard-react-router

    Install the React Router integration along with its required peer dependencies: @ovineko/spa-guard, @ovineko/spa-guard-react, react, and react-router.
    pnpm add @ovineko/spa-guard-react-router @ovineko/spa-guard @ovineko/spa-guard-react react react-router
  10. Clean package.json before publishing with @ovineko/clean-pkg-json

    @ovineko/clean-pkg-json is a zero-config tool that removes development-only fields (like devDependencies and scripts) from package.json before publishing and restores them afterward.

    How it works:

    • clean: Creates a package.json.backup and removes all fields not on the whitelist.
    • restore: Replaces package.json from the backup and deletes the backup file.

    Whitelisted Fields:

    • Identity: name, version, description, keywords, author, license
    • Entry points: main, module, types, exports, bin
    • Publishing: files, type, engines, publishConfig, repository, bugs, homepage, sideEffects, funding
    • Dependencies: dependencies, peerDependencies, peerDependenciesMeta, optionalDependencies, bundledDependencies, bundleDependencies
    • Scripts: Only preinstall, install, and postinstall are preserved.
    # Install
    pnpm add -D @ovineko/clean-pkg-json
    
    # Manual Usage
    clean-pkg-json clean    # backup + clean
    clean-pkg-json restore  # restore from backup
  11. Cache and serve SPA HTML with content negotiation

    Use createHtmlCache to pre-compress SPA HTML for multiple languages. The get() method handles accept-encoding (gzip/brotli/zstd), accept-language, and if-none-match (ETag) to return the optimal body and status code.
    const html = await readFile("dist/index.html", "utf8");
    const cache = await createHtmlCache({
      html,
      languages: ["en", "ko", "ja"],
      translations: {
        ko: { heading: "서비스 점검 중입니다" },
      },
    });
    
    // In your request handler:
    const { body, headers, statusCode } = cache.get({
      acceptEncoding: req.headers["accept-encoding"],
      acceptLanguage: req.headers["accept-language"],
      ifNoneMatch: req.headers["if-none-match"],
    });
    res.writeHead(statusCode, headers);
    res.end(body);
  12. Build and test Ovineko packages

    Ovineko uses Turborepo for global builds and pnpm for package-specific tasks. Testing is powered by Vitest. Note that console output is suppressed by default during tests; use the debug command to enable it.
    # Build all packages
    turbo build
    
    # Build a specific package
    cd packages/react-router
    pnpm build
    
    # Run tests in a specific package
    cd packages/react-router
    pnpm test              # Run once
    pnpm test:watch        # Watch mode
    pnpm test:coverage     # With coverage report
    pnpm test:ui           # Open Vitest UI
    pnpm test:debug        # Enable console output (DEBUG=1)