@salesforce/pwa-kit-runtime 4.0.0-extensibility-preview.2 → 4.0.0-extensibility-preview.4
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 +8 -8
- package/ssr/server/build-remote-server.d.ts +6 -1
- package/ssr/server/build-remote-server.d.ts.map +1 -1
- package/ssr/server/build-remote-server.js +111 -16
- package/ssr/server/build-remote-server.test.js +75 -1
- package/ssr/server/constants.d.ts +1 -0
- package/ssr/server/constants.d.ts.map +1 -1
- package/ssr/server/constants.js +2 -1
- package/ssr/server/express.lambda.test.js +89 -33
- package/ssr/server/express.test.js +82 -1
- package/utils/ssr-server/metrics-sender.d.ts.map +1 -1
- package/utils/ssr-server/metrics-sender.js +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/pwa-kit-runtime",
|
|
3
|
-
"version": "4.0.0-extensibility-preview.
|
|
3
|
+
"version": "4.0.0-extensibility-preview.4",
|
|
4
4
|
"description": "The PWAKit Runtime",
|
|
5
5
|
"homepage": "https://github.com/SalesforceCommerceCloud/pwa-kit/tree/develop/packages/pwa-kit-runtime#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@loadable/component": "^5.15.3",
|
|
49
|
-
"@salesforce/pwa-kit-dev": "4.0.0-extensibility-preview.
|
|
50
|
-
"@salesforce/pwa-kit-extension-sdk": "4.0.0-extensibility-preview.
|
|
49
|
+
"@salesforce/pwa-kit-dev": "4.0.0-extensibility-preview.4",
|
|
50
|
+
"@salesforce/pwa-kit-extension-sdk": "4.0.0-extensibility-preview.4",
|
|
51
51
|
"@serverless/event-mocks": "^1.1.1",
|
|
52
52
|
"@types/express": "^4.17.21",
|
|
53
53
|
"aws-lambda-mock-context": "^3.2.1",
|
|
54
54
|
"fs-extra": "^11.1.1",
|
|
55
|
-
"internal-lib-build": "4.0.0-extensibility-preview.
|
|
55
|
+
"internal-lib-build": "4.0.0-extensibility-preview.4",
|
|
56
56
|
"nock": "^13.3.0",
|
|
57
57
|
"nodemon": "^2.0.22",
|
|
58
58
|
"sinon": "^13.0.2",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"supertest": "^4.0.2"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@salesforce/pwa-kit-dev": "4.0.0-extensibility-preview.
|
|
63
|
+
"@salesforce/pwa-kit-dev": "4.0.0-extensibility-preview.4"
|
|
64
64
|
},
|
|
65
65
|
"peerDependenciesMeta": {
|
|
66
66
|
"@salesforce/pwa-kit-dev": {
|
|
@@ -68,11 +68,11 @@
|
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"engines": {
|
|
71
|
-
"node": "^16.11.0 || ^18.0.0 || ^20.0.0",
|
|
72
|
-
"npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
|
|
71
|
+
"node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
|
|
72
|
+
"npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
|
|
73
73
|
},
|
|
74
74
|
"publishConfig": {
|
|
75
75
|
"directory": "dist"
|
|
76
76
|
},
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "5ad3b1f0e598cfe0fbdec5b1212b4dabc0a8733c"
|
|
78
78
|
}
|
|
@@ -74,6 +74,11 @@ export namespace RemoteServerFactory {
|
|
|
74
74
|
* @private
|
|
75
75
|
*/
|
|
76
76
|
function _addSDKInternalHandlers(app: any): void;
|
|
77
|
+
/**
|
|
78
|
+
* Set x-forward-* headers into locals, this is primarily used to facilitate react sdk hook `useOrigin`
|
|
79
|
+
* @private
|
|
80
|
+
*/
|
|
81
|
+
function _setForwardedHeaders(app: any, options: any): void;
|
|
77
82
|
/**
|
|
78
83
|
* @private
|
|
79
84
|
*/
|
|
@@ -156,7 +161,7 @@ export namespace RemoteServerFactory {
|
|
|
156
161
|
* @param app {Express} - an Express App
|
|
157
162
|
* @private
|
|
158
163
|
*/
|
|
159
|
-
function _createHandler(app: Express): {
|
|
164
|
+
function _createHandler(app: Express, options: any): {
|
|
160
165
|
handler: (event: any, context: any, callback: any) => void;
|
|
161
166
|
server: any;
|
|
162
167
|
app: Express;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-remote-server.d.ts","sourceRoot":"","sources":["../../../src/ssr/server/build-remote-server.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build-remote-server.d.ts","sourceRoot":"","sources":["../../../src/ssr/server/build-remote-server.js"],"names":[],"mappings":"AAsEA;;;;GAIG;AACH,gDAKC;;IAWG;;OAEG;IACH,uCAiFC;IAED;;OAEG;IAEH,gDAEC;IAED;;OAEG;IAEH,iDAEC;IAED;;OAEG;IAEH,4CAEC;IAED;;OAEG;IACH,uDAEC;IAED;;OAEG;IAEH,2CAEC;IAED;;OAEG;IACH,6CAEC;IAED;;OAEG;IACH,4DAIC;IAED;;OAEG;IAEH,yCAEC;IAED;;OAEG;IAEH,uCA6CC;IAED;;;OAGG;IACH,uCAcC;IAED;;OAEG;IAEH,+CAEC;IAED;;OAEG;IACH,kDAEC;IAED;;OAEG;IACH,oDAEC;IAED;;OAEG;IACH,+EA2CC;IAED;;OAEG;IACH,sFA2DC;IAED;;OAEG;IAEH,iDAEC;IAED;;;OAGG;IACH,4DAWC;IAED;;OAEG;IACH,6DAwLC;IAED;;OAEG;IAEH,sDAOC;IAED;;OAEG;IACH,yDAOC;IAED;;OAEG;IACH,oEA2EC;IAED;;OAEG;IACH,2CAIC;IAED;;OAEG;IACH,8DAiBC;IAED;;OAEG;IACH,oDA0EC;IAED;;OAEG;IACH,wCAEC;IAED;;OAEG;IACH,gDAGC;IAED;;;;;;;;;;;OAWG;IACH,sDA2CC;IAED;;;;;;;OAOG;IACH,wFAKC;IAED;;OAEG;IACH,4FASC;IAED;;;;;;;;;;OAUG;IACH,6DAWC;IAED;;;;;;;OAOG;IACH;;;;MAmGC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH;;;;;;;;;;;;MAKC;IAED;;OAEG;IAEH,8CAEC;;AA2HE,uDASN"}
|
|
@@ -103,9 +103,9 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
103
103
|
useSLASPrivateClient: false,
|
|
104
104
|
// A regex for identifying which SLAS endpoints the custom SLAS private
|
|
105
105
|
// client secret handler will inject an Authorization header.
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
applySLASPrivateClientToEndpoints: /\/oauth2\/token/
|
|
106
|
+
// To allow additional SLAS endpoints, users can override this value in
|
|
107
|
+
// their project's ssr.js.
|
|
108
|
+
applySLASPrivateClientToEndpoints: /\/oauth2\/(token|passwordless\/(login|token)|password\/(reset|action))/
|
|
109
109
|
};
|
|
110
110
|
options = _extends({}, defaults, options);
|
|
111
111
|
(0, _ssrServer.setQuiet)(options.quiet || process.env.SSR_QUIET);
|
|
@@ -297,6 +297,7 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
297
297
|
// want request-processors applied to development views.
|
|
298
298
|
this._addSDKInternalHandlers(app);
|
|
299
299
|
this._setupSSRRequestProcessorMiddleware(app);
|
|
300
|
+
this._setForwardedHeaders(app, options);
|
|
300
301
|
this._setupLogging(app);
|
|
301
302
|
this._setupMetricsFlushing(app);
|
|
302
303
|
this._setupHealthcheck(app);
|
|
@@ -319,6 +320,8 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
319
320
|
app.disable('x-powered-by');
|
|
320
321
|
const mixin = {
|
|
321
322
|
options,
|
|
323
|
+
// Forcing a GC is no longer necessary, and will be
|
|
324
|
+
// skipped by default (unless FORCE_GC env-var is set).
|
|
322
325
|
_collectGarbage() {
|
|
323
326
|
// Do global.gc in a separate 'then' handler so
|
|
324
327
|
// that all major variables are out of scope and
|
|
@@ -371,6 +374,22 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
371
374
|
_addSDKInternalHandlers(app) {
|
|
372
375
|
// This method is used by the dev server, but is not needed here.
|
|
373
376
|
},
|
|
377
|
+
/**
|
|
378
|
+
* Set x-forward-* headers into locals, this is primarily used to facilitate react sdk hook `useOrigin`
|
|
379
|
+
* @private
|
|
380
|
+
*/
|
|
381
|
+
_setForwardedHeaders(app, options) {
|
|
382
|
+
app.use((req, res, next) => {
|
|
383
|
+
var _req$headers, _req$headers2;
|
|
384
|
+
const xForwardedHost = (_req$headers = req.headers) === null || _req$headers === void 0 ? void 0 : _req$headers['x-forwarded-host'];
|
|
385
|
+
const xForwardedProto = (_req$headers2 = req.headers) === null || _req$headers2 === void 0 ? void 0 : _req$headers2['x-forwarded-proto'];
|
|
386
|
+
if (xForwardedHost) {
|
|
387
|
+
// prettier-ignore
|
|
388
|
+
res.locals.xForwardedOrigin = `${xForwardedProto || options.protocol}://${xForwardedHost}`;
|
|
389
|
+
}
|
|
390
|
+
next();
|
|
391
|
+
});
|
|
392
|
+
},
|
|
374
393
|
/**
|
|
375
394
|
* @private
|
|
376
395
|
*/
|
|
@@ -584,7 +603,7 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
584
603
|
[_ssrNamespacePaths.slasPrivateProxyPath]: ''
|
|
585
604
|
},
|
|
586
605
|
onProxyReq: (proxyRequest, incomingRequest) => {
|
|
587
|
-
var _incomingRequest$path;
|
|
606
|
+
var _incomingRequest$path, _incomingRequest$path2;
|
|
588
607
|
(0, _configureProxy.applyProxyRequestHeaders)({
|
|
589
608
|
proxyRequest,
|
|
590
609
|
incomingRequest,
|
|
@@ -594,8 +613,7 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
594
613
|
});
|
|
595
614
|
|
|
596
615
|
// We pattern match and add client secrets only to endpoints that
|
|
597
|
-
// match the regex specified by options.applySLASPrivateClientToEndpoints
|
|
598
|
-
// By default, this regex matches only calls to SLAS /oauth2/token
|
|
616
|
+
// match the regex specified by options.applySLASPrivateClientToEndpoints
|
|
599
617
|
// (see option defaults at the top of this file).
|
|
600
618
|
// Other SLAS endpoints, ie. SLAS authenticate (/oauth2/login) and
|
|
601
619
|
// SLAS logout (/oauth2/logout), use the Authorization header for a different
|
|
@@ -603,6 +621,11 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
603
621
|
if ((_incomingRequest$path = incomingRequest.path) !== null && _incomingRequest$path !== void 0 && _incomingRequest$path.match(options.applySLASPrivateClientToEndpoints)) {
|
|
604
622
|
proxyRequest.setHeader('Authorization', `Basic ${encodedSlasCredentials}`);
|
|
605
623
|
}
|
|
624
|
+
|
|
625
|
+
// /oauth2/trusted-agent/token endpoint requires a different auth header
|
|
626
|
+
if ((_incomingRequest$path2 = incomingRequest.path) !== null && _incomingRequest$path2 !== void 0 && _incomingRequest$path2.match(/\/oauth2\/trusted-agent\/token/)) {
|
|
627
|
+
proxyRequest.setHeader('_sfdc_client_auth', encodedSlasCredentials);
|
|
628
|
+
}
|
|
606
629
|
},
|
|
607
630
|
onProxyRes: (proxyRes, req) => {
|
|
608
631
|
if (proxyRes.statusCode && proxyRes.statusCode >= 400) {
|
|
@@ -646,6 +669,9 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
646
669
|
// NOTE: Think about changing the name of this function to `applyApplicationExtensions`. First look into
|
|
647
670
|
// what a common pattern is for application enhancement.
|
|
648
671
|
(0, _express3.applyApplicationExtensions)(app);
|
|
672
|
+
if (options !== null && options !== void 0 && options.encodeNonAsciiHttpHeaders) {
|
|
673
|
+
app.use(encodeNonAsciiMiddleware);
|
|
674
|
+
}
|
|
649
675
|
applyPatches(options);
|
|
650
676
|
},
|
|
651
677
|
/**
|
|
@@ -740,8 +766,27 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
740
766
|
encoding: 'utf8'
|
|
741
767
|
});
|
|
742
768
|
|
|
769
|
+
// If the service worker is not updated when content security policy headers inside
|
|
770
|
+
// ssr.js are changed, then service worker initiated requests will continue to use
|
|
771
|
+
// the old CSP headers.
|
|
772
|
+
//
|
|
773
|
+
// This is problematic in stacked CDN setups where an old service worker with
|
|
774
|
+
// old CSPs can remain cached if the content of the service worker itself is not changed.
|
|
775
|
+
//
|
|
776
|
+
// To ensure the service worker is refetched when CSPs are changed, we factor in
|
|
777
|
+
// the CSP headers when generating the Etag.
|
|
778
|
+
//
|
|
779
|
+
// See https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE000025yeu9YAA/view
|
|
780
|
+
// and https://salesforce-internal.slack.com/archives/C01GLHLBPT5/p1730739370922629
|
|
781
|
+
// for more details.
|
|
782
|
+
|
|
783
|
+
const contentSecurityPolicyHeader = res.getHeaders()[_constants.CONTENT_SECURITY_POLICY] || '';
|
|
784
|
+
|
|
743
785
|
// Serve the file, with a strong ETag
|
|
744
|
-
|
|
786
|
+
// For this to be a valid ETag, the string must be placed between ""
|
|
787
|
+
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag#etag_value for
|
|
788
|
+
// more details
|
|
789
|
+
res.set('etag', `"${(0, _ssrServer.getHashForString)(content + contentSecurityPolicyHeader)}"`);
|
|
745
790
|
res.set(_constants.CONTENT_TYPE, 'application/javascript');
|
|
746
791
|
res.send(content);
|
|
747
792
|
},
|
|
@@ -804,13 +849,29 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
804
849
|
* @param app {Express} - an Express App
|
|
805
850
|
* @private
|
|
806
851
|
*/
|
|
807
|
-
_createHandler(app) {
|
|
852
|
+
_createHandler(app, options) {
|
|
808
853
|
// This flag is initially false, and is set true on the first request
|
|
809
854
|
// handled by a Lambda. If it is true on entry to the handler function,
|
|
810
855
|
// it indicates that the Lambda container has been reused.
|
|
811
856
|
let lambdaContainerReused = false;
|
|
812
857
|
const server = _awsServerlessExpress.default.createServer(app, null, binaryMimeTypes);
|
|
813
858
|
const handler = (event, context, callback) => {
|
|
859
|
+
// encode non ASCII request headers
|
|
860
|
+
if (options !== null && options !== void 0 && options.encodeNonAsciiHttpHeaders) {
|
|
861
|
+
Object.keys(event.headers).forEach(key => {
|
|
862
|
+
if (!isASCII(event.headers[key])) {
|
|
863
|
+
event.headers[key] = encodeURIComponent(event.headers[key]);
|
|
864
|
+
// x-encoded-headers keeps track of which headers have been modified and encoded
|
|
865
|
+
if (event.headers[_constants.X_ENCODED_HEADERS]) {
|
|
866
|
+
// append header key
|
|
867
|
+
event.headers[_constants.X_ENCODED_HEADERS] = `${event.headers[_constants.X_ENCODED_HEADERS]},${key}`;
|
|
868
|
+
} else {
|
|
869
|
+
event.headers[_constants.X_ENCODED_HEADERS] = key;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
|
|
814
875
|
// We don't want to wait for an empty event loop once the response
|
|
815
876
|
// has been sent. Setting this to false will "send the response
|
|
816
877
|
// right away when the callback executes", but any pending events
|
|
@@ -829,12 +890,15 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
829
890
|
// the response to the browser.
|
|
830
891
|
context.callbackWaitsForEmptyEventLoop = false;
|
|
831
892
|
if (lambdaContainerReused) {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
893
|
+
const forceGarbageCollection = process.env.FORCE_GC;
|
|
894
|
+
if (forceGarbageCollection && forceGarbageCollection.toLowerCase() === 'true') {
|
|
895
|
+
// DESKTOP-434 If this Lambda container is being reused,
|
|
896
|
+
// clean up memory now, so that we start with low usage.
|
|
897
|
+
// These regular GC calls take about 80-100 mS each, as opposed
|
|
898
|
+
// to forced GC calls, which occur randomly and can take several
|
|
899
|
+
// hundred mS.
|
|
900
|
+
app._collectGarbage();
|
|
901
|
+
}
|
|
838
902
|
app.sendMetric('LambdaReused');
|
|
839
903
|
} else {
|
|
840
904
|
// This is the first use of this container, so set the
|
|
@@ -912,8 +976,8 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
|
|
|
912
976
|
createHandler(options, customizeApp) {
|
|
913
977
|
process.on('unhandledRejection', _ssrServer.catchAndLog);
|
|
914
978
|
const app = this._createApp(options);
|
|
915
|
-
customizeApp(app);
|
|
916
|
-
return this._createHandler(app);
|
|
979
|
+
customizeApp(app, options);
|
|
980
|
+
return this._createHandler(app, options);
|
|
917
981
|
},
|
|
918
982
|
/**
|
|
919
983
|
* @private
|
|
@@ -996,6 +1060,37 @@ const errorHandlerMiddleware = (err, req, res, next) => {
|
|
|
996
1060
|
res.sendStatus(500);
|
|
997
1061
|
};
|
|
998
1062
|
|
|
1063
|
+
/**
|
|
1064
|
+
* Helper function that checks if a string is composed of ASCII characters
|
|
1065
|
+
* We only check printable ASCII characters and not special ASCII characters
|
|
1066
|
+
* such as NULL
|
|
1067
|
+
*
|
|
1068
|
+
* @private
|
|
1069
|
+
*/
|
|
1070
|
+
const isASCII = str => {
|
|
1071
|
+
return /^[\x20-\x7E]*$/.test(str);
|
|
1072
|
+
};
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* Express Middleware applied to responses that encode any non ASCII headers
|
|
1076
|
+
*
|
|
1077
|
+
* @private
|
|
1078
|
+
*/
|
|
1079
|
+
const encodeNonAsciiMiddleware = (req, res, next) => {
|
|
1080
|
+
const originalSetHeader = res.setHeader;
|
|
1081
|
+
res.setHeader = function (key, value) {
|
|
1082
|
+
if (!isASCII(value)) {
|
|
1083
|
+
originalSetHeader.call(this, key, encodeURIComponent(value));
|
|
1084
|
+
let encodedHeaders = res.getHeader(_constants.X_ENCODED_HEADERS);
|
|
1085
|
+
encodedHeaders = encodedHeaders ? `${encodedHeaders},${key}` : key;
|
|
1086
|
+
originalSetHeader.call(this, _constants.X_ENCODED_HEADERS, encodedHeaders);
|
|
1087
|
+
} else {
|
|
1088
|
+
originalSetHeader.call(this, key, value);
|
|
1089
|
+
}
|
|
1090
|
+
};
|
|
1091
|
+
next();
|
|
1092
|
+
};
|
|
1093
|
+
|
|
999
1094
|
/**
|
|
1000
1095
|
* Wrap the function fn in such a way that it will be called at most once. Subsequent
|
|
1001
1096
|
* calls will always return the same value.
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var _supertest = _interopRequireDefault(require("supertest"));
|
|
4
4
|
var _buildRemoteServer = require("./build-remote-server");
|
|
5
|
+
var _constants = require("./constants");
|
|
6
|
+
var _awsServerlessExpress = _interopRequireDefault(require("aws-serverless-express"));
|
|
5
7
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
8
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
7
9
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -13,6 +15,12 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
13
15
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
14
16
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
15
17
|
*/
|
|
18
|
+
jest.mock('aws-serverless-express', () => {
|
|
19
|
+
return {
|
|
20
|
+
createServer: jest.fn(),
|
|
21
|
+
proxy: jest.fn()
|
|
22
|
+
};
|
|
23
|
+
});
|
|
16
24
|
const opts = (overrides = {}) => {
|
|
17
25
|
const defaults = {
|
|
18
26
|
buildDir: './src/ssr/server/test_fixtures',
|
|
@@ -178,4 +186,70 @@ describe('remote server factory test coverage', () => {
|
|
|
178
186
|
// ]
|
|
179
187
|
// ]).toF
|
|
180
188
|
// })
|
|
181
|
-
// })
|
|
189
|
+
// })
|
|
190
|
+
describe('encodeNonAsciiHttpHeaders flag in options to createHandler', () => {
|
|
191
|
+
test('encodes request headers', () => {
|
|
192
|
+
const mockApp = {
|
|
193
|
+
sendMetric: jest.fn()
|
|
194
|
+
};
|
|
195
|
+
const mockOptions = {
|
|
196
|
+
encodeNonAsciiHttpHeaders: true
|
|
197
|
+
};
|
|
198
|
+
const originalHeaders = {
|
|
199
|
+
'x-non-ascii-header-one': 'テスト',
|
|
200
|
+
'x-non-ascii-header-two': '测试',
|
|
201
|
+
'x-regular-header': 'ascii-str'
|
|
202
|
+
};
|
|
203
|
+
const event = {
|
|
204
|
+
headers: _objectSpread({}, originalHeaders)
|
|
205
|
+
};
|
|
206
|
+
const expectedHeaders = {
|
|
207
|
+
'x-non-ascii-header-one': '%E3%83%86%E3%82%B9%E3%83%88',
|
|
208
|
+
'x-non-ascii-header-two': '%E6%B5%8B%E8%AF%95',
|
|
209
|
+
'x-encoded-headers': 'x-non-ascii-header-one,x-non-ascii-header-two',
|
|
210
|
+
'x-regular-header': 'ascii-str'
|
|
211
|
+
};
|
|
212
|
+
const {
|
|
213
|
+
handler
|
|
214
|
+
} = _buildRemoteServer.RemoteServerFactory._createHandler(mockApp, mockOptions);
|
|
215
|
+
expect(event.headers).toEqual(originalHeaders);
|
|
216
|
+
handler(event, {}, {});
|
|
217
|
+
expect(event.headers).toEqual(expectedHeaders);
|
|
218
|
+
expect(decodeURIComponent(event.headers['x-non-ascii-header-one'])).toEqual(originalHeaders['x-non-ascii-header-one']);
|
|
219
|
+
});
|
|
220
|
+
test('encodes response headers', () => {
|
|
221
|
+
const mockApp = {
|
|
222
|
+
use: jest.fn()
|
|
223
|
+
};
|
|
224
|
+
const mockOptions = {
|
|
225
|
+
encodeNonAsciiHttpHeaders: true
|
|
226
|
+
};
|
|
227
|
+
const res = {
|
|
228
|
+
headers: {},
|
|
229
|
+
setHeader: (key, value) => {
|
|
230
|
+
res.headers[key] = value;
|
|
231
|
+
},
|
|
232
|
+
getHeader: key => {
|
|
233
|
+
return res.headers[key];
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
const nonASCIIheader = 'x-non-ascii-header';
|
|
237
|
+
const nonASCIIstr = 'テスト';
|
|
238
|
+
const expectedEncoding = '%E3%83%86%E3%82%B9%E3%83%88';
|
|
239
|
+
const regularHeaderKey = 'x-regular-header';
|
|
240
|
+
const regularHeaderValue = 'ascii-str';
|
|
241
|
+
_buildRemoteServer.RemoteServerFactory._setupCommonMiddleware(mockApp, mockOptions);
|
|
242
|
+
const encodeNonAsciiMiddleware = mockApp.use.mock.calls[3][0];
|
|
243
|
+
res.setHeader(nonASCIIheader, nonASCIIstr);
|
|
244
|
+
expect(res.getHeader(nonASCIIheader)).toEqual(nonASCIIstr);
|
|
245
|
+
encodeNonAsciiMiddleware({}, res, () => {});
|
|
246
|
+
res.setHeader(nonASCIIheader, nonASCIIstr);
|
|
247
|
+
expect(res.getHeader(nonASCIIheader)).toEqual(expectedEncoding);
|
|
248
|
+
expect(decodeURI(expectedEncoding)).toEqual(nonASCIIstr);
|
|
249
|
+
expect(res.getHeader(_constants.X_ENCODED_HEADERS)).toEqual(nonASCIIheader);
|
|
250
|
+
|
|
251
|
+
// confirm ASCII headers are not modified
|
|
252
|
+
res.setHeader(regularHeaderKey, regularHeaderValue);
|
|
253
|
+
expect(res.getHeader(regularHeaderKey)).toEqual(regularHeaderValue);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
@@ -8,6 +8,7 @@ export const CONTENT_ENCODING: "content-encoding";
|
|
|
8
8
|
export const X_ORIGINAL_CONTENT_TYPE: "x-original-content-type";
|
|
9
9
|
export const X_MOBIFY_QUERYSTRING: "x-mobify-querystring";
|
|
10
10
|
export const X_MOBIFY_FROM_CACHE: "x-mobify-from-cache";
|
|
11
|
+
export const X_ENCODED_HEADERS: "x-encoded-headers";
|
|
11
12
|
export const SET_COOKIE: "set-cookie";
|
|
12
13
|
export const CACHE_CONTROL: "cache-control";
|
|
13
14
|
export const NO_CACHE: "max-age=0, nocache, nostore, must-revalidate";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/ssr/server/constants.js"],"names":[],"mappings":"AAMA,kEAAkE;AAClE,4BAA4B;AAC5B,4CAA4C;AAE5C,oEAAoE;AACpE,gDAAgD;AAGhD,0CAA0C;AAC1C,kDAAkD;AAClD,gEAAgE;AAChE,0DAA0D;AAC1D,wDAAwD;AACxD,sCAAsC;AACtC,4CAA4C;AAC5C,sEAAsE;AACtE,gEAAgE;AAChE,oEAAoE;AAEpE,2EAA2E;AAC3E,4DAA4D"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/ssr/server/constants.js"],"names":[],"mappings":"AAMA,kEAAkE;AAClE,4BAA4B;AAC5B,4CAA4C;AAE5C,oEAAoE;AACpE,gDAAgD;AAGhD,0CAA0C;AAC1C,kDAAkD;AAClD,gEAAgE;AAChE,0DAA0D;AAC1D,wDAAwD;AACxD,oDAAoD;AACpD,sCAAsC;AACtC,4CAA4C;AAC5C,sEAAsE;AACtE,gEAAgE;AAChE,oEAAoE;AAEpE,2EAA2E;AAC3E,4DAA4D"}
|
package/ssr/server/constants.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.X_ORIGINAL_CONTENT_TYPE = exports.X_MOBIFY_QUERYSTRING = exports.X_MOBIFY_FROM_CACHE = exports.STRICT_TRANSPORT_SECURITY = exports.STATIC_ASSETS = exports.SLAS_CUSTOM_PROXY_PATH = exports.SET_COOKIE = exports.PROXY_PATH_PREFIX = exports.NO_CACHE = exports.CONTENT_TYPE = exports.CONTENT_SECURITY_POLICY = exports.CONTENT_ENCODING = exports.CACHE_CONTROL = exports.BUILD = exports.APPLICATION_OCTET_STREAM = void 0;
|
|
6
|
+
exports.X_ORIGINAL_CONTENT_TYPE = exports.X_MOBIFY_QUERYSTRING = exports.X_MOBIFY_FROM_CACHE = exports.X_ENCODED_HEADERS = exports.STRICT_TRANSPORT_SECURITY = exports.STATIC_ASSETS = exports.SLAS_CUSTOM_PROXY_PATH = exports.SET_COOKIE = exports.PROXY_PATH_PREFIX = exports.NO_CACHE = exports.CONTENT_TYPE = exports.CONTENT_SECURITY_POLICY = exports.CONTENT_ENCODING = exports.CACHE_CONTROL = exports.BUILD = exports.APPLICATION_OCTET_STREAM = void 0;
|
|
7
7
|
/*
|
|
8
8
|
* Copyright (c) 2021, salesforce.com, inc.
|
|
9
9
|
* All rights reserved.
|
|
@@ -23,6 +23,7 @@ const CONTENT_ENCODING = exports.CONTENT_ENCODING = 'content-encoding';
|
|
|
23
23
|
const X_ORIGINAL_CONTENT_TYPE = exports.X_ORIGINAL_CONTENT_TYPE = 'x-original-content-type';
|
|
24
24
|
const X_MOBIFY_QUERYSTRING = exports.X_MOBIFY_QUERYSTRING = 'x-mobify-querystring';
|
|
25
25
|
const X_MOBIFY_FROM_CACHE = exports.X_MOBIFY_FROM_CACHE = 'x-mobify-from-cache';
|
|
26
|
+
const X_ENCODED_HEADERS = exports.X_ENCODED_HEADERS = 'x-encoded-headers';
|
|
26
27
|
const SET_COOKIE = exports.SET_COOKIE = 'set-cookie';
|
|
27
28
|
const CACHE_CONTROL = exports.CACHE_CONTROL = 'cache-control';
|
|
28
29
|
const NO_CACHE = exports.NO_CACHE = 'max-age=0, nocache, nostore, must-revalidate';
|
|
@@ -54,6 +54,54 @@ const testFixtures = path.resolve(process.cwd(), 'src/ssr/server/test_fixtures')
|
|
|
54
54
|
const httpsAgent = new https.Agent({
|
|
55
55
|
rejectUnauthorized: false
|
|
56
56
|
});
|
|
57
|
+
function createServerWithGCSpy() {
|
|
58
|
+
const route = jest.fn((req, res) => {
|
|
59
|
+
res.send('<html/>');
|
|
60
|
+
});
|
|
61
|
+
const options = {
|
|
62
|
+
buildDir: testFixtures,
|
|
63
|
+
mobify: testPackageMobify,
|
|
64
|
+
sslFilePath: path.join(testFixtures, 'localhost.pem'),
|
|
65
|
+
quiet: true,
|
|
66
|
+
port: TEST_PORT,
|
|
67
|
+
fetchAgents: {
|
|
68
|
+
https: httpsAgent
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const {
|
|
72
|
+
handler,
|
|
73
|
+
server,
|
|
74
|
+
app
|
|
75
|
+
} = RemoteServerFactory.createHandler(options, app => {
|
|
76
|
+
app.get('/*', route);
|
|
77
|
+
});
|
|
78
|
+
const collectGarbage = jest.spyOn(app, '_collectGarbage');
|
|
79
|
+
const sendMetric = jest.spyOn(app, 'sendMetric');
|
|
80
|
+
return {
|
|
81
|
+
route,
|
|
82
|
+
handler,
|
|
83
|
+
collectGarbage,
|
|
84
|
+
sendMetric,
|
|
85
|
+
server
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function createApiGatewayEvent() {
|
|
89
|
+
// Set up a fake event and a fake context for the Lambda call
|
|
90
|
+
const event = createEvent('aws:apiGateway', {
|
|
91
|
+
path: '/',
|
|
92
|
+
body: undefined
|
|
93
|
+
});
|
|
94
|
+
if (event.queryStringParameters) {
|
|
95
|
+
delete event.queryStringParameters;
|
|
96
|
+
}
|
|
97
|
+
const context = AWSMockContext({
|
|
98
|
+
functionName: 'SSRTest'
|
|
99
|
+
});
|
|
100
|
+
return {
|
|
101
|
+
event,
|
|
102
|
+
context
|
|
103
|
+
};
|
|
104
|
+
}
|
|
57
105
|
describe('SSRServer Lambda integration', () => {
|
|
58
106
|
let savedEnvironment;
|
|
59
107
|
let server;
|
|
@@ -329,42 +377,50 @@ describe('SSRServer Lambda integration', () => {
|
|
|
329
377
|
X_HEADERS_TO_REMOVE_ORIGIN.forEach(key => expect(reqHeaders[key]).toBeUndefined());
|
|
330
378
|
});
|
|
331
379
|
});
|
|
332
|
-
test('Lambda reuse
|
|
333
|
-
const route = jest.fn((req, res) => {
|
|
334
|
-
res.send('<html/>');
|
|
335
|
-
});
|
|
336
|
-
const options = {
|
|
337
|
-
buildDir: testFixtures,
|
|
338
|
-
mobify: testPackageMobify,
|
|
339
|
-
sslFilePath: path.join(testFixtures, 'localhost.pem'),
|
|
340
|
-
quiet: true,
|
|
341
|
-
port: TEST_PORT,
|
|
342
|
-
fetchAgents: {
|
|
343
|
-
https: httpsAgent
|
|
344
|
-
}
|
|
345
|
-
};
|
|
380
|
+
test('Lambda reuse -- Default Behavior', () => {
|
|
346
381
|
const {
|
|
347
|
-
|
|
382
|
+
route,
|
|
348
383
|
handler,
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
});
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
384
|
+
collectGarbage,
|
|
385
|
+
sendMetric,
|
|
386
|
+
new_server
|
|
387
|
+
} = createServerWithGCSpy();
|
|
388
|
+
const {
|
|
389
|
+
event,
|
|
390
|
+
context
|
|
391
|
+
} = createApiGatewayEvent();
|
|
392
|
+
server = new_server;
|
|
393
|
+
const call = event => new Promise(resolve => handler(event, context, (err, response) => resolve(response)));
|
|
394
|
+
return Promise.resolve().then(() => call(event)).then(response => {
|
|
395
|
+
// First request - Lambda container created
|
|
396
|
+
expect(response.statusCode).toBe(200);
|
|
397
|
+
expect(collectGarbage.mock.calls).toHaveLength(0);
|
|
398
|
+
expect(route.mock.calls).toHaveLength(1);
|
|
399
|
+
expect(sendMetric).toHaveBeenCalledWith('LambdaCreated');
|
|
400
|
+
expect(sendMetric).not.toHaveBeenCalledWith('LambdaReused');
|
|
401
|
+
}).then(() => call(event)).then(response => {
|
|
402
|
+
// Second call - Lambda container reused
|
|
403
|
+
expect(response.statusCode).toBe(200);
|
|
404
|
+
expect(collectGarbage.mock.calls).toHaveLength(0);
|
|
405
|
+
expect(route.mock.calls).toHaveLength(2);
|
|
406
|
+
expect(sendMetric).toHaveBeenCalledWith('LambdaCreated');
|
|
407
|
+
expect(sendMetric).toHaveBeenCalledWith('LambdaReused');
|
|
367
408
|
});
|
|
409
|
+
});
|
|
410
|
+
test('Lambda reuse -- with Forced Garbage Collection Enabled', () => {
|
|
411
|
+
process.env.FORCE_GC = 'true';
|
|
412
|
+
const {
|
|
413
|
+
event,
|
|
414
|
+
context
|
|
415
|
+
} = createApiGatewayEvent();
|
|
416
|
+
const {
|
|
417
|
+
route,
|
|
418
|
+
handler,
|
|
419
|
+
collectGarbage,
|
|
420
|
+
sendMetric,
|
|
421
|
+
new_server
|
|
422
|
+
} = createServerWithGCSpy();
|
|
423
|
+
server = new_server;
|
|
368
424
|
const call = event => new Promise(resolve => handler(event, context, (err, response) => resolve(response)));
|
|
369
425
|
return Promise.resolve().then(() => call(event)).then(response => {
|
|
370
426
|
// First request - Lambda container created
|
|
@@ -19,6 +19,8 @@ var _crypto = require("crypto");
|
|
|
19
19
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
20
20
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
21
21
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
23
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
22
24
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
23
25
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
24
26
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -477,6 +479,40 @@ describe('SSRServer operation', () => {
|
|
|
477
479
|
expect(response.headers['set-cookie']).toBeUndefined();
|
|
478
480
|
});
|
|
479
481
|
});
|
|
482
|
+
test('should set xForwardedOrigin based on defined x-forwarded-host and x-forwarded-proto headers', () => {
|
|
483
|
+
process.env = {
|
|
484
|
+
MRT_ALLOW_COOKIES: 'true'
|
|
485
|
+
};
|
|
486
|
+
const forwardedHost = 'www.example.com';
|
|
487
|
+
const forwardedProto = 'https';
|
|
488
|
+
const app = _buildRemoteServer.RemoteServerFactory._createApp(opts());
|
|
489
|
+
const route = (req, res) => {
|
|
490
|
+
expect(req.headers['x-forwarded-host']).toBe(forwardedHost);
|
|
491
|
+
expect(res.locals.xForwardedOrigin).toBe(`${forwardedProto}://${forwardedHost}`);
|
|
492
|
+
res.sendStatus(200);
|
|
493
|
+
};
|
|
494
|
+
app.get('/*', route);
|
|
495
|
+
return (0, _supertest.default)(app).get('/').set('x-forwarded-host', forwardedHost).set('x-forwarded-proto', 'https').then(response => {
|
|
496
|
+
expect(response.status).toBe(200);
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
test('should set xForwardedOrigin based on defined x-forwarded-host and undefined x-forwarded-proto headers', () => {
|
|
500
|
+
process.env = {
|
|
501
|
+
MRT_ALLOW_COOKIES: 'true'
|
|
502
|
+
};
|
|
503
|
+
const options = opts();
|
|
504
|
+
const forwardedHost = 'www.example.com';
|
|
505
|
+
const app = _buildRemoteServer.RemoteServerFactory._createApp(options);
|
|
506
|
+
const route = (req, res) => {
|
|
507
|
+
expect(req.headers['x-forwarded-host']).toBe(forwardedHost);
|
|
508
|
+
expect(res.locals.xForwardedOrigin).toBe(`${options.protocol}://${forwardedHost}`);
|
|
509
|
+
res.sendStatus(200);
|
|
510
|
+
};
|
|
511
|
+
app.get('/*', route);
|
|
512
|
+
return (0, _supertest.default)(app).get('/').set('x-forwarded-host', forwardedHost).then(response => {
|
|
513
|
+
expect(response.status).toBe(200);
|
|
514
|
+
});
|
|
515
|
+
});
|
|
480
516
|
test(`should reject POST requests to /`, () => {
|
|
481
517
|
const app = _buildRemoteServer.RemoteServerFactory._createApp(opts());
|
|
482
518
|
const route = (req, res) => {
|
|
@@ -948,5 +984,50 @@ describe('SLAS private client proxy', () => {
|
|
|
948
984
|
expect(response.body.host).toBe('shortCode.api.commercecloud.salesforce.com');
|
|
949
985
|
expect(response.body['x-mobify']).toBe('true');
|
|
950
986
|
});
|
|
951
|
-
});
|
|
987
|
+
}, 15000);
|
|
988
|
+
test('does not add _sfdc_client_auth header if request not for /oauth2/trusted-agent/token', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
989
|
+
process.env.PWA_KIT_SLAS_CLIENT_SECRET = 'a secret';
|
|
990
|
+
const encodedCredentials = Buffer.from('clientId:a secret').toString('base64');
|
|
991
|
+
const app = _buildRemoteServer.RemoteServerFactory._createApp(opts({
|
|
992
|
+
mobify: {
|
|
993
|
+
app: {
|
|
994
|
+
commerceAPI: {
|
|
995
|
+
parameters: {
|
|
996
|
+
clientId: 'clientId',
|
|
997
|
+
shortCode: 'shortCode'
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
},
|
|
1002
|
+
useSLASPrivateClient: true,
|
|
1003
|
+
slasTarget: slasTarget
|
|
1004
|
+
}));
|
|
1005
|
+
return yield (0, _supertest.default)(app).get('/mobify/slas/oauth2/other-path').then(response => {
|
|
1006
|
+
expect(response.body._sfdc_client_auth).toBeUndefined();
|
|
1007
|
+
});
|
|
1008
|
+
}), 15000);
|
|
1009
|
+
test('adds _sfdc_client_auth header if request is for /oauth2/trusted-agent/token', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
1010
|
+
process.env.PWA_KIT_SLAS_CLIENT_SECRET = 'a secret';
|
|
1011
|
+
const encodedCredentials = Buffer.from('clientId:a secret').toString('base64');
|
|
1012
|
+
const app = _buildRemoteServer.RemoteServerFactory._createApp(opts({
|
|
1013
|
+
mobify: {
|
|
1014
|
+
app: {
|
|
1015
|
+
commerceAPI: {
|
|
1016
|
+
parameters: {
|
|
1017
|
+
clientId: 'clientId',
|
|
1018
|
+
shortCode: 'shortCode'
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
},
|
|
1023
|
+
useSLASPrivateClient: true,
|
|
1024
|
+
slasTarget: slasTarget,
|
|
1025
|
+
trustedAgentAuthPathMatch: /\/oauth2\/trusted-agent\/token/
|
|
1026
|
+
}));
|
|
1027
|
+
return yield (0, _supertest.default)(app).get('/mobify/slas/private/oauth2/trusted-agent/token').then(response => {
|
|
1028
|
+
expect(response.body['_sfdc_client_auth']).toBe(encodedCredentials);
|
|
1029
|
+
expect(response.body.host).toBe('shortCode.api.commercecloud.salesforce.com');
|
|
1030
|
+
expect(response.body['x-mobify']).toBe('true');
|
|
1031
|
+
});
|
|
1032
|
+
}), 15000);
|
|
952
1033
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics-sender.d.ts","sourceRoot":"","sources":["../../../src/utils/ssr-server/metrics-sender.js"],"names":[],"mappings":"AASA;;;;;;;GAOG;AACH;IAKQ,iDAAe;IAKf,cAAgB;IAGpB;;;OAGG;IACH,0BAEC;IAED;;;;;;OAMG;IACH,
|
|
1
|
+
{"version":3,"file":"metrics-sender.d.ts","sourceRoot":"","sources":["../../../src/utils/ssr-server/metrics-sender.js"],"names":[],"mappings":"AASA;;;;;;;GAOG;AACH;IAKQ,iDAAe;IAKf,cAAgB;IAGpB;;;OAGG;IACH,0BAEC;IAED;;;;;;OAMG;IACH,eAiBC;IAED;;;;;;;;OAQG;IACH,uBA0BC;IAED;;;;OAIG;IACH,+BAyBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,aA4BC;CACJ;;;IAOD;;;;;OAKG;IACH,oCAKC"}
|
|
@@ -59,7 +59,11 @@ class MetricsSender {
|
|
|
59
59
|
apiVersion: '2010-08-01',
|
|
60
60
|
// The AWS_REGION variable is defined by the Lambda
|
|
61
61
|
// environment.
|
|
62
|
-
region: process.env.AWS_REGION || 'us-east-1'
|
|
62
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
63
|
+
// Setting maxRetries to 0 will prevent the SDK from retrying.
|
|
64
|
+
// This is necessary because under high load, there will be backpressure
|
|
65
|
+
// on the Lambda function, and causing severe performance issues (400-500ms latency)
|
|
66
|
+
maxRetries: 0
|
|
63
67
|
});
|
|
64
68
|
}
|
|
65
69
|
return this._CW;
|