grafast 0.1.1-beta.0 → 0.1.1-beta.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.
Files changed (81) hide show
  1. package/README.md +1 -2
  2. package/dist/args.js +62 -0
  3. package/dist/assert.js +24 -0
  4. package/dist/bucket.js +4 -0
  5. package/dist/config.js +99 -0
  6. package/dist/constraints.js +72 -0
  7. package/dist/deferred.js +25 -0
  8. package/dist/dev.js +10 -0
  9. package/dist/engine/LayerPlan.js +536 -0
  10. package/dist/engine/OperationPlan.js +2543 -0
  11. package/dist/engine/OutputPlan.js +1059 -0
  12. package/dist/engine/StepTracker.js +524 -0
  13. package/dist/engine/executeBucket.js +700 -0
  14. package/dist/engine/executeOutputPlan.js +21 -0
  15. package/dist/engine/lib/withGlobalLayerPlan.js +36 -0
  16. package/dist/envelop.js +73 -5
  17. package/dist/error.js +62 -0
  18. package/dist/establishOperationPlan.js +186 -0
  19. package/dist/execute.js +80 -0
  20. package/dist/exportAs.js +57 -0
  21. package/dist/global.js +13 -0
  22. package/dist/grafastGraphql.js +133 -0
  23. package/dist/grafastPrint.js +177 -0
  24. package/dist/graphqlCollectFields.js +217 -0
  25. package/dist/graphqlMergeSelectionSets.js +60 -0
  26. package/dist/index.d.ts +161 -2
  27. package/dist/index.js +255 -499
  28. package/dist/input.js +159 -0
  29. package/dist/inspect.js +20 -0
  30. package/dist/interfaces.d.ts +3 -160
  31. package/dist/interfaces.js +63 -0
  32. package/dist/makeGrafastSchema.js +174 -0
  33. package/dist/mermaid.js +290 -7
  34. package/dist/operationPlan-input.js +449 -0
  35. package/dist/planJSONInterfaces.js +3 -0
  36. package/dist/polymorphic.js +73 -0
  37. package/dist/prepare.js +763 -0
  38. package/dist/step.js +396 -0
  39. package/dist/steps/__inputDynamicScalar.js +125 -0
  40. package/dist/steps/__inputList.js +110 -0
  41. package/dist/steps/__inputObject.js +128 -0
  42. package/dist/steps/__inputStaticLeaf.js +43 -0
  43. package/dist/steps/__item.js +50 -0
  44. package/dist/steps/__trackedValue.js +257 -0
  45. package/dist/steps/__value.js +47 -0
  46. package/dist/steps/access.js +183 -0
  47. package/dist/steps/applyTransforms.js +151 -0
  48. package/dist/steps/connection.js +315 -0
  49. package/dist/steps/constant.js +72 -0
  50. package/dist/steps/each.js +64 -0
  51. package/dist/steps/error.js +32 -0
  52. package/dist/steps/filter.js +32 -0
  53. package/dist/steps/first.js +49 -0
  54. package/dist/steps/graphqlResolver.js +260 -0
  55. package/dist/steps/groupBy.js +40 -0
  56. package/dist/steps/index.js +117 -0
  57. package/dist/steps/lambda.js +58 -0
  58. package/dist/steps/last.js +41 -0
  59. package/dist/steps/list.js +75 -0
  60. package/dist/steps/listTransform.js +185 -0
  61. package/dist/steps/listen.js +61 -0
  62. package/dist/steps/load.d.ts +4 -4
  63. package/dist/steps/load.js +310 -0
  64. package/dist/steps/node.d.ts +6 -6
  65. package/dist/steps/node.js +107 -0
  66. package/dist/steps/object.js +195 -0
  67. package/dist/steps/partitionByIndex.js +86 -0
  68. package/dist/steps/proxy.js +114 -0
  69. package/dist/steps/remapKeys.js +84 -0
  70. package/dist/steps/reverse.js +52 -0
  71. package/dist/steps/setter.js +28 -0
  72. package/dist/stringifyPayload.js +59 -0
  73. package/dist/stripAnsi.js +14 -0
  74. package/dist/subscribe.js +14 -0
  75. package/dist/thereCanBeOnlyOne.js +21 -0
  76. package/dist/timeSource.js +8 -0
  77. package/dist/utils.js +698 -0
  78. package/dist/version.d.ts +1 -1
  79. package/dist/version.js +6 -0
  80. package/package.json +9 -4
  81. package/dist/LICENSES.txt +0 -300
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeOutputPlan = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const assert = tslib_1.__importStar(require("../assert.js"));
6
+ const dev_js_1 = require("../dev.js");
7
+ /**
8
+ * @internal
9
+ */
10
+ function executeOutputPlan(ctx, outputPlan, bucket, bucketIndex, outputDataAsString) {
11
+ if (dev_js_1.isDev) {
12
+ assert.strictEqual(bucket.isComplete, true, "Can only process an output plan for a completed bucket");
13
+ }
14
+ // PERF: feels like this path could be done more efficiently
15
+ const mutablePath = ["SOMEONE_FORGOT_TO_SLICE_THE_PATH!", ...ctx.path];
16
+ return outputDataAsString
17
+ ? outputPlan.executeString(ctx.root, mutablePath, bucket, bucketIndex)
18
+ : outputPlan.execute(ctx.root, mutablePath, bucket, bucketIndex);
19
+ }
20
+ exports.executeOutputPlan = executeOutputPlan;
21
+ //# sourceMappingURL=executeOutputPlan.js.map
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.currentPolymorphicPaths = exports.currentLayerPlan = exports.withGlobalLayerPlan = void 0;
4
+ let globalData_layerPlan = undefined;
5
+ let globalData_polymorphicPaths = undefined;
6
+ function withGlobalLayerPlan(layerPlan, polymorphicPaths, callback, callbackThis, ...callbackArgs) {
7
+ const oldLayerPlan = globalData_layerPlan;
8
+ globalData_layerPlan = layerPlan;
9
+ const oldPolymorphicPaths = globalData_polymorphicPaths;
10
+ globalData_polymorphicPaths = polymorphicPaths;
11
+ try {
12
+ return callback.apply(callbackThis, callbackArgs);
13
+ }
14
+ finally {
15
+ globalData_layerPlan = oldLayerPlan;
16
+ globalData_polymorphicPaths = oldPolymorphicPaths;
17
+ }
18
+ }
19
+ exports.withGlobalLayerPlan = withGlobalLayerPlan;
20
+ function currentLayerPlan() {
21
+ if (globalData_layerPlan === undefined) {
22
+ throw new Error(
23
+ // Must only be called from inside `withGlobalLayerPlan`!
24
+ "Now is not a valid time to call `currentLayerPlan`. This error typically occurs when you attempt to call a Grafast step function from outside of the planning lifecycle - it's important to note that Grafast plans must be resolved synchronously, so check for 'async' or 'setTimeout' or any location where a step function is called outside of a plan resolver. For more information, read about plan resolvers: https://grafast.org/grafast/plan-resolvers");
25
+ }
26
+ return globalData_layerPlan;
27
+ }
28
+ exports.currentLayerPlan = currentLayerPlan;
29
+ function currentPolymorphicPaths() {
30
+ if (globalData_polymorphicPaths === undefined) {
31
+ throw new Error("GrafastInternalError<b0b05743-8b21-42c6-9b53-925013d88bd1>: currentPolymorphicPaths called out of turn; must only called within a withGlobalLayerPlan callback");
32
+ }
33
+ return globalData_polymorphicPaths;
34
+ }
35
+ exports.currentPolymorphicPaths = currentPolymorphicPaths;
36
+ //# sourceMappingURL=withGlobalLayerPlan.js.map
package/dist/envelop.js CHANGED
@@ -1,5 +1,73 @@
1
- // Convince Node to allow ESM named imports
2
-
3
-
4
- // Bundled module
5
- "use strict";!function(e,r){"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define([],r):"object"==typeof exports?exports.grafast=r():e.grafast=r()}(this,(()=>(this.webpackChunkgrafast=this.webpackChunkgrafast||[]).push([[764],{3837:(e,r,s)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.useMoreDetailedErrors=r.useGrafast=void 0;const t=s(6587),n=s(6522),a=s(680);function o(e,r){if(!1===e||Array.isArray(e)&&0===e.length)return;const s=Array.isArray(r)?r.join(","):r;if(!s)return;const t=s.split(",");return!0===e||void 0===e?t:e.filter((e=>t.includes(e)))}r.useGrafast=(e={})=>{const{explainAllowed:r=!0}=e;return{async onExecute(e){const s=e.args.contextValue?.req?.headers["x-graphql-explain"],n=o(r,s);e.setExecuteFn((e=>(0,t.execute)(e,{grafast:{explain:n}})))},async onSubscribe(e){const s=e.args.contextValue,t=(s?.req?.headers||s?.request?.headers||s?.connectionParams)?.["x-graphql-explain"],n=o(r,t);e.setSubscribeFn((async e=>(0,a.subscribe)(e,{grafast:{explain:n}})))}}};r.useMoreDetailedErrors=()=>({onExecute:()=>({onExecuteDone({result:e}){"errors"in e&&e.errors&&(e.errors=e.errors.map((e=>{const r=e.toJSON();return Object.assign(r,{message:(0,n.stripAnsi)(r.message),extensions:{stack:(0,n.stripAnsi)(e.stack??"").split("\n")}})})))}})})}},e=>{var r;return r=3837,e(e.s=r)}])));
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useMoreDetailedErrors = exports.useGrafast = void 0;
4
+ const execute_js_1 = require("./execute.js");
5
+ const stripAnsi_js_1 = require("./stripAnsi.js");
6
+ const subscribe_js_1 = require("./subscribe.js");
7
+ function processExplain(explainAllowed, explainHeaders) {
8
+ if (explainAllowed === false ||
9
+ (Array.isArray(explainAllowed) && explainAllowed.length === 0)) {
10
+ return undefined;
11
+ }
12
+ const explainHeader = Array.isArray(explainHeaders)
13
+ ? explainHeaders.join(",")
14
+ : explainHeaders;
15
+ if (!explainHeader) {
16
+ return undefined;
17
+ }
18
+ const explainParts = explainHeader.split(",");
19
+ if (explainAllowed === true || explainAllowed === undefined) {
20
+ return explainParts;
21
+ }
22
+ // Assumption: explainAllowed is relatively short (and unique).
23
+ // PERF: there's probably a faster way to do this...
24
+ return explainAllowed.filter((p) => explainParts.includes(p));
25
+ }
26
+ /**
27
+ * An Envelop plugin that uses Grafast to prepare and execute the GraphQL
28
+ * query.
29
+ */
30
+ const useGrafast = (options = {}) => {
31
+ const { explainAllowed = true } = options;
32
+ return {
33
+ async onExecute(opts) {
34
+ const explainHeaders = opts.args.contextValue?.req?.headers["x-graphql-explain"];
35
+ const explain = processExplain(explainAllowed, explainHeaders);
36
+ opts.setExecuteFn((args) => (0, execute_js_1.execute)(args, {
37
+ grafast: { explain },
38
+ }));
39
+ },
40
+ async onSubscribe(opts) {
41
+ const ctx = opts.args.contextValue;
42
+ const explainHeaders = (ctx?.req?.headers ||
43
+ ctx?.request?.headers ||
44
+ ctx?.connectionParams)?.["x-graphql-explain"];
45
+ const explain = processExplain(explainAllowed, explainHeaders);
46
+ opts.setSubscribeFn(async (args) => (0, subscribe_js_1.subscribe)(args, {
47
+ grafast: { explain },
48
+ }));
49
+ },
50
+ };
51
+ };
52
+ exports.useGrafast = useGrafast;
53
+ /**
54
+ * An Envelop plugin that will make any GraphQL errors easier to read from
55
+ * inside of GraphiQL.
56
+ */
57
+ const useMoreDetailedErrors = () => ({
58
+ onExecute: () => ({
59
+ onExecuteDone({ result }) {
60
+ if ("errors" in result && result.errors) {
61
+ result.errors = result.errors.map((e) => {
62
+ const obj = e.toJSON();
63
+ return Object.assign(obj, {
64
+ message: (0, stripAnsi_js_1.stripAnsi)(obj.message),
65
+ extensions: { stack: (0, stripAnsi_js_1.stripAnsi)(e.stack ?? "").split("\n") },
66
+ });
67
+ });
68
+ }
69
+ },
70
+ }),
71
+ });
72
+ exports.useMoreDetailedErrors = useMoreDetailedErrors;
73
+ //# sourceMappingURL=envelop.js.map
package/dist/error.js ADDED
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var _a, _b;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.isSafeError = exports.SafeError = exports.isGrafastError = exports.newGrafastError = exports._GrafastError = exports.$$error = void 0;
5
+ const interfaces_js_1 = require("./interfaces.js");
6
+ exports.$$error = Symbol("isGrafastError");
7
+ // IMPORTANT: this WILL NOT WORK when compiled down to ES5. It requires ES6+
8
+ // native class support.
9
+ /**
10
+ * When an error occurs during plan execution we wrap it in a GrafastError so
11
+ * that we can pass it around as a value. It gets unwrapped and thrown in the
12
+ * grafast resolver.
13
+ *
14
+ * @internal
15
+ */
16
+ const _GrafastError = class GrafastError extends Error {
17
+ static { _a = exports.$$error; }
18
+ constructor(originalError, planId) {
19
+ if (originalError instanceof exports._GrafastError) {
20
+ throw new Error("GrafastInternalError<62505509-8b21-4ef7-80f5-d0f99873174b>: attempted to wrap a GrafastError with a GrafastError.");
21
+ }
22
+ const message = originalError?.message;
23
+ super(message);
24
+ this[_a] = true;
25
+ Object.setPrototypeOf(this, GrafastError.prototype);
26
+ this.originalError = originalError;
27
+ this.extensions = { grafast: { planId } };
28
+ }
29
+ };
30
+ exports._GrafastError = _GrafastError;
31
+ /**
32
+ * DO NOT ALLOW CONSTRUCTION OF ERRORS OUTSIDE OF THIS MODULE!
33
+ *
34
+ * @internal
35
+ */
36
+ function newGrafastError(error, planId) {
37
+ return new exports._GrafastError(error, planId);
38
+ }
39
+ exports.newGrafastError = newGrafastError;
40
+ /**
41
+ * Is the given value a GrafastError? This is the only public API that people
42
+ * should use for looking at GrafastErrors.
43
+ */
44
+ function isGrafastError(value) {
45
+ return typeof value === "object" && value !== null && exports.$$error in value;
46
+ }
47
+ exports.isGrafastError = isGrafastError;
48
+ class SafeError extends Error {
49
+ static { _b = interfaces_js_1.$$safeError; }
50
+ constructor(message, extensions = undefined, errorOptions) {
51
+ super(message, errorOptions);
52
+ this.extensions = extensions;
53
+ this[_b] = true;
54
+ Object.setPrototypeOf(this, SafeError.prototype);
55
+ }
56
+ }
57
+ exports.SafeError = SafeError;
58
+ function isSafeError(error) {
59
+ return error[interfaces_js_1.$$safeError];
60
+ }
61
+ exports.isSafeError = isSafeError;
62
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.establishOperationPlan = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const lru_1 = tslib_1.__importDefault(require("@graphile/lru"));
6
+ const debug_1 = tslib_1.__importDefault(require("debug"));
7
+ const constraints_js_1 = require("./constraints.js");
8
+ const dev_js_1 = require("./dev.js");
9
+ const index_js_1 = require("./index.js");
10
+ const interfaces_js_1 = require("./interfaces.js");
11
+ const timeSource_js_1 = require("./timeSource.js");
12
+ const debug = (0, debug_1.default)("grafast:establishOperationPlan");
13
+ // How long is a timeout valid for? Here I've set it to 60 seconds.
14
+ const TIMEOUT_TIMEOUT = (typeof process !== "undefined" &&
15
+ typeof process.env.GRAFAST_TIMEOUT_VALIDITY_MS === "string"
16
+ ? parseInt(process.env.GRAFAST_TIMEOUT_VALIDITY_MS, 10)
17
+ : null) || 60000;
18
+ // OPTIMIZE: we should consider increasing the timeout once the process has been
19
+ // running a while (since the JIT should have kicked in) - we could even use
20
+ // `setTimeout` to trigger it after certain amount of time elapsed.
21
+ /**
22
+ * This is a development-only validation to check fragments do, in fact, match
23
+ * - even if the objects themselves differ.
24
+ */
25
+ function reallyAssertFragmentsMatch(oldFragments, fragments) {
26
+ if (oldFragments !== fragments) {
27
+ debug("fragments aren't `===` for same operation");
28
+ // Consistency check - we assume that if the operation is the same then
29
+ // the fragments will be, but this may not be the case depending on if
30
+ // GraphQL.js caches the operation node.
31
+ const oldKeys = Object.keys(oldFragments).sort();
32
+ const newKeys = Object.keys(fragments).sort();
33
+ const oldKeyStr = oldKeys.join(",");
34
+ const newKeyStr = newKeys.join(",");
35
+ if (oldKeyStr.length !== newKeyStr.length) {
36
+ throw new Error(`Inconsistency error: operation matches, but fragment keys differ: '${oldKeyStr}' != '${newKeyStr}'.`);
37
+ }
38
+ for (const key of newKeys) {
39
+ if (oldFragments[key] !== fragments[key]) {
40
+ throw new Error(`Inconsistency error: operation matches, fragment names match, but fragment '${key}' is not '===' to the previous value.`);
41
+ }
42
+ }
43
+ }
44
+ }
45
+ // Optimise this away in production.
46
+ const assertFragmentsMatch = !dev_js_1.isDev ? dev_js_1.noop : reallyAssertFragmentsMatch;
47
+ /**
48
+ * Implements the `IsOpPlanCompatible` algorithm.
49
+ *
50
+ * @remarks Due to the optimisation in `establishOperationPlan`, the schema, document
51
+ * and operationName checks have already been performed.
52
+ */
53
+ function isOperationPlanCompatible(operationPlan, variableValues, context, rootValue) {
54
+ const { variableValuesConstraints, contextConstraints, rootValueConstraints, } = operationPlan;
55
+ if (!(0, constraints_js_1.matchesConstraints)(variableValuesConstraints, variableValues)) {
56
+ return false;
57
+ }
58
+ if (!(0, constraints_js_1.matchesConstraints)(contextConstraints, context)) {
59
+ return false;
60
+ }
61
+ if (!(0, constraints_js_1.matchesConstraints)(rootValueConstraints, rootValue)) {
62
+ return false;
63
+ }
64
+ return true;
65
+ }
66
+ /**
67
+ * Implements the `EstablishOpPlan` algorithm.
68
+ *
69
+ * @remarks Though EstablishOpPlan accepts document and operationName, we
70
+ * instead accept operation and fragments since they're easier to get a hold of
71
+ * in GraphQL.js.
72
+ */
73
+ // eslint-disable-next-line @typescript-eslint/ban-types
74
+ function establishOperationPlan(schema, operation, fragments, variableValues, context, rootValue, planningTimeout = null) {
75
+ let cacheByOperation = schema.extensions.grafast?.[interfaces_js_1.$$cacheByOperation];
76
+ let cache = cacheByOperation?.get(operation);
77
+ // These two variables to make it easy to trim the linked list later.
78
+ let count = 0;
79
+ let lastButOneItem = null;
80
+ if (cache !== undefined) {
81
+ // Dev-only validation
82
+ assertFragmentsMatch(cache.fragments, fragments);
83
+ let previousItem = null;
84
+ let linkedItem = cache.possibleOperationPlans;
85
+ while (linkedItem) {
86
+ const value = linkedItem.value;
87
+ if (value instanceof index_js_1.SafeError) {
88
+ if (value.extensions?.[interfaces_js_1.$$timeout] != null) {
89
+ if (value.extensions[interfaces_js_1.$$ts] < timeSource_js_1.timeSource.now() - TIMEOUT_TIMEOUT) {
90
+ // Remove this out of date timeout
91
+ linkedItem = linkedItem.next;
92
+ if (previousItem !== null) {
93
+ previousItem.next = linkedItem;
94
+ }
95
+ else {
96
+ cache.possibleOperationPlans = linkedItem;
97
+ }
98
+ continue;
99
+ }
100
+ if (planningTimeout !== null &&
101
+ value.extensions[interfaces_js_1.$$timeout] >= planningTimeout) {
102
+ // It was a timeout error - do not retry
103
+ throw value;
104
+ }
105
+ else {
106
+ // That's Not My Timeout, let's try again.
107
+ }
108
+ }
109
+ else {
110
+ // Not a timeout error - this will always fail in the same way?
111
+ throw value;
112
+ }
113
+ }
114
+ else if (value instanceof Error) {
115
+ // Not a timeout error - this will always fail in the same way?
116
+ throw value;
117
+ }
118
+ else if (isOperationPlanCompatible(value, variableValues, context, rootValue)) {
119
+ // Hoist to top of linked list
120
+ if (previousItem !== null) {
121
+ // Remove linkedItem from existing chain
122
+ previousItem.next = linkedItem.next;
123
+ // Add rest of chain after linkedItem
124
+ linkedItem.next = cache.possibleOperationPlans;
125
+ // linkedItem is now head of chain
126
+ cache.possibleOperationPlans = linkedItem;
127
+ }
128
+ // We found a suitable OperationPlan - use that!
129
+ return value;
130
+ }
131
+ count++;
132
+ lastButOneItem = previousItem;
133
+ previousItem = linkedItem;
134
+ linkedItem = linkedItem.next;
135
+ }
136
+ }
137
+ // No suitable OperationPlan found, time to make one.
138
+ let operationPlan;
139
+ let error;
140
+ try {
141
+ operationPlan = new index_js_1.OperationPlan(schema, operation, fragments, variableValues, context, rootValue, planningTimeout);
142
+ }
143
+ catch (e) {
144
+ error = e;
145
+ }
146
+ // Store it to the cache
147
+ if (!cacheByOperation) {
148
+ if (!schema.extensions.grafast) {
149
+ schema.extensions.grafast = Object.create(null);
150
+ }
151
+ cacheByOperation = new lru_1.default({
152
+ maxLength: schema.extensions.grafast.operationsCacheMaxLength ?? 500,
153
+ });
154
+ schema.extensions.grafast[interfaces_js_1.$$cacheByOperation] = cacheByOperation;
155
+ }
156
+ const operationPlanOrError = operationPlan ?? error;
157
+ if (!cache) {
158
+ cache = {
159
+ fragments,
160
+ possibleOperationPlans: { value: operationPlanOrError, next: null },
161
+ };
162
+ cacheByOperation.set(operation, cache);
163
+ }
164
+ else {
165
+ const max = schema.extensions.grafast.operationOperationPlansCacheMaxLength ?? 50;
166
+ if (count >= max) {
167
+ // Remove the tail to ensure we never grow too big
168
+ lastButOneItem.next = null;
169
+ count--;
170
+ // LOGGING: we should announce this so that people know there's something that needs fixing in their schema (too much eval?)
171
+ }
172
+ // Add new operationPlan to top of the linked list.
173
+ cache.possibleOperationPlans = {
174
+ value: operationPlanOrError,
175
+ next: cache.possibleOperationPlans,
176
+ };
177
+ }
178
+ if (error !== undefined) {
179
+ throw error;
180
+ }
181
+ else {
182
+ return operationPlan;
183
+ }
184
+ }
185
+ exports.establishOperationPlan = establishOperationPlan;
186
+ //# sourceMappingURL=establishOperationPlan.js.map
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.execute = exports.withGrafastArgs = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const eventemitter3_1 = tslib_1.__importDefault(require("eventemitter3"));
6
+ const config_js_1 = require("./config.js");
7
+ const inspect_js_1 = require("./inspect.js");
8
+ const interfaces_js_1 = require("./interfaces.js");
9
+ const prepare_js_1 = require("./prepare.js");
10
+ const utils_js_1 = require("./utils.js");
11
+ const isDev = typeof process !== "undefined" && process.env.NODE_ENV === "development";
12
+ /**
13
+ * Used by `execute` and `subscribe`.
14
+ * @internal
15
+ */
16
+ function withGrafastArgs(args, resolvedPreset, outputDataAsString) {
17
+ const options = resolvedPreset?.grafast;
18
+ if (isDev) {
19
+ if (args.rootValue != null &&
20
+ (typeof args.rootValue !== "object" ||
21
+ Object.keys(args.rootValue).length > 0)) {
22
+ throw new Error(`Grafast executor doesn't support there being a rootValue (found ${(0, inspect_js_1.inspect)(args.rootValue)})`);
23
+ }
24
+ }
25
+ if (args.rootValue == null) {
26
+ args.rootValue = Object.create(null);
27
+ }
28
+ if (typeof args.rootValue !== "object" || args.rootValue == null) {
29
+ throw new Error("Grafast requires that the 'rootValue' be an object");
30
+ }
31
+ const explain = options?.explain;
32
+ const shouldExplain = !!explain;
33
+ let unlisten = null;
34
+ if (shouldExplain) {
35
+ const eventEmitter = new eventemitter3_1.default();
36
+ const explainOperations = [];
37
+ args.rootValue = Object.assign(Object.create(null), args.rootValue, {
38
+ [interfaces_js_1.$$eventEmitter]: eventEmitter,
39
+ [interfaces_js_1.$$extensions]: {
40
+ explain: {
41
+ operations: explainOperations,
42
+ },
43
+ },
44
+ });
45
+ const handleExplainOperation = ({ operation, }) => {
46
+ if (explain === true || (explain && explain.includes(operation.type))) {
47
+ explainOperations.push(operation);
48
+ }
49
+ };
50
+ eventEmitter.on("explainOperation", handleExplainOperation);
51
+ unlisten = () => {
52
+ eventEmitter.removeListener("explainOperation", handleExplainOperation);
53
+ };
54
+ }
55
+ const rootValue = (0, prepare_js_1.grafastPrepare)(args, {
56
+ explain: options?.explain,
57
+ outputDataAsString,
58
+ timeouts: options?.timeouts,
59
+ });
60
+ if (unlisten !== null) {
61
+ Promise.resolve(rootValue).then(unlisten, unlisten);
62
+ }
63
+ // Convert from PromiseOrDirect to PromiseOrValue
64
+ if ((0, utils_js_1.isPromiseLike)(rootValue)) {
65
+ return Promise.resolve(rootValue);
66
+ }
67
+ else {
68
+ return rootValue;
69
+ }
70
+ }
71
+ exports.withGrafastArgs = withGrafastArgs;
72
+ /**
73
+ * Use this instead of GraphQL.js' execute method and we'll automatically
74
+ * run grafastPrepare for you and handle the result.
75
+ */
76
+ function execute(args, resolvedPreset = config_js_1.NULL_PRESET, outputDataAsString = false) {
77
+ return withGrafastArgs(args, resolvedPreset, outputDataAsString);
78
+ }
79
+ exports.execute = execute;
80
+ //# sourceMappingURL=execute.js.map
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exportAsMany = exports.exportAs = void 0;
4
+ const utils_js_1 = require("./utils.js");
5
+ /**
6
+ * Marks that `thing` is exported from the `grafast` module as
7
+ * `exportName` so that `graphile-export` can convert references to `thing`
8
+ * into an `import` statement.
9
+ *
10
+ * @internal
11
+ */
12
+ function exportAs(moduleName, thing, exportName) {
13
+ if (!("$$export" in thing)) {
14
+ Object.defineProperty(thing, "$$export", {
15
+ value: { moduleName, exportName },
16
+ });
17
+ }
18
+ else {
19
+ const e = thing.$$export;
20
+ if (e.moduleName !== moduleName) {
21
+ throw new Error(`Attempted to export ${thing} as '${moduleName}.${exportName}', but it's already exported as '${e.moduleName}.${e.exportName}' (module name mismatch)`);
22
+ }
23
+ if (typeof e.exportName === "string" || exportName === "string") {
24
+ if (e.exportName !== exportName) {
25
+ throw new Error(`Attempted to export ${thing} as '${moduleName}.${exportName}', but it's already exported as '${e.moduleName}.${e.exportName}' (export name mismatch)`);
26
+ }
27
+ }
28
+ else {
29
+ // Must be arrays
30
+ if (!Array.isArray(e.exportName) ||
31
+ !Array.isArray(exportName) ||
32
+ !(0, utils_js_1.arraysMatch)(e.exportName, exportName)) {
33
+ throw new Error(`Attempted to export ${thing} as '${moduleName}.${exportName}', but it's already exported as '${e.moduleName}.${e.exportName}' (export name path mismatch)`);
34
+ }
35
+ }
36
+ }
37
+ return thing;
38
+ }
39
+ exports.exportAs = exportAs;
40
+ /**
41
+ * Marks that each value in `all` is exported from the `grafast`
42
+ * module as the key in the `all` object so that `graphile-export` can
43
+ * convert references to these values into `import` statements.
44
+ *
45
+ * @internal
46
+ */
47
+ function exportAsMany(moduleName, all) {
48
+ for (const key of Object.keys(all)) {
49
+ const value = all[key];
50
+ if ((typeof value === "object" || typeof value === "function") &&
51
+ value !== null) {
52
+ exportAs(moduleName, all[key], key);
53
+ }
54
+ }
55
+ }
56
+ exports.exportAsMany = exportAsMany;
57
+ //# sourceMappingURL=exportAs.js.map
package/dist/global.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDebug = exports.setDebug = void 0;
4
+ let debug = false;
5
+ function setDebug(newDebug) {
6
+ debug = newDebug;
7
+ }
8
+ exports.setDebug = setDebug;
9
+ function getDebug() {
10
+ return debug;
11
+ }
12
+ exports.getDebug = getDebug;
13
+ //# sourceMappingURL=global.js.map
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.grafastSync = exports.grafast = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const lru_1 = tslib_1.__importDefault(require("@graphile/lru"));
6
+ const graphql = tslib_1.__importStar(require("graphql"));
7
+ const error_js_1 = require("./error.js");
8
+ const execute_js_1 = require("./execute.js");
9
+ const index_js_1 = require("./index.js");
10
+ const interfaces_js_1 = require("./interfaces.js");
11
+ const utils_js_1 = require("./utils.js");
12
+ const { GraphQLError, parse, Source, validate, validateSchema } = graphql;
13
+ /** Rough average size per query */
14
+ const CACHE_MULTIPLIER = 100000;
15
+ const MEGABYTE = 1024 * 1024;
16
+ const queryCacheMaxSizeInBytes = 50 * MEGABYTE;
17
+ const defaultQueryCacheMaxSize = Math.max(2, Math.ceil(queryCacheMaxSizeInBytes / CACHE_MULTIPLIER));
18
+ // If we can use crypto to create a hash, great. Otherwise just use the string.
19
+ let calculateQueryHash;
20
+ try {
21
+ let lastString;
22
+ let lastHash;
23
+ const createHash = require("crypto").createHash;
24
+ if (typeof createHash !== "function") {
25
+ throw new Error("Failed to load createHash");
26
+ }
27
+ calculateQueryHash = (queryString) => {
28
+ if (queryString !== lastString) {
29
+ lastString = queryString;
30
+ lastHash = createHash("sha1").update(queryString).digest("base64");
31
+ }
32
+ return lastHash;
33
+ };
34
+ }
35
+ catch {
36
+ calculateQueryHash = (str) => str;
37
+ }
38
+ const parseAndValidate = (gqlSchema, stringOrSource) => {
39
+ let queryCache = gqlSchema.extensions.grafast?.[interfaces_js_1.$$queryCache];
40
+ if (!queryCache) {
41
+ const cacheSize = gqlSchema.extensions.grafast?.queryCacheMaxLength ??
42
+ defaultQueryCacheMaxSize;
43
+ queryCache = new lru_1.default({ maxLength: cacheSize });
44
+ if (!gqlSchema.extensions.grafast) {
45
+ gqlSchema.extensions.grafast = Object.create(null);
46
+ }
47
+ gqlSchema.extensions.grafast[interfaces_js_1.$$queryCache] = queryCache;
48
+ }
49
+ // Only cache queries that are less than 100kB, we don't want DOS attacks
50
+ // attempting to exhaust our memory.
51
+ const hash = calculateQueryHash(typeof stringOrSource === "string" ? stringOrSource : stringOrSource.body);
52
+ const result = queryCache.get(hash);
53
+ if (result !== undefined) {
54
+ return result;
55
+ }
56
+ else {
57
+ const source = typeof stringOrSource === "string"
58
+ ? new Source(stringOrSource, "GraphQL Http Request")
59
+ : stringOrSource;
60
+ let queryDocumentAst;
61
+ // Catch an errors while parsing so that we can set the `statusCode` to
62
+ // 400. Otherwise we don’t need to parse this way.
63
+ try {
64
+ queryDocumentAst = parse(source);
65
+ // Validate our GraphQL query using given rules.
66
+ const validationErrors = validate(gqlSchema, queryDocumentAst);
67
+ const cacheResult = validationErrors.length > 0 ? validationErrors : queryDocumentAst;
68
+ queryCache.set(hash, cacheResult);
69
+ return cacheResult;
70
+ }
71
+ catch (error) {
72
+ const cacheResult = [
73
+ error instanceof GraphQLError
74
+ ? error
75
+ : new GraphQLError("Validation error occurred", undefined, undefined, undefined, undefined, error),
76
+ ];
77
+ queryCache.set(hash, cacheResult);
78
+ return cacheResult;
79
+ }
80
+ }
81
+ };
82
+ /**
83
+ * A replacement for GraphQL.js' `graphql` method that calls Grafast's
84
+ * execute instead
85
+ */
86
+ function grafast(args, legacyResolvedPreset, legacyCtx) {
87
+ const { schema, source, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver, resolvedPreset = legacyResolvedPreset, requestContext = legacyCtx, } = args;
88
+ // Validate Schema
89
+ const schemaValidationErrors = validateSchema(schema);
90
+ if (schemaValidationErrors.length > 0) {
91
+ return { errors: schemaValidationErrors };
92
+ }
93
+ // Cached parse and validate
94
+ const documentOrErrors = parseAndValidate(schema, source);
95
+ if (Array.isArray(documentOrErrors)) {
96
+ return { errors: documentOrErrors };
97
+ }
98
+ const document = documentOrErrors;
99
+ const executionArgs = {
100
+ schema,
101
+ document,
102
+ rootValue,
103
+ contextValue,
104
+ variableValues,
105
+ operationName,
106
+ fieldResolver,
107
+ typeResolver,
108
+ };
109
+ if (resolvedPreset && requestContext) {
110
+ const argsOrPromise = (0, index_js_1.hookArgs)(executionArgs, resolvedPreset, requestContext);
111
+ if ((0, utils_js_1.isPromiseLike)(argsOrPromise)) {
112
+ return Promise.resolve(argsOrPromise).then((hookedArgs) => (0, execute_js_1.execute)(hookedArgs, resolvedPreset));
113
+ }
114
+ else {
115
+ // Execute
116
+ return (0, execute_js_1.execute)(argsOrPromise, resolvedPreset);
117
+ }
118
+ }
119
+ else {
120
+ // Execute
121
+ return (0, execute_js_1.execute)(executionArgs, resolvedPreset);
122
+ }
123
+ }
124
+ exports.grafast = grafast;
125
+ function grafastSync(args, legacyResolvedPreset, legacyRequestContext) {
126
+ const result = grafast(args, legacyResolvedPreset, legacyRequestContext);
127
+ if ((0, utils_js_1.isPromiseLike)(result)) {
128
+ throw new error_js_1.SafeError("Grafast execution failed to complete synchronously.");
129
+ }
130
+ return result;
131
+ }
132
+ exports.grafastSync = grafastSync;
133
+ //# sourceMappingURL=grafastGraphql.js.map