cwresdev 0.1.4 → 0.1.6
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/package.json +1 -1
- package/src/proxy.js +54 -2
- package/src/server.js +49 -2
package/package.json
CHANGED
package/src/proxy.js
CHANGED
|
@@ -1,12 +1,49 @@
|
|
|
1
1
|
const { Readable } = require("node:stream");
|
|
2
2
|
const { injectLiveReload } = require("./injector");
|
|
3
3
|
|
|
4
|
+
let _stagingCookie = "";
|
|
5
|
+
|
|
6
|
+
async function acquireStagingCookie(proxyOrigin) {
|
|
7
|
+
try {
|
|
8
|
+
const res = await fetch(new URL("/contentEnvironment", proxyOrigin).toString(), {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: { "Content-Type": "application/json" },
|
|
11
|
+
body: JSON.stringify({ contentEnvironment: "staging" }),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
if (!res.ok) {
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const cookies = res.headers.getSetCookie() || [];
|
|
19
|
+
const envCookie = cookies.find((c) => c.startsWith("contentEnvironment="));
|
|
20
|
+
|
|
21
|
+
if (envCookie) {
|
|
22
|
+
_stagingCookie = envCookie.split(";")[0];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return _stagingCookie;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getStagingCookie() {
|
|
32
|
+
return _stagingCookie;
|
|
33
|
+
}
|
|
34
|
+
|
|
4
35
|
function stripHopByHopHeaders(headers) {
|
|
5
36
|
const nextHeaders = { ...headers };
|
|
6
37
|
delete nextHeaders.host;
|
|
7
38
|
delete nextHeaders.connection;
|
|
8
39
|
delete nextHeaders["content-length"];
|
|
9
40
|
delete nextHeaders["transfer-encoding"];
|
|
41
|
+
delete nextHeaders.referer;
|
|
42
|
+
delete nextHeaders.origin;
|
|
43
|
+
delete nextHeaders["sec-fetch-site"];
|
|
44
|
+
delete nextHeaders["sec-fetch-mode"];
|
|
45
|
+
delete nextHeaders["sec-fetch-dest"];
|
|
46
|
+
delete nextHeaders.cookie;
|
|
10
47
|
return nextHeaders;
|
|
11
48
|
}
|
|
12
49
|
|
|
@@ -46,11 +83,17 @@ async function readRequestBody(req) {
|
|
|
46
83
|
return Buffer.concat(chunks);
|
|
47
84
|
}
|
|
48
85
|
|
|
49
|
-
async function proxyRequest({ req, res, target, injectHtml = false }) {
|
|
86
|
+
async function proxyRequest({ req, res, target, injectHtml = false, injectCookie = false }) {
|
|
50
87
|
const body = await readRequestBody(req);
|
|
88
|
+
const outHeaders = stripHopByHopHeaders(req.headers);
|
|
89
|
+
|
|
90
|
+
if (injectCookie && _stagingCookie) {
|
|
91
|
+
outHeaders.cookie = _stagingCookie;
|
|
92
|
+
}
|
|
93
|
+
|
|
51
94
|
const upstream = await fetch(target, {
|
|
52
95
|
method: req.method,
|
|
53
|
-
headers:
|
|
96
|
+
headers: outHeaders,
|
|
54
97
|
body,
|
|
55
98
|
redirect: "manual",
|
|
56
99
|
});
|
|
@@ -61,10 +104,17 @@ async function proxyRequest({ req, res, target, injectHtml = false }) {
|
|
|
61
104
|
"content-encoding",
|
|
62
105
|
"content-length",
|
|
63
106
|
"transfer-encoding",
|
|
107
|
+
"set-cookie",
|
|
64
108
|
]);
|
|
65
109
|
|
|
66
110
|
applyResponseHeaders(upstream.headers, res, omittedHeaders);
|
|
67
111
|
|
|
112
|
+
if (injectCookie) {
|
|
113
|
+
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
114
|
+
res.setHeader("Pragma", "no-cache");
|
|
115
|
+
res.setHeader("Expires", "0");
|
|
116
|
+
}
|
|
117
|
+
|
|
68
118
|
if (req.method === "HEAD" || upstream.status === 204 || upstream.status === 304) {
|
|
69
119
|
res.end();
|
|
70
120
|
return;
|
|
@@ -86,6 +136,8 @@ async function proxyRequest({ req, res, target, injectHtml = false }) {
|
|
|
86
136
|
}
|
|
87
137
|
|
|
88
138
|
module.exports = {
|
|
139
|
+
acquireStagingCookie,
|
|
89
140
|
buildTargetUrl,
|
|
141
|
+
getStagingCookie,
|
|
90
142
|
proxyRequest,
|
|
91
143
|
};
|
package/src/server.js
CHANGED
|
@@ -8,7 +8,7 @@ const { WebSocketServer } = require("ws");
|
|
|
8
8
|
|
|
9
9
|
const { CLIENT_SCRIPT_ROUTE, getClientScriptSource, injectLiveReload } = require("./injector");
|
|
10
10
|
const { startPhpServer, stopPhpServer } = require("./php");
|
|
11
|
-
const { buildTargetUrl, proxyRequest } = require("./proxy");
|
|
11
|
+
const { acquireStagingCookie, buildTargetUrl, proxyRequest } = require("./proxy");
|
|
12
12
|
|
|
13
13
|
const HTML_EXTENSIONS = new Set([".htm", ".html", ".shtm", ".shtml"]);
|
|
14
14
|
const MAX_SSI_INCLUDE_DEPTH = 16;
|
|
@@ -198,6 +198,10 @@ async function startDevServer(config) {
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
const logger = createLogger(config.quiet);
|
|
201
|
+
|
|
202
|
+
await acquireStagingCookie(config.proxyOrigin);
|
|
203
|
+
logger.info("[cwrespro] Staging cookie acquired for CDN proxy.");
|
|
204
|
+
|
|
201
205
|
const packageRoot = path.resolve(__dirname, "..");
|
|
202
206
|
const phpServer = await startPhpServer({
|
|
203
207
|
packageRoot,
|
|
@@ -238,6 +242,7 @@ async function startDevServer(config) {
|
|
|
238
242
|
req,
|
|
239
243
|
res,
|
|
240
244
|
target: buildTargetUrl(config.proxyOrigin, req),
|
|
245
|
+
injectCookie: true,
|
|
241
246
|
});
|
|
242
247
|
} catch (error) {
|
|
243
248
|
next(error);
|
|
@@ -293,9 +298,51 @@ async function startDevServer(config) {
|
|
|
293
298
|
});
|
|
294
299
|
|
|
295
300
|
let reloadTimer = null;
|
|
301
|
+
const ignored = (config.watchIgnored || []).map((pattern) => {
|
|
302
|
+
if (typeof pattern === "function") return pattern;
|
|
303
|
+
if (pattern instanceof RegExp) return pattern;
|
|
304
|
+
if (typeof pattern !== "string") return () => false;
|
|
305
|
+
|
|
306
|
+
const normalized = pattern.replace(/\\/g, "/");
|
|
307
|
+
|
|
308
|
+
// **/segment/** → match paths containing /segment/
|
|
309
|
+
if (normalized.startsWith("**/") && normalized.endsWith("/**")) {
|
|
310
|
+
const segment = normalized.slice(3, -3);
|
|
311
|
+
return (filePath) => filePath.replace(/\\/g, "/").includes(`/${segment}/`);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (normalized.startsWith("**/")) {
|
|
315
|
+
const tail = normalized.slice(3);
|
|
316
|
+
|
|
317
|
+
// **/*suffix → basename ends with suffix (e.g. **/*~)
|
|
318
|
+
if (tail.startsWith("*")) {
|
|
319
|
+
const suffix = tail.slice(1);
|
|
320
|
+
return (filePath) => path.basename(filePath).endsWith(suffix);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// **/prefix* → basename starts with prefix (e.g. **/~*)
|
|
324
|
+
if (tail.endsWith("*") && !tail.slice(0, -1).includes("*")) {
|
|
325
|
+
const prefix = tail.slice(0, -1);
|
|
326
|
+
return (filePath) => path.basename(filePath).startsWith(prefix);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// **/*.ext → match by extension (e.g. **/*.tmp)
|
|
330
|
+
if (tail.includes("*.")) {
|
|
331
|
+
const ext = tail.slice(tail.indexOf("*.") + 1);
|
|
332
|
+
return (filePath) => path.basename(filePath).endsWith(ext);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// **/name or **/dir/name → match end of path (e.g. **/Thumbs.db, **/data/.xml)
|
|
336
|
+
return (filePath) => filePath.replace(/\\/g, "/").endsWith(`/${tail}`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// No glob metacharacters: exact match
|
|
340
|
+
return (filePath) => filePath.replace(/\\/g, "/") === normalized;
|
|
341
|
+
});
|
|
342
|
+
|
|
296
343
|
const watcher = chokidar.watch(config.docRoot, {
|
|
297
344
|
ignoreInitial: true,
|
|
298
|
-
ignored
|
|
345
|
+
ignored,
|
|
299
346
|
});
|
|
300
347
|
|
|
301
348
|
watcher.on("all", (eventName, filePath) => {
|