@isograph/react 0.0.0-main-ae8aa2fe → 0.0.0-main-d3ef6e33

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 (42) hide show
  1. package/dist/core/FragmentReference.d.ts +2 -0
  2. package/dist/core/PromiseWrapper.d.ts +17 -4
  3. package/dist/core/PromiseWrapper.js +35 -10
  4. package/dist/core/cache.d.ts +2 -2
  5. package/dist/core/cache.js +31 -4
  6. package/dist/core/componentCache.d.ts +2 -1
  7. package/dist/core/componentCache.js +2 -2
  8. package/dist/core/entrypoint.d.ts +2 -0
  9. package/dist/core/makeNetworkRequest.d.ts +2 -2
  10. package/dist/core/makeNetworkRequest.js +6 -2
  11. package/dist/core/read.d.ts +5 -1
  12. package/dist/core/read.js +75 -33
  13. package/dist/index.d.ts +6 -6
  14. package/dist/index.js +6 -3
  15. package/dist/loadable-hooks/useClientSideDefer.js +0 -1
  16. package/dist/react/{FragmentReferenceReader.d.ts → FragmentReader.d.ts} +4 -1
  17. package/dist/react/{FragmentReferenceReader.js → FragmentReader.js} +5 -4
  18. package/dist/react/useImperativeReference.d.ts +1 -1
  19. package/dist/react/useImperativeReference.js +3 -2
  20. package/dist/react/useLazyReference.js +2 -3
  21. package/dist/react/useReadAndSubscribe.d.ts +2 -2
  22. package/dist/react/useReadAndSubscribe.js +5 -3
  23. package/dist/react/useRerenderOnChange.d.ts +1 -2
  24. package/dist/react/useRerenderOnChange.js +3 -1
  25. package/dist/react/useResult.d.ts +4 -1
  26. package/dist/react/useResult.js +17 -4
  27. package/package.json +3 -3
  28. package/src/core/FragmentReference.ts +2 -0
  29. package/src/core/PromiseWrapper.ts +58 -12
  30. package/src/core/cache.ts +80 -57
  31. package/src/core/componentCache.ts +6 -1
  32. package/src/core/entrypoint.ts +1 -0
  33. package/src/core/makeNetworkRequest.ts +11 -6
  34. package/src/core/read.ts +108 -41
  35. package/src/index.ts +35 -25
  36. package/src/loadable-hooks/useClientSideDefer.ts +1 -1
  37. package/src/react/{FragmentReferenceReader.tsx → FragmentReader.tsx} +8 -2
  38. package/src/react/useImperativeReference.ts +4 -3
  39. package/src/react/useLazyReference.ts +2 -3
  40. package/src/react/useReadAndSubscribe.ts +8 -5
  41. package/src/react/useRerenderOnChange.ts +2 -2
  42. package/src/react/useResult.ts +28 -1
@@ -4,13 +4,15 @@ exports.useReadAndSubscribe = void 0;
4
4
  const react_1 = require("react");
5
5
  const read_1 = require("../core/read");
6
6
  const useRerenderOnChange_1 = require("./useRerenderOnChange");
7
+ const IsographEnvironmentProvider_1 = require("./IsographEnvironmentProvider");
7
8
  /**
8
9
  * Read the data from a fragment reference and subscribe to updates.
9
10
  * Does not pass the data to the fragment reference's resolver function.
10
11
  */
11
- function useReadAndSubscribe(environment, fragmentReference) {
12
- const [readOutDataAndRecords, setReadOutDataAndRecords] = (0, react_1.useState)(() => (0, read_1.readButDoNotEvaluate)(environment, fragmentReference));
13
- (0, useRerenderOnChange_1.useRerenderOnChange)(environment, readOutDataAndRecords, fragmentReference, setReadOutDataAndRecords);
12
+ function useReadAndSubscribe(fragmentReference, networkRequestOptions) {
13
+ const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
14
+ const [readOutDataAndRecords, setReadOutDataAndRecords] = (0, react_1.useState)(() => (0, read_1.readButDoNotEvaluate)(environment, fragmentReference, networkRequestOptions));
15
+ (0, useRerenderOnChange_1.useRerenderOnChange)(readOutDataAndRecords, fragmentReference, setReadOutDataAndRecords);
14
16
  return readOutDataAndRecords.item;
15
17
  }
16
18
  exports.useReadAndSubscribe = useReadAndSubscribe;
@@ -1,4 +1,3 @@
1
- import { IsographEnvironment } from '../core/IsographEnvironment';
2
1
  import { WithEncounteredRecords } from '../core/read';
3
2
  import { FragmentReference } from '../core/FragmentReference';
4
- export declare function useRerenderOnChange<TReadFromStore extends Object>(environment: IsographEnvironment, encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<any, any>, setEncounteredDataAndRecords: (data: WithEncounteredRecords<TReadFromStore>) => void): void;
3
+ export declare function useRerenderOnChange<TReadFromStore extends Object>(encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<any, any>, setEncounteredDataAndRecords: (data: WithEncounteredRecords<TReadFromStore>) => void): void;
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useRerenderOnChange = void 0;
4
4
  const react_1 = require("react");
5
5
  const cache_1 = require("../core/cache");
6
+ const IsographEnvironmentProvider_1 = require("./IsographEnvironmentProvider");
6
7
  // TODO add unit tests for this. Add integration tests that test
7
8
  // behavior when the encounteredRecords underneath a fragment change.
8
- function useRerenderOnChange(environment, encounteredDataAndRecords, fragmentReference, setEncounteredDataAndRecords) {
9
+ function useRerenderOnChange(encounteredDataAndRecords, fragmentReference, setEncounteredDataAndRecords) {
10
+ const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
9
11
  (0, react_1.useEffect)(() => {
10
12
  return (0, cache_1.subscribe)(environment, encounteredDataAndRecords, fragmentReference, (newEncounteredDataAndRecords) => {
11
13
  setEncounteredDataAndRecords(newEncounteredDataAndRecords);
@@ -1,2 +1,5 @@
1
1
  import { FragmentReference } from '../core/FragmentReference';
2
- export declare function useResult<TReadFromStore extends Object, TClientFieldValue>(fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>): TClientFieldValue;
2
+ import { NetworkRequestReaderOptions } from '../core/read';
3
+ import { PromiseWrapper } from '../core/PromiseWrapper';
4
+ export declare function useResult<TReadFromStore extends Object, TClientFieldValue>(fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>, networkRequestOptions: NetworkRequestReaderOptions): TClientFieldValue;
5
+ export declare function maybeUnwrapNetworkRequest(networkRequest: PromiseWrapper<void, any>, networkRequestOptions: NetworkRequestReaderOptions): void;
@@ -1,20 +1,33 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useResult = void 0;
3
+ exports.maybeUnwrapNetworkRequest = exports.useResult = void 0;
4
4
  const IsographEnvironmentProvider_1 = require("../react/IsographEnvironmentProvider");
5
5
  const componentCache_1 = require("../core/componentCache");
6
6
  const useReadAndSubscribe_1 = require("./useReadAndSubscribe");
7
- function useResult(fragmentReference) {
7
+ const PromiseWrapper_1 = require("../core/PromiseWrapper");
8
+ function useResult(fragmentReference, networkRequestOptions) {
8
9
  const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
10
+ maybeUnwrapNetworkRequest(fragmentReference.networkRequest, networkRequestOptions);
9
11
  switch (fragmentReference.readerArtifact.kind) {
10
12
  case 'ComponentReaderArtifact': {
11
13
  // @ts-expect-error
12
- return (0, componentCache_1.getOrCreateCachedComponent)(environment, fragmentReference.readerArtifact.componentName, fragmentReference);
14
+ return (0, componentCache_1.getOrCreateCachedComponent)(environment, fragmentReference.readerArtifact.componentName, fragmentReference, networkRequestOptions);
13
15
  }
14
16
  case 'EagerReaderArtifact': {
15
- const data = (0, useReadAndSubscribe_1.useReadAndSubscribe)(environment, fragmentReference);
17
+ const data = (0, useReadAndSubscribe_1.useReadAndSubscribe)(fragmentReference, networkRequestOptions);
16
18
  return fragmentReference.readerArtifact.resolver(data);
17
19
  }
18
20
  }
19
21
  }
20
22
  exports.useResult = useResult;
23
+ function maybeUnwrapNetworkRequest(networkRequest, networkRequestOptions) {
24
+ const state = (0, PromiseWrapper_1.getPromiseState)(networkRequest);
25
+ if (state.kind === 'Err' && networkRequestOptions.throwOnNetworkError) {
26
+ throw state.error;
27
+ }
28
+ else if (state.kind === 'Pending' &&
29
+ networkRequestOptions.suspendIfInFlight) {
30
+ throw state.promise;
31
+ }
32
+ }
33
+ exports.maybeUnwrapNetworkRequest = maybeUnwrapNetworkRequest;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isograph/react",
3
- "version": "0.0.0-main-ae8aa2fe",
3
+ "version": "0.0.0-main-d3ef6e33",
4
4
  "description": "Use Isograph with React",
5
5
  "homepage": "https://isograph.dev",
6
6
  "main": "dist/index.js",
@@ -17,8 +17,8 @@
17
17
  "tsc": "tsc"
18
18
  },
19
19
  "dependencies": {
20
- "@isograph/disposable-types": "0.0.0-main-ae8aa2fe",
21
- "@isograph/react-disposable-state": "0.0.0-main-ae8aa2fe",
20
+ "@isograph/disposable-types": "0.0.0-main-d3ef6e33",
21
+ "@isograph/react-disposable-state": "0.0.0-main-d3ef6e33",
22
22
  "react": "^18.2.0"
23
23
  },
24
24
  "devDependencies": {
@@ -1,6 +1,7 @@
1
1
  import { DataId } from './IsographEnvironment';
2
2
  import { RefetchQueryNormalizationArtifactWrapper } from '../core/entrypoint';
3
3
  import { TopLevelReaderArtifact } from './reader';
4
+ import { PromiseWrapper } from './PromiseWrapper';
4
5
 
5
6
  // TODO type this better
6
7
  export type VariableValue = string | number | boolean | null | object;
@@ -21,4 +22,5 @@ export type FragmentReference<
21
22
  readonly variables: Variables | null;
22
23
  // TODO: We should instead have ReaderAst<TClientFieldProps>
23
24
  readonly nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[];
25
+ readonly networkRequest: PromiseWrapper<void, any>;
24
26
  };
@@ -1,29 +1,75 @@
1
+ export type AnyError = any;
2
+
1
3
  const NOT_SET: Symbol = Symbol('NOT_SET');
2
4
  type NotSet = typeof NOT_SET;
3
5
 
6
+ type Result<T, E> =
7
+ | {
8
+ kind: 'Ok';
9
+ value: T;
10
+ }
11
+ | {
12
+ kind: 'Err';
13
+ error: E;
14
+ };
15
+
4
16
  /**
5
17
  * Invariant:
6
18
  * Before the promise is resolved, value becomes non-null.
7
19
  */
8
- export type PromiseWrapper<T> = {
20
+ export type PromiseWrapper<T, E> = {
9
21
  readonly promise: Promise<T>;
10
- value: Exclude<T, NotSet> | NotSet;
22
+ result: Result<Exclude<T, NotSet>, E> | NotSet;
11
23
  };
12
24
 
13
- export function wrapPromise<T>(promise: Promise<T>): PromiseWrapper<T> {
25
+ export function wrapPromise<T>(promise: Promise<T>): PromiseWrapper<T, any> {
14
26
  // TODO confirm suspense works if the promise is already resolved.
15
- const wrapper: PromiseWrapper<T> = { promise, value: NOT_SET };
16
- promise.then((v) => {
17
- // T is assignable to Exclude<T, Symbol> | Symbol
18
- wrapper.value = v as any;
19
- });
27
+ const wrapper: PromiseWrapper<T, any> = { promise, result: NOT_SET };
28
+ promise
29
+ .then((v) => {
30
+ // v is assignable to Exclude<T, Symbol> | Symbol
31
+ wrapper.result = { kind: 'Ok', value: v as any };
32
+ })
33
+ .catch((e) => {
34
+ // e is assignable to Exclude<T, Symbol> | Symbol
35
+ wrapper.result = { kind: 'Err', error: e as any };
36
+ });
20
37
  return wrapper;
21
38
  }
22
39
 
23
- export function useReadPromise<T>(p: PromiseWrapper<T>): T {
24
- if (p.value !== NOT_SET) {
25
- // Safety: p.value is either NOT_SET or an actual value.
26
- return p.value as any;
40
+ export function readPromise<T, E>(p: PromiseWrapper<T, E>): T {
41
+ const { result } = p;
42
+ if (result !== NOT_SET) {
43
+ // Safety: p.result is either NOT_SET or an actual value.
44
+ const resultKind = result as Result<T, any>;
45
+ if (resultKind.kind === 'Ok') {
46
+ return resultKind.value;
47
+ } else {
48
+ throw resultKind.error;
49
+ }
27
50
  }
51
+
28
52
  throw p.promise;
29
53
  }
54
+
55
+ export type PromiseState<T, E> =
56
+ | {
57
+ kind: 'Pending';
58
+ promise: Promise<T>;
59
+ }
60
+ | Result<T, E>;
61
+
62
+ export function getPromiseState<T, E>(
63
+ p: PromiseWrapper<T, E>,
64
+ ): PromiseState<T, E> {
65
+ const { result } = p;
66
+ if (result !== NOT_SET) {
67
+ // Safety: p.result is either NOT_SET or an actual value.
68
+ const resultKind = result as Result<T, any>;
69
+ return resultKind;
70
+ }
71
+ return {
72
+ kind: 'Pending',
73
+ promise: p.promise,
74
+ };
75
+ }
package/src/core/cache.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Factory, ParentCache } from '@isograph/react-disposable-state';
2
- import { PromiseWrapper } from './PromiseWrapper';
2
+ import { AnyError, PromiseWrapper } from './PromiseWrapper';
3
3
  import {
4
4
  DataId,
5
5
  ROOT_ID,
@@ -80,15 +80,10 @@ export function getOrCreateCacheForArtifact<
80
80
  environment: IsographEnvironment,
81
81
  artifact: IsographEntrypoint<TReadFromStore, TClientFieldValue>,
82
82
  variables: Variables,
83
- ): ParentCache<PromiseWrapper<TClientFieldValue>> {
83
+ ): ParentCache<PromiseWrapper<void, AnyError>> {
84
84
  const cacheKey = artifact.queryText + JSON.stringify(stableCopy(variables));
85
- const factory: Factory<PromiseWrapper<TClientFieldValue>> = () =>
86
- makeNetworkRequest<TClientFieldValue>(environment, artifact, variables);
87
- return getOrCreateCache<PromiseWrapper<TClientFieldValue>>(
88
- environment,
89
- cacheKey,
90
- factory,
91
- );
85
+ const factory = () => makeNetworkRequest(environment, artifact, variables);
86
+ return getOrCreateCache(environment, cacheKey, factory);
92
87
  }
93
88
 
94
89
  type NetworkResponseScalarValue = string | number | boolean;
@@ -183,64 +178,92 @@ export function onNextChange(environment: IsographEnvironment): Promise<void> {
183
178
  });
184
179
  }
185
180
 
181
+ // Calls to readButDoNotEvaluate can suspend (i.e. throw a promise).
182
+ // Maybe in the future, they will be able to throw errors.
183
+ //
184
+ // That's probably okay to ignore. We don't, however, want to prevent
185
+ // updating other subscriptions if one subscription had missing data.
186
+ function withErrorHandling<T>(f: (t: T) => void): (t: T) => void {
187
+ return (t) => {
188
+ try {
189
+ return f(t);
190
+ } catch {}
191
+ };
192
+ }
193
+
186
194
  function callSubscriptions(
187
195
  environment: IsographEnvironment,
188
196
  recordsEncounteredWhenNormalizing: Set<DataId>,
189
197
  ) {
190
- environment.subscriptions.forEach((subscription) => {
191
- switch (subscription.kind) {
192
- case 'FragmentSubscription': {
193
- // TODO if there are multiple components subscribed to the same
194
- // fragment, we will call readButNotEvaluate multiple times. We
195
- // should fix that.
196
- if (
197
- hasOverlappingIds(
198
- recordsEncounteredWhenNormalizing,
199
- subscription.encounteredDataAndRecords.encounteredRecords,
200
- )
201
- ) {
202
- const newEncounteredDataAndRecords = readButDoNotEvaluate(
203
- environment,
204
- subscription.fragmentReference,
205
- );
206
-
198
+ environment.subscriptions.forEach(
199
+ withErrorHandling((subscription) => {
200
+ switch (subscription.kind) {
201
+ case 'FragmentSubscription': {
202
+ // TODO if there are multiple components subscribed to the same
203
+ // fragment, we will call readButNotEvaluate multiple times. We
204
+ // should fix that.
207
205
  if (
208
- !areEqualObjectsWithDeepComparison(
209
- subscription.encounteredDataAndRecords.item,
210
- newEncounteredDataAndRecords.item,
206
+ hasOverlappingIds(
207
+ recordsEncounteredWhenNormalizing,
208
+ subscription.encounteredDataAndRecords.encounteredRecords,
211
209
  )
212
210
  ) {
213
- if (typeof window !== 'undefined' && window.__LOG) {
214
- console.log('Deep equality - No', {
215
- fragmentReference: subscription.fragmentReference,
216
- old: subscription.encounteredDataAndRecords.item,
217
- new: newEncounteredDataAndRecords.item,
218
- });
219
- }
220
- // TODO deep compare values
221
- subscription.callback(newEncounteredDataAndRecords);
222
- } else {
223
- if (typeof window !== 'undefined' && window.__LOG) {
224
- console.log('Deep equality - Yes', {
225
- fragmentReference: subscription.fragmentReference,
226
- old: subscription.encounteredDataAndRecords.item,
227
- });
211
+ const newEncounteredDataAndRecords = readButDoNotEvaluate(
212
+ environment,
213
+ subscription.fragmentReference,
214
+ // Is this wrong?
215
+ // Reasons to think no:
216
+ // - we are only updating the read-out value, and the network
217
+ // options only affect whether we throw.
218
+ // - the component will re-render, and re-throw on its own, anyway.
219
+ //
220
+ // Reasons to think not:
221
+ // - it seems more efficient to suspend here and not update state,
222
+ // if we expect that the component will just throw anyway
223
+ // - consistency
224
+ // - it's also weird, this is called from makeNetworkRequest, where
225
+ // we don't currently pass network request options
226
+ {},
227
+ );
228
+
229
+ if (
230
+ !areEqualObjectsWithDeepComparison(
231
+ subscription.encounteredDataAndRecords.item,
232
+ newEncounteredDataAndRecords.item,
233
+ )
234
+ ) {
235
+ if (typeof window !== 'undefined' && window.__LOG) {
236
+ console.log('Deep equality - No', {
237
+ fragmentReference: subscription.fragmentReference,
238
+ old: subscription.encounteredDataAndRecords.item,
239
+ new: newEncounteredDataAndRecords.item,
240
+ });
241
+ }
242
+ // TODO deep compare values
243
+ subscription.callback(newEncounteredDataAndRecords);
244
+ } else {
245
+ if (typeof window !== 'undefined' && window.__LOG) {
246
+ console.log('Deep equality - Yes', {
247
+ fragmentReference: subscription.fragmentReference,
248
+ old: subscription.encounteredDataAndRecords.item,
249
+ });
250
+ }
228
251
  }
229
252
  }
253
+ return;
254
+ }
255
+ case 'AnyRecords': {
256
+ return subscription.callback();
257
+ }
258
+ default: {
259
+ // Ensure we have covered all variants
260
+ const _: never = subscription;
261
+ _;
262
+ throw new Error('Unexpected case');
230
263
  }
231
- return;
232
- }
233
- case 'AnyRecords': {
234
- return subscription.callback();
235
- }
236
- default: {
237
- // Ensure we have covered all variants
238
- const _: never = subscription;
239
- _;
240
- throw new Error('Unexpected case');
241
264
  }
242
- }
243
- });
265
+ }),
266
+ );
244
267
  }
245
268
 
246
269
  function hasOverlappingIds(set1: Set<DataId>, set2: Set<DataId>): boolean {
@@ -563,7 +586,7 @@ function getStoreKeyChunkForArgumentValue(
563
586
  return argumentValue.value;
564
587
  }
565
588
  case 'Variable': {
566
- return variables[argumentValue.name];
589
+ return variables[argumentValue.name] ?? 'null';
567
590
  }
568
591
  case 'String': {
569
592
  return argumentValue.value;
@@ -2,11 +2,13 @@ import { stableCopy } from './cache';
2
2
  import { IsographEnvironment } from './IsographEnvironment';
3
3
  import { FragmentReference } from './FragmentReference';
4
4
  import { useReadAndSubscribe } from '../react/useReadAndSubscribe';
5
+ import { NetworkRequestReaderOptions } from './read';
5
6
 
6
7
  export function getOrCreateCachedComponent(
7
8
  environment: IsographEnvironment,
8
9
  componentName: string,
9
10
  fragmentReference: FragmentReference<any, any>,
11
+ networkRequestOptions: NetworkRequestReaderOptions,
10
12
  ): React.FC<any> {
11
13
  // cachedComponentsById is a three layer cache: id, then component name, then
12
14
  // stringified args. These three, together, uniquely identify a read at a given
@@ -27,7 +29,10 @@ export function getOrCreateCachedComponent(
27
29
  byArgs[stringifiedArgs] ??
28
30
  (() => {
29
31
  function Component(additionalRuntimeProps: { [key: string]: any }) {
30
- const data = useReadAndSubscribe(environment, fragmentReference);
32
+ const data = useReadAndSubscribe(
33
+ fragmentReference,
34
+ networkRequestOptions,
35
+ );
31
36
 
32
37
  if (typeof window !== 'undefined' && window.__LOG) {
33
38
  console.log(
@@ -74,3 +74,4 @@ export type ExtractReadFromStore<Type> =
74
74
  Type extends IsographEntrypoint<infer X, any> ? X : never;
75
75
  export type ExtractResolverResult<Type> =
76
76
  Type extends IsographEntrypoint<any, infer X> ? X : never;
77
+ export type ExtractProps<Type> = Type extends React.FC<infer X> ? X : never;
@@ -11,14 +11,14 @@ import {
11
11
  unretainQuery,
12
12
  } from './garbageCollection';
13
13
  import { IsographEnvironment } from './IsographEnvironment';
14
- import { PromiseWrapper, wrapPromise } from './PromiseWrapper';
14
+ import { AnyError, PromiseWrapper, wrapPromise } from './PromiseWrapper';
15
15
  import { normalizeData } from './cache';
16
16
 
17
- export function makeNetworkRequest<T>(
17
+ export function makeNetworkRequest(
18
18
  environment: IsographEnvironment,
19
19
  artifact: RefetchQueryNormalizationArtifact | IsographEntrypoint<any, any>,
20
20
  variables: Variables,
21
- ): ItemCleanupPair<PromiseWrapper<T>> {
21
+ ): ItemCleanupPair<PromiseWrapper<void, AnyError>> {
22
22
  if (typeof window !== 'undefined' && window.__LOG) {
23
23
  console.log('make network request', artifact, variables);
24
24
  }
@@ -33,6 +33,13 @@ export function makeNetworkRequest<T>(
33
33
  console.log('network response', artifact, networkResponse);
34
34
  }
35
35
 
36
+ if (networkResponse.errors != null) {
37
+ // @ts-expect-error Why are we getting the wrong constructor here?
38
+ throw new Error('GraphQL network response had errors', {
39
+ cause: networkResponse,
40
+ });
41
+ }
42
+
36
43
  if (status.kind === 'UndisposedIncomplete') {
37
44
  normalizeData(
38
45
  environment,
@@ -51,13 +58,11 @@ export function makeNetworkRequest<T>(
51
58
  };
52
59
  retainQuery(environment, retainedQuery);
53
60
  }
54
- // TODO return null
55
- return networkResponse;
56
61
  });
57
62
 
58
63
  const wrapper = wrapPromise(promise);
59
64
 
60
- const response: ItemCleanupPair<PromiseWrapper<T>> = [
65
+ const response: ItemCleanupPair<PromiseWrapper<void, AnyError>> = [
61
66
  wrapper,
62
67
  () => {
63
68
  if (status.kind === 'UndisposedComplete') {