@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,579 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.n = (module)=>{
5
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
6
+ __webpack_require__.d(getter, {
7
+ a: getter
8
+ });
9
+ return getter;
10
+ };
11
+ })();
12
+ (()=>{
13
+ __webpack_require__.d = (exports1, definition)=>{
14
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
15
+ enumerable: true,
16
+ get: definition[key]
17
+ });
18
+ };
19
+ })();
20
+ (()=>{
21
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
22
+ })();
23
+ (()=>{
24
+ __webpack_require__.r = (exports1)=>{
25
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
26
+ value: 'Module'
27
+ });
28
+ Object.defineProperty(exports1, '__esModule', {
29
+ value: true
30
+ });
31
+ };
32
+ })();
33
+ var __webpack_exports__ = {};
34
+ __webpack_require__.r(__webpack_exports__);
35
+ __webpack_require__.d(__webpack_exports__, {
36
+ Server: ()=>Server
37
+ });
38
+ const server_core_namespaceObject = require("@modern-js/server-core");
39
+ const utils_namespaceObject = require("@modern-js/utils");
40
+ const external_fs_namespaceObject = require("fs");
41
+ const external_path_namespaceObject = require("path");
42
+ var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_namespaceObject);
43
+ const contractGateAutopilot_js_namespaceObject = require("../libs/contractGateAutopilot.js");
44
+ const loadConfig_js_namespaceObject = require("../libs/loadConfig.js");
45
+ const metrics_js_namespaceObject = require("../libs/metrics.js");
46
+ const runtimeFallbackWorkerLane_js_namespaceObject = require("../libs/runtimeFallbackWorkerLane.js");
47
+ const telemetry_js_namespaceObject = require("../libs/telemetry.js");
48
+ const external_utils_js_namespaceObject = require("../utils.js");
49
+ const external_modernServerSplit_js_namespaceObject = require("./modernServerSplit.js");
50
+ const CONTRACT_GATE_SNAPSHOT_SCHEMA_VERSION = 1;
51
+ const DEFAULT_RUNTIME_FALLBACK_GATE_NAME = 'runtime-mf-fallback-health';
52
+ const DEFAULT_RUNTIME_FALLBACK_FAILURE_HOLD_MS = 300000;
53
+ const DEFAULT_RUNTIME_FALLBACK_MAX_BODY_BYTES = 16384;
54
+ class Server {
55
+ async init({ disableHttpServer = false } = {
56
+ disableHttpServer: false
57
+ }) {
58
+ const { options } = this;
59
+ await this.loadServerEnv(options);
60
+ this.initServerConfig(options);
61
+ await this.injectContext(this.runner, options);
62
+ this.runner = await this.createHookRunner();
63
+ await this.initConfig(this.runner, options);
64
+ await this.initTelemetry(options);
65
+ await this.injectContext(this.runner, options);
66
+ this.server = this.serverImpl(options);
67
+ await this.runPrepareHook(this.runner);
68
+ if (!disableHttpServer) this.app = await this.server.createHTTPServer(this.getRequestHandler());
69
+ {
70
+ const result = await this.runner.beforeServerInit({
71
+ app: this.app,
72
+ server: this.server
73
+ });
74
+ ({ app: this.app = this.app, server: this.server } = result);
75
+ }
76
+ await this.server.onInit(this.runner, this.app);
77
+ {
78
+ const result = await this.runner.afterServerInit({
79
+ app: this.app,
80
+ server: this.server
81
+ });
82
+ ({ app: this.app = this.app, server: this.server } = result);
83
+ }
84
+ return this;
85
+ }
86
+ runConfigHook(runner, serverConfig) {
87
+ const newServerConfig = runner.config(serverConfig || {});
88
+ return newServerConfig;
89
+ }
90
+ async runPrepareHook(runner) {
91
+ runner.prepare();
92
+ }
93
+ initServerConfig(options) {
94
+ const { pwd, serverConfigFile } = options;
95
+ const distDirectory = external_path_default().join(pwd, options.config.output.path || 'dist');
96
+ const serverConfigPath = (0, loadConfig_js_namespaceObject.getServerConfigPath)(distDirectory, serverConfigFile);
97
+ const serverConfig = (0, loadConfig_js_namespaceObject.requireConfig)(serverConfigPath);
98
+ this.serverConfig = serverConfig;
99
+ }
100
+ async initConfig(runner, options) {
101
+ const { pwd, config } = options;
102
+ const { serverConfig } = this;
103
+ const finalServerConfig = this.runConfigHook(runner, serverConfig);
104
+ const resolvedConfigPath = (0, utils_namespaceObject.ensureAbsolutePath)(pwd, external_path_default().join(config.output.path || 'dist', utils_namespaceObject.OUTPUT_CONFIG_FILE));
105
+ options.config = (0, loadConfig_js_namespaceObject.loadConfig)({
106
+ cliConfig: config,
107
+ serverConfig: finalServerConfig,
108
+ resolvedConfigPath
109
+ });
110
+ }
111
+ async initTelemetry(options) {
112
+ const telemetryConfig = options.config.server?.telemetry;
113
+ if (!telemetryConfig) return;
114
+ const hasEnabledExporters = (0, telemetry_js_namespaceObject.hasEnabledTelemetryExporters)(telemetryConfig);
115
+ if (true !== telemetryConfig.enabled && !hasEnabledExporters) return;
116
+ const registry = new telemetry_js_namespaceObject.TelemetryRegistry({
117
+ service: telemetryConfig.service || options.appContext?.metaName || 'modern-js',
118
+ module: telemetryConfig.module || 'server',
119
+ environment: telemetryConfig.environment || process.env.MODERN_ENV || process.env.NODE_ENV || 'development',
120
+ samplingRate: telemetryConfig.samplingRate,
121
+ flushIntervalMs: telemetryConfig.flushIntervalMs,
122
+ maxBatchSize: telemetryConfig.maxBatchSize,
123
+ maxQueueSize: telemetryConfig.maxQueueSize,
124
+ redactionKeys: telemetryConfig.redactionKeys,
125
+ slo: {
126
+ queueUtilizationWarnThreshold: telemetryConfig.slo?.queueUtilizationWarnThreshold,
127
+ queueDroppedWarnThreshold: telemetryConfig.slo?.queueDroppedWarnThreshold,
128
+ alertCooldownMs: telemetryConfig.slo?.alertCooldownMs,
129
+ onAlert: (alert)=>{
130
+ options.logger?.warn(`[telemetry.slo] ${alert.type} threshold=${alert.threshold} value=${alert.value} depth=${alert.queueDepth}/${alert.queueCapacity} dropped=${alert.totalDropped}`);
131
+ }
132
+ }
133
+ });
134
+ if (telemetryConfig.exporters?.otlp?.enabled) await registry.register((0, telemetry_js_namespaceObject.createOtlpTelemetryExporter)(telemetryConfig.exporters.otlp));
135
+ if (telemetryConfig.exporters?.victoriaMetrics?.enabled) await registry.register((0, telemetry_js_namespaceObject.createVictoriaMetricsTelemetryExporter)(telemetryConfig.exporters.victoriaMetrics));
136
+ try {
137
+ await registry.startupHealthCheck({
138
+ failLoud: telemetryConfig.failLoudStartup ?? true
139
+ });
140
+ } catch (error) {
141
+ await registry.shutdown();
142
+ throw error;
143
+ }
144
+ options.metrics = (0, telemetry_js_namespaceObject.createTelemetryAwareMetrics)(options.metrics || metrics_js_namespaceObject.metrics, registry);
145
+ this.telemetryRegistry = registry;
146
+ const canaryConfig = telemetryConfig.canary;
147
+ if (canaryConfig?.enabled) {
148
+ const contractGates = canaryConfig.contractGates;
149
+ const orchestrator = new telemetry_js_namespaceObject.TelemetryCanaryOrchestrator({
150
+ registry,
151
+ evaluationIntervalMs: canaryConfig.evaluationIntervalMs,
152
+ minConsecutiveHealthyEvaluations: canaryConfig.minConsecutiveHealthyEvaluations,
153
+ rollbackConsecutiveFailures: canaryConfig.rollbackConsecutiveFailures,
154
+ maxQueueUtilization: canaryConfig.maxQueueUtilization,
155
+ maxTotalDropped: canaryConfig.maxTotalDropped,
156
+ maxUnhealthyExporters: canaryConfig.maxUnhealthyExporters,
157
+ requiredContractGates: Object.keys(contractGates || {}),
158
+ onPromote: (decision)=>{
159
+ options.logger?.info(`[telemetry.canary] promoted after ${decision.consecutiveHealthy} healthy evaluations`);
160
+ this.emitCanaryDecisionMetric(registry, decision, 'promote');
161
+ },
162
+ onRollback: (decision)=>{
163
+ options.logger?.error(`[telemetry.canary] rollback triggered failures=${decision.failures.map((item)=>item.reason).join(',')}`);
164
+ this.emitCanaryDecisionMetric(registry, decision, 'rollback');
165
+ }
166
+ });
167
+ if (contractGates) orchestrator.setContractGates(contractGates);
168
+ this.canaryOrchestrator = orchestrator;
169
+ orchestrator.start();
170
+ const autopilotEnabled = canaryConfig.autopilot?.enabled ?? true;
171
+ if (autopilotEnabled) {
172
+ const gateSnapshotPath = this.resolveContractGateSnapshotPath(options, canaryConfig.autopilot?.gateSnapshotPath);
173
+ this.contractGateAutopilot = new contractGateAutopilot_js_namespaceObject.ContractGateAutopilot({
174
+ orchestrator,
175
+ gateSnapshotPath,
176
+ pollIntervalMs: canaryConfig.autopilot?.pollIntervalMs,
177
+ gateStaleAfterMs: canaryConfig.autopilot?.gateStaleAfterMs,
178
+ logger: {
179
+ info: (message)=>{
180
+ options.logger?.info(message);
181
+ },
182
+ warn: (message)=>{
183
+ options.logger?.warn(message);
184
+ }
185
+ }
186
+ });
187
+ await this.contractGateAutopilot.start();
188
+ const runtimeSignalConfig = canaryConfig.autopilot?.runtimeFallbackSignal;
189
+ const runtimeSignalEnabled = runtimeSignalConfig?.enabled ?? true;
190
+ if (runtimeSignalEnabled) {
191
+ const workerLaneConfig = runtimeSignalConfig?.workerLane;
192
+ const workerLaneEnabledFromEnv = 'true' === process.env.MODERN_RUNTIME_FALLBACK_WORKER_LANE;
193
+ const workerLaneEnabled = 'boolean' == typeof workerLaneConfig?.enabled ? workerLaneConfig.enabled : workerLaneEnabledFromEnv;
194
+ this.runtimeFallbackSignalConfig = {
195
+ endpoint: (0, telemetry_js_namespaceObject.resolveRuntimeFallbackSignalEndpoint)(runtimeSignalConfig?.endpoint),
196
+ gateName: runtimeSignalConfig?.gateName?.trim() || DEFAULT_RUNTIME_FALLBACK_GATE_NAME,
197
+ gateSnapshotPath,
198
+ failureHoldMs: Math.max(1000, runtimeSignalConfig?.failureHoldMs ?? DEFAULT_RUNTIME_FALLBACK_FAILURE_HOLD_MS),
199
+ maxBodyBytes: Math.max(512, runtimeSignalConfig?.maxBodyBytes ?? DEFAULT_RUNTIME_FALLBACK_MAX_BODY_BYTES),
200
+ auth: (0, telemetry_js_namespaceObject.normalizeRuntimeFallbackSignalAuthConfig)(runtimeSignalConfig?.auth),
201
+ trustPolicy: (0, telemetry_js_namespaceObject.normalizeRuntimeFallbackTrustPolicy)(runtimeSignalConfig?.trustPolicy),
202
+ runtimeState: (0, telemetry_js_namespaceObject.createRuntimeFallbackSignalRuntimeState)(),
203
+ workerLane: {
204
+ enabled: workerLaneEnabled,
205
+ timeoutMs: Math.max(25, workerLaneConfig?.timeoutMs ?? runtimeFallbackWorkerLane_js_namespaceObject.DEFAULT_RUNTIME_FALLBACK_WORKER_TIMEOUT_MS),
206
+ workerSuccessCount: 0,
207
+ fallbackToMainThreadCount: 0
208
+ }
209
+ };
210
+ }
211
+ }
212
+ orchestrator.evaluate();
213
+ }
214
+ }
215
+ resolveContractGateSnapshotPath(options, configuredPath) {
216
+ const rawPath = configuredPath || process.env.MODERN_CONTRACT_GATES_FILE || '.modern/contract-gates.json';
217
+ if (external_path_default().isAbsolute(rawPath)) return rawPath;
218
+ return external_path_default().resolve(options.pwd, rawPath);
219
+ }
220
+ emitCanaryDecisionMetric(registry, decision, action) {
221
+ try {
222
+ registry.enqueueMetric({
223
+ name: `telemetry.canary.${action}`,
224
+ value: 1,
225
+ unit: 'count',
226
+ tags: {
227
+ action,
228
+ state: decision.state,
229
+ failures: String(decision.failures.length)
230
+ }
231
+ });
232
+ } catch (_error) {}
233
+ }
234
+ async close() {
235
+ if (this.contractGateAutopilot) {
236
+ this.contractGateAutopilot.stop();
237
+ this.contractGateAutopilot = void 0;
238
+ }
239
+ this.runtimeFallbackSignalConfig = void 0;
240
+ if (this.canaryOrchestrator) this.canaryOrchestrator.stop();
241
+ if (this.telemetryRegistry) await this.telemetryRegistry.shutdown();
242
+ if (!this.app) return;
243
+ await new Promise((resolve)=>{
244
+ this.app.close(()=>resolve());
245
+ });
246
+ }
247
+ listen(options, listener) {
248
+ const callback = ()=>{
249
+ listener?.();
250
+ };
251
+ if ('object' == typeof options) {
252
+ if (process.env.PORT) Object.assign(options, {
253
+ port: process.env.PORT
254
+ });
255
+ this.app.listen(options, callback);
256
+ } else this.app.listen(process.env.PORT || options || 8080, callback);
257
+ }
258
+ getRequestHandler() {
259
+ const requestHandler = this.server.getRequestHandler();
260
+ return (req, res, next)=>{
261
+ if (this.shouldHandleRuntimeStatus(req)) return void this.handleRuntimeStatus(req, res);
262
+ if (this.shouldHandleRuntimeFallbackSignal(req)) return void this.handleRuntimeFallbackSignal(req, res);
263
+ return requestHandler(req, res, next);
264
+ };
265
+ }
266
+ shouldHandleRuntimeFallbackSignal(req) {
267
+ const runtimeSignalConfig = this.runtimeFallbackSignalConfig;
268
+ if (!runtimeSignalConfig) return false;
269
+ if ('POST' !== (req.method || 'GET').toUpperCase()) return false;
270
+ const pathName = this.getRequestPath(req.url);
271
+ return pathName === runtimeSignalConfig.endpoint;
272
+ }
273
+ shouldHandleRuntimeStatus(req) {
274
+ if ('GET' !== (req.method || 'GET').toUpperCase()) return false;
275
+ const pathName = this.getRequestPath(req.url);
276
+ return pathName === this.runtimeStatusEndpoint;
277
+ }
278
+ getRequestPath(urlValue) {
279
+ try {
280
+ const requestUrl = new URL(urlValue || '/', 'http://127.0.0.1');
281
+ return requestUrl.pathname;
282
+ } catch (_error) {
283
+ return '/';
284
+ }
285
+ }
286
+ async readRequestBody(req, maxBodyBytes) {
287
+ return new Promise((resolve, reject)=>{
288
+ const chunks = [];
289
+ let totalBytes = 0;
290
+ let done = false;
291
+ const cleanup = ()=>{
292
+ req.off('data', onData);
293
+ req.off('end', onEnd);
294
+ req.off('error', onError);
295
+ };
296
+ const onData = (chunk)=>{
297
+ if (done) return;
298
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
299
+ totalBytes += buffer.length;
300
+ if (totalBytes > maxBodyBytes) {
301
+ const error = new Error('runtime fallback signal payload too large');
302
+ error.code = 'PAYLOAD_TOO_LARGE';
303
+ done = true;
304
+ cleanup();
305
+ reject(error);
306
+ return;
307
+ }
308
+ chunks.push(buffer);
309
+ };
310
+ const onEnd = ()=>{
311
+ if (done) return;
312
+ done = true;
313
+ cleanup();
314
+ resolve(Buffer.concat(chunks).toString('utf8'));
315
+ };
316
+ const onError = (error)=>{
317
+ if (done) return;
318
+ done = true;
319
+ cleanup();
320
+ reject(error);
321
+ };
322
+ req.on('data', onData);
323
+ req.on('end', onEnd);
324
+ req.on('error', onError);
325
+ });
326
+ }
327
+ async handleRuntimeFallbackSignal(req, res) {
328
+ const runtimeSignalConfig = this.runtimeFallbackSignalConfig;
329
+ if (!runtimeSignalConfig) {
330
+ res.statusCode = 404;
331
+ res.end();
332
+ return;
333
+ }
334
+ try {
335
+ (0, telemetry_js_namespaceObject.enforceRuntimeFallbackSignalAuthToken)(this.getRequestHeader(req, runtimeSignalConfig.auth.headerName), runtimeSignalConfig.auth);
336
+ const rawBody = await this.readRequestBody(req, runtimeSignalConfig.maxBodyBytes);
337
+ const payload = (0, telemetry_js_namespaceObject.parseRuntimeFallbackSignalPayloadFromRawBody)(rawBody, runtimeSignalConfig.maxBodyBytes);
338
+ const trustResult = (0, telemetry_js_namespaceObject.enforceRuntimeFallbackSignalTrustPolicy)(payload, {
339
+ trustPolicy: runtimeSignalConfig.trustPolicy,
340
+ runtimeState: runtimeSignalConfig.runtimeState
341
+ });
342
+ if (trustResult.deduped) {
343
+ res.statusCode = 202;
344
+ res.setHeader('content-type', 'application/json');
345
+ res.end('{"ok":true,"deduped":true}');
346
+ return;
347
+ }
348
+ let persistedByWorkerLane = false;
349
+ if (runtimeSignalConfig.workerLane.enabled) {
350
+ const workerResult = await (0, runtimeFallbackWorkerLane_js_namespaceObject.persistRuntimeFallbackContractGateInWorker)({
351
+ snapshotPath: runtimeSignalConfig.gateSnapshotPath,
352
+ gateName: runtimeSignalConfig.gateName,
353
+ failureHoldMs: runtimeSignalConfig.failureHoldMs,
354
+ payload: payload,
355
+ schemaVersion: CONTRACT_GATE_SNAPSHOT_SCHEMA_VERSION
356
+ }, {
357
+ enabled: true,
358
+ timeoutMs: runtimeSignalConfig.workerLane.timeoutMs
359
+ });
360
+ if (workerResult.ok) {
361
+ persistedByWorkerLane = true;
362
+ runtimeSignalConfig.workerLane.workerSuccessCount += 1;
363
+ runtimeSignalConfig.workerLane.lastError = void 0;
364
+ const payloadRecord = payload;
365
+ const reason = 'string' == typeof payloadRecord.reason ? payloadRecord.reason : 'runtime_fallback';
366
+ const phase = 'string' == typeof payloadRecord.phase ? payloadRecord.phase : 'unknown';
367
+ const appName = 'string' == typeof payloadRecord.appName ? payloadRecord.appName : 'unknown';
368
+ this.options.logger?.warn(`[telemetry.canary.autopilot] runtime fallback signal gate=${runtimeSignalConfig.gateName} reason=${reason} phase=${phase} app=${appName} workerLane=true`);
369
+ } else {
370
+ runtimeSignalConfig.workerLane.fallbackToMainThreadCount += 1;
371
+ runtimeSignalConfig.workerLane.lastError = workerResult.error;
372
+ this.options.logger?.warn(`[telemetry.canary.autopilot] runtime fallback worker lane fallback: ${workerResult.error || 'unknown_error'}`);
373
+ }
374
+ }
375
+ if (!persistedByWorkerLane) await this.persistRuntimeFallbackContractGate(payload, runtimeSignalConfig);
376
+ res.statusCode = 202;
377
+ res.setHeader('content-type', 'application/json');
378
+ res.end('{"ok":true}');
379
+ } catch (error) {
380
+ const signalError = error;
381
+ res.statusCode = (0, telemetry_js_namespaceObject.getRuntimeSignalErrorStatusCode)(signalError);
382
+ res.setHeader('content-type', 'application/json');
383
+ res.end(`{"ok":false,"error":${JSON.stringify(signalError instanceof Error ? signalError.message : String(signalError))}}`);
384
+ this.options.logger?.warn(`[telemetry.canary.autopilot] runtime fallback signal rejected: ${error instanceof Error ? error.message : String(error)}`);
385
+ }
386
+ }
387
+ async handleRuntimeStatus(req, res) {
388
+ try {
389
+ if (this.runtimeFallbackSignalConfig?.auth.enabled) (0, telemetry_js_namespaceObject.enforceRuntimeFallbackSignalAuthToken)(this.getRequestHeader(req, this.runtimeFallbackSignalConfig.auth.headerName), this.runtimeFallbackSignalConfig.auth);
390
+ res.statusCode = 200;
391
+ res.setHeader('content-type', 'application/json');
392
+ res.end(JSON.stringify(this.buildRuntimeStatusPayload()));
393
+ } catch (error) {
394
+ const signalError = error;
395
+ res.statusCode = (0, telemetry_js_namespaceObject.getRuntimeSignalErrorStatusCode)(signalError);
396
+ res.setHeader('content-type', 'application/json');
397
+ res.end(`{"ok":false,"error":${JSON.stringify(signalError instanceof Error ? signalError.message : String(signalError))}}`);
398
+ }
399
+ }
400
+ buildRuntimeStatusPayload() {
401
+ const telemetry = this.telemetryRegistry ? {
402
+ enabled: true,
403
+ queueStats: this.telemetryRegistry.getQueueStats(),
404
+ exporterHealth: this.telemetryRegistry.getExporterHealth()
405
+ } : {
406
+ enabled: false,
407
+ queueStats: null,
408
+ exporterHealth: []
409
+ };
410
+ const canary = this.canaryOrchestrator ? {
411
+ enabled: true,
412
+ ...this.canaryOrchestrator.getStatusSnapshot()
413
+ } : {
414
+ enabled: false
415
+ };
416
+ const runtimeFallbackSignal = this.runtimeFallbackSignalConfig ? {
417
+ enabled: true,
418
+ endpoint: this.runtimeFallbackSignalConfig.endpoint,
419
+ gateName: this.runtimeFallbackSignalConfig.gateName,
420
+ failureHoldMs: this.runtimeFallbackSignalConfig.failureHoldMs,
421
+ maxBodyBytes: this.runtimeFallbackSignalConfig.maxBodyBytes,
422
+ auth: {
423
+ enabled: this.runtimeFallbackSignalConfig.auth.enabled,
424
+ headerName: this.runtimeFallbackSignalConfig.auth.headerName
425
+ },
426
+ trustPolicy: {
427
+ allowedApps: this.runtimeFallbackSignalConfig.trustPolicy.allowedApps,
428
+ allowedEntryOrigins: this.runtimeFallbackSignalConfig.trustPolicy.allowedEntryOrigins,
429
+ enforceRuntimeDigest: this.runtimeFallbackSignalConfig.trustPolicy.enforceRuntimeDigest,
430
+ expectedRuntimeDigestsCount: Object.keys(this.runtimeFallbackSignalConfig.trustPolicy.expectedRuntimeDigests).length,
431
+ maxSignalsPerWindow: this.runtimeFallbackSignalConfig.trustPolicy.maxSignalsPerWindow,
432
+ windowMs: this.runtimeFallbackSignalConfig.trustPolicy.windowMs,
433
+ dedupeWindowMs: this.runtimeFallbackSignalConfig.trustPolicy.dedupeWindowMs
434
+ },
435
+ workerLane: {
436
+ enabled: this.runtimeFallbackSignalConfig.workerLane.enabled,
437
+ timeoutMs: this.runtimeFallbackSignalConfig.workerLane.timeoutMs,
438
+ workerSuccessCount: this.runtimeFallbackSignalConfig.workerLane.workerSuccessCount,
439
+ fallbackToMainThreadCount: this.runtimeFallbackSignalConfig.workerLane.fallbackToMainThreadCount,
440
+ lastError: this.runtimeFallbackSignalConfig.workerLane.lastError
441
+ }
442
+ } : {
443
+ enabled: false
444
+ };
445
+ return {
446
+ ok: true,
447
+ timestamp: Date.now(),
448
+ telemetry,
449
+ canary,
450
+ runtimeFallbackSignal
451
+ };
452
+ }
453
+ getRequestHeader(req, headerName) {
454
+ const raw = req.headers[headerName.toLowerCase()];
455
+ if (Array.isArray(raw)) return raw[0];
456
+ if ('string' == typeof raw) return raw;
457
+ }
458
+ async persistRuntimeFallbackContractGate(payload, runtimeSignalConfig) {
459
+ const now = Date.now();
460
+ const snapshotPath = runtimeSignalConfig.gateSnapshotPath;
461
+ let snapshot = {
462
+ schemaVersion: CONTRACT_GATE_SNAPSHOT_SCHEMA_VERSION,
463
+ updatedAt: now,
464
+ gates: {}
465
+ };
466
+ if (await utils_namespaceObject.fs.pathExists(snapshotPath)) try {
467
+ const raw = await external_fs_namespaceObject.promises.readFile(snapshotPath, 'utf8');
468
+ const parsed = JSON.parse(raw);
469
+ if (parsed && 'object' == typeof parsed) snapshot = {
470
+ schemaVersion: 'number' == typeof parsed.schemaVersion ? parsed.schemaVersion : CONTRACT_GATE_SNAPSHOT_SCHEMA_VERSION,
471
+ updatedAt: 'number' == typeof parsed.updatedAt ? parsed.updatedAt : now,
472
+ gates: parsed.gates && 'object' == typeof parsed.gates ? parsed.gates : {}
473
+ };
474
+ } catch (_error) {
475
+ snapshot = {
476
+ schemaVersion: CONTRACT_GATE_SNAPSHOT_SCHEMA_VERSION,
477
+ updatedAt: now,
478
+ gates: {}
479
+ };
480
+ }
481
+ const reason = 'string' == typeof payload.reason ? payload.reason : 'runtime_fallback';
482
+ const phase = 'string' == typeof payload.phase ? payload.phase : 'unknown';
483
+ const appName = 'string' == typeof payload.appName ? payload.appName : 'unknown';
484
+ const entry = 'string' == typeof payload.entry ? payload.entry : void 0;
485
+ snapshot.schemaVersion = CONTRACT_GATE_SNAPSHOT_SCHEMA_VERSION;
486
+ snapshot.updatedAt = now;
487
+ snapshot.gates = snapshot.gates || {};
488
+ snapshot.gates[runtimeSignalConfig.gateName] = {
489
+ passed: false,
490
+ reason: `runtime_fallback:${reason} phase=${phase} app=${appName}${entry ? ` entry=${entry}` : ''}`,
491
+ updatedAt: now,
492
+ expiresAt: now + runtimeSignalConfig.failureHoldMs,
493
+ source: 'runtime-mf-fallback-signal',
494
+ metadata: payload
495
+ };
496
+ await external_fs_namespaceObject.promises.mkdir(external_path_default().dirname(snapshotPath), {
497
+ recursive: true
498
+ });
499
+ await external_fs_namespaceObject.promises.writeFile(snapshotPath, `${JSON.stringify(snapshot, null, 2)}\n`);
500
+ this.options.logger?.warn(`[telemetry.canary.autopilot] runtime fallback signal gate=${runtimeSignalConfig.gateName} reason=${reason} phase=${phase} app=${appName}`);
501
+ }
502
+ async render(req, res, url) {
503
+ return this.server.render(req, res, url);
504
+ }
505
+ async createHookRunner() {
506
+ server_core_namespaceObject.serverManager.clear();
507
+ const { options } = this;
508
+ const { internalPlugins = utils_namespaceObject.INTERNAL_SERVER_PLUGINS, pwd, plugins = [] } = options;
509
+ const serverPlugins = this.serverConfig.plugins || [];
510
+ const loadedPlugins = (0, server_core_namespaceObject.loadPlugins)(pwd, [
511
+ ...serverPlugins,
512
+ ...plugins
513
+ ], {
514
+ internalPlugins
515
+ });
516
+ (0, external_utils_js_namespaceObject.debug)('plugins', loadedPlugins);
517
+ loadedPlugins.forEach((p)=>{
518
+ server_core_namespaceObject.serverManager.usePlugin(p);
519
+ });
520
+ const hooksRunner = await server_core_namespaceObject.serverManager.init();
521
+ return hooksRunner;
522
+ }
523
+ async injectContext(runner, options) {
524
+ const appContext = this.initAppContext();
525
+ const { config, pwd } = options;
526
+ server_core_namespaceObject.ConfigContext.set(config);
527
+ server_core_namespaceObject.AppContext.set({
528
+ ...appContext,
529
+ distDirectory: external_path_default().join(pwd, config.output.path || 'dist')
530
+ });
531
+ }
532
+ initAppContext() {
533
+ const { options } = this;
534
+ const { pwd: appDirectory, plugins = [], config, appContext } = options;
535
+ const serverPlugins = plugins.map((p)=>({
536
+ server: p
537
+ }));
538
+ return {
539
+ appDirectory,
540
+ apiDirectory: appContext?.apiDirectory,
541
+ lambdaDirectory: appContext?.lambdaDirectory,
542
+ sharedDirectory: appContext?.sharedDirectory || external_path_default().resolve(appDirectory, utils_namespaceObject.SHARED_DIR),
543
+ distDirectory: external_path_default().join(appDirectory, config.output.path || 'dist'),
544
+ plugins: serverPlugins
545
+ };
546
+ }
547
+ async loadServerEnv(options) {
548
+ const { pwd: appDirectory } = options;
549
+ const serverEnv = process.env.MODERN_ENV;
550
+ const defaultEnvPath = external_path_default().resolve(appDirectory, ".env");
551
+ const serverEnvPath = external_path_default().resolve(appDirectory, `.env.${serverEnv}`);
552
+ for (const envPath of [
553
+ serverEnvPath,
554
+ defaultEnvPath
555
+ ])if (await utils_namespaceObject.fs.pathExists(envPath) && !(await utils_namespaceObject.fs.stat(envPath)).isDirectory()) {
556
+ const envConfig = utils_namespaceObject.dotenv.config({
557
+ path: envPath
558
+ });
559
+ (0, utils_namespaceObject.dotenvExpand)(envConfig);
560
+ }
561
+ }
562
+ constructor(options){
563
+ this.serverImpl = external_modernServerSplit_js_namespaceObject.createProdServer;
564
+ this.runtimeStatusEndpoint = telemetry_js_namespaceObject.DEFAULT_RUNTIME_STATUS_ENDPOINT;
565
+ options.logger = options.logger || (0, utils_namespaceObject.createLogger)({
566
+ level: 'warn'
567
+ });
568
+ options.metrics = options.metrics || metrics_js_namespaceObject.metrics;
569
+ this.options = options;
570
+ this.serverConfig = {};
571
+ }
572
+ }
573
+ exports.Server = __webpack_exports__.Server;
574
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
575
+ "Server"
576
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
577
+ Object.defineProperty(exports, '__esModule', {
578
+ value: true
579
+ });