@bleedingdev/modern-js-prod-server 3.2.0-ultramodern.0

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.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/dist/cjs/apply.js +97 -0
  4. package/dist/cjs/index.js +89 -0
  5. package/dist/cjs/libs/contractGateAutopilot.js +36 -0
  6. package/dist/cjs/libs/loadConfig.js +72 -0
  7. package/dist/cjs/libs/metrics.js +41 -0
  8. package/dist/cjs/libs/render/index.js +125 -0
  9. package/dist/cjs/libs/render/ssr.js +118 -0
  10. package/dist/cjs/libs/render/utils.js +72 -0
  11. package/dist/cjs/libs/runtimeFallbackWorkerLane.js +167 -0
  12. package/dist/cjs/libs/telemetry.js +87 -0
  13. package/dist/cjs/netlify.js +56 -0
  14. package/dist/cjs/server/index.js +579 -0
  15. package/dist/cjs/server/modernServer.js +472 -0
  16. package/dist/cjs/server/modernServerSplit.js +38 -0
  17. package/dist/cjs/types.js +18 -0
  18. package/dist/cjs/utils.js +38 -0
  19. package/dist/esm/apply.mjs +63 -0
  20. package/dist/esm/index.mjs +26 -0
  21. package/dist/esm/libs/contractGateAutopilot.mjs +1 -0
  22. package/dist/esm/libs/loadConfig.mjs +22 -0
  23. package/dist/esm/libs/metrics.mjs +7 -0
  24. package/dist/esm/libs/render/index.mjs +81 -0
  25. package/dist/esm/libs/render/ssr.mjs +73 -0
  26. package/dist/esm/libs/render/utils.mjs +35 -0
  27. package/dist/esm/libs/runtimeFallbackWorkerLane.mjs +130 -0
  28. package/dist/esm/libs/telemetry.mjs +1 -0
  29. package/dist/esm/netlify.mjs +22 -0
  30. package/dist/esm/rslib-runtime.mjs +18 -0
  31. package/dist/esm/server/index.mjs +535 -0
  32. package/dist/esm/server/modernServer.mjs +419 -0
  33. package/dist/esm/server/modernServerSplit.mjs +4 -0
  34. package/dist/esm/types.mjs +0 -0
  35. package/dist/esm/utils.mjs +4 -0
  36. package/dist/esm-node/apply.mjs +64 -0
  37. package/dist/esm-node/index.mjs +27 -0
  38. package/dist/esm-node/libs/contractGateAutopilot.mjs +2 -0
  39. package/dist/esm-node/libs/loadConfig.mjs +23 -0
  40. package/dist/esm-node/libs/metrics.mjs +8 -0
  41. package/dist/esm-node/libs/render/index.mjs +82 -0
  42. package/dist/esm-node/libs/render/ssr.mjs +75 -0
  43. package/dist/esm-node/libs/render/utils.mjs +36 -0
  44. package/dist/esm-node/libs/runtimeFallbackWorkerLane.mjs +131 -0
  45. package/dist/esm-node/libs/telemetry.mjs +2 -0
  46. package/dist/esm-node/netlify.mjs +23 -0
  47. package/dist/esm-node/rslib-runtime.mjs +19 -0
  48. package/dist/esm-node/server/index.mjs +536 -0
  49. package/dist/esm-node/server/modernServer.mjs +421 -0
  50. package/dist/esm-node/server/modernServerSplit.mjs +5 -0
  51. package/dist/esm-node/types.mjs +1 -0
  52. package/dist/esm-node/utils.mjs +5 -0
  53. package/dist/types/apply.d.ts +6 -0
  54. package/dist/types/index.d.ts +13 -0
  55. package/dist/types/libs/metrics.d.ts +8 -0
  56. package/dist/types/libs/telemetry.d.ts +2 -0
  57. package/dist/types/netlify.d.ts +3 -0
  58. package/dist/types/types.d.ts +15 -0
  59. package/package.json +79 -0
  60. package/rslib.config.mts +4 -0
  61. package/rstest.config.mts +7 -0
@@ -0,0 +1,7 @@
1
+ const noop = ()=>{};
2
+ const metrics = {
3
+ emitCounter: noop,
4
+ emitTimer: noop,
5
+ gauges: noop
6
+ };
7
+ export { metrics };
@@ -0,0 +1,81 @@
1
+ import { cutNameByHyphen, mime } from "@modern-js/utils";
2
+ import path from "path";
3
+ import { ERROR_DIGEST } from "../../constants";
4
+ import { shouldFlushServerHeader } from "../preload/shouldFlushServerHeader";
5
+ import { readFile } from "./reader";
6
+ import { handleDirectory } from "./static";
7
+ import { injectServerData } from "./utils.mjs";
8
+ import * as __rspack_external__ssr_mjs_81ad94dd from "./ssr.mjs";
9
+ const calcFallback = (metaName)=>`x-${cutNameByHyphen(metaName)}-ssr-fallback`;
10
+ const readUnsafeHeaders = (ssrConfig)=>{
11
+ if (!ssrConfig || 'object' != typeof ssrConfig) return;
12
+ const unsafeHeaders = ssrConfig.unsafeHeaders;
13
+ if (!Array.isArray(unsafeHeaders)) return;
14
+ return unsafeHeaders.filter((header)=>'string' == typeof header && header.trim().length > 0);
15
+ };
16
+ const resolveUnsafeHeaders = (conf, entryName)=>{
17
+ if (!entryName) return readUnsafeHeaders(conf.server?.ssr);
18
+ const entrySSRConfig = conf.server?.ssrByEntries?.[entryName];
19
+ return readUnsafeHeaders(entrySSRConfig) ?? readUnsafeHeaders(conf.server?.ssr);
20
+ };
21
+ const createRenderHandler = ({ distDir, staticGenerate, conf, forceCSR, nonce, ssrRender, metaName = 'modern-js' })=>async function({ ctx, route, runner }) {
22
+ if (ctx.resHasHandled()) return null;
23
+ const { entryPath, urlPath } = route;
24
+ const unsafeHeaders = resolveUnsafeHeaders(conf, route.entryName);
25
+ const entry = path.join(distDir, entryPath);
26
+ if (!route.isSPA) {
27
+ const result = await handleDirectory(ctx, entry, urlPath);
28
+ return result;
29
+ }
30
+ const templatePath = entry;
31
+ const content = await readFile(templatePath);
32
+ if (!content) return null;
33
+ const useCSR = forceCSR && (ctx.query.csr || ctx.headers[calcFallback(metaName)]);
34
+ if (route.isSSR && !useCSR) try {
35
+ const userAgent = ctx.getReqHeader('User-Agent');
36
+ const disablePreload = Boolean(ctx.headers[`x-${cutNameByHyphen(metaName)}-disable-preload`]);
37
+ if (shouldFlushServerHeader(conf.server, userAgent, disablePreload)) {
38
+ const { flushServerHeader } = await import("../preload");
39
+ flushServerHeader({
40
+ serverConf: conf.server,
41
+ ctx,
42
+ distDir,
43
+ template: content.toString(),
44
+ headers: {
45
+ 'Content-Type': mime.contentType(path.extname(templatePath))
46
+ }
47
+ });
48
+ }
49
+ const ssrRenderOptions = {
50
+ distDir,
51
+ entryName: route.entryName,
52
+ urlPath: route.urlPath,
53
+ bundle: route.bundle,
54
+ template: content.toString(),
55
+ staticGenerate,
56
+ unsafeHeaders,
57
+ nonce
58
+ };
59
+ const result = await (ssrRender ? ssrRender(ctx, ssrRenderOptions, runner) : __rspack_external__ssr_mjs_81ad94dd.render(ctx, {
60
+ distDir,
61
+ entryName: route.entryName,
62
+ urlPath: route.urlPath,
63
+ bundle: route.bundle,
64
+ template: content.toString(),
65
+ staticGenerate,
66
+ unsafeHeaders,
67
+ nonce
68
+ }, runner));
69
+ return result;
70
+ } catch (err) {
71
+ ctx.error(ERROR_DIGEST.ERENDER, err.stack || err.message);
72
+ ctx.res.set(calcFallback(metaName), '1');
73
+ }
74
+ return {
75
+ content: route.entryName ? injectServerData(content.toString(), ctx, {
76
+ unsafeHeaders
77
+ }) : content,
78
+ contentType: mime.contentType(path.extname(templatePath))
79
+ };
80
+ };
81
+ export { createRenderHandler };
@@ -0,0 +1,73 @@
1
+ import { LOADABLE_STATS_FILE, ROUTE_MANIFEST_FILE, SERVER_RENDER_FUNCTION_NAME, fs, mime } from "@modern-js/utils";
2
+ import path from "path";
3
+ import cache from "./cache";
4
+ import { createLogger, createMetrics } from "./measure";
5
+ import { injectServerData, injectServerDataStream } from "./utils.mjs";
6
+ const render = async (ctx, renderOptions, runner)=>{
7
+ const { urlPath, bundle, distDir, template, entryName, staticGenerate, enableUnsafeCtx = false, unsafeHeaders, nonce } = renderOptions;
8
+ const bundleJS = path.join(distDir, bundle);
9
+ const loadableUri = path.join(distDir, LOADABLE_STATS_FILE);
10
+ const loadableStats = fs.existsSync(loadableUri) ? require(loadableUri) : '';
11
+ const routesManifestUri = path.join(distDir, ROUTE_MANIFEST_FILE);
12
+ const routeManifest = fs.existsSync(routesManifestUri) ? require(routesManifestUri) : void 0;
13
+ const context = {
14
+ request: {
15
+ baseUrl: urlPath,
16
+ params: ctx.params,
17
+ pathname: ctx.path,
18
+ host: ctx.host,
19
+ query: ctx.query,
20
+ url: ctx.href,
21
+ headers: ctx.headers
22
+ },
23
+ response: {
24
+ setHeader: (key, value)=>ctx.res.setHeader(key, value),
25
+ status: (code)=>{
26
+ ctx.res.statusCode = code;
27
+ },
28
+ locals: ctx.res?.locals || {}
29
+ },
30
+ redirection: {},
31
+ template,
32
+ loadableStats,
33
+ routeManifest,
34
+ entryName,
35
+ staticGenerate,
36
+ logger: void 0,
37
+ metrics: void 0,
38
+ reporter: ctx.reporter,
39
+ serverTiming: ctx.serverTiming,
40
+ req: ctx.req,
41
+ res: ctx.res,
42
+ enableUnsafeCtx,
43
+ unsafeHeaders,
44
+ nonce
45
+ };
46
+ context.logger = createLogger(context, ctx.logger);
47
+ context.metrics = createMetrics(context, ctx.metrics);
48
+ runner.extendSSRContext(context);
49
+ const bundleJSContent = await Promise.resolve(require(bundleJS));
50
+ const serverRender = bundleJSContent[SERVER_RENDER_FUNCTION_NAME];
51
+ const content = await cache(serverRender, ctx)(context);
52
+ const { url, status = 302 } = context.redirection;
53
+ if (url) return {
54
+ content: url,
55
+ contentType: '',
56
+ statusCode: status,
57
+ redirect: true
58
+ };
59
+ if ('string' == typeof content) return {
60
+ content: injectServerData(content, ctx, {
61
+ unsafeHeaders
62
+ }),
63
+ contentType: mime.contentType('html')
64
+ };
65
+ return {
66
+ content: '',
67
+ contentStream: injectServerDataStream(content, ctx, {
68
+ unsafeHeaders
69
+ }),
70
+ contentType: mime.contentType('html')
71
+ };
72
+ };
73
+ export { render };
@@ -0,0 +1,35 @@
1
+ import { sanitizeSSRPayload } from "@modern-js/runtime-utils/node";
2
+ import { Transform } from "stream";
3
+ const SERVER_DATA_MARKUP = (payload)=>`<script type="application/json" id="__MODERN_SERVER_DATA__">${payload}</script>`;
4
+ const injectIntoHead = (content, payload)=>{
5
+ const scriptTag = SERVER_DATA_MARKUP(payload);
6
+ if (content.includes('</head>')) return content.replace('</head>', `${scriptTag}</head>`);
7
+ return `${scriptTag}${content}`;
8
+ };
9
+ const injectServerData = (content, context, options)=>{
10
+ const serverData = sanitizeSSRPayload(context.serverData, {
11
+ unsafeHeaders: options?.unsafeHeaders,
12
+ treatRootAsHeaders: true
13
+ }).payload;
14
+ return injectIntoHead(content, JSON.stringify(serverData));
15
+ };
16
+ const injectServerDataStream = (content, context, options)=>{
17
+ const serverData = sanitizeSSRPayload(context.serverData, {
18
+ unsafeHeaders: options?.unsafeHeaders,
19
+ treatRootAsHeaders: true
20
+ }).payload;
21
+ const payload = JSON.stringify(serverData);
22
+ let buffer = '';
23
+ const injector = new Transform({
24
+ transform (chunk, _encoding, callback) {
25
+ buffer += chunk.toString();
26
+ callback();
27
+ },
28
+ flush (callback) {
29
+ this.push(injectIntoHead(buffer, payload));
30
+ callback();
31
+ }
32
+ });
33
+ return content.pipe(injector);
34
+ };
35
+ export { injectServerData, injectServerDataStream };
@@ -0,0 +1,130 @@
1
+ import { Worker } from "node:worker_threads";
2
+ const DEFAULT_RUNTIME_FALLBACK_WORKER_TIMEOUT_MS = 250;
3
+ const WORKER_SCRIPT = `
4
+ const { parentPort, workerData } = require('node:worker_threads');
5
+ const fs = require('node:fs/promises');
6
+ const path = require('node:path');
7
+
8
+ const isRecord = value => typeof value === 'object' && value !== null && !Array.isArray(value);
9
+
10
+ const main = async () => {
11
+ const now = Date.now();
12
+ const snapshotPath = String(workerData.snapshotPath || '');
13
+ const gateName = String(workerData.gateName || 'runtime-mf-fallback-health');
14
+ const failureHoldMsRaw = Number(workerData.failureHoldMs);
15
+ const failureHoldMs = Number.isFinite(failureHoldMsRaw) && failureHoldMsRaw > 0
16
+ ? Math.floor(failureHoldMsRaw)
17
+ : 300000;
18
+ const schemaVersionRaw = Number(workerData.schemaVersion);
19
+ const schemaVersion = Number.isFinite(schemaVersionRaw) ? schemaVersionRaw : 1;
20
+ const payload = isRecord(workerData.payload) ? workerData.payload : {};
21
+
22
+ let snapshot = {
23
+ schemaVersion,
24
+ updatedAt: now,
25
+ gates: {},
26
+ };
27
+
28
+ try {
29
+ const raw = await fs.readFile(snapshotPath, 'utf8');
30
+ const parsed = JSON.parse(raw);
31
+ if (isRecord(parsed)) {
32
+ snapshot = {
33
+ schemaVersion: typeof parsed.schemaVersion === 'number' ? parsed.schemaVersion : schemaVersion,
34
+ updatedAt: typeof parsed.updatedAt === 'number' ? parsed.updatedAt : now,
35
+ gates: isRecord(parsed.gates) ? parsed.gates : {},
36
+ };
37
+ }
38
+ } catch (_error) {
39
+ // start from empty snapshot when file does not exist or cannot be parsed
40
+ }
41
+
42
+ const reason = typeof payload.reason === 'string' ? payload.reason : 'runtime_fallback';
43
+ const phase = typeof payload.phase === 'string' ? payload.phase : 'unknown';
44
+ const appName = typeof payload.appName === 'string' ? payload.appName : 'unknown';
45
+ const entry = typeof payload.entry === 'string' ? payload.entry : undefined;
46
+
47
+ snapshot.schemaVersion = schemaVersion;
48
+ snapshot.updatedAt = now;
49
+ snapshot.gates = isRecord(snapshot.gates) ? snapshot.gates : {};
50
+ snapshot.gates[gateName] = {
51
+ passed: false,
52
+ reason: \`runtime_fallback:\${reason} phase=\${phase} app=\${appName}\${entry ? \` entry=\${entry}\` : ''}\`,
53
+ updatedAt: now,
54
+ expiresAt: now + failureHoldMs,
55
+ source: 'runtime-mf-fallback-signal',
56
+ metadata: payload,
57
+ };
58
+
59
+ await fs.mkdir(path.dirname(snapshotPath), { recursive: true });
60
+ await fs.writeFile(snapshotPath, JSON.stringify(snapshot, null, 2) + '\\n');
61
+
62
+ return {
63
+ ok: true,
64
+ };
65
+ };
66
+
67
+ main()
68
+ .then(result => {
69
+ parentPort.postMessage(result);
70
+ })
71
+ .catch(error => {
72
+ parentPort.postMessage({
73
+ ok: false,
74
+ error: error && error.message ? error.message : String(error),
75
+ });
76
+ });
77
+ `;
78
+ const normalizeErrorMessage = (error)=>{
79
+ if (error instanceof Error) return error.message;
80
+ return String(error);
81
+ };
82
+ const persistRuntimeFallbackContractGateInWorker = async (payload, config)=>{
83
+ if (!config.enabled) return {
84
+ ok: false,
85
+ error: 'worker_lane_disabled'
86
+ };
87
+ return new Promise((resolve)=>{
88
+ let settled = false;
89
+ const worker = new Worker(WORKER_SCRIPT, {
90
+ eval: true,
91
+ workerData: payload
92
+ });
93
+ const finish = (result)=>{
94
+ if (settled) return;
95
+ settled = true;
96
+ clearTimeout(timeoutId);
97
+ worker.terminate().catch(()=>{});
98
+ resolve(result);
99
+ };
100
+ const timeoutId = setTimeout(()=>{
101
+ finish({
102
+ ok: false,
103
+ error: 'worker_lane_timeout'
104
+ });
105
+ }, Math.max(25, config.timeoutMs));
106
+ worker.once('message', (message)=>{
107
+ if (message && 'object' == typeof message && true === message.ok) return void finish({
108
+ ok: true
109
+ });
110
+ finish({
111
+ ok: false,
112
+ error: message && 'object' == typeof message && 'error' in message ? String(message.error || 'worker_error') : 'worker_error'
113
+ });
114
+ });
115
+ worker.once('error', (error)=>{
116
+ finish({
117
+ ok: false,
118
+ error: normalizeErrorMessage(error)
119
+ });
120
+ });
121
+ worker.once('exit', (code)=>{
122
+ if (settled || 0 === code) return;
123
+ finish({
124
+ ok: false,
125
+ error: `worker_lane_exit_${String(code)}`
126
+ });
127
+ });
128
+ });
129
+ };
130
+ export { DEFAULT_RUNTIME_FALLBACK_WORKER_TIMEOUT_MS, persistRuntimeFallbackContractGateInWorker };
@@ -0,0 +1 @@
1
+ export { DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT, DEFAULT_RUNTIME_STATUS_ENDPOINT, TelemetryCanaryOrchestrator, TelemetryRegistry, TelemetryStartupHealthError, createOtlpTelemetryExporter, createRuntimeFallbackSignalRuntimeState, createRuntimeSignalError, createTelemetryAwareMetrics, createVictoriaMetricsTelemetryExporter, enforceRuntimeFallbackSignalAuthToken, enforceRuntimeFallbackSignalTrustPolicy, getRuntimeSignalErrorStatusCode, hasEnabledTelemetryExporters, normalizeRuntimeFallbackSignalAuthConfig, normalizeRuntimeFallbackTrustPolicy, parseRuntimeFallbackSignalPayloadFromRawBody, resolveRuntimeFallbackSignalEndpoint } from "@modern-js/server-core";
@@ -0,0 +1,22 @@
1
+ import { createServerBase } from "@modern-js/server-core";
2
+ import { loadServerCliConfig, loadServerEnv, loadServerRuntimeConfig } from "@modern-js/server-core/node";
3
+ import { applyPlugins } from "./apply.mjs";
4
+ const createNetlifyFunction = async (options)=>{
5
+ await loadServerEnv(options);
6
+ const serverBaseOptions = options;
7
+ const serverCliConfig = loadServerCliConfig(options.pwd, options.config);
8
+ if (serverCliConfig) options.config = serverCliConfig;
9
+ const serverRuntimeConfig = await loadServerRuntimeConfig(options.serverConfigPath);
10
+ if (serverRuntimeConfig) {
11
+ serverBaseOptions.serverConfig = serverRuntimeConfig;
12
+ serverBaseOptions.plugins = [
13
+ ...serverRuntimeConfig.plugins || [],
14
+ ...options.plugins || []
15
+ ];
16
+ }
17
+ const server = createServerBase(serverBaseOptions);
18
+ await applyPlugins(server, options);
19
+ await server.init();
20
+ return (request, context)=>server.handle(request, context);
21
+ };
22
+ export { createNetlifyFunction };
@@ -0,0 +1,18 @@
1
+ var __webpack_modules__ = {};
2
+ var __webpack_module_cache__ = {};
3
+ function __webpack_require__(moduleId) {
4
+ var cachedModule = __webpack_module_cache__[moduleId];
5
+ if (void 0 !== cachedModule) return cachedModule.exports;
6
+ var module = __webpack_module_cache__[moduleId] = {
7
+ exports: {}
8
+ };
9
+ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
10
+ return module.exports;
11
+ }
12
+ __webpack_require__.m = __webpack_modules__;
13
+ (()=>{
14
+ __webpack_require__.add = function(modules) {
15
+ Object.assign(__webpack_require__.m, modules);
16
+ };
17
+ })();
18
+ export { __webpack_require__ };