@quintype/framework 7.1.1-socket-timeout.2 → 7.2.0-fcm-madrid.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/client/start.js +29 -85
- package/package.json +3 -3
- package/server/handlers/fcm-registration-handler.js +4 -2
- package/server/routes.js +3 -1
- package/server/start.js +3 -11
package/client/start.js
CHANGED
|
@@ -7,12 +7,7 @@
|
|
|
7
7
|
* @module start
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
BreakingNews,
|
|
12
|
-
CLIENT_SIDE_RENDERED,
|
|
13
|
-
NAVIGATE_TO_PAGE,
|
|
14
|
-
PAGE_LOADING
|
|
15
|
-
} from "@quintype/components";
|
|
10
|
+
import { BreakingNews, CLIENT_SIDE_RENDERED, NAVIGATE_TO_PAGE, PAGE_LOADING } from "@quintype/components";
|
|
16
11
|
import { createBrowserHistory } from "history";
|
|
17
12
|
import get from "lodash/get";
|
|
18
13
|
import React from "react";
|
|
@@ -21,17 +16,12 @@ import { Provider } from "react-redux";
|
|
|
21
16
|
import { IsomorphicComponent } from "../isomorphic/component";
|
|
22
17
|
import { makePickComponentSync } from "../isomorphic/impl/make-pick-component-sync";
|
|
23
18
|
import { createQtStore } from "../store/create-store";
|
|
24
|
-
import {
|
|
25
|
-
registerPageView,
|
|
26
|
-
registerStoryShare,
|
|
27
|
-
setMemberId,
|
|
28
|
-
startAnalytics
|
|
29
|
-
} from "./analytics";
|
|
19
|
+
import { registerPageView, registerStoryShare, setMemberId, startAnalytics } from "./analytics";
|
|
30
20
|
import { initializeFCM } from "./impl/fcm";
|
|
31
21
|
import {
|
|
32
22
|
checkForServiceWorkerUpdates,
|
|
33
23
|
registerServiceWorker,
|
|
34
|
-
setupServiceWorkerUpdates
|
|
24
|
+
setupServiceWorkerUpdates,
|
|
35
25
|
} from "./impl/load-service-worker";
|
|
36
26
|
|
|
37
27
|
require("../assetify/client")();
|
|
@@ -55,28 +45,20 @@ export const app = {
|
|
|
55
45
|
};
|
|
56
46
|
|
|
57
47
|
function getRouteDataAndPath(path, mountAt) {
|
|
58
|
-
const relativePath = path.startsWith(mountAt)
|
|
59
|
-
? path.slice(mountAt.length)
|
|
60
|
-
: path;
|
|
48
|
+
const relativePath = path.startsWith(mountAt) ? path.slice(mountAt.length) : path;
|
|
61
49
|
return [`${mountAt || ""}/route-data.json`, relativePath];
|
|
62
50
|
}
|
|
63
51
|
|
|
64
|
-
function getRouteData(
|
|
65
|
-
path,
|
|
66
|
-
{ location = global.location, existingFetch, mountAt = global.qtMountAt }
|
|
67
|
-
) {
|
|
52
|
+
function getRouteData(path, { location = global.location, existingFetch, mountAt = global.qtMountAt }) {
|
|
68
53
|
// if mountAt is set, then hit /mountAt/route-data, remove mountAt from path
|
|
69
54
|
|
|
70
55
|
const [routeDataPath, relativePath] = getRouteDataAndPath(path, mountAt);
|
|
71
56
|
const url = new URL(relativePath, location.origin);
|
|
72
57
|
return (
|
|
73
58
|
existingFetch ||
|
|
74
|
-
fetch(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}`,
|
|
78
|
-
{ credentials: "same-origin" }
|
|
79
|
-
)
|
|
59
|
+
fetch(`${routeDataPath}?path=${encodeURIComponent(url.pathname)}${url.search ? `&${url.search.slice(1)}` : ""}`, {
|
|
60
|
+
credentials: "same-origin",
|
|
61
|
+
})
|
|
80
62
|
)
|
|
81
63
|
.then((response) => {
|
|
82
64
|
if (response.status == 404) {
|
|
@@ -99,11 +81,7 @@ function getRouteData(
|
|
|
99
81
|
}
|
|
100
82
|
|
|
101
83
|
function maybeBypassServiceWorker(e) {
|
|
102
|
-
if (
|
|
103
|
-
global.qtLoadedFromShell ||
|
|
104
|
-
`${location.pathname}${location.search}${location.hash}` !=
|
|
105
|
-
`${path}#bypass-sw`
|
|
106
|
-
) {
|
|
84
|
+
if (global.qtLoadedFromShell || `${location.pathname}${location.search}${location.hash}` != `${path}#bypass-sw`) {
|
|
107
85
|
location.href = `${path}#bypass-sw`;
|
|
108
86
|
location.reload();
|
|
109
87
|
}
|
|
@@ -124,8 +102,7 @@ let pickComponentWrapper = null;
|
|
|
124
102
|
* @returns {void}
|
|
125
103
|
*/
|
|
126
104
|
export function navigateToPage(dispatch, path, doNotPushPath) {
|
|
127
|
-
const pathname =
|
|
128
|
-
!path || path === "undefined" ? global.location.pathname : path;
|
|
105
|
+
const pathname = !path || path === "undefined" ? global.location.pathname : path;
|
|
129
106
|
|
|
130
107
|
if (global.disableAjaxNavigation) {
|
|
131
108
|
global.location = pathname;
|
|
@@ -134,8 +111,7 @@ export function navigateToPage(dispatch, path, doNotPushPath) {
|
|
|
134
111
|
dispatch({ type: PAGE_LOADING });
|
|
135
112
|
getRouteData(pathname, {}).then((page) => {
|
|
136
113
|
if (!page) {
|
|
137
|
-
console &&
|
|
138
|
-
console.log("Recieved a null page. Expecting the browser to redirect.");
|
|
114
|
+
console && console.log("Recieved a null page. Expecting the browser to redirect.");
|
|
139
115
|
return;
|
|
140
116
|
}
|
|
141
117
|
|
|
@@ -147,8 +123,7 @@ export function navigateToPage(dispatch, path, doNotPushPath) {
|
|
|
147
123
|
}
|
|
148
124
|
|
|
149
125
|
Promise.resolve(
|
|
150
|
-
pickComponentWrapper &&
|
|
151
|
-
pickComponentWrapper.preloadComponent(page.pageType, page.subPageType)
|
|
126
|
+
pickComponentWrapper && pickComponentWrapper.preloadComponent(page.pageType, page.subPageType)
|
|
152
127
|
).then(() => {
|
|
153
128
|
dispatch({
|
|
154
129
|
type: NAVIGATE_TO_PAGE,
|
|
@@ -177,8 +152,7 @@ export function navigateToPage(dispatch, path, doNotPushPath) {
|
|
|
177
152
|
* @returns {void}
|
|
178
153
|
*/
|
|
179
154
|
export function maybeNavigateTo(path, store) {
|
|
180
|
-
if (store.getState().qt.currentPath != path)
|
|
181
|
-
navigateToPage(store.dispatch, path, true);
|
|
155
|
+
if (store.getState().qt.currentPath != path) navigateToPage(store.dispatch, path, true);
|
|
182
156
|
}
|
|
183
157
|
|
|
184
158
|
/**
|
|
@@ -205,24 +179,12 @@ export function maybeSetUrl(path, title) {
|
|
|
205
179
|
* @param {callback} callback Callback on completion
|
|
206
180
|
*/
|
|
207
181
|
export function renderComponent(clazz, container, store, props = {}, callback) {
|
|
208
|
-
const component = React.createElement(
|
|
209
|
-
Provider,
|
|
210
|
-
{ store },
|
|
211
|
-
React.createElement(clazz, props || {})
|
|
212
|
-
);
|
|
182
|
+
const component = React.createElement(Provider, { store }, React.createElement(clazz, props || {}));
|
|
213
183
|
|
|
214
184
|
if (props.hydrate) {
|
|
215
|
-
return ReactDOM.hydrate(
|
|
216
|
-
component,
|
|
217
|
-
document.getElementById(container),
|
|
218
|
-
callback
|
|
219
|
-
);
|
|
185
|
+
return ReactDOM.hydrate(component, document.getElementById(container), callback);
|
|
220
186
|
}
|
|
221
|
-
return ReactDOM.render(
|
|
222
|
-
component,
|
|
223
|
-
document.getElementById(container),
|
|
224
|
-
callback
|
|
225
|
-
);
|
|
187
|
+
return ReactDOM.render(component, document.getElementById(container), callback);
|
|
226
188
|
}
|
|
227
189
|
|
|
228
190
|
/**
|
|
@@ -233,19 +195,11 @@ export function renderComponent(clazz, container, store, props = {}, callback) {
|
|
|
233
195
|
* @param {Object} props Properties to bootstrap the component with
|
|
234
196
|
* @param {boolean} props.hydrate Hydrate the component instead of rendering it
|
|
235
197
|
*/
|
|
236
|
-
export function renderIsomorphicComponent(
|
|
237
|
-
container,
|
|
238
|
-
store,
|
|
239
|
-
pickComponent,
|
|
240
|
-
props
|
|
241
|
-
) {
|
|
198
|
+
export function renderIsomorphicComponent(container, store, pickComponent, props) {
|
|
242
199
|
if (!store.getState().qt.disableIsomorphicComponent) {
|
|
243
200
|
pickComponentWrapper = makePickComponentSync(pickComponent);
|
|
244
201
|
return pickComponentWrapper
|
|
245
|
-
.preloadComponent(
|
|
246
|
-
store.getState().qt.pageType,
|
|
247
|
-
store.getState().qt.subPageType
|
|
248
|
-
)
|
|
202
|
+
.preloadComponent(store.getState().qt.pageType, store.getState().qt.subPageType)
|
|
249
203
|
.then(() =>
|
|
250
204
|
renderComponent(
|
|
251
205
|
IsomorphicComponent,
|
|
@@ -267,12 +221,7 @@ export function renderIsomorphicComponent(
|
|
|
267
221
|
* @param {Object} props Properties to bootstrap the component with
|
|
268
222
|
*/
|
|
269
223
|
export function renderBreakingNews(container, store, view, props) {
|
|
270
|
-
return renderComponent(
|
|
271
|
-
BreakingNews,
|
|
272
|
-
container,
|
|
273
|
-
store,
|
|
274
|
-
Object.assign({ view }, props)
|
|
275
|
-
);
|
|
224
|
+
return renderComponent(BreakingNews, container, store, Object.assign({ view }, props));
|
|
276
225
|
}
|
|
277
226
|
|
|
278
227
|
function getJsonContent(id) {
|
|
@@ -294,7 +243,7 @@ function runWithTiming(name, f) {
|
|
|
294
243
|
* @param {Object} reducers A list of custom reducers for your application. This will be merged with the built in reducers
|
|
295
244
|
* @param {Object} opts Options
|
|
296
245
|
* @param {function} opts.preRenderApplication Render a part of the application on boot. See [preRenderApplication](https://developers.quintype.com/malibu/isomorphic-rendering/client-side-architecture.html#prerenderapplication)
|
|
297
|
-
* @param {
|
|
246
|
+
* @param {(function|string)} opts.fcmMessagingSenderId Enable Firebase Cloud Messaging for push notifications
|
|
298
247
|
* @param {boolean} opts.enableServiceWorker Should service worker be enabled
|
|
299
248
|
* @param {string} opts.serviceWorkerLocation Location of the service worker (default: /service-worker.js). Note, if using mountAt, this is relative to the mount point.
|
|
300
249
|
* @param {number} opts.appVersion App Version. See [Updating App Version](https://developers.quintype.com/malibu/tutorial/updating-app-version)
|
|
@@ -306,8 +255,7 @@ export function startApp(renderApplication, reducers, opts) {
|
|
|
306
255
|
global.app = app;
|
|
307
256
|
const { location } = global;
|
|
308
257
|
const path = `${location.pathname}${location.search || ""}`;
|
|
309
|
-
const staticData =
|
|
310
|
-
global.staticPageStoreContent || getJsonContent("static-page");
|
|
258
|
+
const staticData = global.staticPageStoreContent || getJsonContent("static-page");
|
|
311
259
|
const dataPromise = staticData
|
|
312
260
|
? Promise.resolve(staticData.qt)
|
|
313
261
|
: getRouteData(path, { existingFetch: global.initialFetch });
|
|
@@ -316,10 +264,7 @@ export function startApp(renderApplication, reducers, opts) {
|
|
|
316
264
|
|
|
317
265
|
const store = createQtStore(
|
|
318
266
|
reducers,
|
|
319
|
-
(staticData && staticData.qt) ||
|
|
320
|
-
global.initialPage ||
|
|
321
|
-
getJsonContent("initial-page") ||
|
|
322
|
-
{},
|
|
267
|
+
(staticData && staticData.qt) || global.initialPage || getJsonContent("initial-page") || {},
|
|
323
268
|
{}
|
|
324
269
|
);
|
|
325
270
|
|
|
@@ -331,29 +276,28 @@ export function startApp(renderApplication, reducers, opts) {
|
|
|
331
276
|
|
|
332
277
|
function doStartApp(page, opts) {
|
|
333
278
|
if (!page) {
|
|
334
|
-
console &&
|
|
335
|
-
console.log("Received a null page. Expecting the browser to redirect.");
|
|
279
|
+
console && console.log("Received a null page. Expecting the browser to redirect.");
|
|
336
280
|
return;
|
|
337
281
|
}
|
|
338
282
|
|
|
339
283
|
store.dispatch({ type: NAVIGATE_TO_PAGE, page, currentPath: path });
|
|
340
|
-
|
|
341
|
-
|
|
284
|
+
|
|
285
|
+
if (opts.fcmMessagingSenderId) {
|
|
286
|
+
const mssgSenderId =
|
|
287
|
+
typeof opts.fcmMessagingSenderId === "function" ? opts.fcmMessagingSenderId(page) : opts.fcmMessagingSenderId;
|
|
342
288
|
initializeFCM(mssgSenderId);
|
|
343
289
|
}
|
|
344
290
|
|
|
345
291
|
const { config: { "theme-attributes": pageThemeAttributes = {} } = {} } = page;
|
|
346
292
|
const version = pageThemeAttributes["cache-burst"] || app.getAppVersion();
|
|
347
293
|
|
|
348
|
-
const serviceWorkerPromise = registerServiceWorker({...opts, version});
|
|
294
|
+
const serviceWorkerPromise = registerServiceWorker({ ...opts, version });
|
|
349
295
|
|
|
350
296
|
setupServiceWorkerUpdates(serviceWorkerPromise, app, store, page, opts);
|
|
351
297
|
|
|
352
298
|
runWithTiming("qt_render", () => renderApplication(store));
|
|
353
299
|
|
|
354
|
-
history.listen((change) =>
|
|
355
|
-
app.maybeNavigateTo(`${change.pathname}${change.search || ""}`, store)
|
|
356
|
-
);
|
|
300
|
+
history.listen((change) => app.maybeNavigateTo(`${change.pathname}${change.search || ""}`, store));
|
|
357
301
|
|
|
358
302
|
registerPageView(store.getState().qt);
|
|
359
303
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quintype/framework",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.2.0-fcm-madrid.0",
|
|
4
4
|
"description": "Libraries to help build Quintype Node.js apps",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@ampproject/toolbox-optimizer": "2.8.3",
|
|
30
30
|
"@quintype/amp": "^2.4.19",
|
|
31
|
-
"@quintype/backend": "^2.2.
|
|
31
|
+
"@quintype/backend": "^2.2.0",
|
|
32
32
|
"@quintype/components": "^3.0.0",
|
|
33
33
|
"@quintype/prerender-node": "^3.2.24",
|
|
34
34
|
"@quintype/seo": "^1.38.1",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"compression": "^1.7.4",
|
|
39
39
|
"ejs": "^3.1.6",
|
|
40
40
|
"express": "^4.17.1",
|
|
41
|
-
"firebase": "^
|
|
41
|
+
"firebase": "^6.0.2",
|
|
42
42
|
"get-youtube-id": "^1.0.1",
|
|
43
43
|
"grpc": "^1.21.1",
|
|
44
44
|
"http-proxy": "^1.18.1",
|
|
@@ -5,7 +5,8 @@ exports.registerFCMTopic = async function registerFCM(
|
|
|
5
5
|
req,
|
|
6
6
|
res,
|
|
7
7
|
next,
|
|
8
|
-
{ config, client, publisherConfig }
|
|
8
|
+
{ config, client, publisherConfig },
|
|
9
|
+
fcmServerKey
|
|
9
10
|
) {
|
|
10
11
|
const token = get(req, ["body", "token"], null);
|
|
11
12
|
if (!token) {
|
|
@@ -13,7 +14,8 @@ exports.registerFCMTopic = async function registerFCM(
|
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const serverKey =
|
|
17
|
+
const serverKey = typeof fcmServerKey === "function" ? fcmServerKey(config) : fcmServerKey;
|
|
18
|
+
|
|
17
19
|
if (!serverKey) {
|
|
18
20
|
res.status(500).send("Server Key is not available");
|
|
19
21
|
return;
|
package/server/routes.js
CHANGED
|
@@ -276,6 +276,7 @@ function getWithConfig(app, route, handler, opts = {}) {
|
|
|
276
276
|
* @param {boolean|function} redirectToLowercaseSlugs If set or evaluates to true, then for every story-page request having capital latin letters in the slug, it responds with a 301 redirect to the lowercase slug URL. (default: true)
|
|
277
277
|
* @param {boolean|function} shouldEncodeAmpUri If set to true, then for every story-page request the slug will be encoded, in case of a vernacular slug this should be set to false. Receives path as param (default: true)
|
|
278
278
|
* @param {number} sMaxAge Overrides the s-maxage value, the default value is set to 900 seconds. We can set `isomorphicRoutesSmaxage: 900` under `publisher` in publisher.yml config file that comes from BlackKnight or pass sMaxAge as a param.
|
|
279
|
+
* @param {(string|function)} fcmServerKey FCM serverKey is used for registering FCM Topic.
|
|
279
280
|
* @param {string} appLoadingPlaceholder This string gets injected into the app container when the page is loaded via service worker. Can be used to show skeleton layouts, animations or other progress indicators before it is replaced by the page content.
|
|
280
281
|
*/
|
|
281
282
|
exports.isomorphicRoutes = function isomorphicRoutes(
|
|
@@ -319,6 +320,7 @@ exports.isomorphicRoutes = function isomorphicRoutes(
|
|
|
319
320
|
shouldEncodeAmpUri,
|
|
320
321
|
sMaxAge = 900,
|
|
321
322
|
appLoadingPlaceholder = "",
|
|
323
|
+
fcmServerKey = "",
|
|
322
324
|
}
|
|
323
325
|
) {
|
|
324
326
|
const withConfig = withConfigPartial(getClient, logError, publisherConfig, configWrapper);
|
|
@@ -410,7 +412,7 @@ exports.isomorphicRoutes = function isomorphicRoutes(
|
|
|
410
412
|
})
|
|
411
413
|
);
|
|
412
414
|
|
|
413
|
-
app.post("/register-fcm-topic", bodyParser.json(), withConfig(registerFCMTopic, { publisherConfig }));
|
|
415
|
+
app.post("/register-fcm-topic", bodyParser.json(), withConfig(registerFCMTopic, { publisherConfig }, fcmServerKey));
|
|
414
416
|
|
|
415
417
|
if (manifestFn) {
|
|
416
418
|
app.get("/manifest.json", withConfig(handleManifest, { manifestFn, logError }));
|
package/server/start.js
CHANGED
|
@@ -16,7 +16,6 @@ const process = require("process");
|
|
|
16
16
|
const { initializeAllClients } = require("./api-client");
|
|
17
17
|
const logger = require("./logger");
|
|
18
18
|
const logSuccess = chalk.bold.cyanBright;
|
|
19
|
-
const http = require('http');
|
|
20
19
|
|
|
21
20
|
function startMaster({ workers = 4 }) {
|
|
22
21
|
let terminating = false;
|
|
@@ -54,7 +53,7 @@ function startMaster({ workers = 4 }) {
|
|
|
54
53
|
);
|
|
55
54
|
|
|
56
55
|
if (terminating) {
|
|
57
|
-
if (aliveWorkers.length
|
|
56
|
+
if (aliveWorkers.length == 0) {
|
|
58
57
|
logger.info("All Workers Terminated. Gracefully Exiting");
|
|
59
58
|
process.exit();
|
|
60
59
|
}
|
|
@@ -74,19 +73,12 @@ async function startWorker(appThunk, opts) {
|
|
|
74
73
|
const app = appThunk();
|
|
75
74
|
|
|
76
75
|
await initializeAllClients();
|
|
77
|
-
const server =
|
|
76
|
+
const server = app.listen(opts.port || 3000, () => {
|
|
78
77
|
console.log(logSuccess(`||=============================||`));
|
|
79
|
-
console.log(logSuccess(`|| App listening on port ${opts.port || 3000}! ||`))
|
|
78
|
+
console.log(logSuccess(`|| App listening on port ${opts.port || 3000}! ||`))
|
|
80
79
|
console.log(logSuccess(`||=============================||`));
|
|
81
80
|
});
|
|
82
81
|
|
|
83
|
-
server.setTimeout(opts.socketTimeout || 2000,()=>{
|
|
84
|
-
console.log("Socket is destroyed due to timeout");
|
|
85
|
-
server.close(()=>{
|
|
86
|
-
console.log("Server is closed");
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
|
|
90
82
|
process.on("SIGTERM", () => {
|
|
91
83
|
server.close(() => {
|
|
92
84
|
cluster.worker.disconnect();
|