@foxford/den 3.7.0 → 4.1.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.
- package/README.mdx +58 -7
- package/adapter.d.cts +1 -1
- package/adapter.d.ts +1 -1
- package/bin/den.cjs +3 -3
- package/bin/den.js +1 -1
- package/builder/index.cjs +2 -2
- package/builder/index.d.cts +4 -2
- package/builder/index.d.ts +4 -2
- package/builder/index.js +1 -1
- package/{chunk-2GTQK2PZ.js → chunk-7FOG2MJV.js} +9 -6
- package/chunk-A2CYL5LY.js +240 -0
- package/chunk-HJFBEJT6.cjs +240 -0
- package/{chunk-P4J4M2WZ.cjs → chunk-IATA5QZ7.cjs} +9 -6
- package/{define-repository-AO7JI6Cb.d.ts → define-repository-Ck45La_2.d.ts} +1 -1
- package/{define-repository-C0MI-J32.d.cts → define-repository-DAyeXF48.d.cts} +1 -1
- package/{define-slot-CdWdFM16.d.ts → define-slot-BTlLQ__T.d.ts} +1 -1
- package/{define-slot-BEeHNEph.d.cts → define-slot-C6hrdJS3.d.cts} +1 -1
- package/define.d.cts +3 -3
- package/define.d.ts +3 -3
- package/{descriptor-BSaHM5B4.d.ts → descriptor-CNJFrEbS.d.ts} +2 -2
- package/{descriptor-C2j6Zz6c.d.cts → descriptor-DmfJP4jQ.d.cts} +2 -2
- package/index.d.cts +6 -6
- package/index.d.ts +6 -6
- package/island/index.d.cts +9 -6
- package/island/index.d.ts +9 -6
- package/ops/index.cjs +17 -0
- package/ops/index.d.cts +39 -0
- package/ops/index.d.ts +39 -0
- package/ops/index.js +17 -0
- package/package.json +25 -16
- package/{routes-BvV405k4.d.cts → routes-DQ4ud4bu.d.cts} +1 -1
- package/{routes-Di3K_0uQ.d.ts → routes-TkIxQ0Uc.d.ts} +1 -1
- package/serve/index.cjs +270 -17
- package/serve/index.d.cts +21 -6
- package/serve/index.d.ts +21 -6
- package/serve/index.js +273 -20
- package/{types-BxMQ-VOd.d.cts → types-Ccd5bmt1.d.cts} +23 -4
- package/{types-BxMQ-VOd.d.ts → types-Ccd5bmt1.d.ts} +23 -4
- package/{view-adapter-DMLlp3Iu.d.cts → view-adapter-CrHh7CjB.d.cts} +2 -2
- package/{view-adapter-DNLRSFka.d.ts → view-adapter-DPDvv09J.d.ts} +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foxford/den",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Den — декларативный метафреймворк Foxford (core runtime)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"foxford",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"den": "./den.js"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@prometheus-io/client": "0.16.1",
|
|
33
34
|
"fastify": "^5.12.1",
|
|
34
35
|
"@foxford/ioc": "^1.1.2",
|
|
35
36
|
"@foxford/logger": "^1.2.2"
|
|
@@ -75,6 +76,11 @@
|
|
|
75
76
|
"require": "./island/index.cjs",
|
|
76
77
|
"types": "./island/index.d.ts"
|
|
77
78
|
},
|
|
79
|
+
"./ops": {
|
|
80
|
+
"import": "./ops/index.js",
|
|
81
|
+
"require": "./ops/index.cjs",
|
|
82
|
+
"types": "./ops/index.d.ts"
|
|
83
|
+
},
|
|
78
84
|
"./serve": {
|
|
79
85
|
"import": "./serve/index.js",
|
|
80
86
|
"require": "./serve/index.cjs",
|
|
@@ -89,17 +95,19 @@
|
|
|
89
95
|
"adapter.js",
|
|
90
96
|
"bin",
|
|
91
97
|
"builder",
|
|
92
|
-
"chunk-2GTQK2PZ.js",
|
|
93
98
|
"chunk-3RX2OSUL.js",
|
|
94
99
|
"chunk-6FNC3XMI.js",
|
|
95
100
|
"chunk-6QV4L6R2.cjs",
|
|
101
|
+
"chunk-7FOG2MJV.js",
|
|
102
|
+
"chunk-A2CYL5LY.js",
|
|
96
103
|
"chunk-A6ZPAM6Z.cjs",
|
|
97
104
|
"chunk-C7BM4DGX.cjs",
|
|
98
105
|
"chunk-E23E2VUC.js",
|
|
99
106
|
"chunk-E56BKBQZ.js",
|
|
100
107
|
"chunk-H5DKRHHQ.cjs",
|
|
108
|
+
"chunk-HJFBEJT6.cjs",
|
|
109
|
+
"chunk-IATA5QZ7.cjs",
|
|
101
110
|
"chunk-KQAB6C6Q.cjs",
|
|
102
|
-
"chunk-P4J4M2WZ.cjs",
|
|
103
111
|
"chunk-QTWJTYZW.cjs",
|
|
104
112
|
"chunk-RG7ZV5BD.js",
|
|
105
113
|
"chunk-T5QVCXVB.cjs",
|
|
@@ -107,33 +115,34 @@
|
|
|
107
115
|
"chunk-WBHHHICS.js",
|
|
108
116
|
"chunk-XOJ2VWX4.cjs",
|
|
109
117
|
"chunk-XQ7EHXHG.js",
|
|
110
|
-
"define-repository-
|
|
111
|
-
"define-repository-
|
|
112
|
-
"define-slot-
|
|
113
|
-
"define-slot-
|
|
118
|
+
"define-repository-Ck45La_2.d.ts",
|
|
119
|
+
"define-repository-DAyeXF48.d.cts",
|
|
120
|
+
"define-slot-BTlLQ__T.d.ts",
|
|
121
|
+
"define-slot-C6hrdJS3.d.cts",
|
|
114
122
|
"define.cjs",
|
|
115
123
|
"define.d.cts",
|
|
116
124
|
"define.d.ts",
|
|
117
125
|
"define.js",
|
|
118
126
|
"den.js",
|
|
119
|
-
"descriptor-
|
|
120
|
-
"descriptor-
|
|
127
|
+
"descriptor-CNJFrEbS.d.ts",
|
|
128
|
+
"descriptor-DmfJP4jQ.d.cts",
|
|
121
129
|
"index.cjs",
|
|
122
130
|
"index.d.cts",
|
|
123
131
|
"index.d.ts",
|
|
124
132
|
"index.js",
|
|
125
133
|
"island",
|
|
134
|
+
"ops",
|
|
126
135
|
"package.json",
|
|
127
|
-
"routes-
|
|
128
|
-
"routes-
|
|
136
|
+
"routes-DQ4ud4bu.d.cts",
|
|
137
|
+
"routes-TkIxQ0Uc.d.ts",
|
|
129
138
|
"serve",
|
|
130
139
|
"server-render-CocWXQKC.d.cts",
|
|
131
140
|
"server-render-CocWXQKC.d.ts",
|
|
132
|
-
"types-
|
|
133
|
-
"types-
|
|
134
|
-
"view-adapter-
|
|
135
|
-
"view-adapter-
|
|
141
|
+
"types-Ccd5bmt1.d.cts",
|
|
142
|
+
"types-Ccd5bmt1.d.ts",
|
|
143
|
+
"view-adapter-CrHh7CjB.d.cts",
|
|
144
|
+
"view-adapter-DPDvv09J.d.ts"
|
|
136
145
|
],
|
|
137
|
-
"sha": "
|
|
146
|
+
"sha": "c941b51",
|
|
138
147
|
"scripts": {}
|
|
139
148
|
}
|
package/serve/index.cjs
CHANGED
|
@@ -14,6 +14,15 @@ require('../chunk-6QV4L6R2.cjs');
|
|
|
14
14
|
var _chunkA6ZPAM6Zcjs = require('../chunk-A6ZPAM6Z.cjs');
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
var _chunkHJFBEJT6cjs = require('../chunk-HJFBEJT6.cjs');
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
17
26
|
var _chunkT5QVCXVBcjs = require('../chunk-T5QVCXVB.cjs');
|
|
18
27
|
|
|
19
28
|
// src/serve/index.ts
|
|
@@ -79,7 +88,7 @@ function matchClaim(app, pathname) {
|
|
|
79
88
|
}
|
|
80
89
|
return (_b = (_a = _chunkQTWJTYZWcjs.matchRoute.call(void 0, app.routes, pathname)) == null ? void 0 : _a.params) != null ? _b : null;
|
|
81
90
|
}
|
|
82
|
-
function
|
|
91
|
+
function requestContextOf(req, fromBody) {
|
|
83
92
|
const headers = {};
|
|
84
93
|
const forwarded = {
|
|
85
94
|
"accept-language": req.headers["x-forwarded-accept-language"],
|
|
@@ -91,22 +100,32 @@ function browserContext(req) {
|
|
|
91
100
|
}
|
|
92
101
|
}
|
|
93
102
|
const cookie = req.headers.cookie;
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
const backendHeaders = _chunkT5QVCXVBcjs.__spreadValues.call(void 0, _chunkT5QVCXVBcjs.__spreadValues.call(void 0, {}, typeof cookie === "string" && cookie !== "" ? { cookie } : {}), fromBody);
|
|
104
|
+
return { backendHeaders, cookies: _chunkQTWJTYZWcjs.parseCookieHeader.call(void 0, cookie), headers };
|
|
105
|
+
}
|
|
106
|
+
function backendHeadersOf(value) {
|
|
107
|
+
if (value === void 0) {
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
111
|
+
return "invalid";
|
|
112
|
+
}
|
|
113
|
+
const entries = Object.entries(value);
|
|
114
|
+
if (entries.some(([, single]) => typeof single !== "string")) {
|
|
115
|
+
return "invalid";
|
|
96
116
|
}
|
|
97
|
-
return
|
|
117
|
+
return Object.fromEntries(entries.map(([name, single]) => [name.toLowerCase(), single]));
|
|
98
118
|
}
|
|
99
119
|
var appPlugin = (instance, options) => {
|
|
100
120
|
var _a, _b;
|
|
101
121
|
const { app, slowRenderMs = DEFAULT_SLOW_RENDER_MS } = options;
|
|
102
122
|
const appLog = (_a = _logger.log.getLogger(app.name)) != null ? _a : _chunkA6ZPAM6Zcjs.logger;
|
|
103
123
|
const serveLog = (_b = appLog.getLogger("serve")) != null ? _b : appLog;
|
|
104
|
-
instance.get("/_health", () => "ok");
|
|
105
124
|
instance.get("/_routes", (_req, reply) => {
|
|
106
125
|
void reply.header("cache-control", "no-store");
|
|
107
126
|
return claim(app);
|
|
108
127
|
});
|
|
109
|
-
function handleRender(req, reply, target, inputs) {
|
|
128
|
+
function handleRender(req, reply, target, inputs, rawBackendHeaders) {
|
|
110
129
|
return _chunkT5QVCXVBcjs.__async.call(void 0, this, null, function* () {
|
|
111
130
|
if (typeof target !== "string" || !target.startsWith("/")) {
|
|
112
131
|
return reply.code(400).send({ error: "\u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u043D \u0438\u043B\u0438 \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 url" });
|
|
@@ -114,6 +133,10 @@ var appPlugin = (instance, options) => {
|
|
|
114
133
|
if (inputs !== void 0 && (typeof inputs !== "object" || inputs === null || Array.isArray(inputs))) {
|
|
115
134
|
return reply.code(400).send({ error: "inputs \u0434\u043E\u043B\u0436\u043D\u044B \u0431\u044B\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C \u043F\u043E \u043A\u043B\u044E\u0447\u0443 token.description" });
|
|
116
135
|
}
|
|
136
|
+
const backendHeaders = backendHeadersOf(rawBackendHeaders);
|
|
137
|
+
if (backendHeaders === "invalid") {
|
|
138
|
+
return reply.code(400).send({ error: "backendHeaders \u0434\u043E\u043B\u0436\u043D\u044B \u0431\u044B\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C \xAB\u0438\u043C\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430 \u2192 \u0441\u0442\u0440\u043E\u043A\u0430\xBB" });
|
|
139
|
+
}
|
|
117
140
|
const { pathname, search } = new URL(target, "http://localhost");
|
|
118
141
|
const params = matchClaim(app, pathname);
|
|
119
142
|
if (params === null) {
|
|
@@ -123,7 +146,7 @@ var appPlugin = (instance, options) => {
|
|
|
123
146
|
const startedAt = Date.now();
|
|
124
147
|
try {
|
|
125
148
|
const result = yield _chunkQTWJTYZWcjs.renderApp.call(void 0, app, {
|
|
126
|
-
context:
|
|
149
|
+
context: requestContextOf(req, backendHeaders),
|
|
127
150
|
inputs,
|
|
128
151
|
params,
|
|
129
152
|
pathname,
|
|
@@ -140,12 +163,15 @@ var appPlugin = (instance, options) => {
|
|
|
140
163
|
}
|
|
141
164
|
});
|
|
142
165
|
}
|
|
143
|
-
instance.get(
|
|
166
|
+
instance.get(
|
|
167
|
+
"/_render",
|
|
168
|
+
(req, reply) => handleRender(req, reply, req.query.url, void 0, void 0)
|
|
169
|
+
);
|
|
144
170
|
instance.route({
|
|
145
171
|
handler: (req, reply) => {
|
|
146
172
|
var _a2;
|
|
147
173
|
const body = (_a2 = req.body) != null ? _a2 : {};
|
|
148
|
-
return handleRender(req, reply, body.url, body.inputs);
|
|
174
|
+
return handleRender(req, reply, body.url, body.inputs, body.backendHeaders);
|
|
149
175
|
},
|
|
150
176
|
method: "QUERY",
|
|
151
177
|
url: "/_render"
|
|
@@ -153,14 +179,235 @@ var appPlugin = (instance, options) => {
|
|
|
153
179
|
return Promise.resolve();
|
|
154
180
|
};
|
|
155
181
|
|
|
182
|
+
// src/serve/process.ts
|
|
183
|
+
var _cluster = require('cluster'); var _cluster2 = _interopRequireDefault(_cluster);
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
// src/serve/worker.ts
|
|
187
|
+
|
|
188
|
+
var ALIVE = "den:app-worker-alive";
|
|
189
|
+
var SIGNALS = ["SIGTERM", "SIGINT"];
|
|
190
|
+
var SHUTDOWN_MS = 1e4;
|
|
191
|
+
function startWorker(appName, start) {
|
|
192
|
+
return _chunkT5QVCXVBcjs.__async.call(void 0, this, null, function* () {
|
|
193
|
+
const aggregation = _chunkHJFBEJT6cjs.clusterMetrics.call(void 0, );
|
|
194
|
+
const logger2 = _logger.log.getLogger(appName).getLogger("cluster");
|
|
195
|
+
let timer;
|
|
196
|
+
let closing;
|
|
197
|
+
const starting = start();
|
|
198
|
+
const close = () => {
|
|
199
|
+
closing != null ? closing : closing = (() => _chunkT5QVCXVBcjs.__async.call(void 0, null, null, function* () {
|
|
200
|
+
clearInterval(timer);
|
|
201
|
+
try {
|
|
202
|
+
const instance = yield starting;
|
|
203
|
+
yield instance.close();
|
|
204
|
+
} finally {
|
|
205
|
+
try {
|
|
206
|
+
if (process.connected) yield aggregation.shutdown();
|
|
207
|
+
} finally {
|
|
208
|
+
for (const signal of SIGNALS) process.removeListener(signal, shutdown);
|
|
209
|
+
process.removeListener("disconnect", shutdown);
|
|
210
|
+
if (process.connected) process.disconnect();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}))();
|
|
214
|
+
return closing;
|
|
215
|
+
};
|
|
216
|
+
const shutdown = () => {
|
|
217
|
+
const deadline = setTimeout(() => process.exit(1), SHUTDOWN_MS);
|
|
218
|
+
deadline.unref();
|
|
219
|
+
void close().then(() => process.exit(0)).catch((error) => {
|
|
220
|
+
logger2.error("\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u0432\u043E\u0440\u043A\u0435\u0440\u0430 \u043D\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C:", error);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
for (const signal of SIGNALS) process.on(signal, shutdown);
|
|
225
|
+
process.once("disconnect", shutdown);
|
|
226
|
+
try {
|
|
227
|
+
yield starting;
|
|
228
|
+
if (!closing) {
|
|
229
|
+
const notify = () => {
|
|
230
|
+
var _a;
|
|
231
|
+
if (process.connected) (_a = process.send) == null ? void 0 : _a.call(process, { type: ALIVE });
|
|
232
|
+
};
|
|
233
|
+
timer = setInterval(notify, 2e3);
|
|
234
|
+
timer.unref();
|
|
235
|
+
notify();
|
|
236
|
+
}
|
|
237
|
+
} catch (error) {
|
|
238
|
+
yield close().catch(() => void 0);
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
return { close };
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/serve/process.ts
|
|
246
|
+
var STARTUP_MS = 6e4;
|
|
247
|
+
function startAppProcess(appName, options, start) {
|
|
248
|
+
return _chunkT5QVCXVBcjs.__async.call(void 0, this, null, function* () {
|
|
249
|
+
var _a;
|
|
250
|
+
const workers = (_a = options.workers) != null ? _a : 1;
|
|
251
|
+
if (!Number.isSafeInteger(workers) || workers < 1) {
|
|
252
|
+
throw new Error("WORKERS must be a positive integer");
|
|
253
|
+
}
|
|
254
|
+
if (workers === 1) {
|
|
255
|
+
const instance = yield start(options);
|
|
256
|
+
return { close: () => instance.close() };
|
|
257
|
+
}
|
|
258
|
+
const metrics = _chunkHJFBEJT6cjs.getProcessMetrics.call(void 0, );
|
|
259
|
+
metrics.startRuntime(appName);
|
|
260
|
+
if (_cluster2.default.isWorker) {
|
|
261
|
+
return startWorker(appName, () => start(_chunkT5QVCXVBcjs.__spreadProps.call(void 0, _chunkT5QVCXVBcjs.__spreadValues.call(void 0, {}, options), { gracefulShutdown: false, ops: false })));
|
|
262
|
+
}
|
|
263
|
+
return startPrimary(appName, options, workers);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function startPrimary(appName, options, workers) {
|
|
267
|
+
return _chunkT5QVCXVBcjs.__async.call(void 0, this, null, function* () {
|
|
268
|
+
const aggregation = _chunkHJFBEJT6cjs.clusterMetrics.call(void 0, );
|
|
269
|
+
const logger2 = _logger.log.getLogger(appName).getLogger("cluster");
|
|
270
|
+
const children = /* @__PURE__ */ new Set();
|
|
271
|
+
const alive = /* @__PURE__ */ new Map();
|
|
272
|
+
let ops;
|
|
273
|
+
let closing;
|
|
274
|
+
let started = false;
|
|
275
|
+
let resolveReady = () => void 0;
|
|
276
|
+
let rejectReady = () => void 0;
|
|
277
|
+
const ready = new Promise((resolve, reject) => {
|
|
278
|
+
resolveReady = resolve;
|
|
279
|
+
rejectReady = reject;
|
|
280
|
+
});
|
|
281
|
+
void ready.catch(() => void 0);
|
|
282
|
+
const timeout = setTimeout(() => rejectReady(new Error("Den workers startup timeout")), STARTUP_MS);
|
|
283
|
+
const onMessage = (worker, message) => {
|
|
284
|
+
if (children.has(worker) && typeof message === "object" && message !== null && "type" in message && message.type === ALIVE) {
|
|
285
|
+
alive.set(worker.id, Date.now());
|
|
286
|
+
if (alive.size === workers) resolveReady();
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
const close = () => {
|
|
290
|
+
closing != null ? closing : closing = (() => _chunkT5QVCXVBcjs.__async.call(void 0, null, null, function* () {
|
|
291
|
+
clearTimeout(timeout);
|
|
292
|
+
resolveReady();
|
|
293
|
+
_cluster2.default.removeListener("message", onMessage);
|
|
294
|
+
yield Promise.all([...children].map(stopWorker));
|
|
295
|
+
if (ops) yield _chunkHJFBEJT6cjs.closeHttpServer.call(void 0, ops);
|
|
296
|
+
yield aggregation.shutdown();
|
|
297
|
+
for (const signal of SIGNALS) process.removeListener(signal, shutdown);
|
|
298
|
+
}))();
|
|
299
|
+
return closing;
|
|
300
|
+
};
|
|
301
|
+
const shutdown = () => {
|
|
302
|
+
void close().then(() => process.exit()).catch((error) => {
|
|
303
|
+
logger2.error("\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043A\u043B\u0430\u0441\u0442\u0435\u0440\u0430 \u043D\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C:", error);
|
|
304
|
+
process.exit(1);
|
|
305
|
+
});
|
|
306
|
+
};
|
|
307
|
+
const failed = (error) => {
|
|
308
|
+
if (closing) return;
|
|
309
|
+
if (!started) {
|
|
310
|
+
rejectReady(error);
|
|
311
|
+
} else {
|
|
312
|
+
logger2.error(error);
|
|
313
|
+
process.exitCode = 1;
|
|
314
|
+
shutdown();
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
_cluster2.default.on("message", onMessage);
|
|
318
|
+
if (options.gracefulShutdown !== false) {
|
|
319
|
+
for (const signal of SIGNALS) process.on(signal, shutdown);
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
if (options.ops !== false) {
|
|
323
|
+
const supplied = options.ops;
|
|
324
|
+
ops = yield _chunkHJFBEJT6cjs.startOpsServer.call(void 0, _chunkT5QVCXVBcjs.__spreadProps.call(void 0, _chunkT5QVCXVBcjs.__spreadValues.call(void 0, {}, supplied), {
|
|
325
|
+
collect: aggregation.collect,
|
|
326
|
+
contentType: aggregation.contentType,
|
|
327
|
+
isLive: () => {
|
|
328
|
+
var _a;
|
|
329
|
+
return [...children].some((worker) => {
|
|
330
|
+
var _a2;
|
|
331
|
+
return worker.isConnected() && Date.now() - ((_a2 = alive.get(worker.id)) != null ? _a2 : 0) < 1e4;
|
|
332
|
+
}) && ((_a = supplied == null ? void 0 : supplied.isLive) == null ? void 0 : _a.call(supplied)) !== false;
|
|
333
|
+
}
|
|
334
|
+
}));
|
|
335
|
+
}
|
|
336
|
+
if (closing) {
|
|
337
|
+
if (ops) yield _chunkHJFBEJT6cjs.closeHttpServer.call(void 0, ops);
|
|
338
|
+
yield closing;
|
|
339
|
+
return { close };
|
|
340
|
+
}
|
|
341
|
+
for (let i = 0; i < workers; i++) {
|
|
342
|
+
const worker = _cluster2.default.fork();
|
|
343
|
+
children.add(worker);
|
|
344
|
+
worker.once("error", failed);
|
|
345
|
+
worker.once("exit", (code, signal) => {
|
|
346
|
+
alive.delete(worker.id);
|
|
347
|
+
failed(new Error(`Den worker ${String(worker.process.pid)} exited (${String(code != null ? code : signal)})`));
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
yield ready;
|
|
351
|
+
started = true;
|
|
352
|
+
clearTimeout(timeout);
|
|
353
|
+
if (!closing) logger2.info(`\u0437\u0430\u043F\u0443\u0449\u0435\u043D\u043E \u0432\u043E\u0440\u043A\u0435\u0440\u043E\u0432: ${String(workers)}`);
|
|
354
|
+
return { close };
|
|
355
|
+
} catch (error) {
|
|
356
|
+
yield close();
|
|
357
|
+
throw error;
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
function stopWorker(worker) {
|
|
362
|
+
return _chunkT5QVCXVBcjs.__async.call(void 0, this, null, function* () {
|
|
363
|
+
if (worker.isDead()) return;
|
|
364
|
+
yield new Promise((resolve) => {
|
|
365
|
+
const timeout = setTimeout(() => worker.kill("SIGKILL"), SHUTDOWN_MS);
|
|
366
|
+
worker.once("exit", () => {
|
|
367
|
+
clearTimeout(timeout);
|
|
368
|
+
resolve();
|
|
369
|
+
});
|
|
370
|
+
worker.kill("SIGTERM");
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
156
375
|
// src/serve/index.ts
|
|
376
|
+
function serveAppProcess(app, options = {}) {
|
|
377
|
+
return startAppProcess(app.name, options, (serveOptions) => serveApp(app, serveOptions));
|
|
378
|
+
}
|
|
157
379
|
var SHUTDOWN_SIGNALS = ["SIGTERM", "SIGINT"];
|
|
158
380
|
function serveApp(_0) {
|
|
159
381
|
return _chunkT5QVCXVBcjs.__async.call(void 0, this, arguments, function* (app, options = {}) {
|
|
160
|
-
var _a, _b, _c, _d;
|
|
382
|
+
var _a, _b, _c, _d, _e;
|
|
161
383
|
const appLog = (_a = _logger.log.getLogger(app.name)) != null ? _a : _chunkA6ZPAM6Zcjs.logger;
|
|
162
384
|
const serveLog = (_b = appLog.getLogger("serve")) != null ? _b : appLog;
|
|
163
385
|
const instance = _fastify2.default.call(void 0, { logger: false });
|
|
386
|
+
const metrics = _chunkHJFBEJT6cjs.getProcessMetrics.call(void 0, );
|
|
387
|
+
metrics.startRuntime(app.name);
|
|
388
|
+
let ops;
|
|
389
|
+
const shutdown = () => {
|
|
390
|
+
void instance.close();
|
|
391
|
+
};
|
|
392
|
+
instance.addHook("onRequest", (req, reply, done) => {
|
|
393
|
+
if (_chunkHJFBEJT6cjs.isOpsPath.call(void 0, req.url)) {
|
|
394
|
+
void reply.code(404).send();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
metrics.trackHttp(req.raw, reply.raw, () => {
|
|
398
|
+
var _a2;
|
|
399
|
+
return (_a2 = req.routeOptions.url) != null ? _a2 : "unmatched";
|
|
400
|
+
});
|
|
401
|
+
done();
|
|
402
|
+
});
|
|
403
|
+
instance.addHook("onClose", () => _chunkT5QVCXVBcjs.__async.call(void 0, null, null, function* () {
|
|
404
|
+
for (const signal of SHUTDOWN_SIGNALS) {
|
|
405
|
+
process.removeListener(signal, shutdown);
|
|
406
|
+
}
|
|
407
|
+
if (ops) {
|
|
408
|
+
yield _chunkHJFBEJT6cjs.closeHttpServer.call(void 0, ops);
|
|
409
|
+
}
|
|
410
|
+
}));
|
|
164
411
|
yield instance.register(appPlugin, { app, slowRenderMs: options.slowRenderMs });
|
|
165
412
|
if (options.assets) {
|
|
166
413
|
registerAssets(instance, options.assets);
|
|
@@ -174,14 +421,19 @@ function serveApp(_0) {
|
|
|
174
421
|
serveLog.info(`\u2190 ${String(reply.statusCode)} ${req.method} ${req.url} ${elapsed}\u043C\u0441`);
|
|
175
422
|
done();
|
|
176
423
|
});
|
|
177
|
-
|
|
178
|
-
|
|
424
|
+
try {
|
|
425
|
+
yield (_c = options.configure) == null ? void 0 : _c.call(options, instance);
|
|
426
|
+
if (options.ops !== false) {
|
|
427
|
+
ops = yield _chunkHJFBEJT6cjs.startOpsServer.call(void 0, options.ops);
|
|
428
|
+
}
|
|
429
|
+
yield instance.listen({ host: (_d = options.host) != null ? _d : "0.0.0.0", port: (_e = options.port) != null ? _e : 8080 });
|
|
430
|
+
} catch (error) {
|
|
431
|
+
yield instance.close();
|
|
432
|
+
throw error;
|
|
433
|
+
}
|
|
179
434
|
if (options.gracefulShutdown !== false) {
|
|
180
435
|
for (const signal of SHUTDOWN_SIGNALS) {
|
|
181
|
-
process.once(signal,
|
|
182
|
-
serveLog.info(`${signal}: \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u044E \u0438\u043D\u0441\u0442\u0430\u043D\u0441`);
|
|
183
|
-
void instance.close();
|
|
184
|
-
});
|
|
436
|
+
process.once(signal, shutdown);
|
|
185
437
|
}
|
|
186
438
|
}
|
|
187
439
|
serveLog.info(
|
|
@@ -195,4 +447,5 @@ function serveApp(_0) {
|
|
|
195
447
|
|
|
196
448
|
|
|
197
449
|
|
|
198
|
-
|
|
450
|
+
|
|
451
|
+
exports.appPlugin = appPlugin; exports.loadAppEnv = _chunkKQAB6C6Qcjs.loadAppEnv; exports.registerAssets = registerAssets; exports.serveApp = serveApp; exports.serveAppProcess = serveAppProcess;
|
package/serve/index.d.cts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { FastifyInstance, FastifyPluginAsync } from 'fastify';
|
|
2
|
-
import { I as IslandDescriptor } from '../descriptor-
|
|
3
|
-
import { A as AppRoute } from '../routes-
|
|
4
|
-
import '../
|
|
5
|
-
import '../
|
|
2
|
+
import { I as IslandDescriptor } from '../descriptor-DmfJP4jQ.cjs';
|
|
3
|
+
import { A as AppRoute } from '../routes-DQ4ud4bu.cjs';
|
|
4
|
+
import { OpsOptions } from '../ops/index.cjs';
|
|
5
|
+
import '../define-slot-C6hrdJS3.cjs';
|
|
6
|
+
import '../types-Ccd5bmt1.cjs';
|
|
6
7
|
import '@foxford/ioc';
|
|
8
|
+
import '@prometheus-io/client';
|
|
9
|
+
import 'node:http';
|
|
7
10
|
|
|
8
11
|
/** Что раздаётся и по какому префиксу. */
|
|
9
12
|
interface AppAssetsSource {
|
|
@@ -31,7 +34,7 @@ interface AppPluginOptions {
|
|
|
31
34
|
slowRenderMs?: number;
|
|
32
35
|
}
|
|
33
36
|
/**
|
|
34
|
-
* Регистрирует ручки приложения на инстансе fastify: `/_render`, `/_routes
|
|
37
|
+
* Регистрирует ручки приложения на инстансе fastify: `/_render`, `/_routes`.
|
|
35
38
|
*
|
|
36
39
|
* Плагином, поэтому монтируется и в свой сервер, и в чужой — под префиксом, рядом с ручками
|
|
37
40
|
* потребителя, вместе с его плагинами.
|
|
@@ -41,6 +44,14 @@ interface AppPluginOptions {
|
|
|
41
44
|
*/
|
|
42
45
|
declare const appPlugin: FastifyPluginAsync<AppPluginOptions>;
|
|
43
46
|
|
|
47
|
+
interface AppProcess {
|
|
48
|
+
close: () => Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
interface ServeAppProcessOptions extends ServeAppOptions {
|
|
51
|
+
/** Число процессов приложения; по умолчанию 1. Каждый воркер имеет свой контейнер. */
|
|
52
|
+
workers?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
/**
|
|
45
56
|
* Кладёт умолчания из `<root>/.env` в окружение процесса.
|
|
46
57
|
*
|
|
@@ -50,10 +61,14 @@ declare const appPlugin: FastifyPluginAsync<AppPluginOptions>;
|
|
|
50
61
|
*/
|
|
51
62
|
declare function loadAppEnv(root: string): void;
|
|
52
63
|
|
|
64
|
+
/** Точка входа самостоятельного процесса: один инстанс либо cluster с общим портом. */
|
|
65
|
+
declare function serveAppProcess(app: ServableApp, options?: ServeAppProcessOptions): Promise<AppProcess>;
|
|
53
66
|
/** Настройки инстанса. */
|
|
54
67
|
interface ServeAppOptions {
|
|
55
68
|
/** Порт; `0` — свободный, фактический смотри в `server.addresses()`. */
|
|
56
69
|
port?: number;
|
|
70
|
+
/** Второй HTTP-сервер для probes и метрик; false — подключается потребителем. */
|
|
71
|
+
ops?: OpsOptions | false;
|
|
57
72
|
/** Интерфейс прослушивания. */
|
|
58
73
|
host?: string;
|
|
59
74
|
/** Порог, выше которого рендер считается медленным и уходит в `warn`, мс. */
|
|
@@ -88,4 +103,4 @@ interface ServeAppOptions {
|
|
|
88
103
|
*/
|
|
89
104
|
declare function serveApp(app: ServableApp, options?: ServeAppOptions): Promise<FastifyInstance>;
|
|
90
105
|
|
|
91
|
-
export { type AppAssetsSource, type AppPluginOptions, type ServableApp, type ServeAppOptions, appPlugin, loadAppEnv, registerAssets, serveApp };
|
|
106
|
+
export { type AppAssetsSource, type AppPluginOptions, type AppProcess, type ServableApp, type ServeAppOptions, type ServeAppProcessOptions, appPlugin, loadAppEnv, registerAssets, serveApp, serveAppProcess };
|
package/serve/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { FastifyInstance, FastifyPluginAsync } from 'fastify';
|
|
2
|
-
import { I as IslandDescriptor } from '../descriptor-
|
|
3
|
-
import { A as AppRoute } from '../routes-
|
|
4
|
-
import '../
|
|
5
|
-
import '../
|
|
2
|
+
import { I as IslandDescriptor } from '../descriptor-CNJFrEbS.js';
|
|
3
|
+
import { A as AppRoute } from '../routes-TkIxQ0Uc.js';
|
|
4
|
+
import { OpsOptions } from '../ops/index.js';
|
|
5
|
+
import '../define-slot-BTlLQ__T.js';
|
|
6
|
+
import '../types-Ccd5bmt1.js';
|
|
6
7
|
import '@foxford/ioc';
|
|
8
|
+
import '@prometheus-io/client';
|
|
9
|
+
import 'node:http';
|
|
7
10
|
|
|
8
11
|
/** Что раздаётся и по какому префиксу. */
|
|
9
12
|
interface AppAssetsSource {
|
|
@@ -31,7 +34,7 @@ interface AppPluginOptions {
|
|
|
31
34
|
slowRenderMs?: number;
|
|
32
35
|
}
|
|
33
36
|
/**
|
|
34
|
-
* Регистрирует ручки приложения на инстансе fastify: `/_render`, `/_routes
|
|
37
|
+
* Регистрирует ручки приложения на инстансе fastify: `/_render`, `/_routes`.
|
|
35
38
|
*
|
|
36
39
|
* Плагином, поэтому монтируется и в свой сервер, и в чужой — под префиксом, рядом с ручками
|
|
37
40
|
* потребителя, вместе с его плагинами.
|
|
@@ -41,6 +44,14 @@ interface AppPluginOptions {
|
|
|
41
44
|
*/
|
|
42
45
|
declare const appPlugin: FastifyPluginAsync<AppPluginOptions>;
|
|
43
46
|
|
|
47
|
+
interface AppProcess {
|
|
48
|
+
close: () => Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
interface ServeAppProcessOptions extends ServeAppOptions {
|
|
51
|
+
/** Число процессов приложения; по умолчанию 1. Каждый воркер имеет свой контейнер. */
|
|
52
|
+
workers?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
/**
|
|
45
56
|
* Кладёт умолчания из `<root>/.env` в окружение процесса.
|
|
46
57
|
*
|
|
@@ -50,10 +61,14 @@ declare const appPlugin: FastifyPluginAsync<AppPluginOptions>;
|
|
|
50
61
|
*/
|
|
51
62
|
declare function loadAppEnv(root: string): void;
|
|
52
63
|
|
|
64
|
+
/** Точка входа самостоятельного процесса: один инстанс либо cluster с общим портом. */
|
|
65
|
+
declare function serveAppProcess(app: ServableApp, options?: ServeAppProcessOptions): Promise<AppProcess>;
|
|
53
66
|
/** Настройки инстанса. */
|
|
54
67
|
interface ServeAppOptions {
|
|
55
68
|
/** Порт; `0` — свободный, фактический смотри в `server.addresses()`. */
|
|
56
69
|
port?: number;
|
|
70
|
+
/** Второй HTTP-сервер для probes и метрик; false — подключается потребителем. */
|
|
71
|
+
ops?: OpsOptions | false;
|
|
57
72
|
/** Интерфейс прослушивания. */
|
|
58
73
|
host?: string;
|
|
59
74
|
/** Порог, выше которого рендер считается медленным и уходит в `warn`, мс. */
|
|
@@ -88,4 +103,4 @@ interface ServeAppOptions {
|
|
|
88
103
|
*/
|
|
89
104
|
declare function serveApp(app: ServableApp, options?: ServeAppOptions): Promise<FastifyInstance>;
|
|
90
105
|
|
|
91
|
-
export { type AppAssetsSource, type AppPluginOptions, type ServableApp, type ServeAppOptions, appPlugin, loadAppEnv, registerAssets, serveApp };
|
|
106
|
+
export { type AppAssetsSource, type AppPluginOptions, type AppProcess, type ServableApp, type ServeAppOptions, type ServeAppProcessOptions, appPlugin, loadAppEnv, registerAssets, serveApp, serveAppProcess };
|