@foxford/den 3.6.0 → 4.0.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 +31 -6
- 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-2P5TAWRW.cjs +227 -0
- package/chunk-DUU4MQ4B.js +227 -0
- package/{chunk-2GTQK2PZ.js → chunk-FMRORLLE.js} +6 -4
- package/{chunk-P4J4M2WZ.cjs → chunk-OC4LQ2CK.cjs} +6 -4
- 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.cjs +23 -1
- package/island/index.d.cts +17 -7
- package/island/index.d.ts +17 -7
- package/island/index.js +22 -0
- 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 +70 -16
- package/serve/index.d.cts +10 -5
- package/serve/index.d.ts +10 -5
- package/serve/index.js +71 -17
- 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/serve/index.cjs
CHANGED
|
@@ -14,6 +14,13 @@ require('../chunk-6QV4L6R2.cjs');
|
|
|
14
14
|
var _chunkA6ZPAM6Zcjs = require('../chunk-A6ZPAM6Z.cjs');
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
var _chunk2P5TAWRWcjs = require('../chunk-2P5TAWRW.cjs');
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
17
24
|
var _chunkT5QVCXVBcjs = require('../chunk-T5QVCXVB.cjs');
|
|
18
25
|
|
|
19
26
|
// src/serve/index.ts
|
|
@@ -79,7 +86,7 @@ function matchClaim(app, pathname) {
|
|
|
79
86
|
}
|
|
80
87
|
return (_b = (_a = _chunkQTWJTYZWcjs.matchRoute.call(void 0, app.routes, pathname)) == null ? void 0 : _a.params) != null ? _b : null;
|
|
81
88
|
}
|
|
82
|
-
function
|
|
89
|
+
function requestContextOf(req, fromBody) {
|
|
83
90
|
const headers = {};
|
|
84
91
|
const forwarded = {
|
|
85
92
|
"accept-language": req.headers["x-forwarded-accept-language"],
|
|
@@ -91,22 +98,32 @@ function browserContext(req) {
|
|
|
91
98
|
}
|
|
92
99
|
}
|
|
93
100
|
const cookie = req.headers.cookie;
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
const backendHeaders = _chunkT5QVCXVBcjs.__spreadValues.call(void 0, _chunkT5QVCXVBcjs.__spreadValues.call(void 0, {}, typeof cookie === "string" && cookie !== "" ? { cookie } : {}), fromBody);
|
|
102
|
+
return { backendHeaders, cookies: _chunkQTWJTYZWcjs.parseCookieHeader.call(void 0, cookie), headers };
|
|
103
|
+
}
|
|
104
|
+
function backendHeadersOf(value) {
|
|
105
|
+
if (value === void 0) {
|
|
106
|
+
return void 0;
|
|
107
|
+
}
|
|
108
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
109
|
+
return "invalid";
|
|
96
110
|
}
|
|
97
|
-
|
|
111
|
+
const entries = Object.entries(value);
|
|
112
|
+
if (entries.some(([, single]) => typeof single !== "string")) {
|
|
113
|
+
return "invalid";
|
|
114
|
+
}
|
|
115
|
+
return Object.fromEntries(entries.map(([name, single]) => [name.toLowerCase(), single]));
|
|
98
116
|
}
|
|
99
117
|
var appPlugin = (instance, options) => {
|
|
100
118
|
var _a, _b;
|
|
101
119
|
const { app, slowRenderMs = DEFAULT_SLOW_RENDER_MS } = options;
|
|
102
120
|
const appLog = (_a = _logger.log.getLogger(app.name)) != null ? _a : _chunkA6ZPAM6Zcjs.logger;
|
|
103
121
|
const serveLog = (_b = appLog.getLogger("serve")) != null ? _b : appLog;
|
|
104
|
-
instance.get("/_health", () => "ok");
|
|
105
122
|
instance.get("/_routes", (_req, reply) => {
|
|
106
123
|
void reply.header("cache-control", "no-store");
|
|
107
124
|
return claim(app);
|
|
108
125
|
});
|
|
109
|
-
function handleRender(req, reply, target, inputs) {
|
|
126
|
+
function handleRender(req, reply, target, inputs, rawBackendHeaders) {
|
|
110
127
|
return _chunkT5QVCXVBcjs.__async.call(void 0, this, null, function* () {
|
|
111
128
|
if (typeof target !== "string" || !target.startsWith("/")) {
|
|
112
129
|
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 +131,10 @@ var appPlugin = (instance, options) => {
|
|
|
114
131
|
if (inputs !== void 0 && (typeof inputs !== "object" || inputs === null || Array.isArray(inputs))) {
|
|
115
132
|
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
133
|
}
|
|
134
|
+
const backendHeaders = backendHeadersOf(rawBackendHeaders);
|
|
135
|
+
if (backendHeaders === "invalid") {
|
|
136
|
+
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" });
|
|
137
|
+
}
|
|
117
138
|
const { pathname, search } = new URL(target, "http://localhost");
|
|
118
139
|
const params = matchClaim(app, pathname);
|
|
119
140
|
if (params === null) {
|
|
@@ -123,7 +144,7 @@ var appPlugin = (instance, options) => {
|
|
|
123
144
|
const startedAt = Date.now();
|
|
124
145
|
try {
|
|
125
146
|
const result = yield _chunkQTWJTYZWcjs.renderApp.call(void 0, app, {
|
|
126
|
-
context:
|
|
147
|
+
context: requestContextOf(req, backendHeaders),
|
|
127
148
|
inputs,
|
|
128
149
|
params,
|
|
129
150
|
pathname,
|
|
@@ -140,12 +161,15 @@ var appPlugin = (instance, options) => {
|
|
|
140
161
|
}
|
|
141
162
|
});
|
|
142
163
|
}
|
|
143
|
-
instance.get(
|
|
164
|
+
instance.get(
|
|
165
|
+
"/_render",
|
|
166
|
+
(req, reply) => handleRender(req, reply, req.query.url, void 0, void 0)
|
|
167
|
+
);
|
|
144
168
|
instance.route({
|
|
145
169
|
handler: (req, reply) => {
|
|
146
170
|
var _a2;
|
|
147
171
|
const body = (_a2 = req.body) != null ? _a2 : {};
|
|
148
|
-
return handleRender(req, reply, body.url, body.inputs);
|
|
172
|
+
return handleRender(req, reply, body.url, body.inputs, body.backendHeaders);
|
|
149
173
|
},
|
|
150
174
|
method: "QUERY",
|
|
151
175
|
url: "/_render"
|
|
@@ -157,10 +181,35 @@ var appPlugin = (instance, options) => {
|
|
|
157
181
|
var SHUTDOWN_SIGNALS = ["SIGTERM", "SIGINT"];
|
|
158
182
|
function serveApp(_0) {
|
|
159
183
|
return _chunkT5QVCXVBcjs.__async.call(void 0, this, arguments, function* (app, options = {}) {
|
|
160
|
-
var _a, _b, _c, _d;
|
|
184
|
+
var _a, _b, _c, _d, _e;
|
|
161
185
|
const appLog = (_a = _logger.log.getLogger(app.name)) != null ? _a : _chunkA6ZPAM6Zcjs.logger;
|
|
162
186
|
const serveLog = (_b = appLog.getLogger("serve")) != null ? _b : appLog;
|
|
163
187
|
const instance = _fastify2.default.call(void 0, { logger: false });
|
|
188
|
+
const metrics = _chunk2P5TAWRWcjs.getProcessMetrics.call(void 0, );
|
|
189
|
+
metrics.startRuntime(app.name);
|
|
190
|
+
let ops;
|
|
191
|
+
const shutdown = () => {
|
|
192
|
+
void instance.close();
|
|
193
|
+
};
|
|
194
|
+
instance.addHook("onRequest", (req, reply, done) => {
|
|
195
|
+
if (_chunk2P5TAWRWcjs.isOpsPath.call(void 0, req.url)) {
|
|
196
|
+
void reply.code(404).send();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
metrics.trackHttp(req.raw, reply.raw, () => {
|
|
200
|
+
var _a2;
|
|
201
|
+
return (_a2 = req.routeOptions.url) != null ? _a2 : "unmatched";
|
|
202
|
+
});
|
|
203
|
+
done();
|
|
204
|
+
});
|
|
205
|
+
instance.addHook("onClose", () => _chunkT5QVCXVBcjs.__async.call(void 0, null, null, function* () {
|
|
206
|
+
for (const signal of SHUTDOWN_SIGNALS) {
|
|
207
|
+
process.removeListener(signal, shutdown);
|
|
208
|
+
}
|
|
209
|
+
if (ops) {
|
|
210
|
+
yield _chunk2P5TAWRWcjs.closeHttpServer.call(void 0, ops);
|
|
211
|
+
}
|
|
212
|
+
}));
|
|
164
213
|
yield instance.register(appPlugin, { app, slowRenderMs: options.slowRenderMs });
|
|
165
214
|
if (options.assets) {
|
|
166
215
|
registerAssets(instance, options.assets);
|
|
@@ -174,14 +223,19 @@ function serveApp(_0) {
|
|
|
174
223
|
serveLog.info(`\u2190 ${String(reply.statusCode)} ${req.method} ${req.url} ${elapsed}\u043C\u0441`);
|
|
175
224
|
done();
|
|
176
225
|
});
|
|
177
|
-
|
|
178
|
-
|
|
226
|
+
try {
|
|
227
|
+
yield (_c = options.configure) == null ? void 0 : _c.call(options, instance);
|
|
228
|
+
if (options.ops !== false) {
|
|
229
|
+
ops = yield _chunk2P5TAWRWcjs.startOpsServer.call(void 0, options.ops);
|
|
230
|
+
}
|
|
231
|
+
yield instance.listen({ host: (_d = options.host) != null ? _d : "0.0.0.0", port: (_e = options.port) != null ? _e : 8080 });
|
|
232
|
+
} catch (error) {
|
|
233
|
+
yield instance.close();
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
179
236
|
if (options.gracefulShutdown !== false) {
|
|
180
237
|
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
|
-
});
|
|
238
|
+
process.once(signal, shutdown);
|
|
185
239
|
}
|
|
186
240
|
}
|
|
187
241
|
serveLog.info(
|
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
|
* потребителя, вместе с его плагинами.
|
|
@@ -54,6 +57,8 @@ declare function loadAppEnv(root: string): void;
|
|
|
54
57
|
interface ServeAppOptions {
|
|
55
58
|
/** Порт; `0` — свободный, фактический смотри в `server.addresses()`. */
|
|
56
59
|
port?: number;
|
|
60
|
+
/** Второй HTTP-сервер для probes и метрик; false — подключается потребителем. */
|
|
61
|
+
ops?: OpsOptions | false;
|
|
57
62
|
/** Интерфейс прослушивания. */
|
|
58
63
|
host?: string;
|
|
59
64
|
/** Порог, выше которого рендер считается медленным и уходит в `warn`, мс. */
|
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
|
* потребителя, вместе с его плагинами.
|
|
@@ -54,6 +57,8 @@ declare function loadAppEnv(root: string): void;
|
|
|
54
57
|
interface ServeAppOptions {
|
|
55
58
|
/** Порт; `0` — свободный, фактический смотри в `server.addresses()`. */
|
|
56
59
|
port?: number;
|
|
60
|
+
/** Второй HTTP-сервер для probes и метрик; false — подключается потребителем. */
|
|
61
|
+
ops?: OpsOptions | false;
|
|
57
62
|
/** Интерфейс прослушивания. */
|
|
58
63
|
host?: string;
|
|
59
64
|
/** Порог, выше которого рендер считается медленным и уходит в `warn`, мс. */
|
package/serve/index.js
CHANGED
|
@@ -13,7 +13,14 @@ import {
|
|
|
13
13
|
logger
|
|
14
14
|
} from "../chunk-TPBI6TOU.js";
|
|
15
15
|
import {
|
|
16
|
-
|
|
16
|
+
closeHttpServer,
|
|
17
|
+
getProcessMetrics,
|
|
18
|
+
isOpsPath,
|
|
19
|
+
startOpsServer
|
|
20
|
+
} from "../chunk-DUU4MQ4B.js";
|
|
21
|
+
import {
|
|
22
|
+
__async,
|
|
23
|
+
__spreadValues
|
|
17
24
|
} from "../chunk-6FNC3XMI.js";
|
|
18
25
|
|
|
19
26
|
// src/serve/index.ts
|
|
@@ -79,7 +86,7 @@ function matchClaim(app, pathname) {
|
|
|
79
86
|
}
|
|
80
87
|
return (_b = (_a = matchRoute(app.routes, pathname)) == null ? void 0 : _a.params) != null ? _b : null;
|
|
81
88
|
}
|
|
82
|
-
function
|
|
89
|
+
function requestContextOf(req, fromBody) {
|
|
83
90
|
const headers = {};
|
|
84
91
|
const forwarded = {
|
|
85
92
|
"accept-language": req.headers["x-forwarded-accept-language"],
|
|
@@ -91,22 +98,32 @@ function browserContext(req) {
|
|
|
91
98
|
}
|
|
92
99
|
}
|
|
93
100
|
const cookie = req.headers.cookie;
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
const backendHeaders = __spreadValues(__spreadValues({}, typeof cookie === "string" && cookie !== "" ? { cookie } : {}), fromBody);
|
|
102
|
+
return { backendHeaders, cookies: parseCookieHeader(cookie), headers };
|
|
103
|
+
}
|
|
104
|
+
function backendHeadersOf(value) {
|
|
105
|
+
if (value === void 0) {
|
|
106
|
+
return void 0;
|
|
107
|
+
}
|
|
108
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
109
|
+
return "invalid";
|
|
110
|
+
}
|
|
111
|
+
const entries = Object.entries(value);
|
|
112
|
+
if (entries.some(([, single]) => typeof single !== "string")) {
|
|
113
|
+
return "invalid";
|
|
96
114
|
}
|
|
97
|
-
return
|
|
115
|
+
return Object.fromEntries(entries.map(([name, single]) => [name.toLowerCase(), single]));
|
|
98
116
|
}
|
|
99
117
|
var appPlugin = (instance, options) => {
|
|
100
118
|
var _a, _b;
|
|
101
119
|
const { app, slowRenderMs = DEFAULT_SLOW_RENDER_MS } = options;
|
|
102
120
|
const appLog = (_a = log.getLogger(app.name)) != null ? _a : logger;
|
|
103
121
|
const serveLog = (_b = appLog.getLogger("serve")) != null ? _b : appLog;
|
|
104
|
-
instance.get("/_health", () => "ok");
|
|
105
122
|
instance.get("/_routes", (_req, reply) => {
|
|
106
123
|
void reply.header("cache-control", "no-store");
|
|
107
124
|
return claim(app);
|
|
108
125
|
});
|
|
109
|
-
function handleRender(req, reply, target, inputs) {
|
|
126
|
+
function handleRender(req, reply, target, inputs, rawBackendHeaders) {
|
|
110
127
|
return __async(this, null, function* () {
|
|
111
128
|
if (typeof target !== "string" || !target.startsWith("/")) {
|
|
112
129
|
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 +131,10 @@ var appPlugin = (instance, options) => {
|
|
|
114
131
|
if (inputs !== void 0 && (typeof inputs !== "object" || inputs === null || Array.isArray(inputs))) {
|
|
115
132
|
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
133
|
}
|
|
134
|
+
const backendHeaders = backendHeadersOf(rawBackendHeaders);
|
|
135
|
+
if (backendHeaders === "invalid") {
|
|
136
|
+
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" });
|
|
137
|
+
}
|
|
117
138
|
const { pathname, search } = new URL(target, "http://localhost");
|
|
118
139
|
const params = matchClaim(app, pathname);
|
|
119
140
|
if (params === null) {
|
|
@@ -123,7 +144,7 @@ var appPlugin = (instance, options) => {
|
|
|
123
144
|
const startedAt = Date.now();
|
|
124
145
|
try {
|
|
125
146
|
const result = yield renderApp(app, {
|
|
126
|
-
context:
|
|
147
|
+
context: requestContextOf(req, backendHeaders),
|
|
127
148
|
inputs,
|
|
128
149
|
params,
|
|
129
150
|
pathname,
|
|
@@ -140,12 +161,15 @@ var appPlugin = (instance, options) => {
|
|
|
140
161
|
}
|
|
141
162
|
});
|
|
142
163
|
}
|
|
143
|
-
instance.get(
|
|
164
|
+
instance.get(
|
|
165
|
+
"/_render",
|
|
166
|
+
(req, reply) => handleRender(req, reply, req.query.url, void 0, void 0)
|
|
167
|
+
);
|
|
144
168
|
instance.route({
|
|
145
169
|
handler: (req, reply) => {
|
|
146
170
|
var _a2;
|
|
147
171
|
const body = (_a2 = req.body) != null ? _a2 : {};
|
|
148
|
-
return handleRender(req, reply, body.url, body.inputs);
|
|
172
|
+
return handleRender(req, reply, body.url, body.inputs, body.backendHeaders);
|
|
149
173
|
},
|
|
150
174
|
method: "QUERY",
|
|
151
175
|
url: "/_render"
|
|
@@ -157,10 +181,35 @@ var appPlugin = (instance, options) => {
|
|
|
157
181
|
var SHUTDOWN_SIGNALS = ["SIGTERM", "SIGINT"];
|
|
158
182
|
function serveApp(_0) {
|
|
159
183
|
return __async(this, arguments, function* (app, options = {}) {
|
|
160
|
-
var _a, _b, _c, _d;
|
|
184
|
+
var _a, _b, _c, _d, _e;
|
|
161
185
|
const appLog = (_a = log2.getLogger(app.name)) != null ? _a : logger;
|
|
162
186
|
const serveLog = (_b = appLog.getLogger("serve")) != null ? _b : appLog;
|
|
163
187
|
const instance = Fastify({ logger: false });
|
|
188
|
+
const metrics = getProcessMetrics();
|
|
189
|
+
metrics.startRuntime(app.name);
|
|
190
|
+
let ops;
|
|
191
|
+
const shutdown = () => {
|
|
192
|
+
void instance.close();
|
|
193
|
+
};
|
|
194
|
+
instance.addHook("onRequest", (req, reply, done) => {
|
|
195
|
+
if (isOpsPath(req.url)) {
|
|
196
|
+
void reply.code(404).send();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
metrics.trackHttp(req.raw, reply.raw, () => {
|
|
200
|
+
var _a2;
|
|
201
|
+
return (_a2 = req.routeOptions.url) != null ? _a2 : "unmatched";
|
|
202
|
+
});
|
|
203
|
+
done();
|
|
204
|
+
});
|
|
205
|
+
instance.addHook("onClose", () => __async(null, null, function* () {
|
|
206
|
+
for (const signal of SHUTDOWN_SIGNALS) {
|
|
207
|
+
process.removeListener(signal, shutdown);
|
|
208
|
+
}
|
|
209
|
+
if (ops) {
|
|
210
|
+
yield closeHttpServer(ops);
|
|
211
|
+
}
|
|
212
|
+
}));
|
|
164
213
|
yield instance.register(appPlugin, { app, slowRenderMs: options.slowRenderMs });
|
|
165
214
|
if (options.assets) {
|
|
166
215
|
registerAssets(instance, options.assets);
|
|
@@ -174,14 +223,19 @@ function serveApp(_0) {
|
|
|
174
223
|
serveLog.info(`\u2190 ${String(reply.statusCode)} ${req.method} ${req.url} ${elapsed}\u043C\u0441`);
|
|
175
224
|
done();
|
|
176
225
|
});
|
|
177
|
-
|
|
178
|
-
|
|
226
|
+
try {
|
|
227
|
+
yield (_c = options.configure) == null ? void 0 : _c.call(options, instance);
|
|
228
|
+
if (options.ops !== false) {
|
|
229
|
+
ops = yield startOpsServer(options.ops);
|
|
230
|
+
}
|
|
231
|
+
yield instance.listen({ host: (_d = options.host) != null ? _d : "0.0.0.0", port: (_e = options.port) != null ? _e : 8080 });
|
|
232
|
+
} catch (error) {
|
|
233
|
+
yield instance.close();
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
179
236
|
if (options.gracefulShutdown !== false) {
|
|
180
237
|
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
|
-
});
|
|
238
|
+
process.once(signal, shutdown);
|
|
185
239
|
}
|
|
186
240
|
}
|
|
187
241
|
serveLog.info(
|
|
@@ -477,14 +477,33 @@ declare class StateRegistry {
|
|
|
477
477
|
}
|
|
478
478
|
|
|
479
479
|
/**
|
|
480
|
-
*
|
|
481
|
-
*
|
|
480
|
+
* Реквизиты HTTP-запроса. Три поля отвечают на ТРИ РАЗНЫХ вопроса, и путать их нельзя:
|
|
481
|
+
* что прислал браузер, чему равна отдельная кука и что предъявлять бэкенду.
|
|
482
|
+
*
|
|
483
|
+
* На клиенте заголовков нет, куки берутся из документа, а реквизиты бэкенда подставляет
|
|
484
|
+
* сам браузер.
|
|
482
485
|
*/
|
|
483
486
|
interface RequestContext {
|
|
484
|
-
/**
|
|
487
|
+
/**
|
|
488
|
+
* Что прислал БРАУЗЕР: `host`, `accept-language` (в нижнем регистре).
|
|
489
|
+
*
|
|
490
|
+
* Читается для решений о рендере — собрать абсолютную ссылку, выбрать язык. Заголовка
|
|
491
|
+
* `cookie` здесь НЕТ намеренно: собери кто-нибудь по нему запрос — он отправил бы браузерную
|
|
492
|
+
* куку вместо реквизитов этого запроса, и на первом визите это был бы другой посетитель.
|
|
493
|
+
* Нужно значение куки — есть `cookies`; нужно сходить в бэкенд — есть `backendHeaders`.
|
|
494
|
+
*/
|
|
485
495
|
headers: Record<string, string>;
|
|
486
|
-
/**
|
|
496
|
+
/** Разобранные куки — чтобы прочитать значение конкретной куки. */
|
|
487
497
|
cookies: Record<string, string>;
|
|
498
|
+
/**
|
|
499
|
+
* Что предъявлять БЭКЕНДУ в каждом запросе: `cookie` и то, что бэкенд выдал хосту на
|
|
500
|
+
* бутстрапе своими заголовками (идентичность посетителя и прочее).
|
|
501
|
+
*
|
|
502
|
+
* Один набор на все походы приложения, и собирает его хост — до рендера и один раз.
|
|
503
|
+
* Навешивает на клиент расширение рантайма `@foxford/den-sdk`, поэтому прикладной код
|
|
504
|
+
* заголовков не касается вовсе.
|
|
505
|
+
*/
|
|
506
|
+
backendHeaders?: Record<string, string>;
|
|
488
507
|
}
|
|
489
508
|
/**
|
|
490
509
|
* Результат проверки guard.
|
|
@@ -477,14 +477,33 @@ declare class StateRegistry {
|
|
|
477
477
|
}
|
|
478
478
|
|
|
479
479
|
/**
|
|
480
|
-
*
|
|
481
|
-
*
|
|
480
|
+
* Реквизиты HTTP-запроса. Три поля отвечают на ТРИ РАЗНЫХ вопроса, и путать их нельзя:
|
|
481
|
+
* что прислал браузер, чему равна отдельная кука и что предъявлять бэкенду.
|
|
482
|
+
*
|
|
483
|
+
* На клиенте заголовков нет, куки берутся из документа, а реквизиты бэкенда подставляет
|
|
484
|
+
* сам браузер.
|
|
482
485
|
*/
|
|
483
486
|
interface RequestContext {
|
|
484
|
-
/**
|
|
487
|
+
/**
|
|
488
|
+
* Что прислал БРАУЗЕР: `host`, `accept-language` (в нижнем регистре).
|
|
489
|
+
*
|
|
490
|
+
* Читается для решений о рендере — собрать абсолютную ссылку, выбрать язык. Заголовка
|
|
491
|
+
* `cookie` здесь НЕТ намеренно: собери кто-нибудь по нему запрос — он отправил бы браузерную
|
|
492
|
+
* куку вместо реквизитов этого запроса, и на первом визите это был бы другой посетитель.
|
|
493
|
+
* Нужно значение куки — есть `cookies`; нужно сходить в бэкенд — есть `backendHeaders`.
|
|
494
|
+
*/
|
|
485
495
|
headers: Record<string, string>;
|
|
486
|
-
/**
|
|
496
|
+
/** Разобранные куки — чтобы прочитать значение конкретной куки. */
|
|
487
497
|
cookies: Record<string, string>;
|
|
498
|
+
/**
|
|
499
|
+
* Что предъявлять БЭКЕНДУ в каждом запросе: `cookie` и то, что бэкенд выдал хосту на
|
|
500
|
+
* бутстрапе своими заголовками (идентичность посетителя и прочее).
|
|
501
|
+
*
|
|
502
|
+
* Один набор на все походы приложения, и собирает его хост — до рендера и один раз.
|
|
503
|
+
* Навешивает на клиент расширение рантайма `@foxford/den-sdk`, поэтому прикладной код
|
|
504
|
+
* заголовков не касается вовсе.
|
|
505
|
+
*/
|
|
506
|
+
backendHeaders?: Record<string, string>;
|
|
488
507
|
}
|
|
489
508
|
/**
|
|
490
509
|
* Результат проверки guard.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { I as IslandDescriptor } from './descriptor-
|
|
1
|
+
import { I as IslandDescriptor } from './descriptor-DmfJP4jQ.cjs';
|
|
2
2
|
import { S as ServerRenderResult } from './server-render-CocWXQKC.cjs';
|
|
3
|
-
import { L as LayerDefinition, h as LayerConfig } from './types-
|
|
3
|
+
import { L as LayerDefinition, h as LayerConfig } from './types-Ccd5bmt1.cjs';
|
|
4
4
|
import { Container, Token } from '@foxford/ioc';
|
|
5
5
|
|
|
6
6
|
/** Что нужно адаптеру, чтобы отрисовать остров на сервере. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { I as IslandDescriptor } from './descriptor-
|
|
1
|
+
import { I as IslandDescriptor } from './descriptor-CNJFrEbS.js';
|
|
2
2
|
import { S as ServerRenderResult } from './server-render-CocWXQKC.js';
|
|
3
|
-
import { L as LayerDefinition, h as LayerConfig } from './types-
|
|
3
|
+
import { L as LayerDefinition, h as LayerConfig } from './types-Ccd5bmt1.js';
|
|
4
4
|
import { Container, Token } from '@foxford/ioc';
|
|
5
5
|
|
|
6
6
|
/** Что нужно адаптеру, чтобы отрисовать остров на сервере. */
|