npm.io
1.0.0-rc.1 • Published 3d ago

@jgdina/next

Licence
GPL-3.0-only
Version
1.0.0-rc.1
Deps
3
Size
85 kB
Vulns
0
Weekly
0

@jgdina/next

Thin Next.js App Router adapters for jGDINA v1. The package is licensed under GPL-3.0-only, like the rest of jGDINA.

The root entry point is server-only and uses @jgdina/node. The @jgdina/next/client entry point is browser-only and re-exports @jgdina/browser; neither entry point imports next at runtime.

Next.js 16 is the tested and supported RC target. Keep the Node worker package external so its compiled worker entry remains adjacent to the adapter at runtime:

// next.config.mjs
const nextConfig = {
  serverExternalPackages: ["@jgdina/node"],
};

export default nextConfig;

Node Route Handler

Keep the reusable handler in a normal module so tests or a controlled server shutdown can call its cleanup API:

// lib/jgdina-route.ts
import { createJGDINARouteHandler } from "@jgdina/next";

const route = createJGDINARouteHandler({
  maxBodyBytes: 1_048_576,
  node: { size: 1 },
});

export const handleJGDINAPost = route.POST;
export const closeJGDINARoute = route.close;
// app/api/jgdina/route.ts
import { handleJGDINAPost } from "../../../lib/jgdina-route";

// jGDINA uses worker_threads and therefore must not run at the Edge.
export const runtime = "nodejs";

export const POST = handleJGDINAPost;

The worker pool is not created until the first well-formed request and is then reused by later requests in the same module instance. close() is idempotent; after it runs, the handler returns 503 and does not create another pool.

Send a JSON FitInput:

const response = await fetch("/api/jgdina", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    responses: [[0, 0], [0, 1], [1, 0], [1, 1]],
    qMatrix: [[1], [1]],
    model: "DINA",
  }),
});

const payload = await response.json();
if (!payload.ok) throw new Error(payload.error.message);
console.log(payload.result);

Successful responses are { ok: true, result }. Errors are { ok: false, error: { code, message, details? } }. The adapter rejects wrong methods (405), non-JSON content (415), malformed JSON (400), and bodies over the configured byte limit (413) before it starts a worker. Valid jGDINA input/resource errors return 422; aborts return 408; unexpected failures return a generic 500 response without internal messages or stacks.

Fully client-side and static

No API route is required when the fit should remain in the browser. Put the client code behind the browser-only subpath:

// components/client-fit.tsx
"use client";

import { createJGDINAClient } from "@jgdina/next/client";

const jgdina = createJGDINAClient();

export function ClientFit() {
  async function run() {
    const result = await jgdina.fit({
      responses: [[0, 0], [0, 1], [1, 0], [1, 1]],
      qMatrix: [[1], [1]],
      model: "DINA",
    });
    console.log(result);
  }

  return <button onClick={run}>Fit in this browser</button>;
}
// app/client/page.tsx
import { ClientFit } from "../../components/client-fit";

export const dynamic = "force-static";

export default function ClientPage() {
  return <ClientFit />;
}

Each browser fit runs CPU-heavy numerical estimation in a dedicated Web Worker. Input validation/copying and transport packing still run synchronously on the main thread before the Worker starts, and result parsing/assertion run there after it finishes. Worker-phase cancellation is prompt because it terminates the active Worker; it cannot interrupt those synchronous pre/post phases. The complete runnable layout is in examples/next-app.

Production boundary

The adapter supplies a bounded JSON body, a lazy worker pool, request-signal cancellation, and structured errors. It does not supply authentication, tenancy, quotas, a wall-clock deadline, a durable queue, persistence, or statistical model-fit diagnostics.

For production, make posteriorStorage: "scores-only" the application default, start with a one-worker pool, set both request and active-memory budgets, and verify worker packaging and cancellation in the target provider. Move fits to an application-owned durable job system when they can approach a request deadline or must survive a disconnect/restart.

The complete local jGDINA workspace contains the production and API guides. This archive includes the preferred TypeScript source and exact package-local rebuild procedure in SOURCE.md, compatibility provenance in UPSTREAM.md, and the GPL-3.0-only license with NOTICE.