@webiny/aws-helpers 0.0.0-unstable.78f581c1d2 → 0.0.0-unstable.7be00a75a9
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/LICENSE +2 -7
- package/README.md +11 -0
- package/cloudfrontFunctions/cookies.d.ts +1 -1
- package/cloudfrontFunctions/cookies.js +18 -27
- package/cloudfrontFunctions/cookies.js.map +1 -1
- package/cloudfrontFunctions/headers.d.ts +1 -1
- package/cloudfrontFunctions/headers.js +22 -23
- package/cloudfrontFunctions/headers.js.map +1 -1
- package/cloudfrontFunctions/index.d.ts +6 -6
- package/cloudfrontFunctions/index.js +6 -6
- package/cloudfrontFunctions/querystring.d.ts +1 -1
- package/cloudfrontFunctions/querystring.js +16 -33
- package/cloudfrontFunctions/querystring.js.map +1 -1
- package/cloudfrontFunctions/redirect.d.ts +1 -1
- package/cloudfrontFunctions/redirect.js +19 -21
- package/cloudfrontFunctions/redirect.js.map +1 -1
- package/cloudfrontFunctions/types.d.ts +6 -6
- package/cloudfrontFunctions/types.js +0 -1
- package/cloudfrontFunctions/utils.d.ts +1 -1
- package/cloudfrontFunctions/utils.js +8 -19
- package/cloudfrontFunctions/utils.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lambdaEdge/cookies.d.ts +1 -1
- package/lambdaEdge/cookies.js +20 -23
- package/lambdaEdge/cookies.js.map +1 -1
- package/lambdaEdge/headers.d.ts +1 -1
- package/lambdaEdge/headers.js +9 -6
- package/lambdaEdge/headers.js.map +1 -1
- package/lambdaEdge/index.d.ts +7 -7
- package/lambdaEdge/index.js +7 -7
- package/lambdaEdge/redirect.d.ts +1 -1
- package/lambdaEdge/redirect.js +29 -29
- package/lambdaEdge/redirect.js.map +1 -1
- package/lambdaEdge/request.d.ts +1 -1
- package/lambdaEdge/request.js +26 -19
- package/lambdaEdge/request.js.map +1 -1
- package/lambdaEdge/response.d.ts +1 -1
- package/lambdaEdge/response.js +10 -7
- package/lambdaEdge/response.js.map +1 -1
- package/lambdaEdge/types.d.ts +8 -8
- package/lambdaEdge/types.js +0 -1
- package/lambdaEdge/utils.d.ts +1 -1
- package/lambdaEdge/utils.js +8 -5
- package/lambdaEdge/utils.js.map +1 -1
- package/package.json +11 -8
- package/rslib-runtime.js +14 -0
- package/rslib-runtime.js.map +1 -0
- package/stagedRollouts/functions/adminOriginRequest.js +24 -27
- package/stagedRollouts/functions/adminOriginRequest.js.map +1 -1
- package/stagedRollouts/functions/configOriginRequest.js +48 -48
- package/stagedRollouts/functions/configOriginRequest.js.map +1 -1
- package/stagedRollouts/functions/originRequest.js +15 -14
- package/stagedRollouts/functions/originRequest.js.map +1 -1
- package/stagedRollouts/functions/viewerRequest.js +20 -40
- package/stagedRollouts/functions/viewerRequest.js.map +1 -1
- package/stagedRollouts/functions/viewerResponse.js +12 -16
- package/stagedRollouts/functions/viewerResponse.js.map +1 -1
- package/stagedRollouts/utils/common.js +8 -5
- package/stagedRollouts/utils/common.js.map +1 -1
- package/stagedRollouts/utils/headerBlacklist.js +30 -12
- package/stagedRollouts/utils/headerBlacklist.js.map +1 -1
- package/stagedRollouts/utils/loadOriginPage.d.ts +1 -1
- package/stagedRollouts/utils/loadOriginPage.js +75 -98
- package/stagedRollouts/utils/loadOriginPage.js.map +1 -1
- package/stagedRollouts/utils/loadTrafficSplittingConfig.d.ts +2 -2
- package/stagedRollouts/utils/loadTrafficSplittingConfig.js +39 -57
- package/stagedRollouts/utils/loadTrafficSplittingConfig.js.map +1 -1
- package/stagedRollouts/utils/loadVariantOrigin.d.ts +2 -2
- package/stagedRollouts/utils/loadVariantOrigin.js +45 -77
- package/stagedRollouts/utils/loadVariantOrigin.js.map +1 -1
- package/stagedRollouts/utils/log.js +6 -7
- package/stagedRollouts/utils/log.js.map +1 -1
- package/cloudfrontFunctions/index.js.map +0 -1
- package/cloudfrontFunctions/types.js.map +0 -1
- package/index.js.map +0 -1
- package/lambdaEdge/index.js.map +0 -1
- package/lambdaEdge/types.js.map +0 -1
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import { defineCloudfrontFunctionResponseHandler, setResponseCookie } from "../../cloudfrontFunctions";
|
|
2
|
-
import { variantRandomKey } from "../utils/common";
|
|
3
|
-
defineCloudfrontFunctionResponseHandler(event
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (variantRandom) {
|
|
11
|
-
setResponseCookie(response, {
|
|
12
|
-
name: variantRandomKey,
|
|
13
|
-
value: variantRandom
|
|
1
|
+
import { defineCloudfrontFunctionResponseHandler, setResponseCookie } from "../../cloudfrontFunctions/index.js";
|
|
2
|
+
import { variantRandomKey } from "../utils/common.js";
|
|
3
|
+
defineCloudfrontFunctionResponseHandler((event)=>{
|
|
4
|
+
const request = event.request;
|
|
5
|
+
const response = event.response;
|
|
6
|
+
const variantRandom = request.headers[variantRandomKey]?.value;
|
|
7
|
+
if (variantRandom) setResponseCookie(response, {
|
|
8
|
+
name: variantRandomKey,
|
|
9
|
+
value: variantRandom
|
|
14
10
|
});
|
|
15
|
-
|
|
11
|
+
return response;
|
|
12
|
+
});
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
});
|
|
14
|
+
//# sourceMappingURL=viewerResponse.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"stagedRollouts/functions/viewerResponse.js","sources":["../../../src/stagedRollouts/functions/viewerResponse.ts"],"sourcesContent":["import {\n defineCloudfrontFunctionResponseHandler,\n setResponseCookie\n} from \"~/cloudfrontFunctions/index.js\";\n\nimport { variantRandomKey } from \"../utils/common.js\";\n\ndefineCloudfrontFunctionResponseHandler(event => {\n const request = event.request;\n const response = event.response;\n\n const variantRandom = request.headers[variantRandomKey]?.value;\n if (variantRandom) {\n setResponseCookie(response, {\n name: variantRandomKey,\n value: variantRandom\n });\n }\n\n return response;\n});\n"],"names":["defineCloudfrontFunctionResponseHandler","event","request","response","variantRandom","variantRandomKey","setResponseCookie"],"mappings":";;AAOAA,wCAAwCC,CAAAA;IACpC,MAAMC,UAAUD,MAAM,OAAO;IAC7B,MAAME,WAAWF,MAAM,QAAQ;IAE/B,MAAMG,gBAAgBF,QAAQ,OAAO,CAACG,iBAAiB,EAAE;IACzD,IAAID,eACAE,kBAAkBH,UAAU;QACxB,MAAME;QACN,OAAOD;IACX;IAGJ,OAAOD;AACX"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
const variantFixedKey = "webiny-variant-fixed";
|
|
2
|
+
const variantRandomKey = "webiny-variant-random";
|
|
3
|
+
function pointsToFile(uri) {
|
|
4
|
+
return /\/[^/]+\.[^/]+$/.test(uri);
|
|
5
|
+
}
|
|
6
|
+
export { pointsToFile, variantFixedKey, variantRandomKey };
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"stagedRollouts/utils/common.js","sources":["../../../src/stagedRollouts/utils/common.ts"],"sourcesContent":["export const variantFixedKey = \"webiny-variant-fixed\";\nexport const variantRandomKey = \"webiny-variant-random\";\n\nexport function pointsToFile(uri: string) {\n return /\\/[^/]+\\.[^/]+$/.test(uri);\n}\n"],"names":["variantFixedKey","variantRandomKey","pointsToFile","uri"],"mappings":"AAAO,MAAMA,kBAAkB;AACxB,MAAMC,mBAAmB;AAEzB,SAASC,aAAaC,GAAW;IACpC,OAAO,kBAAkB,IAAI,CAACA;AAClC"}
|
|
@@ -1,13 +1,31 @@
|
|
|
1
|
-
const blacklistedHeaders = new Set([
|
|
2
|
-
"connection",
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
const blacklistedHeaders = new Set([
|
|
2
|
+
"connection",
|
|
3
|
+
"expect",
|
|
4
|
+
"keep-Alive",
|
|
5
|
+
"proxy-authenticate",
|
|
6
|
+
"proxy-authorization",
|
|
7
|
+
"proxy-connection",
|
|
8
|
+
"trailer",
|
|
9
|
+
"upgrade",
|
|
10
|
+
"x-accel-buffering",
|
|
11
|
+
"x-accel-charset",
|
|
12
|
+
"x-accel-limit-rate",
|
|
13
|
+
"x-accel-redirect",
|
|
14
|
+
"x-cache",
|
|
15
|
+
"x-forwarded-proto",
|
|
16
|
+
"x-real-op",
|
|
17
|
+
"content-length",
|
|
18
|
+
"transfer-encoding",
|
|
19
|
+
"via"
|
|
20
|
+
]);
|
|
21
|
+
const blacklistedHeadersRegex = [
|
|
22
|
+
/^x-amz-cf-/,
|
|
23
|
+
/^x-edge-/
|
|
24
|
+
];
|
|
25
|
+
function isHeaderBlacklisted(header) {
|
|
26
|
+
header = header.toLocaleLowerCase();
|
|
27
|
+
return blacklistedHeaders.has(header) || blacklistedHeadersRegex.some((r)=>r.test(header));
|
|
28
|
+
}
|
|
29
|
+
export { isHeaderBlacklisted };
|
|
9
30
|
|
|
10
|
-
|
|
11
|
-
header = header.toLocaleLowerCase();
|
|
12
|
-
return blacklistedHeaders.has(header) || blacklistedHeadersRegex.some(r => r.test(header));
|
|
13
|
-
}
|
|
31
|
+
//# sourceMappingURL=headerBlacklist.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"stagedRollouts/utils/headerBlacklist.js","sources":["../../../src/stagedRollouts/utils/headerBlacklist.ts"],"sourcesContent":["const blacklistedHeaders = new Set([\n // blacklisted headers\n \"connection\",\n \"expect\",\n \"keep-Alive\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"proxy-connection\",\n \"trailer\",\n \"upgrade\",\n \"x-accel-buffering\",\n \"x-accel-charset\",\n \"x-accel-limit-rate\",\n \"x-accel-redirect\",\n \"x-cache\",\n \"x-forwarded-proto\",\n \"x-real-op\",\n // readonly headers\n \"content-length\",\n \"transfer-encoding\",\n \"via\"\n]);\n\nconst blacklistedHeadersRegex = [/^x-amz-cf-/, /^x-edge-/];\n\n/**\n * Some headers cannot be modified with lambda edge.\n * Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-functions-restrictions.html\n */\nexport function isHeaderBlacklisted(header: string) {\n header = header.toLocaleLowerCase();\n return blacklistedHeaders.has(header) || blacklistedHeadersRegex.some(r => r.test(header));\n}\n"],"names":["blacklistedHeaders","Set","blacklistedHeadersRegex","isHeaderBlacklisted","header","r"],"mappings":"AAAA,MAAMA,qBAAqB,IAAIC,IAAI;IAE/B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IAEA;IACA;IACA;CACH;AAED,MAAMC,0BAA0B;IAAC;IAAc;CAAW;AAMnD,SAASC,oBAAoBC,MAAc;IAC9CA,SAASA,OAAO,iBAAiB;IACjC,OAAOJ,mBAAmB,GAAG,CAACI,WAAWF,wBAAwB,IAAI,CAACG,CAAAA,IAAKA,EAAE,IAAI,CAACD;AACtF"}
|
|
@@ -1,107 +1,84 @@
|
|
|
1
1
|
import { get } from "https";
|
|
2
2
|
import { load } from "cheerio";
|
|
3
|
-
import {
|
|
4
|
-
import { isHeaderBlacklisted } from "./headerBlacklist";
|
|
5
|
-
import { logDebug } from "./log";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
key: header,
|
|
50
|
-
value: value
|
|
51
|
-
}];
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
logDebug(`Page parsed`);
|
|
56
|
-
resolve(response);
|
|
57
|
-
});
|
|
3
|
+
import { parseSrcset, stringifySrcset } from "srcset";
|
|
4
|
+
import { isHeaderBlacklisted } from "./headerBlacklist.js";
|
|
5
|
+
import { logDebug } from "./log.js";
|
|
6
|
+
function loadOriginPage(domain, path) {
|
|
7
|
+
return new Promise((resolve, reject)=>{
|
|
8
|
+
logDebug(`Pulling page from ${domain}${path}`);
|
|
9
|
+
let responseBody = "";
|
|
10
|
+
const req = get({
|
|
11
|
+
hostname: domain,
|
|
12
|
+
port: 443,
|
|
13
|
+
path: path
|
|
14
|
+
}, (res)=>{
|
|
15
|
+
res.on("data", (chunk)=>responseBody += chunk);
|
|
16
|
+
res.on("end", ()=>{
|
|
17
|
+
logDebug("Parsing page");
|
|
18
|
+
const html = parseHtml(responseBody, domain);
|
|
19
|
+
const response = {
|
|
20
|
+
body: html,
|
|
21
|
+
status: "200",
|
|
22
|
+
statusDescription: "ok",
|
|
23
|
+
headers: {}
|
|
24
|
+
};
|
|
25
|
+
for (const header of Object.keys(res.headers)){
|
|
26
|
+
if (isHeaderBlacklisted(header)) continue;
|
|
27
|
+
const value = res.headers[header];
|
|
28
|
+
if (Array.isArray(value)) response.headers[header] = value.map((h)=>({
|
|
29
|
+
key: header,
|
|
30
|
+
value: h
|
|
31
|
+
}));
|
|
32
|
+
else if (value) response.headers[header] = [
|
|
33
|
+
{
|
|
34
|
+
key: header,
|
|
35
|
+
value: value
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
logDebug("Page parsed");
|
|
40
|
+
resolve(response);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
req.on("error", (e)=>{
|
|
44
|
+
reject({
|
|
45
|
+
statusCode: 500,
|
|
46
|
+
body: e.message
|
|
47
|
+
});
|
|
48
|
+
});
|
|
58
49
|
});
|
|
59
|
-
req.on("error", e => {
|
|
60
|
-
reject({
|
|
61
|
-
statusCode: 500,
|
|
62
|
-
body: e.message
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
50
|
}
|
|
67
|
-
|
|
68
51
|
function parseHtml(html, domain) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
52
|
+
const doc = load(html);
|
|
53
|
+
const host = `https://${domain}`;
|
|
54
|
+
doc("head > link").each((_i, el)=>{
|
|
55
|
+
prefixUrl(el, "href", host);
|
|
56
|
+
});
|
|
57
|
+
doc("script").each((_i, el)=>{
|
|
58
|
+
prefixUrl(el, "src", host);
|
|
59
|
+
});
|
|
60
|
+
doc("body").find("img").each((_i, el)=>{
|
|
61
|
+
prefixUrl(el, "src", host);
|
|
62
|
+
const srcset = el.attribs["srcset"];
|
|
63
|
+
if (srcset) {
|
|
64
|
+
const srcsetParsed = parseSrcset(srcset);
|
|
65
|
+
const srcsetRebased = srcsetParsed.map((src)=>{
|
|
66
|
+
if (src.url.startsWith("/")) return {
|
|
67
|
+
url: host + src.url,
|
|
68
|
+
density: src.density,
|
|
69
|
+
width: src.width
|
|
70
|
+
};
|
|
71
|
+
return src;
|
|
72
|
+
});
|
|
73
|
+
el.attribs["srcset"] = stringifySrcset(srcsetRebased);
|
|
91
74
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
});
|
|
95
|
-
el.attribs["srcset"] = stringifySrcset(srcsetRebased);
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
return doc.html();
|
|
75
|
+
});
|
|
76
|
+
return doc.html();
|
|
99
77
|
}
|
|
100
|
-
|
|
101
78
|
function prefixUrl(el, attr, host) {
|
|
102
|
-
|
|
79
|
+
const href = el.attribs[attr];
|
|
80
|
+
if (href && href.startsWith("/")) el.attribs[attr] = host + href;
|
|
81
|
+
}
|
|
82
|
+
export { loadOriginPage };
|
|
103
83
|
|
|
104
|
-
|
|
105
|
-
el.attribs[attr] = host + href;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
84
|
+
//# sourceMappingURL=loadOriginPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"stagedRollouts/utils/loadOriginPage.js","sources":["../../../src/stagedRollouts/utils/loadOriginPage.ts"],"sourcesContent":["import type { CloudFrontResponse } from \"~/lambdaEdge/index.js\";\nimport { get } from \"https\";\nimport { load } from \"cheerio\";\nimport type { SrcSetDefinition } from \"srcset\";\nimport { parseSrcset, stringifySrcset } from \"srcset\";\nimport { isHeaderBlacklisted } from \"./headerBlacklist.js\";\nimport { logDebug } from \"./log.js\";\n\n// TODO cheerio does not have Element type, so we define it here\ninterface Element {\n attribs: {\n [key: string]: string;\n };\n}\n\n/**\n * Load HTML from origin and perform transformation of URLs to absolute\n * @param domain Domain of the origin cloudfront\n * @param path Path of the file we want to retrieve\n * @returns Response object\n */\nexport function loadOriginPage(domain: string, path: string) {\n return new Promise<CloudFrontResponse>((resolve, reject) => {\n logDebug(`Pulling page from ${domain}${path}`);\n let responseBody = \"\";\n const req = get(\n {\n hostname: domain,\n port: 443,\n path: path\n },\n res => {\n res.on(\"data\", chunk => (responseBody += chunk));\n res.on(\"end\", () => {\n logDebug(`Parsing page`);\n const html = parseHtml(responseBody, domain);\n const response: CloudFrontResponse = {\n body: html,\n status: \"200\",\n statusDescription: \"ok\",\n headers: {}\n };\n\n // Rewrite headers from the HTTP response\n for (const header of Object.keys(res.headers)) {\n // We cannot set any header we want.\n // CloudFront is restricting us from setting or changing some headers.\n if (isHeaderBlacklisted(header)) {\n continue;\n }\n\n const value = res.headers[header];\n if (Array.isArray(value)) {\n response.headers[header] = value.map(h => ({\n key: header,\n value: h\n }));\n } else if (value) {\n response.headers[header] = [\n {\n key: header,\n value: value\n }\n ];\n }\n }\n\n logDebug(`Page parsed`);\n resolve(response);\n });\n }\n );\n\n req.on(\"error\", e => {\n reject({\n statusCode: 500,\n body: e.message\n });\n });\n });\n}\n\nfunction parseHtml(html: string, domain: string) {\n const doc = load(html);\n const host = `https://${domain}`;\n\n doc(\"head > link\").each((_i, el) => {\n prefixUrl(el, \"href\", host);\n });\n\n doc(\"script\").each((_i, el) => {\n prefixUrl(el, \"src\", host);\n });\n\n doc(\"body\")\n .find(\"img\")\n .each((_i, el) => {\n prefixUrl(el, \"src\", host);\n\n // Handle also srcset property for responsive images.\n const srcset = el.attribs[\"srcset\"];\n if (srcset) {\n const srcsetParsed = parseSrcset(srcset);\n const srcsetRebased = srcsetParsed.map<SrcSetDefinition>(src => {\n if (src.url.startsWith(\"/\")) {\n return {\n url: host + src.url,\n density: src.density,\n width: src.width\n };\n }\n\n return src;\n });\n\n el.attribs[\"srcset\"] = stringifySrcset(srcsetRebased);\n }\n });\n\n return doc.html();\n}\n\nfunction prefixUrl(el: Element, attr: string, host: string) {\n const href = el.attribs[attr];\n if (href && href.startsWith(\"/\")) {\n el.attribs[attr] = host + href;\n }\n}\n"],"names":["loadOriginPage","domain","path","Promise","resolve","reject","logDebug","responseBody","req","get","res","chunk","html","parseHtml","response","header","Object","isHeaderBlacklisted","value","Array","h","e","doc","load","host","_i","el","prefixUrl","srcset","srcsetParsed","parseSrcset","srcsetRebased","src","stringifySrcset","attr","href"],"mappings":";;;;;AAqBO,SAASA,eAAeC,MAAc,EAAEC,IAAY;IACvD,OAAO,IAAIC,QAA4B,CAACC,SAASC;QAC7CC,SAAS,CAAC,kBAAkB,EAAEL,SAASC,MAAM;QAC7C,IAAIK,eAAe;QACnB,MAAMC,MAAMC,IACR;YACI,UAAUR;YACV,MAAM;YACN,MAAMC;QACV,GACAQ,CAAAA;YACIA,IAAI,EAAE,CAAC,QAAQC,CAAAA,QAAUJ,gBAAgBI;YACzCD,IAAI,EAAE,CAAC,OAAO;gBACVJ,SAAS;gBACT,MAAMM,OAAOC,UAAUN,cAAcN;gBACrC,MAAMa,WAA+B;oBACjC,MAAMF;oBACN,QAAQ;oBACR,mBAAmB;oBACnB,SAAS,CAAC;gBACd;gBAGA,KAAK,MAAMG,UAAUC,OAAO,IAAI,CAACN,IAAI,OAAO,EAAG;oBAG3C,IAAIO,oBAAoBF,SACpB;oBAGJ,MAAMG,QAAQR,IAAI,OAAO,CAACK,OAAO;oBACjC,IAAII,MAAM,OAAO,CAACD,QACdJ,SAAS,OAAO,CAACC,OAAO,GAAGG,MAAM,GAAG,CAACE,CAAAA,IAAM;4BACvC,KAAKL;4BACL,OAAOK;wBACX;yBACG,IAAIF,OACPJ,SAAS,OAAO,CAACC,OAAO,GAAG;wBACvB;4BACI,KAAKA;4BACL,OAAOG;wBACX;qBACH;gBAET;gBAEAZ,SAAS;gBACTF,QAAQU;YACZ;QACJ;QAGJN,IAAI,EAAE,CAAC,SAASa,CAAAA;YACZhB,OAAO;gBACH,YAAY;gBACZ,MAAMgB,EAAE,OAAO;YACnB;QACJ;IACJ;AACJ;AAEA,SAASR,UAAUD,IAAY,EAAEX,MAAc;IAC3C,MAAMqB,MAAMC,KAAKX;IACjB,MAAMY,OAAO,CAAC,QAAQ,EAAEvB,QAAQ;IAEhCqB,IAAI,eAAe,IAAI,CAAC,CAACG,IAAIC;QACzBC,UAAUD,IAAI,QAAQF;IAC1B;IAEAF,IAAI,UAAU,IAAI,CAAC,CAACG,IAAIC;QACpBC,UAAUD,IAAI,OAAOF;IACzB;IAEAF,IAAI,QACC,IAAI,CAAC,OACL,IAAI,CAAC,CAACG,IAAIC;QACPC,UAAUD,IAAI,OAAOF;QAGrB,MAAMI,SAASF,GAAG,OAAO,CAAC,SAAS;QACnC,IAAIE,QAAQ;YACR,MAAMC,eAAeC,YAAYF;YACjC,MAAMG,gBAAgBF,aAAa,GAAG,CAAmBG,CAAAA;gBACrD,IAAIA,IAAI,GAAG,CAAC,UAAU,CAAC,MACnB,OAAO;oBACH,KAAKR,OAAOQ,IAAI,GAAG;oBACnB,SAASA,IAAI,OAAO;oBACpB,OAAOA,IAAI,KAAK;gBACpB;gBAGJ,OAAOA;YACX;YAEAN,GAAG,OAAO,CAAC,SAAS,GAAGO,gBAAgBF;QAC3C;IACJ;IAEJ,OAAOT,IAAI,IAAI;AACnB;AAEA,SAASK,UAAUD,EAAW,EAAEQ,IAAY,EAAEV,IAAY;IACtD,MAAMW,OAAOT,GAAG,OAAO,CAACQ,KAAK;IAC7B,IAAIC,QAAQA,KAAK,UAAU,CAAC,MACxBT,GAAG,OAAO,CAACQ,KAAK,GAAGV,OAAOW;AAElC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { CloudFrontRequestEvent } from "../../lambdaEdge";
|
|
1
|
+
import type { CloudFrontRequestEvent } from "../../lambdaEdge/index.js";
|
|
2
2
|
export interface VariantConfig {
|
|
3
3
|
domain: string;
|
|
4
4
|
weight: number;
|
|
5
5
|
}
|
|
6
|
-
export
|
|
6
|
+
export type GatewayConfig = Record<string, VariantConfig>;
|
|
7
7
|
/**
|
|
8
8
|
* Loads traffic splitting config.
|
|
9
9
|
* It will, however not call WCP directly, but serve it from a locally cached file,
|
|
@@ -1,65 +1,47 @@
|
|
|
1
1
|
import { get } from "https";
|
|
2
|
-
import { logDebug } from "./log";
|
|
3
|
-
|
|
4
|
-
// but it can use it's own cache for a lookup.
|
|
5
|
-
|
|
6
|
-
const configPath = "/_config"; // Config is locally cached within live lambda for a short time (1 minute).
|
|
7
|
-
// Config must be cached per domain.
|
|
8
|
-
// Otherwise cache will spill over different apps, because we may share this lambda.
|
|
9
|
-
|
|
2
|
+
import { logDebug } from "./log.js";
|
|
3
|
+
const configPath = "/_config";
|
|
10
4
|
const configCache = new Map();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let config = configCache.get(domain);
|
|
24
|
-
|
|
25
|
-
if (!config || isCacheExpired(config.timestamp)) {
|
|
26
|
-
logDebug("No config in cache");
|
|
27
|
-
config = {
|
|
28
|
-
config: await loadConfigCore(domain),
|
|
29
|
-
timestamp: Date.now()
|
|
30
|
-
};
|
|
31
|
-
configCache.set(domain, config);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return config.config;
|
|
5
|
+
async function loadTrafficSplittingConfig(event) {
|
|
6
|
+
const domain = event.Records[0].cf.config.distributionDomainName;
|
|
7
|
+
let config = configCache.get(domain);
|
|
8
|
+
if (!config || isCacheExpired(config.timestamp)) {
|
|
9
|
+
logDebug("No config in cache");
|
|
10
|
+
config = {
|
|
11
|
+
config: await loadConfigCore(domain),
|
|
12
|
+
timestamp: Date.now()
|
|
13
|
+
};
|
|
14
|
+
configCache.set(domain, config);
|
|
15
|
+
}
|
|
16
|
+
return config.config;
|
|
35
17
|
}
|
|
36
|
-
|
|
37
18
|
function loadConfigCore(domain) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
19
|
+
return new Promise((resolve, reject)=>{
|
|
20
|
+
let dataString = "";
|
|
21
|
+
const req = get({
|
|
22
|
+
hostname: domain,
|
|
23
|
+
port: 443,
|
|
24
|
+
path: configPath
|
|
25
|
+
}, function(res) {
|
|
26
|
+
res.on("data", (chunk)=>{
|
|
27
|
+
dataString += chunk;
|
|
28
|
+
});
|
|
29
|
+
res.on("end", ()=>{
|
|
30
|
+
resolve(JSON.parse(dataString));
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
req.on("error", (e)=>{
|
|
34
|
+
reject({
|
|
35
|
+
statusCode: 500,
|
|
36
|
+
body: e.message
|
|
37
|
+
});
|
|
38
|
+
});
|
|
57
39
|
});
|
|
58
|
-
});
|
|
59
40
|
}
|
|
60
|
-
|
|
61
41
|
function isCacheExpired(timestamp) {
|
|
62
|
-
|
|
42
|
+
const ttl = 60000;
|
|
43
|
+
return Date.now() - timestamp > ttl;
|
|
44
|
+
}
|
|
45
|
+
export { loadTrafficSplittingConfig };
|
|
63
46
|
|
|
64
|
-
|
|
65
|
-
}
|
|
47
|
+
//# sourceMappingURL=loadTrafficSplittingConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"stagedRollouts/utils/loadTrafficSplittingConfig.js","sources":["../../../src/stagedRollouts/utils/loadTrafficSplittingConfig.ts"],"sourcesContent":["import { get } from \"https\";\nimport type { CloudFrontRequestEvent } from \"~/lambdaEdge/index.js\";\nimport { logDebug } from \"./log.js\";\n\n// Config file has a fixed URL within CDN, so it can be properly cached.\n// This way we achieve better performance, because CDN does not have to call WCP API for config every time,\n// but it can use it's own cache for a lookup.\nconst configPath = \"/_config\";\n\n// Config is locally cached within live lambda for a short time (1 minute).\n// Config must be cached per domain.\n// Otherwise cache will spill over different apps, because we may share this lambda.\nconst configCache = new Map<string, GatewayConfigCache>();\n\ninterface GatewayConfigCache {\n config: GatewayConfig;\n timestamp: number;\n}\n\nexport interface VariantConfig {\n domain: string;\n weight: number;\n}\n\nexport type GatewayConfig = Record<string, VariantConfig>;\n\n/**\n * Loads traffic splitting config.\n * It will, however not call WCP directly, but serve it from a locally cached file,\n * as explained here https://www.notion.so/webiny/How-traffic-config-is-cached-2c8db57ca2b547a2b2fb1adf378cd191\n */\nexport async function loadTrafficSplittingConfig(event: CloudFrontRequestEvent) {\n // Retrieve domain of the CloudFront distribution.\n // We need it to make sure we cache config per application.\n // For example API and website could share the same lambda instance.\n // So we cache it separately for each domain (each CloudFront).\n const domain = event.Records[0].cf.config.distributionDomainName;\n\n let config = configCache.get(domain);\n if (!config || isCacheExpired(config.timestamp)) {\n logDebug(\"No config in cache\");\n config = {\n config: await loadConfigCore(domain),\n timestamp: Date.now()\n };\n\n configCache.set(domain, config);\n }\n\n return config.config;\n}\n\nfunction loadConfigCore(domain: string) {\n return new Promise<GatewayConfig>((resolve, reject) => {\n let dataString = \"\";\n\n const req = get(\n {\n hostname: domain,\n port: 443,\n path: configPath\n },\n function (res) {\n res.on(\"data\", chunk => {\n dataString += chunk;\n });\n res.on(\"end\", () => {\n resolve(JSON.parse(dataString));\n });\n }\n );\n\n req.on(\"error\", e => {\n reject({\n statusCode: 500,\n body: e.message\n });\n });\n });\n}\n\nfunction isCacheExpired(timestamp: number) {\n const ttl = 60 * 1000; // 1 minute\n return Date.now() - timestamp > ttl;\n}\n"],"names":["configPath","configCache","Map","loadTrafficSplittingConfig","event","domain","config","isCacheExpired","logDebug","loadConfigCore","Date","Promise","resolve","reject","dataString","req","get","res","chunk","JSON","e","timestamp","ttl"],"mappings":";;AAOA,MAAMA,aAAa;AAKnB,MAAMC,cAAc,IAAIC;AAmBjB,eAAeC,2BAA2BC,KAA6B;IAK1E,MAAMC,SAASD,MAAM,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,sBAAsB;IAEhE,IAAIE,SAASL,YAAY,GAAG,CAACI;IAC7B,IAAI,CAACC,UAAUC,eAAeD,OAAO,SAAS,GAAG;QAC7CE,SAAS;QACTF,SAAS;YACL,QAAQ,MAAMG,eAAeJ;YAC7B,WAAWK,KAAK,GAAG;QACvB;QAEAT,YAAY,GAAG,CAACI,QAAQC;IAC5B;IAEA,OAAOA,OAAO,MAAM;AACxB;AAEA,SAASG,eAAeJ,MAAc;IAClC,OAAO,IAAIM,QAAuB,CAACC,SAASC;QACxC,IAAIC,aAAa;QAEjB,MAAMC,MAAMC,IACR;YACI,UAAUX;YACV,MAAM;YACN,MAAML;QACV,GACA,SAAUiB,GAAG;YACTA,IAAI,EAAE,CAAC,QAAQC,CAAAA;gBACXJ,cAAcI;YAClB;YACAD,IAAI,EAAE,CAAC,OAAO;gBACVL,QAAQO,KAAK,KAAK,CAACL;YACvB;QACJ;QAGJC,IAAI,EAAE,CAAC,SAASK,CAAAA;YACZP,OAAO;gBACH,YAAY;gBACZ,MAAMO,EAAE,OAAO;YACnB;QACJ;IACJ;AACJ;AAEA,SAASb,eAAec,SAAiB;IACrC,MAAMC,MAAM;IACZ,OAAOZ,KAAK,GAAG,KAAKW,YAAYC;AACpC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CloudFrontRequestEvent } from "../../lambdaEdge";
|
|
1
|
+
import type { CloudFrontRequestEvent } from "../../lambdaEdge/index.js";
|
|
2
2
|
export declare function loadVariantOrigin(event: CloudFrontRequestEvent): Promise<import("aws-lambda").CloudFrontRequest | import("aws-lambda").CloudFrontResultResponse | {
|
|
3
|
-
variant: import("
|
|
3
|
+
variant: import("../utils/loadTrafficSplittingConfig.js").VariantConfig;
|
|
4
4
|
}>;
|