postgraphile 4.12.11 → 5.0.0-0.3
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 +46 -0
- package/LICENSE.md +15 -20
- package/README.md +20 -171
- package/dist/cli-run.d.ts +3 -0
- package/dist/cli-run.d.ts.map +1 -0
- package/dist/cli-run.js +7 -0
- package/dist/cli-run.js.map +1 -0
- package/dist/cli.d.ts +21 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +180 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/PgV4BehaviorPlugin.d.ts +11 -0
- package/dist/plugins/PgV4BehaviorPlugin.d.ts.map +1 -0
- package/dist/plugins/PgV4BehaviorPlugin.js +73 -0
- package/dist/plugins/PgV4BehaviorPlugin.js.map +1 -0
- package/dist/plugins/PgV4InflectionPlugin.d.ts +11 -0
- package/dist/plugins/PgV4InflectionPlugin.d.ts.map +1 -0
- package/dist/plugins/PgV4InflectionPlugin.js +91 -0
- package/dist/plugins/PgV4InflectionPlugin.js.map +1 -0
- package/dist/plugins/PgV4NoIgnoreIndexes.d.ts +2 -0
- package/dist/plugins/PgV4NoIgnoreIndexes.d.ts.map +1 -0
- package/dist/plugins/PgV4NoIgnoreIndexes.js +72 -0
- package/dist/plugins/PgV4NoIgnoreIndexes.js.map +1 -0
- package/dist/plugins/PgV4SmartTagsPlugin.d.ts +11 -0
- package/dist/plugins/PgV4SmartTagsPlugin.d.ts.map +1 -0
- package/dist/plugins/PgV4SmartTagsPlugin.js +190 -0
- package/dist/plugins/PgV4SmartTagsPlugin.js.map +1 -0
- package/dist/presets/amber.d.ts +5 -0
- package/dist/presets/amber.d.ts.map +1 -0
- package/dist/presets/amber.js +38 -0
- package/dist/presets/amber.js.map +1 -0
- package/dist/presets/v4.d.ts +34 -0
- package/dist/presets/v4.d.ts.map +1 -0
- package/dist/presets/v4.js +142 -0
- package/dist/presets/v4.js.map +1 -0
- package/dist/schema.d.ts +34 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +82 -0
- package/dist/schema.js.map +1 -0
- package/package.json +77 -154
- package/build/assets/favicon.ico.d.ts +0 -3
- package/build/assets/favicon.ico.js +0 -6
- package/build/assets/graphiql.html.d.ts +0 -2
- package/build/assets/graphiql.html.js +0 -6
- package/build/index.d.ts +0 -8
- package/build/index.js +0 -34
- package/build/interfaces.d.ts +0 -162
- package/build/interfaces.js +0 -3
- package/build/plugins.d.ts +0 -3
- package/build/plugins.js +0 -53
- package/build/postgraphile/cli.d.ts +0 -3
- package/build/postgraphile/cli.js +0 -541
- package/build/postgraphile/extendedFormatError.d.ts +0 -9
- package/build/postgraphile/extendedFormatError.js +0 -51
- package/build/postgraphile/http/createPostGraphileHttpRequestHandler.d.ts +0 -11
- package/build/postgraphile/http/createPostGraphileHttpRequestHandler.js +0 -974
- package/build/postgraphile/http/frameworks.d.ts +0 -110
- package/build/postgraphile/http/frameworks.js +0 -258
- package/build/postgraphile/http/liveSubscribe.d.ts +0 -22
- package/build/postgraphile/http/liveSubscribe.js +0 -89
- package/build/postgraphile/http/mapAsyncIterator.d.ts +0 -15
- package/build/postgraphile/http/mapAsyncIterator.js +0 -71
- package/build/postgraphile/http/setupServerSentEvents.d.ts +0 -9
- package/build/postgraphile/http/setupServerSentEvents.js +0 -51
- package/build/postgraphile/http/subscriptions.d.ts +0 -7
- package/build/postgraphile/http/subscriptions.js +0 -410
- package/build/postgraphile/index.d.ts +0 -5
- package/build/postgraphile/index.js +0 -14
- package/build/postgraphile/pluginHook.d.ts +0 -104
- package/build/postgraphile/pluginHook.js +0 -100
- package/build/postgraphile/postgraphile.d.ts +0 -20
- package/build/postgraphile/postgraphile.js +0 -332
- package/build/postgraphile/postgraphilerc.d.ts +0 -2
- package/build/postgraphile/postgraphilerc.js +0 -16
- package/build/postgraphile/schema/exportPostGraphileSchema.d.ts +0 -6
- package/build/postgraphile/schema/exportPostGraphileSchema.js +0 -45
- package/build/postgraphile/shutdownActions.d.ts +0 -41
- package/build/postgraphile/shutdownActions.js +0 -87
- package/build/postgraphile/withPostGraphileContext.d.ts +0 -55
- package/build/postgraphile/withPostGraphileContext.js +0 -457
- package/build/postgres/inventory/pgClientFromContext.d.ts +0 -8
- package/build/postgres/inventory/pgClientFromContext.js +0 -21
- package/build-turbo/assets/favicon.ico.d.ts +0 -3
- package/build-turbo/assets/favicon.ico.js +0 -6
- package/build-turbo/assets/graphiql.html.d.ts +0 -2
- package/build-turbo/assets/graphiql.html.js +0 -6
- package/build-turbo/index.d.ts +0 -8
- package/build-turbo/index.js +0 -34
- package/build-turbo/interfaces.d.ts +0 -162
- package/build-turbo/interfaces.js +0 -3
- package/build-turbo/plugins.d.ts +0 -3
- package/build-turbo/plugins.js +0 -53
- package/build-turbo/postgraphile/cli.d.ts +0 -3
- package/build-turbo/postgraphile/cli.js +0 -572
- package/build-turbo/postgraphile/extendedFormatError.d.ts +0 -9
- package/build-turbo/postgraphile/extendedFormatError.js +0 -61
- package/build-turbo/postgraphile/http/createPostGraphileHttpRequestHandler.d.ts +0 -11
- package/build-turbo/postgraphile/http/createPostGraphileHttpRequestHandler.js +0 -982
- package/build-turbo/postgraphile/http/frameworks.d.ts +0 -110
- package/build-turbo/postgraphile/http/frameworks.js +0 -258
- package/build-turbo/postgraphile/http/liveSubscribe.d.ts +0 -22
- package/build-turbo/postgraphile/http/liveSubscribe.js +0 -89
- package/build-turbo/postgraphile/http/mapAsyncIterator.d.ts +0 -15
- package/build-turbo/postgraphile/http/mapAsyncIterator.js +0 -71
- package/build-turbo/postgraphile/http/setupServerSentEvents.d.ts +0 -9
- package/build-turbo/postgraphile/http/setupServerSentEvents.js +0 -51
- package/build-turbo/postgraphile/http/subscriptions.d.ts +0 -7
- package/build-turbo/postgraphile/http/subscriptions.js +0 -409
- package/build-turbo/postgraphile/index.d.ts +0 -5
- package/build-turbo/postgraphile/index.js +0 -14
- package/build-turbo/postgraphile/pluginHook.d.ts +0 -104
- package/build-turbo/postgraphile/pluginHook.js +0 -100
- package/build-turbo/postgraphile/postgraphile.d.ts +0 -20
- package/build-turbo/postgraphile/postgraphile.js +0 -337
- package/build-turbo/postgraphile/postgraphilerc.d.ts +0 -2
- package/build-turbo/postgraphile/postgraphilerc.js +0 -16
- package/build-turbo/postgraphile/schema/exportPostGraphileSchema.d.ts +0 -6
- package/build-turbo/postgraphile/schema/exportPostGraphileSchema.js +0 -45
- package/build-turbo/postgraphile/shutdownActions.d.ts +0 -41
- package/build-turbo/postgraphile/shutdownActions.js +0 -87
- package/build-turbo/postgraphile/withPostGraphileContext.d.ts +0 -55
- package/build-turbo/postgraphile/withPostGraphileContext.js +0 -466
- package/build-turbo/postgres/inventory/pgClientFromContext.d.ts +0 -8
- package/build-turbo/postgres/inventory/pgClientFromContext.js +0 -21
- package/cli.js +0 -6
- package/index.js +0 -5
- package/isTurbo.js +0 -11
- package/plugins.d.ts +0 -1
- package/plugins.js +0 -5
- package/sponsors.json +0 -150
|
@@ -1,982 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isEmpty = void 0;
|
|
4
|
-
/* eslint-disable @typescript-eslint/no-explicit-any,require-atomic-updates */
|
|
5
|
-
const graphql_1 = require("graphql");
|
|
6
|
-
const extendedFormatError_1 = require("../extendedFormatError");
|
|
7
|
-
const pluginHook_1 = require("../pluginHook");
|
|
8
|
-
const setupServerSentEvents_1 = require("./setupServerSentEvents");
|
|
9
|
-
const withPostGraphileContext_1 = require("../withPostGraphileContext");
|
|
10
|
-
const lru_1 = require("@graphile/lru");
|
|
11
|
-
const chalk_1 = require("chalk");
|
|
12
|
-
const Debugger = require("debug"); // tslint:disable-line variable-name
|
|
13
|
-
const httpError = require("http-errors");
|
|
14
|
-
const parseUrl = require("parseurl");
|
|
15
|
-
const finalHandler = require("finalhandler");
|
|
16
|
-
const bodyParser = require("body-parser");
|
|
17
|
-
const crypto = require("crypto");
|
|
18
|
-
const isKoaApp = (a, b) => a.req && a.res && typeof b === 'function';
|
|
19
|
-
const CACHE_MULTIPLIER = 100000;
|
|
20
|
-
const ALLOW_EXPLAIN_PLACEHOLDER = '__SHOULD_ALLOW_EXPLAIN__';
|
|
21
|
-
const noop = () => {
|
|
22
|
-
/* noop */
|
|
23
|
-
};
|
|
24
|
-
const { createHash } = crypto;
|
|
25
|
-
/**
|
|
26
|
-
* The favicon file in `Buffer` format. We can send a `Buffer` directly to the
|
|
27
|
-
* client.
|
|
28
|
-
*
|
|
29
|
-
* @type {Buffer}
|
|
30
|
-
*/
|
|
31
|
-
const favicon_ico_1 = require("../../assets/favicon.ico");
|
|
32
|
-
/**
|
|
33
|
-
* The GraphiQL HTML file as a string. We need it to be a string, because we
|
|
34
|
-
* will use a regular expression to replace some variables.
|
|
35
|
-
*/
|
|
36
|
-
const graphiql_html_1 = require("../../assets/graphiql.html");
|
|
37
|
-
const subscriptions_1 = require("./subscriptions");
|
|
38
|
-
const frameworks_1 = require("./frameworks");
|
|
39
|
-
/**
|
|
40
|
-
* When writing JSON to the browser, we need to be careful that it doesn't get
|
|
41
|
-
* interpretted as HTML.
|
|
42
|
-
*/
|
|
43
|
-
const JS_ESCAPE_LOOKUP = {
|
|
44
|
-
'<': '\\u003c',
|
|
45
|
-
'>': '\\u003e',
|
|
46
|
-
'/': '\\u002f',
|
|
47
|
-
'\u2028': '\\u2028',
|
|
48
|
-
'\u2029': '\\u2029',
|
|
49
|
-
};
|
|
50
|
-
function safeJSONStringify(obj) {
|
|
51
|
-
return JSON.stringify(obj).replace(/[<>/\u2028\u2029]/g, chr => JS_ESCAPE_LOOKUP[chr]);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* When people webpack us up, e.g. for lambda, if they don't want GraphiQL then
|
|
55
|
-
* they can seriously reduce bundle size by omitting the assets.
|
|
56
|
-
*/
|
|
57
|
-
const shouldOmitAssets = process.env.POSTGRAPHILE_OMIT_ASSETS === '1';
|
|
58
|
-
// Used by `createPostGraphileHttpRequestHandler`
|
|
59
|
-
let lastString;
|
|
60
|
-
let lastHash;
|
|
61
|
-
const calculateQueryHash = (queryString) => {
|
|
62
|
-
if (queryString !== lastString) {
|
|
63
|
-
lastString = queryString;
|
|
64
|
-
lastHash = createHash('sha1').update(queryString).digest('base64');
|
|
65
|
-
}
|
|
66
|
-
return lastHash;
|
|
67
|
-
};
|
|
68
|
-
// Fast way of checking if an object is empty,
|
|
69
|
-
// faster than `Object.keys(value).length === 0`.
|
|
70
|
-
// NOTE: we don't need a `hasOwnProperty` call here because isEmpty is called
|
|
71
|
-
// with an `Object.create(null)` object, so it has no no-own properties.
|
|
72
|
-
/* tslint:disable forin */
|
|
73
|
-
function isEmpty(value) {
|
|
74
|
-
for (const _key in value) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
exports.isEmpty = isEmpty;
|
|
80
|
-
/* tslint:enable forin */
|
|
81
|
-
const isPostGraphileDevelopmentMode = process.env.POSTGRAPHILE_ENV === 'development';
|
|
82
|
-
const debugGraphql = Debugger('postgraphile:graphql');
|
|
83
|
-
const debugRequest = Debugger('postgraphile:request');
|
|
84
|
-
/**
|
|
85
|
-
* We need to be able to share the withPostGraphileContext logic between HTTP
|
|
86
|
-
* and websockets
|
|
87
|
-
*/
|
|
88
|
-
function withPostGraphileContextFromReqResGenerator(options) {
|
|
89
|
-
const { pgSettings: pgSettingsGenerator, allowExplain: allowExplainGenerator, jwtSecret, jwtPublicKey, additionalGraphQLContextFromRequest, } = options;
|
|
90
|
-
return async (req, res, moreOptions, fn) => {
|
|
91
|
-
const jwtVerificationSecret = jwtPublicKey || jwtSecret;
|
|
92
|
-
const jwtToken = jwtVerificationSecret ? getJwtToken(req) : null;
|
|
93
|
-
const additionalContext = typeof additionalGraphQLContextFromRequest === 'function'
|
|
94
|
-
? await additionalGraphQLContextFromRequest(req, res)
|
|
95
|
-
: null;
|
|
96
|
-
const pgSettings = typeof pgSettingsGenerator === 'function'
|
|
97
|
-
? await pgSettingsGenerator(req)
|
|
98
|
-
: pgSettingsGenerator;
|
|
99
|
-
const allowExplain = typeof allowExplainGenerator === 'function'
|
|
100
|
-
? await allowExplainGenerator(req)
|
|
101
|
-
: allowExplainGenerator;
|
|
102
|
-
return withPostGraphileContext_1.default({
|
|
103
|
-
...options,
|
|
104
|
-
jwtToken,
|
|
105
|
-
pgSettings,
|
|
106
|
-
explain: allowExplain && req.headers['x-postgraphile-explain'] === 'on',
|
|
107
|
-
...moreOptions,
|
|
108
|
-
}, context => {
|
|
109
|
-
const graphqlContext = additionalContext
|
|
110
|
-
? { ...additionalContext, ...context }
|
|
111
|
-
: context;
|
|
112
|
-
return fn(graphqlContext);
|
|
113
|
-
});
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Creates a GraphQL request handler that can support many different `http` frameworks, including:
|
|
118
|
-
*
|
|
119
|
-
* - Native Node.js `http`.
|
|
120
|
-
* - `connect`.
|
|
121
|
-
* - `express`.
|
|
122
|
-
* - `koa` (2.0).
|
|
123
|
-
*/
|
|
124
|
-
function createPostGraphileHttpRequestHandler(options) {
|
|
125
|
-
const MEGABYTE = 1024 * 1024;
|
|
126
|
-
const subscriptions = !!options.subscriptions;
|
|
127
|
-
const { getGqlSchema, pgPool, pgSettings, pgDefaultRole, shutdownActions, queryCacheMaxSize = 50 * MEGABYTE, extendedErrors, showErrorStack, watchPg, disableQueryLog, enableQueryBatching, websockets = options.subscriptions || options.live ? ['v0', 'v1'] : [], } = options;
|
|
128
|
-
const live = !!options.live;
|
|
129
|
-
const enhanceGraphiql = options.enhanceGraphiql === false ? false : !!options.enhanceGraphiql || subscriptions || live;
|
|
130
|
-
const enableCors = !!options.enableCors || isPostGraphileDevelopmentMode;
|
|
131
|
-
const graphiql = options.graphiql === true;
|
|
132
|
-
if (options['absoluteRoutes']) {
|
|
133
|
-
throw new Error('Sorry - the `absoluteRoutes` setting has been replaced with `externalUrlBase` which solves the issue in a cleaner way. Please update your settings. Thank you for testing a PostGraphile pre-release 🙏');
|
|
134
|
-
}
|
|
135
|
-
// Using let because we might override it on the first request.
|
|
136
|
-
let externalUrlBase = options.externalUrlBase;
|
|
137
|
-
if (externalUrlBase && externalUrlBase.endsWith('/')) {
|
|
138
|
-
throw new Error('externalUrlBase must not end with a slash (`/`)');
|
|
139
|
-
}
|
|
140
|
-
// Validate websockets argument
|
|
141
|
-
if (
|
|
142
|
-
// must be array
|
|
143
|
-
!Array.isArray(websockets) ||
|
|
144
|
-
// empty array = 'none'
|
|
145
|
-
(websockets.length &&
|
|
146
|
-
// array can only hold the versions
|
|
147
|
-
websockets.some(ver => !['v0', 'v1'].includes(ver)))) {
|
|
148
|
-
throw new Error(`Invalid value for \`websockets\` option: '${websockets}'`);
|
|
149
|
-
}
|
|
150
|
-
const pluginHook = pluginHook_1.pluginHookFromOptions(options);
|
|
151
|
-
const origGraphiqlHtml = pluginHook('postgraphile:graphiql:html', graphiql_html_1.default, { options });
|
|
152
|
-
if (pgDefaultRole && typeof pgSettings === 'function') {
|
|
153
|
-
throw new Error('pgDefaultRole cannot be combined with pgSettings(req) - please remove pgDefaultRole and instead always return a `role` key from pgSettings(req).');
|
|
154
|
-
}
|
|
155
|
-
if (pgDefaultRole &&
|
|
156
|
-
pgSettings &&
|
|
157
|
-
typeof pgSettings === 'object' &&
|
|
158
|
-
Object.keys(pgSettings)
|
|
159
|
-
.map(s => s.toLowerCase())
|
|
160
|
-
.includes('role')) {
|
|
161
|
-
throw new Error('pgDefaultRole cannot be combined with pgSettings.role - please use one or the other.');
|
|
162
|
-
}
|
|
163
|
-
if (graphiql && shouldOmitAssets) {
|
|
164
|
-
throw new Error('Cannot enable GraphiQL when POSTGRAPHILE_OMIT_ASSETS is set');
|
|
165
|
-
}
|
|
166
|
-
// Gets the route names for our GraphQL endpoint, and our GraphiQL endpoint.
|
|
167
|
-
const graphqlRoute = options.graphqlRoute || '/graphql';
|
|
168
|
-
const graphiqlRoute = options.graphiqlRoute || '/graphiql';
|
|
169
|
-
// Set the request credential behavior in graphiql.
|
|
170
|
-
const graphiqlCredentials = options.graphiqlCredentials || 'same-origin';
|
|
171
|
-
const eventStreamRoute = options.eventStreamRoute || `${graphqlRoute.replace(/\/+$/, '')}/stream`;
|
|
172
|
-
const externalGraphqlRoute = options.externalGraphqlRoute;
|
|
173
|
-
const externalEventStreamRoute = options.externalEventStreamRoute ||
|
|
174
|
-
(externalGraphqlRoute && !options.eventStreamRoute
|
|
175
|
-
? `${externalGraphqlRoute.replace(/\/+$/, '')}/stream`
|
|
176
|
-
: undefined);
|
|
177
|
-
// Throw an error of the GraphQL and GraphiQL routes are the same.
|
|
178
|
-
if (graphqlRoute === graphiqlRoute)
|
|
179
|
-
throw new Error(`Cannot use the same route, '${graphqlRoute}', for both GraphQL and GraphiQL. Please use different routes.`);
|
|
180
|
-
// Formats an error using the default GraphQL `formatError` function, and
|
|
181
|
-
// custom formatting using some other options.
|
|
182
|
-
const formatError = (error) => {
|
|
183
|
-
// Get the appropriate formatted error object, including any extended error
|
|
184
|
-
// fields if the user wants them.
|
|
185
|
-
const formattedError = extendedErrors && extendedErrors.length
|
|
186
|
-
? extendedFormatError_1.extendedFormatError(error, extendedErrors)
|
|
187
|
-
: graphql_1.formatError(error);
|
|
188
|
-
// If the user wants to see the error’s stack, let’s add it to the
|
|
189
|
-
// formatted error.
|
|
190
|
-
if (showErrorStack)
|
|
191
|
-
formattedError['stack'] =
|
|
192
|
-
error.stack != null && showErrorStack === 'json' ? error.stack.split('\n') : error.stack;
|
|
193
|
-
return formattedError;
|
|
194
|
-
};
|
|
195
|
-
const DEFAULT_HANDLE_ERRORS = (errors) => errors.map(formatError);
|
|
196
|
-
const handleErrors = options.handleErrors || DEFAULT_HANDLE_ERRORS;
|
|
197
|
-
// Define a list of middlewares that will get run before our request handler.
|
|
198
|
-
// Note though that none of these middlewares will intercept a request (i.e.
|
|
199
|
-
// not call `next`). Middlewares that handle a request like favicon
|
|
200
|
-
// middleware will result in a promise that never resolves, and we don’t
|
|
201
|
-
// want that.
|
|
202
|
-
const bodyParserMiddlewares = [
|
|
203
|
-
// Parse JSON bodies.
|
|
204
|
-
bodyParser.json({ limit: options.bodySizeLimit }),
|
|
205
|
-
// Parse URL encoded bodies (forms).
|
|
206
|
-
bodyParser.urlencoded({ extended: false, limit: options.bodySizeLimit }),
|
|
207
|
-
// Parse `application/graphql` content type bodies as text.
|
|
208
|
-
bodyParser.text({ type: 'application/graphql', limit: options.bodySizeLimit }),
|
|
209
|
-
];
|
|
210
|
-
// We'll turn this into one function now so it can be better JIT optimised
|
|
211
|
-
const bodyParserMiddlewaresComposed = bodyParserMiddlewares.reduce((parent, fn) => {
|
|
212
|
-
return (req, res, next) => {
|
|
213
|
-
parent(req, res, error => {
|
|
214
|
-
if (error) {
|
|
215
|
-
return next(error);
|
|
216
|
-
}
|
|
217
|
-
fn(req, res, next);
|
|
218
|
-
});
|
|
219
|
-
};
|
|
220
|
-
}, (_req, _res, next) => next());
|
|
221
|
-
// And we really want that function to be await-able
|
|
222
|
-
const parseBody = (req, res) => new Promise((resolve, reject) => {
|
|
223
|
-
bodyParserMiddlewaresComposed(req,
|
|
224
|
-
// Note: middleware here doesn't actually use the response, but we pass
|
|
225
|
-
// the underlying value so types match up.
|
|
226
|
-
res.getNodeServerResponse(), (error) => {
|
|
227
|
-
if (error) {
|
|
228
|
-
reject(error);
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
resolve();
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
// We only need to calculate the graphiql HTML once; but we need to receive the first request to do so.
|
|
236
|
-
let graphiqlHtml;
|
|
237
|
-
const withPostGraphileContextFromReqRes = withPostGraphileContextFromReqResGenerator(options);
|
|
238
|
-
const staticValidationRules = pluginHook('postgraphile:validationRules:static', graphql_1.specifiedRules, {
|
|
239
|
-
options,
|
|
240
|
-
});
|
|
241
|
-
const cacheSize = Math.ceil(queryCacheMaxSize / CACHE_MULTIPLIER);
|
|
242
|
-
// Do not create an LRU for cache size < 2 because @graphile/lru will baulk.
|
|
243
|
-
const cacheEnabled = cacheSize >= 2;
|
|
244
|
-
const queryCache = cacheEnabled ? new lru_1.default({ maxLength: cacheSize }) : null;
|
|
245
|
-
let lastGqlSchema;
|
|
246
|
-
const parseQuery = (gqlSchema, queryString) => {
|
|
247
|
-
if (gqlSchema !== lastGqlSchema) {
|
|
248
|
-
if (queryCache) {
|
|
249
|
-
queryCache.reset();
|
|
250
|
-
}
|
|
251
|
-
lastGqlSchema = gqlSchema;
|
|
252
|
-
}
|
|
253
|
-
// Only cache queries that are less than 100kB, we don't want DOS attacks
|
|
254
|
-
// attempting to exhaust our memory.
|
|
255
|
-
const canCache = cacheEnabled && queryString.length < 100000;
|
|
256
|
-
const hash = canCache ? calculateQueryHash(queryString) : null;
|
|
257
|
-
const result = canCache ? queryCache.get(hash) : null;
|
|
258
|
-
if (result) {
|
|
259
|
-
return result;
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
const source = new graphql_1.Source(queryString, 'GraphQL Http Request');
|
|
263
|
-
let queryDocumentAst;
|
|
264
|
-
// Catch an errors while parsing so that we can set the `statusCode` to
|
|
265
|
-
// 400. Otherwise we don’t need to parse this way.
|
|
266
|
-
try {
|
|
267
|
-
queryDocumentAst = graphql_1.parse(source);
|
|
268
|
-
}
|
|
269
|
-
catch (error) {
|
|
270
|
-
error.statusCode = 400;
|
|
271
|
-
throw error;
|
|
272
|
-
}
|
|
273
|
-
if (debugRequest.enabled)
|
|
274
|
-
debugRequest('GraphQL query is parsed.');
|
|
275
|
-
// Validate our GraphQL query using given rules.
|
|
276
|
-
const validationErrors = graphql_1.validate(gqlSchema, queryDocumentAst, staticValidationRules);
|
|
277
|
-
const cacheResult = {
|
|
278
|
-
queryDocumentAst,
|
|
279
|
-
validationErrors,
|
|
280
|
-
length: queryString.length,
|
|
281
|
-
};
|
|
282
|
-
if (canCache) {
|
|
283
|
-
queryCache.set(hash, cacheResult);
|
|
284
|
-
}
|
|
285
|
-
return cacheResult;
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
let firstRequestHandler = req => {
|
|
289
|
-
// Never be called again
|
|
290
|
-
firstRequestHandler = null;
|
|
291
|
-
let graphqlRouteForWs = graphqlRoute;
|
|
292
|
-
const { pathname = '' } = parseUrl(req) || {};
|
|
293
|
-
const { pathname: originalPathname = '' } = parseUrl.original(req) || {};
|
|
294
|
-
if (originalPathname !== pathname && originalPathname.endsWith(pathname)) {
|
|
295
|
-
const base = originalPathname.slice(0, originalPathname.length - pathname.length);
|
|
296
|
-
// Our websocket GraphQL route must be at a different place
|
|
297
|
-
graphqlRouteForWs = base + graphqlRouteForWs;
|
|
298
|
-
if (externalUrlBase == null) {
|
|
299
|
-
// User hasn't specified externalUrlBase; let's try and guess it
|
|
300
|
-
// We were mounted on a subpath (e.g. `app.use('/path/to', postgraphile(...))`).
|
|
301
|
-
// Figure out our externalUrlBase for ourselves.
|
|
302
|
-
externalUrlBase = base;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
// Make sure we have a string, at least
|
|
306
|
-
externalUrlBase = externalUrlBase || '';
|
|
307
|
-
// Takes the original GraphiQL HTML file and replaces the default config object.
|
|
308
|
-
graphiqlHtml = origGraphiqlHtml
|
|
309
|
-
? origGraphiqlHtml.replace(/<\/head>/, ` <script>window.POSTGRAPHILE_CONFIG=${safeJSONStringify({
|
|
310
|
-
graphqlUrl: externalGraphqlRoute || `${externalUrlBase}${graphqlRoute}`,
|
|
311
|
-
streamUrl: watchPg
|
|
312
|
-
? externalEventStreamRoute || `${externalUrlBase}${eventStreamRoute}`
|
|
313
|
-
: null,
|
|
314
|
-
enhanceGraphiql,
|
|
315
|
-
// if 'v1' websockets are included, use the v1 client always
|
|
316
|
-
websockets: !websockets.length ? 'none' : websockets.includes('v1') ? 'v1' : 'v0',
|
|
317
|
-
allowExplain: typeof options.allowExplain === 'function'
|
|
318
|
-
? ALLOW_EXPLAIN_PLACEHOLDER
|
|
319
|
-
: !!options.allowExplain,
|
|
320
|
-
credentials: graphiqlCredentials,
|
|
321
|
-
})};</script>\n </head>`)
|
|
322
|
-
: null;
|
|
323
|
-
if (websockets.length) {
|
|
324
|
-
const server = req && req.connection && req.connection['server'];
|
|
325
|
-
if (!server) {
|
|
326
|
-
// tslint:disable-next-line no-console
|
|
327
|
-
console.warn("Failed to find server to add websocket listener to, you'll need to call `enhanceHttpServerWithWebSockets` manually");
|
|
328
|
-
}
|
|
329
|
-
else {
|
|
330
|
-
// Relying on this means that a normal request must come in before an
|
|
331
|
-
// upgrade attempt. It's better to call it manually.
|
|
332
|
-
subscriptions_1.enhanceHttpServerWithWebSockets(server, middleware, {
|
|
333
|
-
graphqlRoute: graphqlRouteForWs,
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
};
|
|
338
|
-
/*
|
|
339
|
-
* If we're not in watch mode, then avoid the cost of `await`ing the schema
|
|
340
|
-
* on every tick by having it available once it was generated.
|
|
341
|
-
*/
|
|
342
|
-
let theOneAndOnlyGraphQLSchema = null;
|
|
343
|
-
if (!watchPg) {
|
|
344
|
-
getGqlSchema()
|
|
345
|
-
.then(schema => {
|
|
346
|
-
theOneAndOnlyGraphQLSchema = schema;
|
|
347
|
-
})
|
|
348
|
-
.catch(noop);
|
|
349
|
-
}
|
|
350
|
-
function neverReject(middlewareName, middleware) {
|
|
351
|
-
return async (res) => {
|
|
352
|
-
try {
|
|
353
|
-
await middleware(res);
|
|
354
|
-
}
|
|
355
|
-
catch (e) {
|
|
356
|
-
console.error(`An unexpected error occurred whilst processing '${middlewareName}'; this indicates a bug. The connection will be terminated.`);
|
|
357
|
-
console.error(e);
|
|
358
|
-
try {
|
|
359
|
-
// At least terminate the connection
|
|
360
|
-
res.statusCode = 500;
|
|
361
|
-
res.end();
|
|
362
|
-
}
|
|
363
|
-
catch (e) {
|
|
364
|
-
/*NOOP*/
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* The actual request handler. It’s an async function so it will return a
|
|
371
|
-
* promise when complete. If the function doesn’t handle anything, it calls
|
|
372
|
-
* `next` to let the next middleware try and handle it. If the function
|
|
373
|
-
* throws an error, it's up to the wrapping middleware (imaginatively named
|
|
374
|
-
* `middleware`, below) to handle the error. Frameworks like Koa have
|
|
375
|
-
* middlewares reject a promise on error, whereas Express requires you pass
|
|
376
|
-
* the error to the `next(err)` function.
|
|
377
|
-
*/
|
|
378
|
-
const requestHandler = async (responseHandler, next) => {
|
|
379
|
-
const res = responseHandler;
|
|
380
|
-
const incomingReq = res.getNodeServerRequest();
|
|
381
|
-
const nodeRes = res.getNodeServerResponse();
|
|
382
|
-
// You can use this hook either to modify the incoming request or to tell
|
|
383
|
-
// PostGraphile not to handle the request further (return null). NOTE: if
|
|
384
|
-
// you return `null` from this hook then you are also responsible for
|
|
385
|
-
// calling `next()` (should that be required).
|
|
386
|
-
const req = pluginHook('postgraphile:http:handler', incomingReq, {
|
|
387
|
-
options,
|
|
388
|
-
res: nodeRes,
|
|
389
|
-
next,
|
|
390
|
-
});
|
|
391
|
-
if (req == null) {
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
const { pathname = '' } = parseUrl(req) || {};
|
|
395
|
-
// Certain things depend on externalUrlBase, which we guess if the user
|
|
396
|
-
// doesn't supply it, so we calculate them on the first request. After
|
|
397
|
-
// first request, this function becomes a NOOP
|
|
398
|
-
if (firstRequestHandler)
|
|
399
|
-
firstRequestHandler(req);
|
|
400
|
-
// ======================================================================
|
|
401
|
-
// GraphQL Watch Stream
|
|
402
|
-
// ======================================================================
|
|
403
|
-
if (watchPg) {
|
|
404
|
-
// Setup an event stream so we can broadcast events to graphiql, etc.
|
|
405
|
-
if (pathname === eventStreamRoute || pathname === '/_postgraphile/stream') {
|
|
406
|
-
return eventStreamRouteHandler(res);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
const isGraphqlRoute = pathname === graphqlRoute;
|
|
410
|
-
// ========================================================================
|
|
411
|
-
// Serve GraphiQL and Related Assets
|
|
412
|
-
// ========================================================================
|
|
413
|
-
if (!shouldOmitAssets && graphiql && !isGraphqlRoute) {
|
|
414
|
-
// ======================================================================
|
|
415
|
-
// Favicon
|
|
416
|
-
// ======================================================================
|
|
417
|
-
// If this is the favicon path and it has not yet been handled, let us
|
|
418
|
-
// serve our GraphQL favicon.
|
|
419
|
-
if (pathname === '/favicon.ico') {
|
|
420
|
-
return faviconRouteHandler(res);
|
|
421
|
-
}
|
|
422
|
-
// ======================================================================
|
|
423
|
-
// GraphiQL HTML
|
|
424
|
-
// ======================================================================
|
|
425
|
-
// If this is the GraphiQL route, show GraphiQL and stop execution.
|
|
426
|
-
if (pathname === graphiqlRoute) {
|
|
427
|
-
// If we are developing PostGraphile, instead just redirect.
|
|
428
|
-
if (isPostGraphileDevelopmentMode) {
|
|
429
|
-
res.statusCode = 302;
|
|
430
|
-
res.setHeader('Location', 'http://localhost:5783');
|
|
431
|
-
res.end();
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
return graphiqlRouteHandler(res);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
if (isGraphqlRoute) {
|
|
438
|
-
return graphqlRouteHandler(res);
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
// This request wasn't for us.
|
|
442
|
-
return next();
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
const eventStreamRouteHandler = neverReject('eventStreamRouteHandler', async function eventStreamRouteHandler(res) {
|
|
446
|
-
try {
|
|
447
|
-
// You can use this hook either to modify the incoming request or to tell
|
|
448
|
-
// PostGraphile not to handle the request further (return null). NOTE: if
|
|
449
|
-
// you return `null` from this hook then you are also responsible for
|
|
450
|
-
// terminating the request however your framework handles that (e.g.
|
|
451
|
-
// `res.send(...)` or `next()`).
|
|
452
|
-
const req = pluginHook('postgraphile:http:eventStreamRouteHandler', res.getNodeServerRequest(), { options, response: res });
|
|
453
|
-
if (req == null) {
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
// Add our CORS headers to be good web citizens (there are perf
|
|
457
|
-
// implications though so be careful!)
|
|
458
|
-
//
|
|
459
|
-
// Always enable CORS when developing PostGraphile because GraphiQL will be
|
|
460
|
-
// on port 5783.
|
|
461
|
-
if (enableCors)
|
|
462
|
-
addCORSHeaders(res);
|
|
463
|
-
if (req.headers.accept !== 'text/event-stream') {
|
|
464
|
-
res.statusCode = 405;
|
|
465
|
-
res.end();
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
setupServerSentEvents_1.default(res, options);
|
|
469
|
-
}
|
|
470
|
-
catch (e) {
|
|
471
|
-
console.error('Unexpected error occurred in eventStreamRouteHandler');
|
|
472
|
-
console.error(e);
|
|
473
|
-
res.statusCode = 500;
|
|
474
|
-
res.end();
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
const faviconRouteHandler = neverReject('faviconRouteHandler', async function faviconRouteHandler(res) {
|
|
478
|
-
// You can use this hook either to modify the incoming request or to tell
|
|
479
|
-
// PostGraphile not to handle the request further (return null). NOTE: if
|
|
480
|
-
// you return `null` from this hook then you are also responsible for
|
|
481
|
-
// terminating the request however your framework handles that (e.g.
|
|
482
|
-
// `res.send(...)` or `next()`).
|
|
483
|
-
const req = pluginHook('postgraphile:http:faviconRouteHandler', res.getNodeServerRequest(), {
|
|
484
|
-
options,
|
|
485
|
-
response: res,
|
|
486
|
-
});
|
|
487
|
-
if (req == null) {
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
// If this is the wrong method, we should let the client know.
|
|
491
|
-
if (!(req.method === 'GET' || req.method === 'HEAD')) {
|
|
492
|
-
res.statusCode = req.method === 'OPTIONS' ? 200 : 405;
|
|
493
|
-
res.setHeader('Allow', 'GET, HEAD, OPTIONS');
|
|
494
|
-
res.end();
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
// Otherwise we are good and should pipe the favicon to the browser.
|
|
498
|
-
res.statusCode = 200;
|
|
499
|
-
res.setHeader('Cache-Control', 'public, max-age=86400');
|
|
500
|
-
res.setHeader('Content-Type', 'image/x-icon');
|
|
501
|
-
// End early if the method is `HEAD`.
|
|
502
|
-
if (req.method === 'HEAD') {
|
|
503
|
-
res.end();
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
res.end(favicon_ico_1.default);
|
|
507
|
-
});
|
|
508
|
-
const graphiqlRouteHandler = neverReject('graphiqlRouteHandler', async function graphiqlRouteHandler(res) {
|
|
509
|
-
// You can use this hook either to modify the incoming request or to tell
|
|
510
|
-
// PostGraphile not to handle the request further (return null). NOTE: if
|
|
511
|
-
// you return `null` from this hook then you are also responsible for
|
|
512
|
-
// terminating the request however your framework handles that (e.g.
|
|
513
|
-
// `res.send(...)` or `next()`).
|
|
514
|
-
const req = pluginHook('postgraphile:http:graphiqlRouteHandler', res.getNodeServerRequest(), {
|
|
515
|
-
options,
|
|
516
|
-
response: res,
|
|
517
|
-
});
|
|
518
|
-
if (req == null) {
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
if (firstRequestHandler)
|
|
522
|
-
firstRequestHandler(req);
|
|
523
|
-
// If using the incorrect method, let the user know.
|
|
524
|
-
if (!(req.method === 'GET' || req.method === 'HEAD')) {
|
|
525
|
-
res.statusCode = req.method === 'OPTIONS' ? 200 : 405;
|
|
526
|
-
res.setHeader('Allow', 'GET, HEAD, OPTIONS');
|
|
527
|
-
res.end();
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
res.statusCode = 200;
|
|
531
|
-
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
532
|
-
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
|
|
533
|
-
res.setHeader('Content-Security-Policy', "frame-ancestors 'self'");
|
|
534
|
-
// End early if the method is `HEAD`.
|
|
535
|
-
if (req.method === 'HEAD') {
|
|
536
|
-
res.end();
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
// Actually renders GraphiQL.
|
|
540
|
-
if (graphiqlHtml && typeof options.allowExplain === 'function') {
|
|
541
|
-
res.end(graphiqlHtml.replace(`"${ALLOW_EXPLAIN_PLACEHOLDER}"`, // Because JSON escaped
|
|
542
|
-
JSON.stringify(!!(await options.allowExplain(req)))));
|
|
543
|
-
}
|
|
544
|
-
else {
|
|
545
|
-
res.end(graphiqlHtml);
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
const graphqlRouteHandler = neverReject('graphqlRouteHandler', async function graphqlRouteHandler(res) {
|
|
549
|
-
// You can use this hook either to modify the incoming request or to tell
|
|
550
|
-
// PostGraphile not to handle the request further (return null). NOTE: if
|
|
551
|
-
// you return `null` from this hook then you are also responsible for
|
|
552
|
-
// terminating the request however your framework handles that (e.g.
|
|
553
|
-
// `res.send(...)` or `next()`).
|
|
554
|
-
const req = pluginHook('postgraphile:http:graphqlRouteHandler', res.getNodeServerRequest(), {
|
|
555
|
-
options,
|
|
556
|
-
response: res,
|
|
557
|
-
});
|
|
558
|
-
if (req == null) {
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
if (firstRequestHandler)
|
|
562
|
-
firstRequestHandler(req);
|
|
563
|
-
// Add our CORS headers to be good web citizens (there are perf
|
|
564
|
-
// implications though so be careful!)
|
|
565
|
-
//
|
|
566
|
-
// Always enable CORS when developing PostGraphile because GraphiQL will be
|
|
567
|
-
// on port 5783.
|
|
568
|
-
if (enableCors)
|
|
569
|
-
addCORSHeaders(res);
|
|
570
|
-
// ========================================================================
|
|
571
|
-
// Execute GraphQL Queries
|
|
572
|
-
// ========================================================================
|
|
573
|
-
// If we didn’t call `next` above, all requests will return 200 by default!
|
|
574
|
-
res.statusCode = 200;
|
|
575
|
-
if (watchPg) {
|
|
576
|
-
// Inform GraphiQL and other clients that they can subscribe to events
|
|
577
|
-
// (such as the schema being updated) at the following URL
|
|
578
|
-
res.setHeader('X-GraphQL-Event-Stream', externalEventStreamRoute || `${externalUrlBase}${eventStreamRoute}`);
|
|
579
|
-
}
|
|
580
|
-
// Don’t execute our GraphQL stuffs for `OPTIONS` requests.
|
|
581
|
-
if (req.method === 'OPTIONS') {
|
|
582
|
-
res.statusCode = 200;
|
|
583
|
-
res.end();
|
|
584
|
-
return;
|
|
585
|
-
}
|
|
586
|
-
// The `result` will be used at the very end in our `finally` block.
|
|
587
|
-
// Statements inside the `try` will assign to `result` when they get
|
|
588
|
-
// a result. We also keep track of `params`.
|
|
589
|
-
let paramsList;
|
|
590
|
-
let results = [];
|
|
591
|
-
const queryTimeStart = !disableQueryLog && process.hrtime();
|
|
592
|
-
let pgRole;
|
|
593
|
-
if (debugRequest.enabled)
|
|
594
|
-
debugRequest('GraphQL query request has begun.');
|
|
595
|
-
let returnArray = false;
|
|
596
|
-
// This big `try`/`catch`/`finally` block represents the execution of our
|
|
597
|
-
// GraphQL query. All errors thrown in this block will be returned to the
|
|
598
|
-
// client as GraphQL errors.
|
|
599
|
-
try {
|
|
600
|
-
// First thing we need to do is get the GraphQL schema for this request.
|
|
601
|
-
// It should never really change unless we are in watch mode.
|
|
602
|
-
const gqlSchema = theOneAndOnlyGraphQLSchema || (await getGqlSchema());
|
|
603
|
-
// Note that we run our middleware after we make sure we are on the
|
|
604
|
-
// correct route. This is so that if our middleware modifies the `req` or
|
|
605
|
-
// `res` objects, only we downstream will see the modifications.
|
|
606
|
-
//
|
|
607
|
-
// We also run our middleware inside the `try` so that we get the GraphQL
|
|
608
|
-
// error reporting style for syntax errors.
|
|
609
|
-
await parseBody(req, res);
|
|
610
|
-
// If this is not one of the correct methods, throw an error.
|
|
611
|
-
if (req.method !== 'POST') {
|
|
612
|
-
res.setHeader('Allow', 'POST, OPTIONS');
|
|
613
|
-
throw httpError(405, 'Only `POST` requests are allowed.');
|
|
614
|
-
}
|
|
615
|
-
// Get the parameters we will use to run a GraphQL request. `params` may
|
|
616
|
-
// include:
|
|
617
|
-
//
|
|
618
|
-
// - `query`: The required GraphQL query string.
|
|
619
|
-
// - `variables`: An optional JSON object containing GraphQL variables.
|
|
620
|
-
// - `operationName`: The optional name of the GraphQL operation we will
|
|
621
|
-
// be executing.
|
|
622
|
-
const body = req.body;
|
|
623
|
-
paramsList = typeof body === 'string' ? { query: body } : body;
|
|
624
|
-
// Validate our paramsList object a bit.
|
|
625
|
-
if (paramsList == null)
|
|
626
|
-
throw httpError(400, 'Must provide an object parameters, not nullish value.');
|
|
627
|
-
if (typeof paramsList !== 'object')
|
|
628
|
-
throw httpError(400, `Expected parameter object, not value of type '${typeof paramsList}'.`);
|
|
629
|
-
if (Array.isArray(paramsList)) {
|
|
630
|
-
if (!enableQueryBatching) {
|
|
631
|
-
throw httpError(501, 'Batching queries as an array is currently unsupported. Please provide a single query object.');
|
|
632
|
-
}
|
|
633
|
-
else {
|
|
634
|
-
returnArray = true;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
else {
|
|
638
|
-
paramsList = [paramsList];
|
|
639
|
-
}
|
|
640
|
-
paramsList = pluginHook('postgraphile:httpParamsList', paramsList, {
|
|
641
|
-
options,
|
|
642
|
-
req,
|
|
643
|
-
res,
|
|
644
|
-
returnArray,
|
|
645
|
-
httpError,
|
|
646
|
-
});
|
|
647
|
-
results = await Promise.all(paramsList.map(async (params) => {
|
|
648
|
-
let queryDocumentAst = null;
|
|
649
|
-
let result;
|
|
650
|
-
const meta = Object.create(null);
|
|
651
|
-
try {
|
|
652
|
-
if (!params)
|
|
653
|
-
throw httpError(400, 'Invalid query structure.');
|
|
654
|
-
const { query, operationName } = params;
|
|
655
|
-
let { variables } = params;
|
|
656
|
-
if (!query)
|
|
657
|
-
throw httpError(400, 'Must provide a query string.');
|
|
658
|
-
// If variables is a string, we assume it is a JSON string and that it
|
|
659
|
-
// needs to be parsed.
|
|
660
|
-
if (typeof variables === 'string') {
|
|
661
|
-
// If variables is just an empty string, we should set it to null and
|
|
662
|
-
// ignore it.
|
|
663
|
-
if (variables === '') {
|
|
664
|
-
variables = null;
|
|
665
|
-
}
|
|
666
|
-
else {
|
|
667
|
-
// Otherwise, let us try to parse it as JSON.
|
|
668
|
-
try {
|
|
669
|
-
variables = JSON.parse(variables);
|
|
670
|
-
}
|
|
671
|
-
catch (error) {
|
|
672
|
-
error.statusCode = 400;
|
|
673
|
-
throw error;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
// Throw an error if `variables` is not an object.
|
|
678
|
-
if (variables != null && typeof variables !== 'object')
|
|
679
|
-
throw httpError(400, `Variables must be an object, not '${typeof variables}'.`);
|
|
680
|
-
// Throw an error if `operationName` is not a string.
|
|
681
|
-
if (operationName != null && typeof operationName !== 'string')
|
|
682
|
-
throw httpError(400, `Operation name must be a string, not '${typeof operationName}'.`);
|
|
683
|
-
let validationErrors;
|
|
684
|
-
({ queryDocumentAst, validationErrors } = parseQuery(gqlSchema, query));
|
|
685
|
-
if (validationErrors.length === 0) {
|
|
686
|
-
// You are strongly encouraged to use
|
|
687
|
-
// `postgraphile:validationRules:static` if possible - you should
|
|
688
|
-
// only use this one if you need access to variables.
|
|
689
|
-
const moreValidationRules = pluginHook('postgraphile:validationRules', [], {
|
|
690
|
-
options,
|
|
691
|
-
req,
|
|
692
|
-
res,
|
|
693
|
-
variables,
|
|
694
|
-
operationName,
|
|
695
|
-
meta,
|
|
696
|
-
});
|
|
697
|
-
if (moreValidationRules.length) {
|
|
698
|
-
validationErrors = graphql_1.validate(gqlSchema, queryDocumentAst, moreValidationRules);
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
// If we have some validation errors, don’t execute the query. Instead
|
|
702
|
-
// send the errors to the client with a `400` code.
|
|
703
|
-
if (validationErrors.length > 0) {
|
|
704
|
-
result = { errors: validationErrors, statusCode: 400 };
|
|
705
|
-
}
|
|
706
|
-
else if (!queryDocumentAst) {
|
|
707
|
-
throw new Error('Could not process query');
|
|
708
|
-
}
|
|
709
|
-
else {
|
|
710
|
-
if (debugRequest.enabled)
|
|
711
|
-
debugRequest('GraphQL query is validated.');
|
|
712
|
-
// Lazily log the query. If this debugger isn’t enabled, don’t run it.
|
|
713
|
-
if (debugGraphql.enabled)
|
|
714
|
-
debugGraphql('%s', graphql_1.print(queryDocumentAst).replace(/\s+/g, ' ').trim());
|
|
715
|
-
result = await withPostGraphileContextFromReqRes(req,
|
|
716
|
-
// For backwards compatibilty we must pass the actual node request object.
|
|
717
|
-
res.getNodeServerResponse(), {
|
|
718
|
-
singleStatement: false,
|
|
719
|
-
queryDocumentAst,
|
|
720
|
-
variables,
|
|
721
|
-
operationName,
|
|
722
|
-
}, (graphqlContext) => {
|
|
723
|
-
pgRole = graphqlContext.pgRole;
|
|
724
|
-
const graphqlResult = graphql_1.execute(gqlSchema, queryDocumentAst, null, graphqlContext, variables, operationName);
|
|
725
|
-
if (typeof graphqlContext.getExplainResults === 'function') {
|
|
726
|
-
return Promise.resolve(graphqlResult).then(async (obj) => ({
|
|
727
|
-
...obj,
|
|
728
|
-
// Add our explain data
|
|
729
|
-
explain: await graphqlContext.getExplainResults(),
|
|
730
|
-
}));
|
|
731
|
-
}
|
|
732
|
-
else {
|
|
733
|
-
return graphqlResult;
|
|
734
|
-
}
|
|
735
|
-
});
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
catch (error) {
|
|
739
|
-
result = {
|
|
740
|
-
errors: [error],
|
|
741
|
-
statusCode: error.status || error.statusCode || 500,
|
|
742
|
-
};
|
|
743
|
-
// If the status code is 500, let’s log our error.
|
|
744
|
-
if (result.statusCode === 500)
|
|
745
|
-
// tslint:disable-next-line no-console
|
|
746
|
-
console.error(error.stack);
|
|
747
|
-
}
|
|
748
|
-
finally {
|
|
749
|
-
// Format our errors so the client doesn’t get the full thing.
|
|
750
|
-
if (result && result.errors) {
|
|
751
|
-
result.errors = handleErrors(result.errors, req, res);
|
|
752
|
-
}
|
|
753
|
-
if (!isEmpty(meta)) {
|
|
754
|
-
result.meta = meta;
|
|
755
|
-
}
|
|
756
|
-
result = pluginHook('postgraphile:http:result', result, {
|
|
757
|
-
options,
|
|
758
|
-
returnArray,
|
|
759
|
-
queryDocumentAst,
|
|
760
|
-
req,
|
|
761
|
-
pgRole,
|
|
762
|
-
});
|
|
763
|
-
// Log the query. If this debugger isn’t enabled, don’t run it.
|
|
764
|
-
if (!disableQueryLog && queryDocumentAst) {
|
|
765
|
-
// To appease TypeScript
|
|
766
|
-
const definitelyQueryDocumentAst = queryDocumentAst;
|
|
767
|
-
// We must reference this before it's deleted!
|
|
768
|
-
const resultStatusCode = result.statusCode;
|
|
769
|
-
const timeDiff = queryTimeStart && process.hrtime(queryTimeStart);
|
|
770
|
-
setImmediate(() => {
|
|
771
|
-
const prettyQuery = graphql_1.print(definitelyQueryDocumentAst)
|
|
772
|
-
.replace(/\s+/g, ' ')
|
|
773
|
-
.trim();
|
|
774
|
-
const errorCount = (result.errors || []).length;
|
|
775
|
-
const ms = timeDiff[0] * 1e3 + timeDiff[1] * 1e-6;
|
|
776
|
-
let message;
|
|
777
|
-
if (resultStatusCode === 401) {
|
|
778
|
-
// Users requested that JWT errors were raised differently:
|
|
779
|
-
//
|
|
780
|
-
// https://github.com/graphile/postgraphile/issues/560
|
|
781
|
-
message = chalk_1.default.red(`401 authentication error`);
|
|
782
|
-
}
|
|
783
|
-
else if (resultStatusCode === 403) {
|
|
784
|
-
message = chalk_1.default.red(`403 forbidden error`);
|
|
785
|
-
}
|
|
786
|
-
else {
|
|
787
|
-
message = chalk_1.default[errorCount === 0 ? 'green' : 'red'](`${errorCount} error(s)`);
|
|
788
|
-
}
|
|
789
|
-
// tslint:disable-next-line no-console
|
|
790
|
-
console.log(`${message} ${pgRole != null ? `as ${chalk_1.default.magenta(pgRole)} ` : ''}in ${chalk_1.default.grey(`${ms.toFixed(2)}ms`)} :: ${prettyQuery}`);
|
|
791
|
-
});
|
|
792
|
-
}
|
|
793
|
-
if (debugRequest.enabled)
|
|
794
|
-
debugRequest('GraphQL query has been executed.');
|
|
795
|
-
}
|
|
796
|
-
return result;
|
|
797
|
-
}));
|
|
798
|
-
}
|
|
799
|
-
catch (error) {
|
|
800
|
-
// Set our status code and send the client our results!
|
|
801
|
-
if (res.statusCode === 200)
|
|
802
|
-
res.statusCode = error.status || error.statusCode || 500;
|
|
803
|
-
// Overwrite entire response
|
|
804
|
-
returnArray = false;
|
|
805
|
-
results = [{ errors: handleErrors([error], req, res) }];
|
|
806
|
-
// If the status code is 500, let’s log our error.
|
|
807
|
-
if (res.statusCode === 500) {
|
|
808
|
-
// tslint:disable-next-line no-console
|
|
809
|
-
console.error(error.stack);
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
finally {
|
|
813
|
-
// Finally, we send the client the results.
|
|
814
|
-
if (!returnArray) {
|
|
815
|
-
if (res.statusCode === 200 && results[0].statusCode) {
|
|
816
|
-
res.statusCode = results[0].statusCode;
|
|
817
|
-
}
|
|
818
|
-
results[0].statusCode = undefined;
|
|
819
|
-
}
|
|
820
|
-
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
821
|
-
const { statusCode, result } = pluginHook('postgraphile:http:end', {
|
|
822
|
-
statusCode: res.statusCode,
|
|
823
|
-
result: returnArray ? results : results[0],
|
|
824
|
-
}, {
|
|
825
|
-
options,
|
|
826
|
-
returnArray,
|
|
827
|
-
req,
|
|
828
|
-
// For backwards compatibility, the underlying response object.
|
|
829
|
-
res: res.getNodeServerResponse(),
|
|
830
|
-
});
|
|
831
|
-
if (statusCode) {
|
|
832
|
-
res.statusCode = statusCode;
|
|
833
|
-
}
|
|
834
|
-
res.end(JSON.stringify(result));
|
|
835
|
-
if (debugRequest.enabled) {
|
|
836
|
-
debugRequest('GraphQL ' + (returnArray ? 'queries' : 'query') + ' request finished.');
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
});
|
|
840
|
-
/**
|
|
841
|
-
* A polymorphic request handler that should detect what `http` framework is
|
|
842
|
-
* being used and specifically handle that framework.
|
|
843
|
-
*
|
|
844
|
-
* Supported frameworks include:
|
|
845
|
-
*
|
|
846
|
-
* - Native Node.js `http`.
|
|
847
|
-
* - `connect`.
|
|
848
|
-
* - `express`.
|
|
849
|
-
* - `koa` (2.0).
|
|
850
|
-
*/
|
|
851
|
-
const middleware = (a, b, c) => {
|
|
852
|
-
// If are arguments look like the arguments to koa middleware, this is
|
|
853
|
-
// `koa` middleware.
|
|
854
|
-
if (isKoaApp(a, b)) {
|
|
855
|
-
// Set the correct `koa` variable names…
|
|
856
|
-
const ctx = a;
|
|
857
|
-
const next = b;
|
|
858
|
-
const responseHandler = new frameworks_1.PostGraphileResponseKoa(ctx, next);
|
|
859
|
-
// Execute our request handler. If an error is thrown, we don’t call
|
|
860
|
-
// `next` with an error. Instead we return the promise and let `koa`
|
|
861
|
-
// handle the error.
|
|
862
|
-
return requestHandler(responseHandler, next);
|
|
863
|
-
}
|
|
864
|
-
else {
|
|
865
|
-
// Set the correct `connect` style variable names. If there was no `next`
|
|
866
|
-
// defined (likely the case if the client is using `http`) we use the
|
|
867
|
-
// final handler.
|
|
868
|
-
const req = a;
|
|
869
|
-
const res = b;
|
|
870
|
-
const next = c || finalHandler(req, res);
|
|
871
|
-
const responseHandler = new frameworks_1.PostGraphileResponseNode(req, res, next);
|
|
872
|
-
// Execute our request handler. If the request errored out, call `next` with the error.
|
|
873
|
-
requestHandler(responseHandler, next).catch(next);
|
|
874
|
-
// No return value.
|
|
875
|
-
}
|
|
876
|
-
};
|
|
877
|
-
middleware.getGraphQLSchema = getGqlSchema;
|
|
878
|
-
middleware.formatError = formatError;
|
|
879
|
-
middleware.pgPool = pgPool;
|
|
880
|
-
middleware.withPostGraphileContextFromReqRes = withPostGraphileContextFromReqRes;
|
|
881
|
-
middleware.handleErrors = handleErrors;
|
|
882
|
-
middleware.options = options;
|
|
883
|
-
middleware.graphqlRoute = graphqlRoute;
|
|
884
|
-
middleware.graphqlRouteHandler = graphqlRouteHandler;
|
|
885
|
-
middleware.graphiqlRoute = graphiqlRoute;
|
|
886
|
-
middleware.graphiqlRouteHandler = graphiql ? graphiqlRouteHandler : null;
|
|
887
|
-
middleware.faviconRouteHandler = graphiql ? faviconRouteHandler : null;
|
|
888
|
-
middleware.eventStreamRoute = eventStreamRoute;
|
|
889
|
-
middleware.eventStreamRouteHandler = watchPg ? eventStreamRouteHandler : null;
|
|
890
|
-
middleware.shutdownActions = shutdownActions;
|
|
891
|
-
// Experimental
|
|
892
|
-
middleware.release = () => shutdownActions.invokeAll();
|
|
893
|
-
const hookedMiddleware = pluginHook('postgraphile:middleware', middleware, {
|
|
894
|
-
options,
|
|
895
|
-
// Experimental
|
|
896
|
-
shutdownActions,
|
|
897
|
-
});
|
|
898
|
-
// Sanity check:
|
|
899
|
-
if (!hookedMiddleware.getGraphQLSchema) {
|
|
900
|
-
throw new Error("Hook for 'postgraphile:middleware' has not copied over the helpers; e.g. missing `Object.assign(newMiddleware, oldMiddleware)`");
|
|
901
|
-
}
|
|
902
|
-
return hookedMiddleware;
|
|
903
|
-
}
|
|
904
|
-
exports.default = createPostGraphileHttpRequestHandler;
|
|
905
|
-
/**
|
|
906
|
-
* Adds CORS to a request. See [this][1] flowchart for an explanation of how
|
|
907
|
-
* CORS works. Note that these headers are set for all requests, CORS
|
|
908
|
-
* algorithms normally run a preflight request using the `OPTIONS` method to
|
|
909
|
-
* get these headers.
|
|
910
|
-
*
|
|
911
|
-
* Note though, that enabling CORS will incur extra costs when it comes to the
|
|
912
|
-
* preflight requests. It is much better if you choose to use a proxy and
|
|
913
|
-
* bypass CORS altogether.
|
|
914
|
-
*
|
|
915
|
-
* [1]: http://www.html5rocks.com/static/images/cors_server_flowchart.png
|
|
916
|
-
*/
|
|
917
|
-
function addCORSHeaders(res) {
|
|
918
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
919
|
-
res.setHeader('Access-Control-Allow-Methods', 'HEAD, GET, POST');
|
|
920
|
-
res.setHeader('Access-Control-Allow-Headers', [
|
|
921
|
-
'Origin',
|
|
922
|
-
'X-Requested-With',
|
|
923
|
-
// Used by `express-graphql` to determine whether to expose the GraphiQL
|
|
924
|
-
// interface (`text/html`) or not.
|
|
925
|
-
'Accept',
|
|
926
|
-
// Used by PostGraphile for auth purposes.
|
|
927
|
-
'Authorization',
|
|
928
|
-
// Used by GraphQL Playground and other Apollo-enabled servers
|
|
929
|
-
'X-Apollo-Tracing',
|
|
930
|
-
// The `Content-*` headers are used when making requests with a body,
|
|
931
|
-
// like in a POST request.
|
|
932
|
-
'Content-Type',
|
|
933
|
-
'Content-Length',
|
|
934
|
-
// For our 'Explain' feature
|
|
935
|
-
'X-PostGraphile-Explain',
|
|
936
|
-
].join(', '));
|
|
937
|
-
res.setHeader('Access-Control-Expose-Headers', ['X-GraphQL-Event-Stream'].join(', '));
|
|
938
|
-
}
|
|
939
|
-
function createBadAuthorizationHeaderError() {
|
|
940
|
-
return httpError(400, 'Authorization header is not of the correct bearer scheme format.');
|
|
941
|
-
}
|
|
942
|
-
/**
|
|
943
|
-
* Parses the `Bearer` auth scheme token out of the `Authorization` header as
|
|
944
|
-
* defined by [RFC7235][1].
|
|
945
|
-
*
|
|
946
|
-
* ```
|
|
947
|
-
* Authorization = credentials
|
|
948
|
-
* credentials = auth-scheme [ 1*SP ( token68 / #auth-param ) ]
|
|
949
|
-
* token68 = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" )*"="
|
|
950
|
-
* ```
|
|
951
|
-
*
|
|
952
|
-
* [1]: https://tools.ietf.org/html/rfc7235
|
|
953
|
-
*
|
|
954
|
-
* @private
|
|
955
|
-
*/
|
|
956
|
-
const authorizationBearerRex = /^\s*bearer\s+([a-z0-9\-._~+/]+=*)\s*$/i;
|
|
957
|
-
/**
|
|
958
|
-
* Gets the JWT token from the Http request’s headers. Specifically the
|
|
959
|
-
* `Authorization` header in the `Bearer` format. Will throw an error if the
|
|
960
|
-
* header is in the incorrect format, but will not throw an error if the header
|
|
961
|
-
* does not exist.
|
|
962
|
-
*
|
|
963
|
-
* @private
|
|
964
|
-
* @param {IncomingMessage} request
|
|
965
|
-
* @returns {string | null}
|
|
966
|
-
*/
|
|
967
|
-
function getJwtToken(request) {
|
|
968
|
-
const { authorization } = request.headers;
|
|
969
|
-
if (Array.isArray(authorization))
|
|
970
|
-
throw createBadAuthorizationHeaderError();
|
|
971
|
-
// If there was no authorization header, just return null.
|
|
972
|
-
if (authorization == null)
|
|
973
|
-
return null;
|
|
974
|
-
const match = authorizationBearerRex.exec(authorization);
|
|
975
|
-
// If we did not match the authorization header with our expected format,
|
|
976
|
-
// throw a 400 error.
|
|
977
|
-
if (!match)
|
|
978
|
-
throw createBadAuthorizationHeaderError();
|
|
979
|
-
// Return the token from our match.
|
|
980
|
-
return match[1];
|
|
981
|
-
}
|
|
982
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlUG9zdEdyYXBoaWxlSHR0cFJlcXVlc3RIYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3Bvc3RncmFwaGlsZS9odHRwL2NyZWF0ZVBvc3RHcmFwaGlsZUh0dHBSZXF1ZXN0SGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw4RUFBOEU7QUFDOUUscUNBV2lCO0FBQ2pCLGdFQUE2RDtBQUU3RCw4Q0FBc0Q7QUFFdEQsbUVBQTREO0FBQzVELHdFQUFpRTtBQUNqRSx1Q0FBZ0M7QUFFaEMsaUNBQTBCO0FBQzFCLGtDQUFtQyxDQUFDLG9DQUFvQztBQUN4RSx5Q0FBMEM7QUFDMUMscUNBQXNDO0FBQ3RDLDZDQUE4QztBQUM5QywwQ0FBMkM7QUFDM0MsaUNBQWtDO0FBRWxDLE1BQU0sUUFBUSxHQUFHLENBQUMsQ0FBTSxFQUFFLENBQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLE9BQU8sQ0FBQyxLQUFLLFVBQVUsQ0FBQztBQUUvRSxNQUFNLGdCQUFnQixHQUFHLE1BQU0sQ0FBQztBQUVoQyxNQUFNLHlCQUF5QixHQUFHLDBCQUEwQixDQUFDO0FBQzdELE1BQU0sSUFBSSxHQUFHLEdBQUcsRUFBRTtJQUNoQixVQUFVO0FBQ1osQ0FBQyxDQUFDO0FBRUYsTUFBTSxFQUFFLFVBQVUsRUFBRSxHQUFHLE1BQU0sQ0FBQztBQUU5Qjs7Ozs7R0FLRztBQUNILDBEQUErQztBQUUvQzs7O0dBR0c7QUFDSCw4REFBMEQ7QUFDMUQsbURBQWtFO0FBQ2xFLDZDQU1zQjtBQUV0Qjs7O0dBR0c7QUFDSCxNQUFNLGdCQUFnQixHQUFHO0lBQ3ZCLEdBQUcsRUFBRSxTQUFTO0lBQ2QsR0FBRyxFQUFFLFNBQVM7SUFDZCxHQUFHLEVBQUUsU0FBUztJQUNkLFFBQVEsRUFBRSxTQUFTO0lBQ25CLFFBQVEsRUFBRSxTQUFTO0NBQ3BCLENBQUM7QUFDRixT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
|