release: WRNexusJS 0.8.0
Quality / quality (ubuntu-latest) (push) Failing after 21s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-02 23:18:51 +05:30
parent 87507edf59
commit 586a6db8ff
625 changed files with 243608 additions and 11210 deletions
+103 -39
View File
@@ -6,7 +6,7 @@
* the running process while the HMR socket morphs fresh HTML into the browser.
*/
import { readFileSync } from "node:fs";
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { resolve, dirname, isAbsolute, join } from "node:path";
import type { Middleware, Mode, SecurityConfig, SeoConfig } from "@wrnexus/core";
import { buildRouter, type Router } from "@wrnexus/router";
@@ -28,6 +28,7 @@ import {
setDb,
registerDb,
registerLazyDb,
getDbPerformanceSnapshot,
} from "@wrnexus/db";
import { connectFromConfig } from "@wrnexus/db/connect";
import { configureStorage, type StorageConfig } from "@wrnexus/uploader";
@@ -38,6 +39,7 @@ import {
loadWrnServerModule,
setCompileCacheDir,
setCompileImportOptions,
setDevCompilerPipeline,
wrnBrowserArtifactUrl,
} from "./pipeline.ts";
import { createRpcHandler } from "@wrnexus/ssr/rpc";
@@ -48,18 +50,27 @@ import { resolvePackageMigrations } from "./plugin-migrations.ts";
import { HmrHub } from "./hmr.ts";
import { startWatcher } from "./watch.ts";
export { RESTART_EXIT_CODE } from "./restart.ts";
export { expandStaticComponents, precomputePartialStaticShell } from "./partial-build.ts";
export { getWrnCompileMetrics, resetWrnCompileMetrics } from "./pipeline.ts";
export type { WrnCompileMetrics } from "./pipeline.ts";
import { resetDevCache } from "./cache.ts";
import type { DevToolbarConfig } from "@wrnexus/dev-toolbar/types";
import { createPluginRunner, discoverPlugins, type PluginInput } from "@wrnexus/plugin";
import type { ObservabilityConfig, TenancyConfig } from "@wrnexus/styles";
import { createDevToolbarCollector, type DevToolbarCollector } from "@wrnexus/dev-toolbar/server";
import {
builtinDevToolbarPanels,
createDevToolbarCollector,
type DevToolbarCollector,
} from "@wrnexus/dev-toolbar/server";
export interface ServeOptions {
appDir: string;
port?: number;
hostname?: string;
/** Development TLS material. Production TLS is normally terminated by the deployment proxy. */
tls?: { cert: string; key: string };
mode?: Mode;
/** Inject the live-reload client (defaults to true in development). */
hmr?: boolean;
@@ -193,6 +204,12 @@ export async function startServer(opts: ServeOptions): Promise<RunningServer> {
includeDevDependencies: true,
strict: true,
warn: (message) => console.warn(`[wrnexus:plugin] ${message}`),
enforcePermissions: (opts.appConfig?.pluginPermissions as { enforce?: boolean } | undefined)
?.enforce,
grantedPermissions: (
opts.appConfig?.pluginPermissions as
{ grants?: Record<string, import("@wrnexus/plugin").PluginPermission[]> } | undefined
)?.grants,
});
const pluginRunner = createPluginRunner(discoveredPlugins, {
@@ -252,6 +269,30 @@ export async function startServer(opts: ServeOptions): Promise<RunningServer> {
);
const pluginContributions = await pluginRunner.contributions();
const virtualModules = new Map<string, string>();
const virtualDir = join(appRoot, ".wrnexus", "virtual");
mkdirSync(virtualDir, { recursive: true });
for (const [index, module] of pluginContributions.virtualModules.entries()) {
const output = join(virtualDir, `plugin-${index}.ts`);
writeFileSync(
output,
await module.load({
root: appRoot,
mode,
command: "dev",
profile: process.env.WRNEXUS_PROFILE,
metadata: new Map(),
warn: (message) => console.warn(`[wrnexus:plugin] ${message}`),
}),
"utf8",
);
virtualModules.set(module.id, output);
}
setDevCompilerPipeline({
transformAst: (ast, file) => pluginRunner.transformAst(ast, file),
transformCode: (code, file) => pluginRunner.transformCode(code, file),
virtualModules,
});
console.log(
`[wrnexus:plugin] discovered: ${
@@ -296,7 +337,7 @@ export async function startServer(opts: ServeOptions): Promise<RunningServer> {
const schemasJs = await schemaRuntime(router);
// i18n is opt-in by the presence of app/locales/*.json.
const localeMessages = loadLocales(join(appDir, "locales"));
const localeMessages = loadLocales(join(appDir, "locales"), { strict: opts.i18n?.strict });
const i18n = Object.keys(localeMessages).length
? resolveI18n(localeMessages, opts.i18n)
: undefined;
@@ -369,6 +410,34 @@ export async function startServer(opts: ServeOptions): Promise<RunningServer> {
})
: undefined;
const middleware = middlewareLoader(router);
const toolbarPlatform = {
wrnexus060: {
clientFunctions: true,
serverFunctions: true,
sharedFunctions: true,
typedOutputs: true,
requestScopedStores: true,
},
plugins: pluginRunner.plugins.map((plugin) => ({ name: plugin.name, version: plugin.version })),
runtimes: pluginContributions.clientRuntimes.map((runtime) => ({
id: runtime.id,
publicPath: runtime.publicPath,
type: runtime.type,
load: runtime.load,
})),
assets: pluginContributions.assets.map((asset) => ({
id: asset.id,
publicPath: asset.publicPath,
contentType: asset.contentType,
})),
componentDirs,
styles: pluginContributions.styles,
routes: {
pages: router.pages.length,
api: router.api.length,
realtime: router.realtime.length,
},
};
const runtimeDeps = {
mode,
@@ -392,13 +461,14 @@ export async function startServer(opts: ServeOptions): Promise<RunningServer> {
clientRuntimes: pluginContributions.clientRuntimes,
hub,
realtimeBus: realtimeBusFromConfig(opts.realtime),
renderHtml: (html: string) => pluginRunner.render(html),
devToolbar:
devToolbarConfig && devToolbarCollector
? {
config: devToolbarConfig,
collector: devToolbarCollector,
root: appRoot,
panels: [
panels: () => [
{
id: "runtime",
title: "Runtime",
@@ -415,39 +485,23 @@ export async function startServer(opts: ServeOptions): Promise<RunningServer> {
"Global/page stores, safe client state, computed values, actions, persistence, and hydration.",
order: 20,
},
{
id: "cache",
title: "Cache",
icon: "layers",
description:
"Request, data, component, and page cache entries plus hit/miss history.",
order: 30,
},
...builtinDevToolbarPanels({
root: appRoot,
platform: toolbarPlatform,
database: getDbPerformanceSnapshot(),
version: { current: "0.8.0" },
}),
...pluginToolbarPanels,
],
platform: {
wrnexus060: {
clientFunctions: true,
serverFunctions: true,
sharedFunctions: true,
typedOutputs: true,
requestScopedStores: true,
},
plugins: pluginRunner.plugins.map((plugin) => ({
name: plugin.name,
version: plugin.version,
})),
runtimes: pluginContributions.clientRuntimes.map((runtime) => ({
id: runtime.id,
publicPath: runtime.publicPath,
type: runtime.type,
load: runtime.load,
})),
assets: pluginContributions.assets.map((asset) => ({
id: asset.id,
publicPath: asset.publicPath,
contentType: asset.contentType,
})),
componentDirs,
styles: pluginContributions.styles,
routes: {
pages: router.pages.length,
api: router.api.length,
realtime: router.realtime.length,
},
},
platform: toolbarPlatform,
}
: undefined,
};
@@ -501,6 +555,7 @@ export async function startServer(opts: ServeOptions): Promise<RunningServer> {
hostname,
development: mode === "development",
maxRequestBodySize: 10 * 1024 * 1024,
...(opts.tls ? { tls: opts.tls } : {}),
fetch(request, server) {
if (new URL(request.url).pathname === "/__wrnexus/rpc") return rpcHandler(request);
return handlers.fetch(request, server);
@@ -551,13 +606,21 @@ export async function startServer(opts: ServeOptions): Promise<RunningServer> {
assets.updateSchemas(await schemaRuntime(router));
}
if (appFiles.some((file) => file === "locales" || file.startsWith("locales/"))) {
const messages = loadLocales(join(appDir, "locales"));
runtimeDeps.i18n = Object.keys(messages).length
? resolveI18n(messages, opts.i18n)
: undefined;
try {
const messages = loadLocales(join(appDir, "locales"), { strict: opts.i18n?.strict });
runtimeDeps.i18n = Object.keys(messages).length
? resolveI18n(messages, opts.i18n)
: undefined;
} catch (error) {
console.warn(
"[wrnexus] locale hot update was incomplete; keeping the last valid bundle",
error,
);
}
}
console.log(`[wrnexus] hot update — ${files.join(", ")}`);
await pluginRunner.hook("hmrUpdate", files);
const storeUpdates: Array<{ name: string; url: string; kind: string }> = [];
for (const changed of files) {
const absolute = isAbsolute(changed) ? changed : resolve(appDir, changed);
@@ -634,6 +697,7 @@ export async function startServer(opts: ServeOptions): Promise<RunningServer> {
watcher?.close();
unsubscribeDevToolbar?.();
server.stop();
void pluginRunner.hook("shutdown");
},
};
}