@quintype/framework 7.0.4-fcm-madrid.0 → 7.1.1-socket-timeout.2
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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [7.1.0](https://github.com/quintype/quintype-node-framework/compare/v7.0.3...v7.1.0) (2022-02-11)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **Custom Layout:** support custom storylimit and custom nestedCollectionLimit ([#288](https://github.com/quintype/quintype-node-framework/issues/288)) ([1e3e8ae](https://github.com/quintype/quintype-node-framework/commit/1e3e8ae7c7da2e336260911cf41f56c5419e9480))
|
|
11
|
+
|
|
5
12
|
### [7.0.3](https://github.com/quintype/quintype-node-framework/compare/v7.0.2...v7.0.3) (2022-02-01)
|
|
6
13
|
|
|
7
14
|
### [7.0.2](https://github.com/quintype/quintype-node-framework/compare/v7.0.1...v7.0.2) (2022-01-05)
|
package/client/start.js
CHANGED
|
@@ -7,7 +7,12 @@
|
|
|
7
7
|
* @module start
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
BreakingNews,
|
|
12
|
+
CLIENT_SIDE_RENDERED,
|
|
13
|
+
NAVIGATE_TO_PAGE,
|
|
14
|
+
PAGE_LOADING
|
|
15
|
+
} from "@quintype/components";
|
|
11
16
|
import { createBrowserHistory } from "history";
|
|
12
17
|
import get from "lodash/get";
|
|
13
18
|
import React from "react";
|
|
@@ -16,12 +21,17 @@ import { Provider } from "react-redux";
|
|
|
16
21
|
import { IsomorphicComponent } from "../isomorphic/component";
|
|
17
22
|
import { makePickComponentSync } from "../isomorphic/impl/make-pick-component-sync";
|
|
18
23
|
import { createQtStore } from "../store/create-store";
|
|
19
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
registerPageView,
|
|
26
|
+
registerStoryShare,
|
|
27
|
+
setMemberId,
|
|
28
|
+
startAnalytics
|
|
29
|
+
} from "./analytics";
|
|
20
30
|
import { initializeFCM } from "./impl/fcm";
|
|
21
31
|
import {
|
|
22
32
|
checkForServiceWorkerUpdates,
|
|
23
33
|
registerServiceWorker,
|
|
24
|
-
setupServiceWorkerUpdates
|
|
34
|
+
setupServiceWorkerUpdates
|
|
25
35
|
} from "./impl/load-service-worker";
|
|
26
36
|
|
|
27
37
|
require("../assetify/client")();
|
|
@@ -45,20 +55,28 @@ export const app = {
|
|
|
45
55
|
};
|
|
46
56
|
|
|
47
57
|
function getRouteDataAndPath(path, mountAt) {
|
|
48
|
-
const relativePath = path.startsWith(mountAt)
|
|
58
|
+
const relativePath = path.startsWith(mountAt)
|
|
59
|
+
? path.slice(mountAt.length)
|
|
60
|
+
: path;
|
|
49
61
|
return [`${mountAt || ""}/route-data.json`, relativePath];
|
|
50
62
|
}
|
|
51
63
|
|
|
52
|
-
function getRouteData(
|
|
64
|
+
function getRouteData(
|
|
65
|
+
path,
|
|
66
|
+
{ location = global.location, existingFetch, mountAt = global.qtMountAt }
|
|
67
|
+
) {
|
|
53
68
|
// if mountAt is set, then hit /mountAt/route-data, remove mountAt from path
|
|
54
69
|
|
|
55
70
|
const [routeDataPath, relativePath] = getRouteDataAndPath(path, mountAt);
|
|
56
71
|
const url = new URL(relativePath, location.origin);
|
|
57
72
|
return (
|
|
58
73
|
existingFetch ||
|
|
59
|
-
fetch(
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
fetch(
|
|
75
|
+
`${routeDataPath}?path=${encodeURIComponent(url.pathname)}${
|
|
76
|
+
url.search ? `&${url.search.slice(1)}` : ""
|
|
77
|
+
}`,
|
|
78
|
+
{ credentials: "same-origin" }
|
|
79
|
+
)
|
|
62
80
|
)
|
|
63
81
|
.then((response) => {
|
|
64
82
|
if (response.status == 404) {
|
|
@@ -81,7 +99,11 @@ function getRouteData(path, { location = global.location, existingFetch, mountAt
|
|
|
81
99
|
}
|
|
82
100
|
|
|
83
101
|
function maybeBypassServiceWorker(e) {
|
|
84
|
-
if (
|
|
102
|
+
if (
|
|
103
|
+
global.qtLoadedFromShell ||
|
|
104
|
+
`${location.pathname}${location.search}${location.hash}` !=
|
|
105
|
+
`${path}#bypass-sw`
|
|
106
|
+
) {
|
|
85
107
|
location.href = `${path}#bypass-sw`;
|
|
86
108
|
location.reload();
|
|
87
109
|
}
|
|
@@ -102,7 +124,8 @@ let pickComponentWrapper = null;
|
|
|
102
124
|
* @returns {void}
|
|
103
125
|
*/
|
|
104
126
|
export function navigateToPage(dispatch, path, doNotPushPath) {
|
|
105
|
-
const pathname =
|
|
127
|
+
const pathname =
|
|
128
|
+
!path || path === "undefined" ? global.location.pathname : path;
|
|
106
129
|
|
|
107
130
|
if (global.disableAjaxNavigation) {
|
|
108
131
|
global.location = pathname;
|
|
@@ -111,7 +134,8 @@ export function navigateToPage(dispatch, path, doNotPushPath) {
|
|
|
111
134
|
dispatch({ type: PAGE_LOADING });
|
|
112
135
|
getRouteData(pathname, {}).then((page) => {
|
|
113
136
|
if (!page) {
|
|
114
|
-
console &&
|
|
137
|
+
console &&
|
|
138
|
+
console.log("Recieved a null page. Expecting the browser to redirect.");
|
|
115
139
|
return;
|
|
116
140
|
}
|
|
117
141
|
|
|
@@ -123,7 +147,8 @@ export function navigateToPage(dispatch, path, doNotPushPath) {
|
|
|
123
147
|
}
|
|
124
148
|
|
|
125
149
|
Promise.resolve(
|
|
126
|
-
pickComponentWrapper &&
|
|
150
|
+
pickComponentWrapper &&
|
|
151
|
+
pickComponentWrapper.preloadComponent(page.pageType, page.subPageType)
|
|
127
152
|
).then(() => {
|
|
128
153
|
dispatch({
|
|
129
154
|
type: NAVIGATE_TO_PAGE,
|
|
@@ -152,7 +177,8 @@ export function navigateToPage(dispatch, path, doNotPushPath) {
|
|
|
152
177
|
* @returns {void}
|
|
153
178
|
*/
|
|
154
179
|
export function maybeNavigateTo(path, store) {
|
|
155
|
-
if (store.getState().qt.currentPath != path)
|
|
180
|
+
if (store.getState().qt.currentPath != path)
|
|
181
|
+
navigateToPage(store.dispatch, path, true);
|
|
156
182
|
}
|
|
157
183
|
|
|
158
184
|
/**
|
|
@@ -179,12 +205,24 @@ export function maybeSetUrl(path, title) {
|
|
|
179
205
|
* @param {callback} callback Callback on completion
|
|
180
206
|
*/
|
|
181
207
|
export function renderComponent(clazz, container, store, props = {}, callback) {
|
|
182
|
-
const component = React.createElement(
|
|
208
|
+
const component = React.createElement(
|
|
209
|
+
Provider,
|
|
210
|
+
{ store },
|
|
211
|
+
React.createElement(clazz, props || {})
|
|
212
|
+
);
|
|
183
213
|
|
|
184
214
|
if (props.hydrate) {
|
|
185
|
-
return ReactDOM.hydrate(
|
|
215
|
+
return ReactDOM.hydrate(
|
|
216
|
+
component,
|
|
217
|
+
document.getElementById(container),
|
|
218
|
+
callback
|
|
219
|
+
);
|
|
186
220
|
}
|
|
187
|
-
return ReactDOM.render(
|
|
221
|
+
return ReactDOM.render(
|
|
222
|
+
component,
|
|
223
|
+
document.getElementById(container),
|
|
224
|
+
callback
|
|
225
|
+
);
|
|
188
226
|
}
|
|
189
227
|
|
|
190
228
|
/**
|
|
@@ -195,11 +233,19 @@ export function renderComponent(clazz, container, store, props = {}, callback) {
|
|
|
195
233
|
* @param {Object} props Properties to bootstrap the component with
|
|
196
234
|
* @param {boolean} props.hydrate Hydrate the component instead of rendering it
|
|
197
235
|
*/
|
|
198
|
-
export function renderIsomorphicComponent(
|
|
236
|
+
export function renderIsomorphicComponent(
|
|
237
|
+
container,
|
|
238
|
+
store,
|
|
239
|
+
pickComponent,
|
|
240
|
+
props
|
|
241
|
+
) {
|
|
199
242
|
if (!store.getState().qt.disableIsomorphicComponent) {
|
|
200
243
|
pickComponentWrapper = makePickComponentSync(pickComponent);
|
|
201
244
|
return pickComponentWrapper
|
|
202
|
-
.preloadComponent(
|
|
245
|
+
.preloadComponent(
|
|
246
|
+
store.getState().qt.pageType,
|
|
247
|
+
store.getState().qt.subPageType
|
|
248
|
+
)
|
|
203
249
|
.then(() =>
|
|
204
250
|
renderComponent(
|
|
205
251
|
IsomorphicComponent,
|
|
@@ -221,7 +267,12 @@ export function renderIsomorphicComponent(container, store, pickComponent, props
|
|
|
221
267
|
* @param {Object} props Properties to bootstrap the component with
|
|
222
268
|
*/
|
|
223
269
|
export function renderBreakingNews(container, store, view, props) {
|
|
224
|
-
return renderComponent(
|
|
270
|
+
return renderComponent(
|
|
271
|
+
BreakingNews,
|
|
272
|
+
container,
|
|
273
|
+
store,
|
|
274
|
+
Object.assign({ view }, props)
|
|
275
|
+
);
|
|
225
276
|
}
|
|
226
277
|
|
|
227
278
|
function getJsonContent(id) {
|
|
@@ -255,7 +306,8 @@ export function startApp(renderApplication, reducers, opts) {
|
|
|
255
306
|
global.app = app;
|
|
256
307
|
const { location } = global;
|
|
257
308
|
const path = `${location.pathname}${location.search || ""}`;
|
|
258
|
-
const staticData =
|
|
309
|
+
const staticData =
|
|
310
|
+
global.staticPageStoreContent || getJsonContent("static-page");
|
|
259
311
|
const dataPromise = staticData
|
|
260
312
|
? Promise.resolve(staticData.qt)
|
|
261
313
|
: getRouteData(path, { existingFetch: global.initialFetch });
|
|
@@ -264,7 +316,10 @@ export function startApp(renderApplication, reducers, opts) {
|
|
|
264
316
|
|
|
265
317
|
const store = createQtStore(
|
|
266
318
|
reducers,
|
|
267
|
-
(staticData && staticData.qt) ||
|
|
319
|
+
(staticData && staticData.qt) ||
|
|
320
|
+
global.initialPage ||
|
|
321
|
+
getJsonContent("initial-page") ||
|
|
322
|
+
{},
|
|
268
323
|
{}
|
|
269
324
|
);
|
|
270
325
|
|
|
@@ -276,33 +331,29 @@ export function startApp(renderApplication, reducers, opts) {
|
|
|
276
331
|
|
|
277
332
|
function doStartApp(page, opts) {
|
|
278
333
|
if (!page) {
|
|
279
|
-
console &&
|
|
334
|
+
console &&
|
|
335
|
+
console.log("Received a null page. Expecting the browser to redirect.");
|
|
280
336
|
return;
|
|
281
337
|
}
|
|
282
338
|
|
|
283
339
|
store.dispatch({ type: NAVIGATE_TO_PAGE, page, currentPath: path });
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (opts.enableFCM || get(pbGeneralConfig, ["notificationType"], "") === "fcm") {
|
|
288
|
-
const mssgSenderId = get(
|
|
289
|
-
pbGeneralConfig,
|
|
290
|
-
["notifications", "fcm", "messagingSenderId"],
|
|
291
|
-
get(page, ["config", "fcmMessageSenderId"], null)
|
|
292
|
-
);
|
|
340
|
+
if (opts.enableFCM) {
|
|
341
|
+
const mssgSenderId = get(page, ["config", "fcmMessageSenderId"], null);
|
|
293
342
|
initializeFCM(mssgSenderId);
|
|
294
343
|
}
|
|
295
344
|
|
|
296
345
|
const { config: { "theme-attributes": pageThemeAttributes = {} } = {} } = page;
|
|
297
346
|
const version = pageThemeAttributes["cache-burst"] || app.getAppVersion();
|
|
298
347
|
|
|
299
|
-
const serviceWorkerPromise = registerServiceWorker({
|
|
348
|
+
const serviceWorkerPromise = registerServiceWorker({...opts, version});
|
|
300
349
|
|
|
301
350
|
setupServiceWorkerUpdates(serviceWorkerPromise, app, store, page, opts);
|
|
302
351
|
|
|
303
352
|
runWithTiming("qt_render", () => renderApplication(store));
|
|
304
353
|
|
|
305
|
-
history.listen((change) =>
|
|
354
|
+
history.listen((change) =>
|
|
355
|
+
app.maybeNavigateTo(`${change.pathname}${change.search || ""}`, store)
|
|
356
|
+
);
|
|
306
357
|
|
|
307
358
|
registerPageView(store.getState().qt);
|
|
308
359
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quintype/framework",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.1.1-socket-timeout.2",
|
|
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.1.0",
|
|
31
|
+
"@quintype/backend": "^2.2.1-socket-timeout.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": "^9.1.1",
|
|
42
42
|
"get-youtube-id": "^1.0.1",
|
|
43
43
|
"grpc": "^1.21.1",
|
|
44
44
|
"http-proxy": "^1.18.1",
|
|
@@ -19,13 +19,21 @@ exports.homeCollectionOrStories = function homeCollectionOrStories(
|
|
|
19
19
|
depth = 1,
|
|
20
20
|
getStoryLimits,
|
|
21
21
|
params = {},
|
|
22
|
-
collectionOfCollectionsIndexes = []
|
|
22
|
+
collectionOfCollectionsIndexes = [],
|
|
23
|
+
customLayouts = [],
|
|
24
|
+
defaultNestedLimit = null
|
|
23
25
|
) {
|
|
24
26
|
return Collection.getCollectionBySlug(
|
|
25
27
|
client,
|
|
26
28
|
"home",
|
|
27
29
|
{ "item-type": "collection", ...params },
|
|
28
|
-
{
|
|
30
|
+
{
|
|
31
|
+
depth,
|
|
32
|
+
...(getStoryLimits && { storyLimits: getStoryLimits() }),
|
|
33
|
+
collectionOfCollectionsIndexes,
|
|
34
|
+
customLayouts,
|
|
35
|
+
defaultNestedLimit,
|
|
36
|
+
}
|
|
29
37
|
).then((collection) => {
|
|
30
38
|
if (collection) return collection;
|
|
31
39
|
return Story.getStories(client).then((stories) =>
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
const { get } = require("lodash");
|
|
2
2
|
const request = require("request-promise");
|
|
3
3
|
|
|
4
|
-
exports.registerFCMTopic = async function registerFCM(
|
|
4
|
+
exports.registerFCMTopic = async function registerFCM(
|
|
5
|
+
req,
|
|
6
|
+
res,
|
|
7
|
+
next,
|
|
8
|
+
{ config, client, publisherConfig }
|
|
9
|
+
) {
|
|
5
10
|
const token = get(req, ["body", "token"], null);
|
|
6
11
|
if (!token) {
|
|
7
12
|
res.status(400).send("No Token Found");
|
|
8
13
|
return;
|
|
9
14
|
}
|
|
10
15
|
|
|
11
|
-
const serverKey = get(
|
|
12
|
-
config,
|
|
13
|
-
["pbConfig", "general", "notifications", "fcm", "serverKey"],
|
|
14
|
-
get(publisherConfig, ["fcm", "serverKey"], null)
|
|
15
|
-
);
|
|
16
|
+
const serverKey = get(publisherConfig, ["fcm", "serverKey"], null);
|
|
16
17
|
if (!serverKey) {
|
|
17
18
|
res.status(500).send("Server Key is not available");
|
|
18
19
|
return;
|
|
@@ -26,7 +26,7 @@ function loadDataForIsomorphicRoute(
|
|
|
26
26
|
loadErrorData,
|
|
27
27
|
url,
|
|
28
28
|
routes,
|
|
29
|
-
{ otherParams, config, client, host, logError, domainSlug, redirectToLowercaseSlugs, cookies }
|
|
29
|
+
{ otherParams, config, client, host, logError, domainSlug, redirectToLowercaseSlugs, cookies, mobileApiEnabled }
|
|
30
30
|
) {
|
|
31
31
|
return loadDataForEachRoute().catch((error) => {
|
|
32
32
|
logError(error);
|
|
@@ -61,6 +61,7 @@ function loadDataForIsomorphicRoute(
|
|
|
61
61
|
next: abortHandler,
|
|
62
62
|
domainSlug,
|
|
63
63
|
cookies,
|
|
64
|
+
mobileApiEnabled,
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
if (result && result[ABORT_HANDLER]) continue;
|
|
@@ -253,6 +254,7 @@ exports.handleIsomorphicDataLoad = function handleIsomorphicDataLoad(
|
|
|
253
254
|
logError,
|
|
254
255
|
host: req.hostname,
|
|
255
256
|
domainSlug,
|
|
257
|
+
mobileApiEnabled,
|
|
256
258
|
}).then((result) => Object.assign({ pageType, disableIsomorphicComponent: true }, result));
|
|
257
259
|
}
|
|
258
260
|
}
|
|
@@ -275,6 +277,7 @@ exports.handleIsomorphicDataLoad = function handleIsomorphicDataLoad(
|
|
|
275
277
|
domainSlug,
|
|
276
278
|
redirectToLowercaseSlugs,
|
|
277
279
|
cookies: req.cookies,
|
|
280
|
+
mobileApiEnabled,
|
|
278
281
|
}).catch((e) => {
|
|
279
282
|
logError(e);
|
|
280
283
|
return { httpStatusCode: 500, pageType: "error" };
|
package/server/start.js
CHANGED
|
@@ -16,6 +16,7 @@ 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');
|
|
19
20
|
|
|
20
21
|
function startMaster({ workers = 4 }) {
|
|
21
22
|
let terminating = false;
|
|
@@ -53,7 +54,7 @@ function startMaster({ workers = 4 }) {
|
|
|
53
54
|
);
|
|
54
55
|
|
|
55
56
|
if (terminating) {
|
|
56
|
-
if (aliveWorkers.length
|
|
57
|
+
if (aliveWorkers.length === 0) {
|
|
57
58
|
logger.info("All Workers Terminated. Gracefully Exiting");
|
|
58
59
|
process.exit();
|
|
59
60
|
}
|
|
@@ -73,12 +74,19 @@ async function startWorker(appThunk, opts) {
|
|
|
73
74
|
const app = appThunk();
|
|
74
75
|
|
|
75
76
|
await initializeAllClients();
|
|
76
|
-
const server = app.listen(opts.port || 3000, () => {
|
|
77
|
+
const server = http.createServer(app).listen(opts.port || 3000, () => {
|
|
77
78
|
console.log(logSuccess(`||=============================||`));
|
|
78
|
-
console.log(logSuccess(`|| App listening on port ${opts.port || 3000}! ||`))
|
|
79
|
+
console.log(logSuccess(`|| App listening on port ${opts.port || 3000}! ||`));
|
|
79
80
|
console.log(logSuccess(`||=============================||`));
|
|
80
81
|
});
|
|
81
82
|
|
|
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
|
+
|
|
82
90
|
process.on("SIGTERM", () => {
|
|
83
91
|
server.close(() => {
|
|
84
92
|
cluster.worker.disconnect();
|