Skip to content

Commit 8ac7982

Browse files
committed
Modify components to support ionic fork
1 parent 9d7016c commit 8ac7982

File tree

11 files changed

+202
-115
lines changed

11 files changed

+202
-115
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ node_modules
44
/data/schema.sql
55
/@app/graphql/index.*
66
/@app/client/.next
7+
**/build

@app/lib/src/withApollo.ts

Lines changed: 0 additions & 111 deletions
This file was deleted.

@app/lib/src/withApollo.tsx

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { getDataFromTree } from "@apollo/react-ssr";
2+
import { InMemoryCache, NormalizedCacheObject } from "apollo-cache-inmemory";
3+
import { ApolloClient } from "apollo-client";
4+
import { ApolloLink, split } from "apollo-link";
5+
import { onError } from "apollo-link-error";
6+
import { HttpLink } from "apollo-link-http";
7+
import { WebSocketLink } from "apollo-link-ws";
8+
import { getOperationAST } from "graphql";
9+
import withApolloBase, { InitApolloOptions } from "next-with-apollo";
10+
import React from "react";
11+
import { SubscriptionClient } from "subscriptions-transport-ws";
12+
import ws from "ws";
13+
14+
import { GraphileApolloLink } from "./GraphileApolloLink";
15+
16+
interface WithApolloOptions {
17+
useNext?: boolean;
18+
rootUrl?: string;
19+
}
20+
21+
let wsClient: SubscriptionClient | null = null;
22+
23+
export function resetWebsocketConnection(): void {
24+
if (wsClient) {
25+
wsClient.close(false, false);
26+
}
27+
}
28+
29+
function makeServerSideLink(req: any, res: any) {
30+
return new GraphileApolloLink({
31+
req,
32+
res,
33+
postgraphileMiddleware: req.app.get("postgraphileMiddleware"),
34+
});
35+
}
36+
37+
function makeClientSideLink(ROOT_URL: string) {
38+
const nextDataEl =
39+
typeof document !== "undefined" && document.getElementById("__NEXT_DATA__");
40+
const headers = {};
41+
if (nextDataEl && nextDataEl.textContent) {
42+
const data = JSON.parse(nextDataEl.textContent);
43+
headers["CSRF-Token"] = data.query.CSRF_TOKEN;
44+
}
45+
const httpLink = new HttpLink({
46+
uri: `${ROOT_URL}/graphql`,
47+
credentials:
48+
process.env.NODE_ENV === "development" ? "include" : "same-origin",
49+
headers,
50+
});
51+
wsClient = new SubscriptionClient(
52+
`${ROOT_URL.replace(/^http/, "ws")}/graphql`,
53+
{
54+
reconnect: true,
55+
},
56+
typeof WebSocket !== "undefined" ? WebSocket : ws
57+
);
58+
const wsLink = new WebSocketLink(wsClient);
59+
60+
// Using the ability to split links, you can send data to each link
61+
// depending on what kind of operation is being sent.
62+
const mainLink = split(
63+
// split based on operation type
64+
({ query, operationName }) => {
65+
const op = getOperationAST(query, operationName);
66+
return (op && op.operation === "subscription") || false;
67+
},
68+
wsLink,
69+
httpLink
70+
);
71+
return mainLink;
72+
}
73+
74+
const getApolloClient = (
75+
{ initialState, ctx }: InitApolloOptions<NormalizedCacheObject>,
76+
withApolloOptions?: WithApolloOptions
77+
): ApolloClient<NormalizedCacheObject> => {
78+
const ROOT_URL = process.env.ROOT_URL || withApolloOptions?.rootUrl;
79+
if (!ROOT_URL) {
80+
throw new Error("ROOT_URL envvar is not set");
81+
}
82+
83+
const onErrorLink = onError(({ graphQLErrors, networkError }) => {
84+
if (graphQLErrors)
85+
graphQLErrors.map(({ message, locations, path }) =>
86+
console.error(
87+
`[GraphQL error]: message: ${message}, location: ${JSON.stringify(
88+
locations
89+
)}, path: ${JSON.stringify(path)}`
90+
)
91+
);
92+
if (networkError) console.error(`[Network error]: ${networkError}`);
93+
});
94+
95+
const { req, res }: any = ctx || {};
96+
const isServer = typeof window === "undefined";
97+
const mainLink =
98+
isServer && req && res
99+
? makeServerSideLink(req, res)
100+
: makeClientSideLink(ROOT_URL);
101+
102+
const client = new ApolloClient({
103+
link: ApolloLink.from([onErrorLink, mainLink]),
104+
cache: new InMemoryCache({
105+
dataIdFromObject: (o) =>
106+
o.__typename === "Query"
107+
? "ROOT_QUERY"
108+
: o.id
109+
? `${o.__typename}:${o.id}`
110+
: null,
111+
}).restore(initialState || {}),
112+
});
113+
114+
return client;
115+
};
116+
117+
const withApolloWithNext = withApolloBase(getApolloClient, {
118+
getDataFromTree,
119+
});
120+
121+
const withApolloWithoutNext = (Component: any, options?: WithApolloOptions) => (
122+
props: any
123+
) => {
124+
const apollo = getApolloClient({}, options);
125+
return <Component {...props} apollo={apollo} />;
126+
};
127+
128+
export const withApollo = (Component: any, options?: WithApolloOptions) =>
129+
options?.useNext === false
130+
? withApolloWithoutNext(Component, options)
131+
: withApolloWithNext(Component);

@app/server/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@graphile/pro": "^0.10.0",
1919
"@types/connect-pg-simple": "^4.2.0",
2020
"@types/connect-redis": "^0.0.13",
21+
"@types/cors": "^2.8.7",
2122
"@types/csurf": "^1.9.36",
2223
"@types/express-session": "^1.17.0",
2324
"@types/helmet": "^0.0.46",
@@ -30,6 +31,7 @@
3031
"chalk": "^4.0.0",
3132
"connect-pg-simple": "^6.1.0",
3233
"connect-redis": "^4.0.4",
34+
"cors": "^2.8.5",
3335
"csurf": "^1.11.0",
3436
"express": "^4.17.1",
3537
"express-session": "^1.17.1",

@app/server/src/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export async function makeApp({
9999
* express middleware. These helpers may be asynchronous, but they should
100100
* operate very rapidly to enable quick as possible server startup.
101101
*/
102+
await middleware.installCors(app);
102103
await middleware.installDatabasePools(app);
103104
await middleware.installWorkerUtils(app);
104105
await middleware.installHelmet(app);

@app/server/src/middleware/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import installCors from "./installCors";
12
import installCSRFProtection from "./installCSRFProtection";
23
import installCypressServerCommand from "./installCypressServerCommand";
34
import installDatabasePools from "./installDatabasePools";
@@ -13,6 +14,7 @@ import installSSR from "./installSSR";
1314
import installWorkerUtils from "./installWorkerUtils";
1415

1516
export {
17+
installCors,
1618
installCSRFProtection,
1719
installDatabasePools,
1820
installWorkerUtils,

@app/server/src/middleware/installCSRFProtection.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
import csrf from "csurf";
22
import { Express } from "express";
3+
import url from "url";
4+
5+
const skipList = process.env.CSRF_SKIP_REFERERS
6+
? process.env.CSRF_SKIP_REFERERS?.replace(/s\s/g, "")
7+
.split(",")
8+
.map((s) => {
9+
// It is prefixed with a protocol
10+
if (s.indexOf("//") !== -1) {
11+
const { host: skipHost } = url.parse(s);
12+
return skipHost;
13+
}
14+
15+
return s;
16+
})
17+
: [];
318

419
export default (app: Express) => {
520
const csrfProtection = csrf({
@@ -21,6 +36,12 @@ export default (app: Express) => {
2136
) {
2237
// Bypass CSRF for GraphiQL
2338
next();
39+
} else if (
40+
skipList &&
41+
skipList.includes(url.parse(req.headers.referer || "").host)
42+
) {
43+
// Bypass CSRF for named referers
44+
next();
2445
} else {
2546
csrfProtection(req, res, next);
2647
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import cors from "cors";
2+
import { Express } from "express";
3+
4+
export default (app: Express) => {
5+
const origin = [];
6+
if (process.env.ROOT_URL) {
7+
origin.push(process.env.ROOT_URL);
8+
}
9+
if (process.env.CORS_ALLOWED_URLS) {
10+
origin.push(
11+
...(process.env.CORS_ALLOWED_URLS?.replace(/s\s/g, "").split(",") || [])
12+
);
13+
}
14+
const corsOptions = {
15+
origin,
16+
credentials: true,
17+
};
18+
app.use(cors(corsOptions));
19+
};

@app/server/src/middleware/installSession.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,13 @@ export default (app: Express) => {
7575
* different authentication method such as bearer tokens.
7676
*/
7777
const wrappedSessionMiddleware: RequestHandler = (req, res, next) => {
78-
if (req.isSameOrigin) {
78+
const origins = [];
79+
if (process.env.SESSION_ALLOWED_ORIGINS) {
80+
origins.push(
81+
...(process.env.SESSION_ALLOWED_ORIGINS?.replace(/s\s/g, "").split(",") || [])
82+
);
83+
}
84+
if (req.isSameOrigin || origins.includes(req.get('Origin') || '')) {
7985
sessionMiddleware(req, res, next);
8086
} else {
8187
next();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"description": "Description of project here",
66
"scripts": {
7-
"setup": "yarn && node ./scripts/setup.js",
7+
"setup": "yarn && node ./scripts/setup.js && lerna run setup",
88
"start": "node ./scripts/start.js",
99
"pretest": "lerna run pretest",
1010
"test": "node scripts/test.js",

0 commit comments

Comments
 (0)