Both of your cameras call themselves "I91ET", so the slimmed dashboard showed two identical names. - A nickname kept in the registry now wins wherever a camera is named: cards, camera page, live view and its window title, pop-outs and the recordings list. It survives a rescan, and clearing it falls back to the camera's own name, then its model. - Rename on the camera page also writes the camera's own name and location over ONVIF SetScopes, so everything else on the network sees them. Since SetScopes replaces every configurable scope, the others are read and sent back untouched; the result is re-read from the camera and reported as applied or adjusted, and the change is audited. - cameraName() lives in a client-safe module, because the registry is server-only and the dashboard names cameras in the browser. - NEXT_DIST_DIR lets a build run while dev servers hold .next. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
48 lines
2.2 KiB
TypeScript
48 lines
2.2 KiB
TypeScript
import { realpathSync } from "node:fs";
|
|
import path from "node:path";
|
|
import type { NextConfig } from "next";
|
|
|
|
/**
|
|
* While onvif is linked to a local checkout outside this project (e.g. the fork, installed
|
|
* with `npm install ../onvif --no-save`), Turbopack only resolves files inside its root, so
|
|
* the root must contain both (Next docs, 03-api-reference/08-turbopack.md "Root directory").
|
|
* Returns undefined for a normal install, leaving the auto-detected root alone.
|
|
*/
|
|
function linkedPackagesRoot(project: string, packages: string[]): string | undefined {
|
|
let root = project;
|
|
for (const name of packages) {
|
|
let target: string;
|
|
try {
|
|
target = realpathSync(path.join(project, "node_modules", name));
|
|
} catch {
|
|
continue;
|
|
}
|
|
while (path.relative(root, target).startsWith("..")) root = path.dirname(root);
|
|
}
|
|
return root === project ? undefined : root;
|
|
}
|
|
|
|
const project = process.cwd();
|
|
const turbopackRoot = linkedPackagesRoot(project, ["onvif"]);
|
|
|
|
const nextConfig: NextConfig = {
|
|
// A build and a dev server sharing .next fight over it; NEXT_DIST_DIR lets a build run
|
|
// to one side while someone is working.
|
|
...(process.env.NEXT_DIST_DIR && { distDir: process.env.NEXT_DIST_DIR }),
|
|
// What gets published: a minimal server plus only the files it needs, so installing the
|
|
// package doesn't drag in Next and React (vrek iss-ej4ahga).
|
|
output: "standalone",
|
|
// Runtime data and the downloaded MediaMTX binary are not part of the app.
|
|
outputFileTracingExcludes: { "/*": ["bin/**/*", ".data/**/*", "node_modules/@img/**/*", "node_modules/sharp/**/*"] },
|
|
// next/image is unused, and leaving it on pulls sharp's platform binaries (tens of MB).
|
|
images: { unoptimized: true },
|
|
// onvif uses Node's dgram/os modules; load it with native require instead of bundling.
|
|
// onvif is bundled rather than listed in serverExternalPackages. Externalizing it made
|
|
// Turbopack emit require("onvif-<hash>") — a name that exists nowhere — because the
|
|
// dependency comes from a git URL, which broke the published package (vrek iss-9zcawn7).
|
|
// Bundled, discovery (dgram) and camera reads work from an installed copy.
|
|
...(turbopackRoot && { turbopack: { root: turbopackRoot } }),
|
|
};
|
|
|
|
export default nextConfig;
|