graphile-build 4.4.4 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md CHANGED
@@ -1,5 +1,4 @@
1
- The MIT License (MIT)
2
- =====================
1
+ # The MIT License (MIT)
3
2
 
4
3
  Copyright © `2018` Benjie Gillam
5
4
 
@@ -23,4 +22,3 @@ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
22
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
23
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
24
  OTHER DEALINGS IN THE SOFTWARE.
26
-
package/README.md CHANGED
@@ -36,7 +36,8 @@ And please give some love to our featured sponsors 🤩:
36
36
 
37
37
  <table><tr>
38
38
  <td align="center"><a href="http://chads.website/"><img src="https://www.graphile.org/images/sponsors/chadf.png" width="90" height="90" alt="Chad Furman" /><br />Chad Furman</a></td>
39
- <td align="center"><a href="https://timescale.com/"><img src="https://www.graphile.org/images/sponsors/timescale.svg" width="90" height="90" alt="Timescale" /><br />Timescale</a></td>
39
+ <td align="center"><a href="https://storyscript.io/?utm_source=postgraphile"><img src="https://www.graphile.org/images/sponsors/storyscript.png" width="90" height="90" alt="Storyscript" /><br />Storyscript</a></td>
40
+ <td align="center"><a href="http://p72.vc/"><img src="https://www.graphile.org/images/sponsors/p72.png" width="90" height="90" alt="Point72 Ventures" /><br />Point72 Ventures</a></td>
40
41
  </tr></table>
41
42
 
42
43
  <!-- SPONSORS_END -->
@@ -41,12 +41,15 @@ export abstract class LiveProvider {
41
41
  export class LiveMonitor {
42
42
  providers: { [namespace: string]: LiveProvider };
43
43
  subscriptionReleasersByCounter: {
44
- [counter: string]: (() => void)[],
44
+ [counter: string]: (() => void)[];
45
45
  };
46
46
  liveConditionsByCounter: { [counter: string]: Array<PredicateGenerator> };
47
47
  changeCounter: number;
48
48
 
49
- constructor(providers: { [namespace: string]: LiveProvider }, extraRootValue: any);
49
+ constructor(
50
+ providers: { [namespace: string]: LiveProvider },
51
+ extraRootValue: any
52
+ );
50
53
 
51
54
  resetBefore(currentCounter: number): void;
52
55
  release(): void;
package/node8plus/Live.js CHANGED
@@ -77,9 +77,76 @@ class LiveMonitor {
77
77
  this.changeCounter = 0;
78
78
  this.liveConditionsByCounter = {};
79
79
 
80
- if (!this.handleChange) {
81
- throw new Error("This is just to make flow happy");
82
- }
80
+ this.handleChange = function () {
81
+ /* This function is throttled to ~25ms (see constructor); it's purpose is
82
+ * to bundle up all the changes that occur in a small window into the same
83
+ * handle change flow, so _reallyHandleChange doesn't get called twice in
84
+ * quick succession. _reallyHandleChange is then further throttled with a
85
+ * larger window, BUT it triggers on both leading and trailing edge,
86
+ * whereas this only triggers on the trailing edge.
87
+ */
88
+ if (this._reallyHandleChange) {
89
+ this._reallyHandleChange();
90
+ }
91
+ };
92
+
93
+ this._reallyHandleChange = function () {
94
+ // This function is throttled to MONITOR_THROTTLE_DURATION (see constructor)
95
+ if (this.changeCallback) {
96
+ // Convince Flow this won't suddenly become null
97
+ const cb = this.changeCallback;
98
+ const counter = this.changeCounter++;
99
+ /*
100
+ * In live queries we need to know when the current result set has
101
+ * finished being calculated so that we know we've received all the
102
+ * liveRecord / liveCollection calls and can release the out of date
103
+ * ones. To achieve this, we use a custom `subscribe` function which
104
+ * calls `rootValue.release()` once the result set has been calculated.
105
+ */
106
+
107
+ this.subscriptionReleasersByCounter[String(counter)] = [];
108
+ this.liveConditionsByCounter[String(counter)] = [];
109
+ const changeRootValue = { ...this.extraRootValue,
110
+ counter,
111
+ liveCollection: this.liveCollection.bind(this, counter),
112
+ liveRecord: this.liveRecord.bind(this, counter),
113
+ liveConditions: this.liveConditionsByCounter[String(counter)],
114
+ release: () => {
115
+ // Despite it's name, this means that the execution has complete, which means we're actually releasing everything *before* this.
116
+ this.resetBefore(counter);
117
+ }
118
+ };
119
+ cb(changeRootValue);
120
+ } else {
121
+ // eslint-disable-next-line no-console
122
+ console.warn("Change occurred, but no-one was listening");
123
+ }
124
+ };
125
+
126
+ this.onChange = function (callback) {
127
+ if (this.released) {
128
+ throw new Error("Monitors cannot be reused.");
129
+ }
130
+
131
+ if (this.changeCallback) {
132
+ throw new Error("Already monitoring for changes");
133
+ } // Throttle to every 250ms
134
+
135
+
136
+ this.changeCallback = callback;
137
+
138
+ if (this.handleChange) {
139
+ setImmediate(this.handleChange);
140
+ }
141
+
142
+ return () => {
143
+ if (this.changeCallback === callback) {
144
+ this.changeCallback = null;
145
+ }
146
+
147
+ this.release();
148
+ };
149
+ };
83
150
 
84
151
  this.handleChange = (0, _lodash.throttle)(this.handleChange.bind(this), DEBOUNCE_DURATION, {
85
152
  leading: false,
@@ -122,12 +189,14 @@ class LiveMonitor {
122
189
 
123
190
  release() {
124
191
  if (this.handleChange) {
192
+ // $FlowFixMe: throttled function
125
193
  this.handleChange.cancel();
126
194
  }
127
195
 
128
196
  this.handleChange = null;
129
197
 
130
198
  if (this._reallyHandleChange) {
199
+ // $FlowFixMe: throttled function
131
200
  this._reallyHandleChange.cancel();
132
201
  }
133
202
 
@@ -135,80 +204,6 @@ class LiveMonitor {
135
204
  this.resetBefore(Infinity);
136
205
  this.providers = {};
137
206
  this.released = true;
138
- } // Tell Flow that we're okay with overwriting this
139
-
140
-
141
- handleChange() {
142
- /* This function is throttled to ~25ms (see constructor); it's purpose is
143
- * to bundle up all the changes that occur in a small window into the same
144
- * handle change flow, so _reallyHandleChange doesn't get called twice in
145
- * quick succession. _reallyHandleChange is then further throttled with a
146
- * larger window, BUT it triggers on both leading and trailing edge,
147
- * whereas this only triggers on the trailing edge.
148
- */
149
- if (this._reallyHandleChange) {
150
- this._reallyHandleChange();
151
- }
152
- } // Tell Flow that we're okay with overwriting this
153
-
154
-
155
- _reallyHandleChange() {
156
- // This function is throttled to MONITOR_THROTTLE_DURATION (see constructor)
157
- if (this.changeCallback) {
158
- // Convince Flow this won't suddenly become null
159
- const cb = this.changeCallback;
160
- const counter = this.changeCounter++;
161
- /*
162
- * In live queries we need to know when the current result set has
163
- * finished being calculated so that we know we've received all the
164
- * liveRecord / liveCollection calls and can release the out of date
165
- * ones. To achieve this, we use a custom `subscribe` function which
166
- * calls `rootValue.release()` once the result set has been calculated.
167
- */
168
-
169
- this.subscriptionReleasersByCounter[String(counter)] = [];
170
- this.liveConditionsByCounter[String(counter)] = [];
171
- const changeRootValue = { ...this.extraRootValue,
172
- counter,
173
- liveCollection: this.liveCollection.bind(this, counter),
174
- liveRecord: this.liveRecord.bind(this, counter),
175
- liveConditions: this.liveConditionsByCounter[String(counter)],
176
- release: () => {
177
- // Despite it's name, this means that the execution has complete, which means we're actually releasing everything *before* this.
178
- this.resetBefore(counter);
179
- }
180
- };
181
- cb(changeRootValue);
182
- } else {
183
- // eslint-disable-next-line no-console
184
- console.warn("Change occurred, but no-one was listening");
185
- }
186
- } // Tell Flow that we're okay with overwriting this
187
-
188
-
189
- onChange(callback) {
190
- if (this.released) {
191
- throw new Error("Monitors cannot be reused.");
192
- }
193
-
194
- if (this.changeCallback) {
195
- throw new Error("Already monitoring for changes");
196
- } // Throttle to every 250ms
197
-
198
-
199
- this.changeCallback = callback;
200
-
201
- if (this.handleChange) {
202
- setImmediate(this.handleChange);
203
- }
204
-
205
- return () => {
206
- if (this.changeCallback === callback) {
207
- this.changeCallback = null;
208
- }
209
-
210
- this.release();
211
- };
212
207
  }
213
208
 
214
209
  liveCollection(counter, namespace, collectionIdentifier, predicate = () => true) {
@@ -85,6 +85,10 @@ export class LiveMonitor {
85
85
  changeCounter: number;
86
86
  extraRootValue: any;
87
87
 
88
+ handleChange: (() => void) | null;
89
+ _reallyHandleChange: (() => void) | null;
90
+ onChange: (callback: () => void) => () => void;
91
+
88
92
  constructor(
89
93
  providers: { [namespace: string]: LiveProvider },
90
94
  extraRootValue: any
@@ -96,9 +100,72 @@ export class LiveMonitor {
96
100
  this.changeCallback = null;
97
101
  this.changeCounter = 0;
98
102
  this.liveConditionsByCounter = {};
99
- if (!this.handleChange) {
100
- throw new Error("This is just to make flow happy");
101
- }
103
+ this.handleChange = function() {
104
+ /* This function is throttled to ~25ms (see constructor); it's purpose is
105
+ * to bundle up all the changes that occur in a small window into the same
106
+ * handle change flow, so _reallyHandleChange doesn't get called twice in
107
+ * quick succession. _reallyHandleChange is then further throttled with a
108
+ * larger window, BUT it triggers on both leading and trailing edge,
109
+ * whereas this only triggers on the trailing edge.
110
+ */
111
+ if (this._reallyHandleChange) {
112
+ this._reallyHandleChange();
113
+ }
114
+ };
115
+
116
+ this._reallyHandleChange = function() {
117
+ // This function is throttled to MONITOR_THROTTLE_DURATION (see constructor)
118
+ if (this.changeCallback) {
119
+ // Convince Flow this won't suddenly become null
120
+ const cb = this.changeCallback;
121
+ const counter = this.changeCounter++;
122
+ /*
123
+ * In live queries we need to know when the current result set has
124
+ * finished being calculated so that we know we've received all the
125
+ * liveRecord / liveCollection calls and can release the out of date
126
+ * ones. To achieve this, we use a custom `subscribe` function which
127
+ * calls `rootValue.release()` once the result set has been calculated.
128
+ */
129
+ this.subscriptionReleasersByCounter[String(counter)] = [];
130
+ this.liveConditionsByCounter[String(counter)] = [];
131
+ const changeRootValue = {
132
+ ...this.extraRootValue,
133
+ counter,
134
+ liveCollection: this.liveCollection.bind(this, counter),
135
+ liveRecord: this.liveRecord.bind(this, counter),
136
+ liveConditions: this.liveConditionsByCounter[String(counter)],
137
+ release: () => {
138
+ // Despite it's name, this means that the execution has complete, which means we're actually releasing everything *before* this.
139
+ this.resetBefore(counter);
140
+ },
141
+ };
142
+ cb(changeRootValue);
143
+ } else {
144
+ // eslint-disable-next-line no-console
145
+ console.warn("Change occurred, but no-one was listening");
146
+ }
147
+ };
148
+
149
+ this.onChange = function(callback: () => void) {
150
+ if (this.released) {
151
+ throw new Error("Monitors cannot be reused.");
152
+ }
153
+ if (this.changeCallback) {
154
+ throw new Error("Already monitoring for changes");
155
+ }
156
+ // Throttle to every 250ms
157
+ this.changeCallback = callback;
158
+ if (this.handleChange) {
159
+ setImmediate(this.handleChange);
160
+ }
161
+ return () => {
162
+ if (this.changeCallback === callback) {
163
+ this.changeCallback = null;
164
+ }
165
+ this.release();
166
+ };
167
+ };
168
+
102
169
  this.handleChange = throttle(
103
170
  this.handleChange.bind(this),
104
171
  DEBOUNCE_DURATION,
@@ -149,10 +216,12 @@ export class LiveMonitor {
149
216
 
150
217
  release() {
151
218
  if (this.handleChange) {
219
+ // $FlowFixMe: throttled function
152
220
  this.handleChange.cancel();
153
221
  }
154
222
  this.handleChange = null;
155
223
  if (this._reallyHandleChange) {
224
+ // $FlowFixMe: throttled function
156
225
  this._reallyHandleChange.cancel();
157
226
  }
158
227
  this._reallyHandleChange = null;
@@ -161,78 +230,6 @@ export class LiveMonitor {
161
230
  this.released = true;
162
231
  }
163
232
 
164
- // Tell Flow that we're okay with overwriting this
165
- handleChange: (() => void) | null;
166
- handleChange() {
167
- /* This function is throttled to ~25ms (see constructor); it's purpose is
168
- * to bundle up all the changes that occur in a small window into the same
169
- * handle change flow, so _reallyHandleChange doesn't get called twice in
170
- * quick succession. _reallyHandleChange is then further throttled with a
171
- * larger window, BUT it triggers on both leading and trailing edge,
172
- * whereas this only triggers on the trailing edge.
173
- */
174
- if (this._reallyHandleChange) {
175
- this._reallyHandleChange();
176
- }
177
- }
178
-
179
- // Tell Flow that we're okay with overwriting this
180
- _reallyHandleChange: (() => void) | null;
181
- _reallyHandleChange() {
182
- // This function is throttled to MONITOR_THROTTLE_DURATION (see constructor)
183
- if (this.changeCallback) {
184
- // Convince Flow this won't suddenly become null
185
- const cb = this.changeCallback;
186
- const counter = this.changeCounter++;
187
- /*
188
- * In live queries we need to know when the current result set has
189
- * finished being calculated so that we know we've received all the
190
- * liveRecord / liveCollection calls and can release the out of date
191
- * ones. To achieve this, we use a custom `subscribe` function which
192
- * calls `rootValue.release()` once the result set has been calculated.
193
- */
194
- this.subscriptionReleasersByCounter[String(counter)] = [];
195
- this.liveConditionsByCounter[String(counter)] = [];
196
- const changeRootValue = {
197
- ...this.extraRootValue,
198
- counter,
199
- liveCollection: this.liveCollection.bind(this, counter),
200
- liveRecord: this.liveRecord.bind(this, counter),
201
- liveConditions: this.liveConditionsByCounter[String(counter)],
202
- release: () => {
203
- // Despite it's name, this means that the execution has complete, which means we're actually releasing everything *before* this.
204
- this.resetBefore(counter);
205
- },
206
- };
207
- cb(changeRootValue);
208
- } else {
209
- // eslint-disable-next-line no-console
210
- console.warn("Change occurred, but no-one was listening");
211
- }
212
- }
213
-
214
- // Tell Flow that we're okay with overwriting this
215
- onChange: (callback: () => void) => void;
216
- onChange(callback: () => void) {
217
- if (this.released) {
218
- throw new Error("Monitors cannot be reused.");
219
- }
220
- if (this.changeCallback) {
221
- throw new Error("Already monitoring for changes");
222
- }
223
- // Throttle to every 250ms
224
- this.changeCallback = callback;
225
- if (this.handleChange) {
226
- setImmediate(this.handleChange);
227
- }
228
- return () => {
229
- if (this.changeCallback === callback) {
230
- this.changeCallback = null;
231
- }
232
- this.release();
233
- };
234
- }
235
-
236
233
  liveCollection(
237
234
  counter: number,
238
235
  namespace: string,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Live.js"],"names":["DEBOUNCE_DURATION","MONITOR_THROTTLE_DURATION","Math","max","parseInt","process","env","LIVE_THROTTLE","LiveSource","subscribeCollection","_callback","_collectionIdentifier","_predicate","subscribeRecord","_recordIdentifier","LiveProvider","constructor","namespace","sources","registerSource","source","push","collectionIdentifierIsValid","recordIdentifierIsValid","LiveMonitor","providers","extraRootValue","released","subscriptionReleasersByCounter","changeCallback","changeCounter","liveConditionsByCounter","handleChange","Error","bind","leading","trailing","_reallyHandleChange","onChange","resetBefore","currentCounter","oldCounters","Object","keys","filter","n","oldCounter","releaser","release","cancel","Infinity","cb","counter","String","changeRootValue","liveCollection","liveRecord","liveConditions","console","warn","callback","setImmediate","collectionIdentifier","predicate","provider","length","recordIdentifier","LiveCoordinator","subscribe","registerProvider","getMonitor","_parent","_args","_context","_info","monitor","liveAbort","e","iterator","throw","makeAsyncIteratorFromMonitor","onClose"],"mappings":"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","sourcesContent":["// @flow\n/* eslint-disable flowtype/no-weak-types */\nimport callbackToAsyncIterator from \"./callbackToAsyncIterator\";\nimport type { GraphQLResolveInfo } from \"graphql\";\nimport { throttle } from \"lodash\";\n\ntype SubscriptionReleaser = () => void;\ntype SubscriptionCallback = () => void;\n\ntype Predicate = (record: any) => boolean;\ntype PredicateGenerator = (data: any) => Predicate;\n\nconst DEBOUNCE_DURATION = 25;\n\nconst MONITOR_THROTTLE_DURATION = Math.max(\n DEBOUNCE_DURATION + 1,\n parseInt(process.env.LIVE_THROTTLE || \"\", 10) || 500\n);\n\n/*\n * Sources are long-lived (i.e. in \"watch\" mode you just re-use the same one\n * over and over) because there is no release for them\n */\nexport class LiveSource {\n subscribeCollection(\n _callback: SubscriptionCallback,\n _collectionIdentifier: any,\n _predicate?: Predicate\n ): SubscriptionReleaser | null {\n return null;\n }\n\n subscribeRecord(\n _callback: SubscriptionCallback,\n _collectionIdentifier: any,\n _recordIdentifier: any\n ): SubscriptionReleaser | null {\n return null;\n }\n}\n\n/*\n * Providers enable a namespace, perform validation, and track the sources used\n * by that namespace within one single schema build. The should not directly use\n * any long-lived features as they do not have an explicit \"release\"/\"close\"\n * command when a new schema is built.\n */\nexport class LiveProvider {\n sources: Array<LiveSource>;\n namespace: string;\n\n constructor(namespace: string) {\n this.namespace = namespace;\n this.sources = [];\n }\n\n registerSource(source: LiveSource) {\n this.sources.push(source);\n }\n\n collectionIdentifierIsValid(_collectionIdentifier: any): boolean {\n return false;\n }\n\n recordIdentifierIsValid(\n _collectionIdentifier: any,\n _recordIdentifier: any\n ): boolean {\n return false;\n }\n}\n\n/*\n * During a single execution of GraphQL (specifically a subscription request),\n * the LiveMonitor tracks the resources viewed and subscribes to updates in them.\n */\nexport class LiveMonitor {\n released: boolean;\n providers: { [namespace: string]: LiveProvider };\n subscriptionReleasersByCounter: {\n [counter: string]: (() => void)[],\n };\n liveConditionsByCounter: { [counter: string]: Array<PredicateGenerator> };\n changeCallback: ((arg: any) => void) | null;\n changeCounter: number;\n extraRootValue: any;\n\n constructor(\n providers: { [namespace: string]: LiveProvider },\n extraRootValue: any\n ) {\n this.extraRootValue = extraRootValue;\n this.released = false;\n this.providers = providers;\n this.subscriptionReleasersByCounter = {};\n this.changeCallback = null;\n this.changeCounter = 0;\n this.liveConditionsByCounter = {};\n if (!this.handleChange) {\n throw new Error(\"This is just to make flow happy\");\n }\n this.handleChange = throttle(\n this.handleChange.bind(this),\n DEBOUNCE_DURATION,\n {\n leading: false,\n trailing: true,\n }\n );\n if (!this._reallyHandleChange) {\n throw new Error(\"This is just to make flow happy\");\n }\n this._reallyHandleChange = throttle(\n this._reallyHandleChange.bind(this),\n MONITOR_THROTTLE_DURATION - DEBOUNCE_DURATION,\n {\n leading: true,\n trailing: true,\n }\n );\n this.onChange = this.onChange.bind(this);\n }\n\n resetBefore(currentCounter: number) {\n // Clear out of date subscriptionReleasers\n {\n const oldCounters = Object.keys(\n this.subscriptionReleasersByCounter\n ).filter(n => parseInt(n, 10) < currentCounter);\n for (const oldCounter of oldCounters) {\n for (const releaser of this.subscriptionReleasersByCounter[\n oldCounter\n ]) {\n releaser();\n }\n delete this.subscriptionReleasersByCounter[oldCounter];\n }\n }\n // Clear out of date liveConditions\n {\n const oldCounters = Object.keys(this.liveConditionsByCounter).filter(\n n => parseInt(n, 10) < currentCounter\n );\n for (const oldCounter of oldCounters) {\n delete this.liveConditionsByCounter[oldCounter];\n }\n }\n }\n\n release() {\n if (this.handleChange) {\n this.handleChange.cancel();\n }\n this.handleChange = null;\n if (this._reallyHandleChange) {\n this._reallyHandleChange.cancel();\n }\n this._reallyHandleChange = null;\n this.resetBefore(Infinity);\n this.providers = {};\n this.released = true;\n }\n\n // Tell Flow that we're okay with overwriting this\n handleChange: (() => void) | null;\n handleChange() {\n /* This function is throttled to ~25ms (see constructor); it's purpose is\n * to bundle up all the changes that occur in a small window into the same\n * handle change flow, so _reallyHandleChange doesn't get called twice in\n * quick succession. _reallyHandleChange is then further throttled with a\n * larger window, BUT it triggers on both leading and trailing edge,\n * whereas this only triggers on the trailing edge.\n */\n if (this._reallyHandleChange) {\n this._reallyHandleChange();\n }\n }\n\n // Tell Flow that we're okay with overwriting this\n _reallyHandleChange: (() => void) | null;\n _reallyHandleChange() {\n // This function is throttled to MONITOR_THROTTLE_DURATION (see constructor)\n if (this.changeCallback) {\n // Convince Flow this won't suddenly become null\n const cb = this.changeCallback;\n const counter = this.changeCounter++;\n /*\n * In live queries we need to know when the current result set has\n * finished being calculated so that we know we've received all the\n * liveRecord / liveCollection calls and can release the out of date\n * ones. To achieve this, we use a custom `subscribe` function which\n * calls `rootValue.release()` once the result set has been calculated.\n */\n this.subscriptionReleasersByCounter[String(counter)] = [];\n this.liveConditionsByCounter[String(counter)] = [];\n const changeRootValue = {\n ...this.extraRootValue,\n counter,\n liveCollection: this.liveCollection.bind(this, counter),\n liveRecord: this.liveRecord.bind(this, counter),\n liveConditions: this.liveConditionsByCounter[String(counter)],\n release: () => {\n // Despite it's name, this means that the execution has complete, which means we're actually releasing everything *before* this.\n this.resetBefore(counter);\n },\n };\n cb(changeRootValue);\n } else {\n // eslint-disable-next-line no-console\n console.warn(\"Change occurred, but no-one was listening\");\n }\n }\n\n // Tell Flow that we're okay with overwriting this\n onChange: (callback: () => void) => void;\n onChange(callback: () => void) {\n if (this.released) {\n throw new Error(\"Monitors cannot be reused.\");\n }\n if (this.changeCallback) {\n throw new Error(\"Already monitoring for changes\");\n }\n // Throttle to every 250ms\n this.changeCallback = callback;\n if (this.handleChange) {\n setImmediate(this.handleChange);\n }\n return () => {\n if (this.changeCallback === callback) {\n this.changeCallback = null;\n }\n this.release();\n };\n }\n\n liveCollection(\n counter: number,\n namespace: string,\n collectionIdentifier: any,\n predicate: (record: any) => boolean = () => true\n ) {\n const handleChange = this.handleChange;\n if (this.released || !handleChange) {\n return;\n }\n const provider = this.providers[namespace];\n if (!provider || provider.sources.length === 0) return;\n if (!provider.collectionIdentifierIsValid(collectionIdentifier)) {\n throw new Error(\n `Invalid collection identifier passed to LiveMonitor[${namespace}]: ${collectionIdentifier}`\n );\n }\n for (const source of provider.sources) {\n const releaser = source.subscribeCollection(\n handleChange,\n collectionIdentifier,\n predicate\n );\n if (releaser) {\n this.subscriptionReleasersByCounter[String(counter)].push(releaser);\n }\n }\n }\n\n liveRecord(\n counter: number,\n namespace: string,\n collectionIdentifier: any,\n recordIdentifier: any\n ) {\n const handleChange = this.handleChange;\n if (this.released || !handleChange) {\n return;\n }\n // TODO: if (recordIdentifier == null) {return}\n const provider = this.providers[namespace];\n if (!provider || provider.sources.length === 0) return;\n if (!provider.collectionIdentifierIsValid(collectionIdentifier)) {\n throw new Error(\n `Invalid collection identifier passed to LiveMonitor[${namespace}]: ${collectionIdentifier}`\n );\n }\n if (\n !provider.recordIdentifierIsValid(collectionIdentifier, recordIdentifier)\n ) {\n throw new Error(\n `Invalid record identifier passed to LiveMonitor[${namespace}]: ${collectionIdentifier}`\n );\n }\n for (const source of provider.sources) {\n const releaser = source.subscribeRecord(\n handleChange,\n collectionIdentifier,\n recordIdentifier\n );\n if (releaser) {\n this.subscriptionReleasersByCounter[String(counter)].push(releaser);\n }\n }\n }\n}\n\n/*\n * There is one coordinator for each build of the GraphQL schema, it tracks the providers\n * and gives a handy `subscribe` method that can be used for live queries (assuming\n * that the `resolve` is provided the same as in a Query).\n */\nexport class LiveCoordinator {\n providers: { [namespace: string]: LiveProvider };\n\n constructor() {\n this.providers = {};\n this.subscribe = this.subscribe.bind(this);\n }\n\n registerProvider(provider: LiveProvider) {\n const { namespace } = provider;\n if (this.providers[namespace]) {\n throw new Error(`Namespace ${namespace} already registered with Live`);\n }\n this.providers[namespace] = provider;\n }\n\n registerSource(namespace: string, source: LiveSource) {\n if (!this.providers[namespace]) {\n // eslint-disable-next-line no-console\n console.warn(\n `LiveProvider '${namespace}' is not registered, skipping live source.`\n );\n return;\n }\n this.providers[namespace].registerSource(source);\n }\n\n getMonitor(extraRootValue: any) {\n return new LiveMonitor(this.providers, extraRootValue);\n }\n\n // Tell Flow that we're okay with overwriting this\n subscribe: (\n _parent: any,\n _args: any,\n context: any,\n _info: GraphQLResolveInfo\n ) => any;\n subscribe(\n _parent: any,\n _args: any,\n _context: any,\n _info: GraphQLResolveInfo\n ) {\n const monitor = this.getMonitor({\n liveAbort: e => {\n if (iterator) iterator.throw(e);\n },\n });\n const iterator = makeAsyncIteratorFromMonitor(monitor);\n return iterator;\n }\n}\n\nexport function makeAsyncIteratorFromMonitor(monitor: LiveMonitor) {\n return callbackToAsyncIterator(monitor.onChange, {\n onClose: release => {\n if (release) release();\n },\n });\n}\n"],"file":"Live.js"}
1
+ {"version":3,"sources":["../src/Live.js"],"names":["DEBOUNCE_DURATION","MONITOR_THROTTLE_DURATION","Math","max","parseInt","process","env","LIVE_THROTTLE","LiveSource","subscribeCollection","_callback","_collectionIdentifier","_predicate","subscribeRecord","_recordIdentifier","LiveProvider","constructor","namespace","sources","registerSource","source","push","collectionIdentifierIsValid","recordIdentifierIsValid","LiveMonitor","providers","extraRootValue","released","subscriptionReleasersByCounter","changeCallback","changeCounter","liveConditionsByCounter","handleChange","_reallyHandleChange","cb","counter","String","changeRootValue","liveCollection","bind","liveRecord","liveConditions","release","resetBefore","console","warn","onChange","callback","Error","setImmediate","leading","trailing","currentCounter","oldCounters","Object","keys","filter","n","oldCounter","releaser","cancel","Infinity","collectionIdentifier","predicate","provider","length","recordIdentifier","LiveCoordinator","subscribe","registerProvider","getMonitor","_parent","_args","_context","_info","monitor","liveAbort","e","iterator","throw","makeAsyncIteratorFromMonitor","onClose"],"mappings":"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","sourcesContent":["// @flow\n/* eslint-disable flowtype/no-weak-types */\nimport callbackToAsyncIterator from \"./callbackToAsyncIterator\";\nimport type { GraphQLResolveInfo } from \"graphql\";\nimport { throttle } from \"lodash\";\n\ntype SubscriptionReleaser = () => void;\ntype SubscriptionCallback = () => void;\n\ntype Predicate = (record: any) => boolean;\ntype PredicateGenerator = (data: any) => Predicate;\n\nconst DEBOUNCE_DURATION = 25;\n\nconst MONITOR_THROTTLE_DURATION = Math.max(\n DEBOUNCE_DURATION + 1,\n parseInt(process.env.LIVE_THROTTLE || \"\", 10) || 500\n);\n\n/*\n * Sources are long-lived (i.e. in \"watch\" mode you just re-use the same one\n * over and over) because there is no release for them\n */\nexport class LiveSource {\n subscribeCollection(\n _callback: SubscriptionCallback,\n _collectionIdentifier: any,\n _predicate?: Predicate\n ): SubscriptionReleaser | null {\n return null;\n }\n\n subscribeRecord(\n _callback: SubscriptionCallback,\n _collectionIdentifier: any,\n _recordIdentifier: any\n ): SubscriptionReleaser | null {\n return null;\n }\n}\n\n/*\n * Providers enable a namespace, perform validation, and track the sources used\n * by that namespace within one single schema build. The should not directly use\n * any long-lived features as they do not have an explicit \"release\"/\"close\"\n * command when a new schema is built.\n */\nexport class LiveProvider {\n sources: Array<LiveSource>;\n namespace: string;\n\n constructor(namespace: string) {\n this.namespace = namespace;\n this.sources = [];\n }\n\n registerSource(source: LiveSource) {\n this.sources.push(source);\n }\n\n collectionIdentifierIsValid(_collectionIdentifier: any): boolean {\n return false;\n }\n\n recordIdentifierIsValid(\n _collectionIdentifier: any,\n _recordIdentifier: any\n ): boolean {\n return false;\n }\n}\n\n/*\n * During a single execution of GraphQL (specifically a subscription request),\n * the LiveMonitor tracks the resources viewed and subscribes to updates in them.\n */\nexport class LiveMonitor {\n released: boolean;\n providers: { [namespace: string]: LiveProvider };\n subscriptionReleasersByCounter: {\n [counter: string]: (() => void)[],\n };\n liveConditionsByCounter: { [counter: string]: Array<PredicateGenerator> };\n changeCallback: ((arg: any) => void) | null;\n changeCounter: number;\n extraRootValue: any;\n\n handleChange: (() => void) | null;\n _reallyHandleChange: (() => void) | null;\n onChange: (callback: () => void) => () => void;\n\n constructor(\n providers: { [namespace: string]: LiveProvider },\n extraRootValue: any\n ) {\n this.extraRootValue = extraRootValue;\n this.released = false;\n this.providers = providers;\n this.subscriptionReleasersByCounter = {};\n this.changeCallback = null;\n this.changeCounter = 0;\n this.liveConditionsByCounter = {};\n this.handleChange = function() {\n /* This function is throttled to ~25ms (see constructor); it's purpose is\n * to bundle up all the changes that occur in a small window into the same\n * handle change flow, so _reallyHandleChange doesn't get called twice in\n * quick succession. _reallyHandleChange is then further throttled with a\n * larger window, BUT it triggers on both leading and trailing edge,\n * whereas this only triggers on the trailing edge.\n */\n if (this._reallyHandleChange) {\n this._reallyHandleChange();\n }\n };\n\n this._reallyHandleChange = function() {\n // This function is throttled to MONITOR_THROTTLE_DURATION (see constructor)\n if (this.changeCallback) {\n // Convince Flow this won't suddenly become null\n const cb = this.changeCallback;\n const counter = this.changeCounter++;\n /*\n * In live queries we need to know when the current result set has\n * finished being calculated so that we know we've received all the\n * liveRecord / liveCollection calls and can release the out of date\n * ones. To achieve this, we use a custom `subscribe` function which\n * calls `rootValue.release()` once the result set has been calculated.\n */\n this.subscriptionReleasersByCounter[String(counter)] = [];\n this.liveConditionsByCounter[String(counter)] = [];\n const changeRootValue = {\n ...this.extraRootValue,\n counter,\n liveCollection: this.liveCollection.bind(this, counter),\n liveRecord: this.liveRecord.bind(this, counter),\n liveConditions: this.liveConditionsByCounter[String(counter)],\n release: () => {\n // Despite it's name, this means that the execution has complete, which means we're actually releasing everything *before* this.\n this.resetBefore(counter);\n },\n };\n cb(changeRootValue);\n } else {\n // eslint-disable-next-line no-console\n console.warn(\"Change occurred, but no-one was listening\");\n }\n };\n\n this.onChange = function(callback: () => void) {\n if (this.released) {\n throw new Error(\"Monitors cannot be reused.\");\n }\n if (this.changeCallback) {\n throw new Error(\"Already monitoring for changes\");\n }\n // Throttle to every 250ms\n this.changeCallback = callback;\n if (this.handleChange) {\n setImmediate(this.handleChange);\n }\n return () => {\n if (this.changeCallback === callback) {\n this.changeCallback = null;\n }\n this.release();\n };\n };\n\n this.handleChange = throttle(\n this.handleChange.bind(this),\n DEBOUNCE_DURATION,\n {\n leading: false,\n trailing: true,\n }\n );\n if (!this._reallyHandleChange) {\n throw new Error(\"This is just to make flow happy\");\n }\n this._reallyHandleChange = throttle(\n this._reallyHandleChange.bind(this),\n MONITOR_THROTTLE_DURATION - DEBOUNCE_DURATION,\n {\n leading: true,\n trailing: true,\n }\n );\n this.onChange = this.onChange.bind(this);\n }\n\n resetBefore(currentCounter: number) {\n // Clear out of date subscriptionReleasers\n {\n const oldCounters = Object.keys(\n this.subscriptionReleasersByCounter\n ).filter(n => parseInt(n, 10) < currentCounter);\n for (const oldCounter of oldCounters) {\n for (const releaser of this.subscriptionReleasersByCounter[\n oldCounter\n ]) {\n releaser();\n }\n delete this.subscriptionReleasersByCounter[oldCounter];\n }\n }\n // Clear out of date liveConditions\n {\n const oldCounters = Object.keys(this.liveConditionsByCounter).filter(\n n => parseInt(n, 10) < currentCounter\n );\n for (const oldCounter of oldCounters) {\n delete this.liveConditionsByCounter[oldCounter];\n }\n }\n }\n\n release() {\n if (this.handleChange) {\n // $FlowFixMe: throttled function\n this.handleChange.cancel();\n }\n this.handleChange = null;\n if (this._reallyHandleChange) {\n // $FlowFixMe: throttled function\n this._reallyHandleChange.cancel();\n }\n this._reallyHandleChange = null;\n this.resetBefore(Infinity);\n this.providers = {};\n this.released = true;\n }\n\n liveCollection(\n counter: number,\n namespace: string,\n collectionIdentifier: any,\n predicate: (record: any) => boolean = () => true\n ) {\n const handleChange = this.handleChange;\n if (this.released || !handleChange) {\n return;\n }\n const provider = this.providers[namespace];\n if (!provider || provider.sources.length === 0) return;\n if (!provider.collectionIdentifierIsValid(collectionIdentifier)) {\n throw new Error(\n `Invalid collection identifier passed to LiveMonitor[${namespace}]: ${collectionIdentifier}`\n );\n }\n for (const source of provider.sources) {\n const releaser = source.subscribeCollection(\n handleChange,\n collectionIdentifier,\n predicate\n );\n if (releaser) {\n this.subscriptionReleasersByCounter[String(counter)].push(releaser);\n }\n }\n }\n\n liveRecord(\n counter: number,\n namespace: string,\n collectionIdentifier: any,\n recordIdentifier: any\n ) {\n const handleChange = this.handleChange;\n if (this.released || !handleChange) {\n return;\n }\n // TODO: if (recordIdentifier == null) {return}\n const provider = this.providers[namespace];\n if (!provider || provider.sources.length === 0) return;\n if (!provider.collectionIdentifierIsValid(collectionIdentifier)) {\n throw new Error(\n `Invalid collection identifier passed to LiveMonitor[${namespace}]: ${collectionIdentifier}`\n );\n }\n if (\n !provider.recordIdentifierIsValid(collectionIdentifier, recordIdentifier)\n ) {\n throw new Error(\n `Invalid record identifier passed to LiveMonitor[${namespace}]: ${collectionIdentifier}`\n );\n }\n for (const source of provider.sources) {\n const releaser = source.subscribeRecord(\n handleChange,\n collectionIdentifier,\n recordIdentifier\n );\n if (releaser) {\n this.subscriptionReleasersByCounter[String(counter)].push(releaser);\n }\n }\n }\n}\n\n/*\n * There is one coordinator for each build of the GraphQL schema, it tracks the providers\n * and gives a handy `subscribe` method that can be used for live queries (assuming\n * that the `resolve` is provided the same as in a Query).\n */\nexport class LiveCoordinator {\n providers: { [namespace: string]: LiveProvider };\n\n constructor() {\n this.providers = {};\n this.subscribe = this.subscribe.bind(this);\n }\n\n registerProvider(provider: LiveProvider) {\n const { namespace } = provider;\n if (this.providers[namespace]) {\n throw new Error(`Namespace ${namespace} already registered with Live`);\n }\n this.providers[namespace] = provider;\n }\n\n registerSource(namespace: string, source: LiveSource) {\n if (!this.providers[namespace]) {\n // eslint-disable-next-line no-console\n console.warn(\n `LiveProvider '${namespace}' is not registered, skipping live source.`\n );\n return;\n }\n this.providers[namespace].registerSource(source);\n }\n\n getMonitor(extraRootValue: any) {\n return new LiveMonitor(this.providers, extraRootValue);\n }\n\n // Tell Flow that we're okay with overwriting this\n subscribe: (\n _parent: any,\n _args: any,\n context: any,\n _info: GraphQLResolveInfo\n ) => any;\n subscribe(\n _parent: any,\n _args: any,\n _context: any,\n _info: GraphQLResolveInfo\n ) {\n const monitor = this.getMonitor({\n liveAbort: e => {\n if (iterator) iterator.throw(e);\n },\n });\n const iterator = makeAsyncIteratorFromMonitor(monitor);\n return iterator;\n }\n}\n\nexport function makeAsyncIteratorFromMonitor(monitor: LiveMonitor) {\n return callbackToAsyncIterator(monitor.onChange, {\n onClose: release => {\n if (release) release();\n },\n });\n}\n"],"file":"Live.js"}
@@ -39,6 +39,7 @@ export type DataForType = {
39
39
  export type InitObject = never;
40
40
 
41
41
  export interface Build {
42
+ graphql: typeof import("graphql");
42
43
  [str: string]: any;
43
44
  }
44
45
  export interface Inflection {
@@ -15,7 +15,9 @@ var graphql = _interopRequireWildcard(require("graphql"));
15
15
 
16
16
  var _events = _interopRequireDefault(require("events"));
17
17
 
18
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
18
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
19
+
20
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; if (obj != null) { var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
19
21
 
20
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
23
 
@@ -344,9 +346,16 @@ class SchemaBuilder extends _events.default {
344
346
 
345
347
  try {
346
348
  this._busy = true;
347
- this._explicitSchemaListener = listener;
349
+ this._explicitSchemaListener = listener; // We want to ignore `triggerChange` calls that occur whilst we're setting
350
+ // up the listeners to prevent an unnecessary double schema build.
351
+
352
+ let ignoreChangeTriggers = true;
348
353
 
349
354
  this.triggerChange = () => {
355
+ if (ignoreChangeTriggers) {
356
+ return;
357
+ }
358
+
350
359
  this._generatedSchema = null; // XXX: optionally debounce
351
360
 
352
361
  try {
@@ -364,7 +373,11 @@ class SchemaBuilder extends _events.default {
364
373
 
365
374
  for (const fn of this.watchers) {
366
375
  await fn(this.triggerChange);
367
- }
376
+ } // Now we're about to build the first schema, any further `triggerChange`
377
+ // calls should be honoured.
378
+
379
+
380
+ ignoreChangeTriggers = false;
368
381
 
369
382
  if (listener) {
370
383
  this.on("schema", listener);
@@ -510,7 +510,15 @@ class SchemaBuilder extends EventEmitter {
510
510
  try {
511
511
  this._busy = true;
512
512
  this._explicitSchemaListener = listener;
513
+
514
+ // We want to ignore `triggerChange` calls that occur whilst we're setting
515
+ // up the listeners to prevent an unnecessary double schema build.
516
+ let ignoreChangeTriggers = true;
517
+
513
518
  this.triggerChange = () => {
519
+ if (ignoreChangeTriggers) {
520
+ return;
521
+ }
514
522
  this._generatedSchema = null;
515
523
  // XXX: optionally debounce
516
524
  try {
@@ -530,10 +538,16 @@ class SchemaBuilder extends EventEmitter {
530
538
  for (const fn of this.watchers) {
531
539
  await fn(this.triggerChange);
532
540
  }
541
+
542
+ // Now we're about to build the first schema, any further `triggerChange`
543
+ // calls should be honoured.
544
+ ignoreChangeTriggers = false;
545
+
533
546
  if (listener) {
534
547
  this.on("schema", listener);
535
548
  }
536
549
  this.emit("schema", this.buildSchema());
550
+
537
551
  this._watching = true;
538
552
  } finally {
539
553
  this._busy = false;