@bleedingdev/modern-js-server 3.5.0-ultramodern.10 → 3.5.0-ultramodern.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,41 +1,15 @@
1
1
  import "node:module";
2
2
  import { connectMid2HonoMid } from "@modern-js/server-core/node";
3
- import { API_DIR, SHARED_DIR } from "@modern-js/utils";
4
- import { getDevOptions, getMockMiddleware, initFileReader, onRepack, startWatcher } from "./helpers/index.mjs";
5
- const devPlugin = (options, compiler)=>({
3
+ import { API_DIR, SHARED_DIR, logger } from "@modern-js/utils";
4
+ import { getDevOptions, getMockMiddleware, initFileReader, isPathInsideDirectory, onRepack, resolveMockDirectory, startWatcher } from "./helpers/index.mjs";
5
+ const devRuntimeMiddlewarePlugin = (options, compiler)=>({
6
6
  name: '@modern-js/plugin-dev',
7
7
  setup (api) {
8
- const { config, pwd, builder, builderDevServer } = options;
9
- const closeCb = [];
8
+ const { pwd, builderDevServer } = options;
10
9
  const dev = getDevOptions(options.dev);
11
10
  api.onPrepare(async ()=>{
12
- const { middlewares: builderMiddlewares, close, connectWebSocket } = builderDevServer || {};
13
- close && closeCb.push(close);
14
- const { middlewares, distDirectory, nodeServer, apiDirectory, sharedDirectory, serverBase } = api.getServerContext();
15
- connectWebSocket && nodeServer && connectWebSocket({
16
- server: nodeServer
17
- });
18
- const hooks = api.getHooks();
19
- builder?.onDevCompileDone(({ stats })=>{
20
- if ('server' !== stats.toJson({
21
- all: false
22
- }).name) onRepack(distDirectory, hooks);
23
- });
24
- const { watchOptions } = config.server;
25
- const watcher = startWatcher({
26
- pwd,
27
- distDir: distDirectory,
28
- apiDir: apiDirectory || API_DIR,
29
- sharedDir: sharedDirectory || SHARED_DIR,
30
- watchOptions,
31
- server: serverBase
32
- });
33
- closeCb.push(watcher.close.bind(watcher));
34
- closeCb.length > 0 && nodeServer?.on('close', ()=>{
35
- closeCb.forEach((cb)=>{
36
- cb();
37
- });
38
- });
11
+ const { middlewares: builderMiddlewares } = builderDevServer || {};
12
+ const { middlewares } = api.getServerContext();
39
13
  const before = [];
40
14
  const after = [];
41
15
  const { setupMiddlewares = [] } = dev;
@@ -53,7 +27,7 @@ const devPlugin = (options, compiler)=>({
53
27
  handler: connectMid2HonoMid(middleware)
54
28
  });
55
29
  });
56
- const mockMiddleware = await getMockMiddleware(pwd);
30
+ const mockMiddleware = await getMockMiddleware(pwd, options.config?.dev?.mockDir);
57
31
  middlewares.push({
58
32
  name: 'mock-dev',
59
33
  handler: mockMiddleware
@@ -75,4 +49,60 @@ const devPlugin = (options, compiler)=>({
75
49
  });
76
50
  }
77
51
  });
78
- export { devPlugin };
52
+ function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, onFileChange, onClose, nodeServer }) {
53
+ const { close, connectWebSocket } = builderDevServer || {};
54
+ const closeCb = [];
55
+ close && closeCb.push(close);
56
+ connectWebSocket && nodeServer && connectWebSocket({
57
+ server: nodeServer
58
+ });
59
+ builder?.onDevCompileDone(({ stats })=>{
60
+ if ('server' !== stats.toJson({
61
+ all: false
62
+ }).name) {
63
+ const runtimeServer = getRuntimeServer();
64
+ if (runtimeServer) onRepack(distDir, runtimeServer.hooks);
65
+ }
66
+ });
67
+ const { watchOptions } = config.server;
68
+ const mockDir = config.dev?.mockDir;
69
+ const mockPath = resolveMockDirectory(pwd, mockDir);
70
+ const watcher = startWatcher({
71
+ pwd,
72
+ distDir,
73
+ apiDir: apiDir || API_DIR,
74
+ sharedDir: sharedDir || SHARED_DIR,
75
+ mockDir,
76
+ watchOptions,
77
+ onChange: (filepath, event)=>{
78
+ const runtimeServer = getRuntimeServer();
79
+ if (runtimeServer && !isPathInsideDirectory(filepath, mockPath)) {
80
+ const fileChangeEvent = {
81
+ type: 'file-change',
82
+ payload: [
83
+ {
84
+ filename: filepath,
85
+ event
86
+ }
87
+ ]
88
+ };
89
+ Promise.resolve(runtimeServer.hooks.onReset.call({
90
+ event: fileChangeEvent
91
+ })).catch((error)=>logger.error(error));
92
+ }
93
+ onFileChange(filepath, event);
94
+ }
95
+ });
96
+ closeCb.push(watcher.close.bind(watcher));
97
+ onClose && closeCb.push(onClose);
98
+ const close$ = ()=>{
99
+ closeCb.forEach((cb)=>{
100
+ cb();
101
+ });
102
+ };
103
+ closeCb.length > 0 && nodeServer?.on('close', close$);
104
+ return {
105
+ close: close$
106
+ };
107
+ }
108
+ export { devRuntimeMiddlewarePlugin, setupDevInfra };
@@ -1,44 +1,16 @@
1
1
  import __rslib_shim_module__ from "node:module";
2
2
  const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/ (()=>import.meta.url)());
3
- import { AGGRED_DIR } from "@modern-js/server-core";
4
- import { SERVER_BUNDLE_DIRECTORY, SERVER_DIR, logger } from "@modern-js/utils";
3
+ import { SERVER_BUNDLE_DIRECTORY, SERVER_DIR } from "@modern-js/utils";
5
4
  import path from "path";
6
5
  import dev_tools_watcher, { mergeWatchOptions } from "../dev-tools/watcher/index.mjs";
7
- import { initOrUpdateMockMiddlewares } from "./mock.mjs";
8
- import { debug } from "./utils.mjs";
6
+ import { resolveMockDirectory } from "./mock.mjs";
9
7
  export * from "./devOptions.mjs";
10
8
  export * from "./fileReader.mjs";
11
9
  export * from "./mock.mjs";
12
10
  export * from "./repack.mjs";
13
- async function onServerChange({ pwd, filepath, event, server }) {
14
- const { mock } = AGGRED_DIR;
15
- const mockPath = path.normalize(path.join(pwd, mock));
16
- const { hooks } = server;
17
- if (filepath.startsWith(mockPath)) {
18
- await initOrUpdateMockMiddlewares(pwd);
19
- logger.info('Finish update the mock handlers');
20
- } else try {
21
- const fileChangeEvent = {
22
- type: 'file-change',
23
- payload: [
24
- {
25
- filename: filepath,
26
- event
27
- }
28
- ]
29
- };
30
- await hooks.onReset.call({
31
- event: fileChangeEvent
32
- });
33
- debug(`Finish reload server, trigger by ${filepath} ${event}`);
34
- } catch (e) {
35
- logger.error(e);
36
- }
37
- }
38
- function startWatcher({ pwd, distDir, apiDir, sharedDir, watchOptions, server }) {
39
- const { mock } = AGGRED_DIR;
11
+ function startWatcher({ pwd, distDir, apiDir, sharedDir, mockDir, watchOptions, onChange }) {
40
12
  const defaultWatched = [
41
- `${mock}/**/*`,
13
+ path.join(resolveMockDirectory(pwd, mockDir), '**/*'),
42
14
  `${SERVER_DIR}/**/*`,
43
15
  `${apiDir}/**`,
44
16
  `${sharedDir}/**/*`,
@@ -55,12 +27,7 @@ function startWatcher({ pwd, distDir, apiDir, sharedDir, watchOptions, server })
55
27
  if (filepath.includes('-server-loaders.js')) return void delete require.cache[filepath];
56
28
  watcher.updateDepTree();
57
29
  watcher.cleanDepCache(filepath);
58
- onServerChange({
59
- pwd,
60
- filepath,
61
- event,
62
- server
63
- });
30
+ onChange(filepath, event);
64
31
  });
65
32
  return watcher;
66
33
  }
@@ -2,10 +2,15 @@ import "node:module";
2
2
  import node_path from "node:path";
3
3
  import { AGGRED_DIR } from "@modern-js/server-core";
4
4
  import { connectMockMid2HonoMid } from "@modern-js/server-core/node";
5
- import { fs } from "@modern-js/utils";
5
+ import { compatibleRequire, fs } from "@modern-js/utils";
6
6
  import { match } from "path-to-regexp";
7
7
  let mockAPIs = [];
8
8
  let mockConfig;
9
+ const resolveMockDirectory = (pwd, mockDir = AGGRED_DIR.mock)=>node_path.resolve(pwd, mockDir);
10
+ const isPathInsideDirectory = (filepath, directory)=>{
11
+ const relativePath = node_path.relative(directory, node_path.resolve(filepath));
12
+ return '' === relativePath || '..' !== relativePath && !relativePath.startsWith(`..${node_path.sep}`) && !node_path.isAbsolute(relativePath);
13
+ };
9
14
  const parseKey = (key)=>{
10
15
  const _blank = ' ';
11
16
  const splitted = key.split(_blank).filter(Boolean);
@@ -21,21 +26,22 @@ const parseKey = (key)=>{
21
26
  path: key
22
27
  };
23
28
  };
24
- const getMockModule = async (pwd)=>{
29
+ const getMockModule = async (pwd, mockDir)=>{
25
30
  const exts = [
26
31
  '.ts',
27
32
  '.js'
28
33
  ];
29
34
  let mockFilePath = '';
35
+ const mockDirectory = resolveMockDirectory(pwd, mockDir);
30
36
  for (const ext of exts){
31
- const maybeMatch = node_path.join(pwd, `${AGGRED_DIR.mock}/index${ext}`);
37
+ const maybeMatch = node_path.join(mockDirectory, `index${ext}`);
32
38
  if (await fs.pathExists(maybeMatch)) {
33
39
  mockFilePath = maybeMatch;
34
40
  break;
35
41
  }
36
42
  }
37
43
  if (!mockFilePath) return;
38
- const { default: mockHandlers, config } = await import(mockFilePath);
44
+ const { default: mockHandlers, config } = await compatibleRequire(mockFilePath, false);
39
45
  const enable = config?.enable;
40
46
  if (false === enable) return;
41
47
  if (!mockHandlers) throw new Error(`Mock file ${mockFilePath} parsed failed!`);
@@ -55,8 +61,8 @@ const getMatched = (request, mockApis)=>{
55
61
  });
56
62
  return matched;
57
63
  };
58
- async function initOrUpdateMockMiddlewares(pwd) {
59
- const mockModule = await getMockModule(pwd);
64
+ async function initOrUpdateMockMiddlewares(pwd, mockDir) {
65
+ const mockModule = await getMockModule(pwd, mockDir);
60
66
  mockConfig = mockModule?.config;
61
67
  mockAPIs = Object.entries(mockModule?.mockHandlers || {}).map(([key, handler])=>{
62
68
  const { method, path } = parseKey(key);
@@ -67,8 +73,8 @@ async function initOrUpdateMockMiddlewares(pwd) {
67
73
  };
68
74
  });
69
75
  }
70
- async function getMockMiddleware(pwd) {
71
- await initOrUpdateMockMiddlewares(pwd);
76
+ async function getMockMiddleware(pwd, mockDir) {
77
+ await initOrUpdateMockMiddlewares(pwd, mockDir);
72
78
  const mockMiddleware = async (c, next)=>{
73
79
  if ('function' == typeof mockConfig?.enable) {
74
80
  const isEnabled = mockConfig.enable(c.env.node.req, c.env.node.res);
@@ -84,4 +90,4 @@ async function getMockMiddleware(pwd) {
84
90
  };
85
91
  return mockMiddleware;
86
92
  }
87
- export { getMatched, getMockMiddleware, initOrUpdateMockMiddlewares };
93
+ export { getMatched, getMockMiddleware, initOrUpdateMockMiddlewares, isPathInsideDirectory, resolveMockDirectory };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * A request handle compatible with `ServerBase.handle` (Hono's `app.fetch`)
3
+ * and the handler accepted by `createNodeServer`.
4
+ */
5
+ export type ReloadableHandle = (request: Request, ...args: any[]) => Response | Promise<Response>;
6
+ export interface ReloadManagerOptions {
7
+ /**
8
+ * The handle used before the first successful build. Optional: when omitted
9
+ * the manager serves a 503 "starting" response until the first build swaps a
10
+ * real handle in (use `setHandle()` for a fail-fast initial boot).
11
+ */
12
+ initialHandle?: ReloadableHandle;
13
+ /**
14
+ * Build a fresh handle (e.g. a brand new runtime `ServerBase`).
15
+ * If this throws, the previously active handle is retained (rollback).
16
+ */
17
+ build: () => Promise<ReloadableHandle>;
18
+ /** Debounce window (ms) used to coalesce rapid `schedule()` calls. */
19
+ debounceMs?: number;
20
+ /**
21
+ * Called after a handle is successfully built and swapped in (e.g. to clean
22
+ * up the previous runtime). The swap has already been committed when this
23
+ * runs, so throwing here does NOT roll back — it is reported via
24
+ * `onReloadError` instead of `onError`.
25
+ */
26
+ onReload?: (handle: ReloadableHandle) => void;
27
+ /**
28
+ * Called when `build()` throws. The previous handle is kept serving. This is
29
+ * the only path that counts as a failed reload.
30
+ */
31
+ onError?: (error: unknown) => void;
32
+ /**
33
+ * Called when the `onReload` callback throws. The new handle is already
34
+ * active; this is a post-swap cleanup/callback failure, never a rollback.
35
+ */
36
+ onReloadError?: (error: unknown) => void;
37
+ }
38
+ /**
39
+ * Owns the single mutable request handle behind a stable forwarding listener.
40
+ *
41
+ * Guarantees required by the dev-server hot-reload design:
42
+ * - Atomic swap: the active handle is replaced by a single assignment, so
43
+ * in-flight requests always run against a consistent handle.
44
+ * - Failure isolation: if `build()` rejects, the previous handle stays active
45
+ * (the dev server never degrades to an empty / broken handle).
46
+ * - Serial execution: reloads never overlap. Requests that arrive while a
47
+ * reload is running are coalesced into a single trailing reload so that the
48
+ * final state always reflects the latest source ("last write wins").
49
+ */
50
+ export declare class ReloadManager {
51
+ #private;
52
+ constructor(options: ReloadManagerOptions);
53
+ /**
54
+ * Replace the active handle directly, bypassing `build()`. Used to seed the
55
+ * initial known-good handle (a fail-fast boot builds the first runtime
56
+ * explicitly so build errors propagate, then seeds it here).
57
+ */
58
+ setHandle(handle: ReloadableHandle): void;
59
+ /**
60
+ * Stable forwarding handle. Pass this to `createNodeServer` once; it always
61
+ * dispatches to the latest active handle, so the Node server never needs to
62
+ * be recreated on reload.
63
+ */
64
+ get handle(): ReloadableHandle;
65
+ /** The currently active resolved handle (introspection / tests). */
66
+ get currentHandle(): ReloadableHandle;
67
+ /** Whether a reload is currently running (introspection / tests). */
68
+ get isReloading(): boolean;
69
+ /**
70
+ * Request a reload, debounced. Multiple calls within the debounce window
71
+ * collapse into a single reload.
72
+ */
73
+ schedule(): void;
74
+ /**
75
+ * Run a reload immediately. If one is already running, mark a trailing
76
+ * reload and return the in-flight promise (which will include the trailing
77
+ * run) so callers can await final settlement.
78
+ */
79
+ reloadNow(): Promise<void>;
80
+ /**
81
+ * Stop the manager: cancel any pending debounced reload and reject all
82
+ * further `schedule()` / `reloadNow()` calls. Wired into the dev server's
83
+ * close chain so a debounce timer that fires after teardown can never
84
+ * rebuild a runtime once the watcher / builder dev server are gone.
85
+ */
86
+ close(): void;
87
+ }
88
+ export declare function createReloadManager(options: ReloadManagerOptions): ReloadManager;
@@ -0,0 +1,27 @@
1
+ interface RuntimeOptionsBase {
2
+ config: Record<string, any>;
3
+ serverConfig?: Record<string, any>;
4
+ plugins?: any[];
5
+ }
6
+ /**
7
+ * Produce a fully-isolated options object for a single runtime build.
8
+ *
9
+ * `buildRuntimeServer` runs for the initial boot AND for every hot reload, so
10
+ * each build must own every container that a plugin or the apply pipeline
11
+ * could append to / rewrite. A shallow `{ ...base }` is NOT enough: `config`,
12
+ * `serverConfig` and `plugins` would still share references, letting one
13
+ * runtime's appended middlewares / plugins leak into the next reload.
14
+ *
15
+ * This clones:
16
+ * - a fresh top-level options object
17
+ * - a fresh `config` with a fresh `config.output` (so writing `assetPrefix`
18
+ * never mutates the caller's original `options.config`)
19
+ * - a fresh `serverConfig` whose `middlewares` / `renderMiddlewares` /
20
+ * `plugins` are new arrays
21
+ * - a fresh top-level `plugins` array
22
+ *
23
+ * Nested config sub-objects that are only read (never appended to) stay shared
24
+ * by reference, which is intentional and cheap.
25
+ */
26
+ export declare function createRuntimeServerOptions<T extends RuntimeOptionsBase>(base: T, assetPrefix?: string): T;
27
+ export {};
@@ -1,9 +1,68 @@
1
+ import type { Server as NodeServer } from 'node:http';
2
+ import type { Http2SecureServer } from 'node:http2';
3
+ import type { Server as NodeHttpsServer } from 'node:https';
1
4
  import type { BuilderInstance, Rspack } from '@modern-js/builder';
2
- import type { ServerBaseOptions, ServerPlugin } from '@modern-js/server-core';
5
+ import type { ServerBase, ServerBaseOptions, ServerPlugin } from '@modern-js/server-core';
6
+ import type { WatchEvent } from './dev-tools/watcher';
3
7
  import type { ModernDevServerOptions } from './types';
4
8
  type BuilderDevServer = Awaited<ReturnType<BuilderInstance['createDevServer']>>;
5
9
  export type DevPluginOptions = ModernDevServerOptions<ServerBaseOptions> & {
6
10
  builderDevServer?: BuilderDevServer;
7
11
  };
8
- export declare const devPlugin: (options: DevPluginOptions, compiler: Rspack.Compiler | Rspack.MultiCompiler | null) => ServerPlugin;
12
+ /**
13
+ * Runtime-level dev middleware injection.
14
+ *
15
+ * This plugin is added to EVERY runtime `ServerBase` that `buildRuntimeServer`
16
+ * creates, so it must be safe to run repeatedly and must NOT touch any
17
+ * process-level resource (the file watcher / websocket / builder hooks / close
18
+ * callbacks all live in `setupDevInfra`). It only pushes request middlewares
19
+ * into the current server's middleware list:
20
+ * - user `dev.setupMiddlewares` (before / after)
21
+ * - the mock middleware
22
+ * - the rsbuild/builder dev middleware (a stable reference, just re-registered)
23
+ * - the file-reader middleware
24
+ */
25
+ export declare const devRuntimeMiddlewarePlugin: (options: DevPluginOptions, compiler: Rspack.Compiler | Rspack.MultiCompiler | null) => ServerPlugin;
26
+ export interface DevInfraOptions {
27
+ config: DevPluginOptions['config'];
28
+ pwd: string;
29
+ distDir: string;
30
+ apiDir?: string;
31
+ sharedDir?: string;
32
+ builder?: BuilderInstance;
33
+ builderDevServer?: BuilderDevServer;
34
+ compiler: Rspack.Compiler | Rspack.MultiCompiler | null;
35
+ nodeServer?: NodeServer | NodeHttpsServer | Http2SecureServer;
36
+ /** Accessor for the currently-active runtime ServerBase (a mutable ref). */
37
+ getRuntimeServer: () => ServerBase | undefined;
38
+ /**
39
+ * Triggered when a watched user server file changes (require cache already
40
+ * busted). Wired to the runtime reload scheduler.
41
+ */
42
+ onFileChange: (filepath: string, event: WatchEvent) => void;
43
+ /**
44
+ * Extra teardown run as part of the dev server close chain (e.g. stopping the
45
+ * reload scheduler so a pending debounced reload can't rebuild after close).
46
+ */
47
+ onClose?: () => void;
48
+ }
49
+ export interface DevInfra {
50
+ /** Tear down every process-level resource. Called when the dev server stops. */
51
+ close: () => void;
52
+ }
53
+ /**
54
+ * Process-level dev infrastructure, created EXACTLY ONCE for the lifetime of
55
+ * the dev server. None of these resources are recreated or torn down by a
56
+ * runtime hot reload:
57
+ * - the rsbuild/builder dev server websocket connection
58
+ * - the builder `onDevCompileDone` -> SSR cache reset hook
59
+ * - the file watcher
60
+ * - close callbacks registered on the Node server's `close` event
61
+ *
62
+ * The watcher / onRepack reach the LIVE runtime hooks through
63
+ * `getRuntimeServer()` (a mutable ref) instead of closing over the initial
64
+ * runtime, so a later phase can swap the trigger to the reload scheduler
65
+ * without leaking a stale closure to a dead runtime.
66
+ */
67
+ export declare function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, onFileChange, onClose, nodeServer, }: DevInfraOptions): DevInfra;
9
68
  export {};
@@ -1,15 +1,20 @@
1
- import { type ServerBase } from '@modern-js/server-core';
2
1
  import { type WatchOptions } from '@modern-js/utils';
3
- import Watcher from '../dev-tools/watcher';
2
+ import Watcher, { type WatchEvent } from '../dev-tools/watcher';
4
3
  export * from './devOptions';
5
4
  export * from './fileReader';
6
5
  export * from './mock';
7
6
  export * from './repack';
8
- export declare function startWatcher({ pwd, distDir, apiDir, sharedDir, watchOptions, server, }: {
7
+ export declare function startWatcher({ pwd, distDir, apiDir, sharedDir, mockDir, watchOptions, onChange, }: {
9
8
  pwd: string;
10
9
  distDir: string;
11
10
  apiDir: string;
12
11
  sharedDir: string;
12
+ mockDir?: string;
13
13
  watchOptions?: WatchOptions;
14
- server: ServerBase;
14
+ /**
15
+ * Called after the require cache for a changed user server file has been
16
+ * busted, so the next runtime build re-imports fresh code. Server loader
17
+ * bundles are handled inline (cache drop only) and never reach this.
18
+ */
19
+ onChange: (filepath: string, event: WatchEvent) => void;
15
20
  }): Watcher;
@@ -10,7 +10,9 @@ type MockAPI = {
10
10
  path: string;
11
11
  handler: MockHandler;
12
12
  };
13
+ export declare const resolveMockDirectory: (pwd: string, mockDir?: string) => string;
14
+ export declare const isPathInsideDirectory: (filepath: string, directory: string) => boolean;
13
15
  export declare const getMatched: (request: InternalRequest, mockApis: MockAPI[]) => MockAPI | undefined;
14
- export declare function initOrUpdateMockMiddlewares(pwd: string): Promise<void>;
15
- export declare function getMockMiddleware(pwd: string): Promise<Middleware>;
16
+ export declare function initOrUpdateMockMiddlewares(pwd: string, mockDir?: string): Promise<void>;
17
+ export declare function getMockMiddleware(pwd: string, mockDir?: string): Promise<Middleware>;
16
18
  export {};
package/package.json CHANGED
@@ -17,13 +17,12 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.5.0-ultramodern.10",
20
+ "version": "3.5.0-ultramodern.101",
21
21
  "types": "./dist/types/index.d.ts",
22
22
  "main": "./dist/cjs/index.js",
23
23
  "exports": {
24
24
  ".": {
25
25
  "types": "./dist/types/index.d.ts",
26
- "modern:source": "./src/index.ts",
27
26
  "node": {
28
27
  "import": "./dist/esm-node/index.mjs",
29
28
  "require": "./dist/cjs/index.js"
@@ -39,30 +38,30 @@
39
38
  }
40
39
  },
41
40
  "dependencies": {
41
+ "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.5.0-ultramodern.101",
42
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.101",
43
+ "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.101",
44
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.101",
45
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.101",
42
46
  "@swc/helpers": "^0.5.23",
43
47
  "axios": "^1.18.1",
44
48
  "connect-history-api-fallback": "^2.0.0",
45
49
  "http-compression": "1.1.3",
46
50
  "minimatch": "^10.2.5",
47
51
  "path-to-regexp": "^8.4.2",
48
- "ws": "^8.21.0",
49
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.10",
50
- "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.5.0-ultramodern.10",
51
- "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.10",
52
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.10",
53
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.10"
52
+ "ws": "^8.21.0"
54
53
  },
55
54
  "devDependencies": {
56
- "@rslib/core": "0.23.1",
55
+ "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.101",
56
+ "@rslib/core": "0.23.2",
57
+ "@scripts/rstest-config": "2.66.0",
57
58
  "@types/connect-history-api-fallback": "^1.5.4",
58
- "@types/node": "^26.0.1",
59
+ "@types/node": "^26.1.1",
59
60
  "@types/ws": "^8.18.1",
60
- "@typescript/native-preview": "7.0.0-dev.20260628.1",
61
- "node-mocks-http": "^1.17.2",
61
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
62
+ "node-mocks-http": "^1.18.0",
62
63
  "tsconfig-paths": "4.2.0",
63
- "websocket": "^1.0.35",
64
- "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.10",
65
- "@scripts/rstest-config": "2.66.0"
64
+ "websocket": "^1.0.35"
66
65
  },
67
66
  "peerDependencies": {
68
67
  "devcert": "^1.2.3",
@@ -78,7 +77,6 @@
78
77
  },
79
78
  "sideEffects": false,
80
79
  "publishConfig": {
81
- "registry": "https://registry.npmjs.org/",
82
80
  "access": "public"
83
81
  },
84
82
  "scripts": {
package/rstest.config.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { withTestPreset } from '@scripts/rstest-config';
2
2
 
3
3
  export default withTestPreset({
4
+ setupFiles: ['@scripts/rstest-config/setup.ts'],
4
5
  globals: true,
5
6
  });