@isograph/react 0.0.0-main-7fb13e90 → 0.0.0-main-9b984d79

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.
@@ -3,6 +3,8 @@ import { ParentCache } from '@isograph/react-disposable-state';
3
3
  import { RetainedQuery } from './garbageCollection';
4
4
  import { WithEncounteredRecords } from './read';
5
5
  import { FragmentReference, Variables } from './FragmentReference';
6
+ import { PromiseWrapper } from './PromiseWrapper';
7
+ import { IsographEntrypoint } from './entrypoint';
6
8
  export type ComponentOrFieldName = string;
7
9
  export type StringifiedArgs = string;
8
10
  type ComponentCache = {
@@ -35,6 +37,7 @@ export type IsographEnvironment = {
35
37
  readonly componentCache: ComponentCache;
36
38
  readonly subscriptions: Subscriptions;
37
39
  readonly fragmentCache: CacheMap<FragmentReference<any, any>>;
40
+ readonly entrypointArtifactCache: Map<string, PromiseWrapper<IsographEntrypoint<any, any>>>;
38
41
  readonly retainedQueries: Set<RetainedQuery>;
39
42
  readonly gcBuffer: Array<RetainedQuery>;
40
43
  readonly gcBufferSize: number;
@@ -64,4 +67,5 @@ export declare function defaultMissingFieldHandler(_storeRecord: StoreRecord, _r
64
67
  } | null, variables: Variables | null): Link | undefined;
65
68
  export declare function assertLink(link: DataTypeValue): Link | null | undefined;
66
69
  export declare function getLink(maybeLink: DataTypeValue): Link | null;
70
+ export declare function getOrLoadIsographArtifact(environment: IsographEnvironment, key: string, loader: () => Promise<IsographEntrypoint<any, any>>): PromiseWrapper<IsographEntrypoint<any, any>>;
67
71
  export {};
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getLink = exports.assertLink = exports.defaultMissingFieldHandler = exports.createIsographStore = exports.createIsographEnvironment = exports.ROOT_ID = void 0;
3
+ exports.getOrLoadIsographArtifact = exports.getLink = exports.assertLink = exports.defaultMissingFieldHandler = exports.createIsographStore = exports.createIsographEnvironment = exports.ROOT_ID = void 0;
4
+ const PromiseWrapper_1 = require("./PromiseWrapper");
4
5
  exports.ROOT_ID = '__ROOT';
5
6
  const DEFAULT_GC_BUFFER_SIZE = 10;
6
7
  function createIsographEnvironment(store, networkFunction, missingFieldHandler) {
@@ -11,6 +12,7 @@ function createIsographEnvironment(store, networkFunction, missingFieldHandler)
11
12
  componentCache: {},
12
13
  subscriptions: new Set(),
13
14
  fragmentCache: {},
15
+ entrypointArtifactCache: new Map(),
14
16
  retainedQueries: new Set(),
15
17
  gcBuffer: [],
16
18
  gcBufferSize: DEFAULT_GC_BUFFER_SIZE,
@@ -58,3 +60,13 @@ function getLink(maybeLink) {
58
60
  return null;
59
61
  }
60
62
  exports.getLink = getLink;
63
+ function getOrLoadIsographArtifact(environment, key, loader) {
64
+ const value = environment.entrypointArtifactCache.get(key);
65
+ if (value != null) {
66
+ return value;
67
+ }
68
+ const wrapped = (0, PromiseWrapper_1.wrapPromise)(loader());
69
+ environment.entrypointArtifactCache.set(key, wrapped);
70
+ return wrapped;
71
+ }
72
+ exports.getOrLoadIsographArtifact = getOrLoadIsographArtifact;
@@ -12,6 +12,11 @@ export type IsographEntrypoint<TReadFromStore extends Object, TClientFieldValue>
12
12
  readonly normalizationAst: NormalizationAst;
13
13
  readonly readerWithRefetchQueries: ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>;
14
14
  };
15
+ export type IsographEntrypointLoader<TReadFromStore extends Object, TClientFieldValue> = {
16
+ readonly kind: 'EntrypointLoader';
17
+ readonly typeAndField: string;
18
+ readonly loader: () => Promise<IsographEntrypoint<TReadFromStore, TClientFieldValue>>;
19
+ };
15
20
  export type NormalizationAstNode = NormalizationScalarField | NormalizationLinkedField | NormalizationInlineFragment;
16
21
  export type NormalizationAst = ReadonlyArray<NormalizationAstNode>;
17
22
  export type NormalizationScalarField = {
package/dist/core/read.js CHANGED
@@ -193,32 +193,40 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, netwo
193
193
  case 'Resolver': {
194
194
  const usedRefetchQueries = field.usedRefetchQueries;
195
195
  const resolverRefetchQueries = usedRefetchQueries.map((index) => nestedRefetchQueries[index]);
196
- const kind = field.readerArtifact.kind;
197
- if (kind === 'EagerReaderArtifact') {
198
- const data = readData(environment, field.readerArtifact.readerAst, root, variables, resolverRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords);
199
- if (data.kind === 'MissingData') {
200
- return {
201
- kind: 'MissingData',
202
- reason: 'Missing data for ' + field.alias + ' on root ' + root,
203
- nestedReason: data,
204
- };
196
+ switch (field.readerArtifact.kind) {
197
+ case 'EagerReaderArtifact': {
198
+ const data = readData(environment, field.readerArtifact.readerAst, root, variables, resolverRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords);
199
+ if (data.kind === 'MissingData') {
200
+ return {
201
+ kind: 'MissingData',
202
+ reason: 'Missing data for ' + field.alias + ' on root ' + root,
203
+ nestedReason: data,
204
+ };
205
+ }
206
+ else {
207
+ target[field.alias] = field.readerArtifact.resolver(data.data);
208
+ }
209
+ break;
205
210
  }
206
- else {
207
- target[field.alias] = field.readerArtifact.resolver(data.data);
211
+ case 'ComponentReaderArtifact': {
212
+ target[field.alias] = (0, componentCache_1.getOrCreateCachedComponent)(environment, field.readerArtifact.componentName, {
213
+ kind: 'FragmentReference',
214
+ readerWithRefetchQueries: (0, PromiseWrapper_1.wrapResolvedValue)({
215
+ kind: 'ReaderWithRefetchQueries',
216
+ readerArtifact: field.readerArtifact,
217
+ nestedRefetchQueries: resolverRefetchQueries,
218
+ }),
219
+ root,
220
+ variables: generateChildVariableMap(variables, field.arguments),
221
+ networkRequest,
222
+ }, networkRequestOptions);
223
+ break;
224
+ }
225
+ default: {
226
+ let _ = field.readerArtifact;
227
+ _;
228
+ throw new Error('Unexpected kind');
208
229
  }
209
- }
210
- else if (kind === 'ComponentReaderArtifact') {
211
- target[field.alias] = (0, componentCache_1.getOrCreateCachedComponent)(environment, field.readerArtifact.componentName, {
212
- kind: 'FragmentReference',
213
- readerWithRefetchQueries: (0, PromiseWrapper_1.wrapResolvedValue)({
214
- kind: 'ReaderWithRefetchQueries',
215
- readerArtifact: field.readerArtifact,
216
- nestedRefetchQueries: resolverRefetchQueries,
217
- }),
218
- root,
219
- variables: generateChildVariableMap(variables, field.arguments),
220
- networkRequest,
221
- }, networkRequestOptions);
222
230
  }
223
231
  break;
224
232
  }
@@ -251,21 +259,65 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, netwo
251
259
  stableStringifyArgs(localVariables),
252
260
  // Fetcher
253
261
  () => {
254
- const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.makeNetworkRequest)(environment, field.entrypoint, localVariables);
255
- const fragmentReference = {
256
- kind: 'FragmentReference',
257
- readerWithRefetchQueries: (0, PromiseWrapper_1.wrapResolvedValue)({
258
- kind: 'ReaderWithRefetchQueries',
259
- readerArtifact: field.entrypoint.readerWithRefetchQueries.readerArtifact,
260
- nestedRefetchQueries: field.entrypoint.readerWithRefetchQueries
261
- .nestedRefetchQueries,
262
- }),
263
- // TODO localVariables is not guaranteed to have an id field
264
- root: localVariables.id,
265
- variables: localVariables,
266
- networkRequest,
262
+ const fragmentReferenceAndDisposeFromEntrypoint = (entrypoint) => {
263
+ const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.makeNetworkRequest)(environment, entrypoint, localVariables);
264
+ const fragmentReference = {
265
+ kind: 'FragmentReference',
266
+ readerWithRefetchQueries: (0, PromiseWrapper_1.wrapResolvedValue)({
267
+ kind: 'ReaderWithRefetchQueries',
268
+ readerArtifact: entrypoint.readerWithRefetchQueries.readerArtifact,
269
+ nestedRefetchQueries: entrypoint.readerWithRefetchQueries
270
+ .nestedRefetchQueries,
271
+ }),
272
+ // TODO localVariables is not guaranteed to have an id field
273
+ root: localVariables.id,
274
+ variables: localVariables,
275
+ networkRequest,
276
+ };
277
+ return [fragmentReference, disposeNetworkRequest];
267
278
  };
268
- return [fragmentReference, disposeNetworkRequest];
279
+ if (field.entrypoint.kind === 'Entrypoint') {
280
+ return fragmentReferenceAndDisposeFromEntrypoint(field.entrypoint);
281
+ }
282
+ else {
283
+ const isographArtifactPromiseWrapper = (0, IsographEnvironment_1.getOrLoadIsographArtifact)(environment, field.entrypoint.typeAndField, field.entrypoint.loader);
284
+ const state = (0, PromiseWrapper_1.getPromiseState)(isographArtifactPromiseWrapper);
285
+ if (state.kind === 'Ok') {
286
+ return fragmentReferenceAndDisposeFromEntrypoint(state.value);
287
+ }
288
+ else {
289
+ // Promise is pending or thrown
290
+ let entrypointLoaderState = { kind: 'EntrypointNotLoaded' };
291
+ const networkRequest = (0, PromiseWrapper_1.wrapPromise)(isographArtifactPromiseWrapper.promise.then((entrypoint) => {
292
+ if (entrypointLoaderState.kind === 'EntrypointNotLoaded') {
293
+ const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.makeNetworkRequest)(environment, entrypoint, localVariables);
294
+ entrypointLoaderState = {
295
+ kind: 'NetworkRequestStarted',
296
+ disposeNetworkRequest,
297
+ };
298
+ return networkRequest.promise;
299
+ }
300
+ }));
301
+ const readerWithRefetchPromise = isographArtifactPromiseWrapper.promise.then((entrypoint) => entrypoint.readerWithRefetchQueries);
302
+ const fragmentReference = {
303
+ kind: 'FragmentReference',
304
+ readerWithRefetchQueries: (0, PromiseWrapper_1.wrapPromise)(readerWithRefetchPromise),
305
+ // TODO localVariables is not guaranteed to have an id field
306
+ root: localVariables.id,
307
+ variables: localVariables,
308
+ networkRequest,
309
+ };
310
+ return [
311
+ fragmentReference,
312
+ () => {
313
+ if (entrypointLoaderState.kind === 'NetworkRequestStarted') {
314
+ entrypointLoaderState.disposeNetworkRequest();
315
+ }
316
+ entrypointLoaderState = { kind: 'Disposed' };
317
+ },
318
+ ];
319
+ }
320
+ }
269
321
  },
270
322
  ];
271
323
  };
@@ -2,7 +2,7 @@
2
2
  import { Factory } from '@isograph/disposable-types';
3
3
  import { FragmentReference } from './FragmentReference';
4
4
  import { ComponentOrFieldName, DataId, IsographEnvironment } from './IsographEnvironment';
5
- import { IsographEntrypoint, RefetchQueryNormalizationArtifact, RefetchQueryNormalizationArtifactWrapper } from './entrypoint';
5
+ import { IsographEntrypoint, IsographEntrypointLoader, RefetchQueryNormalizationArtifact, RefetchQueryNormalizationArtifactWrapper } from './entrypoint';
6
6
  import { Arguments } from './util';
7
7
  export type TopLevelReaderArtifact<TReadFromStore extends Object, TClientFieldValue, TComponentProps extends Record<string, never>> = EagerReaderArtifact<TReadFromStore, TClientFieldValue> | ComponentReaderArtifact<TReadFromStore, TComponentProps>;
8
8
  export type EagerReaderArtifact<TReadFromStore extends Object, TClientFieldValue> = {
@@ -56,7 +56,7 @@ export type ReaderLoadableField = {
56
56
  readonly name: string;
57
57
  readonly queryArguments: Arguments | null;
58
58
  readonly refetchReaderAst: ReaderAst<any>;
59
- readonly entrypoint: IsographEntrypoint<any, any>;
59
+ readonly entrypoint: IsographEntrypoint<any, any> | IsographEntrypointLoader<any, any>;
60
60
  };
61
61
  type StableId = string;
62
62
  export type LoadableField<TArgs, TResult> = (args: TArgs) => [StableId, Factory<FragmentReference<any, TResult>>];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isograph/react",
3
- "version": "0.0.0-main-7fb13e90",
3
+ "version": "0.0.0-main-9b984d79",
4
4
  "description": "Use Isograph with React",
5
5
  "homepage": "https://isograph.dev",
6
6
  "main": "dist/index.js",
@@ -17,9 +17,9 @@
17
17
  "tsc": "tsc"
18
18
  },
19
19
  "dependencies": {
20
- "@isograph/disposable-types": "0.0.0-main-7fb13e90",
21
- "@isograph/react-disposable-state": "0.0.0-main-7fb13e90",
22
- "@isograph/reference-counted-pointer": "0.0.0-main-7fb13e90"
20
+ "@isograph/disposable-types": "0.0.0-main-9b984d79",
21
+ "@isograph/react-disposable-state": "0.0.0-main-9b984d79",
22
+ "@isograph/reference-counted-pointer": "0.0.0-main-9b984d79"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "react": "18.2.0"
@@ -2,6 +2,8 @@ import { ParentCache } from '@isograph/react-disposable-state';
2
2
  import { RetainedQuery } from './garbageCollection';
3
3
  import { WithEncounteredRecords } from './read';
4
4
  import { FragmentReference, Variables } from './FragmentReference';
5
+ import { PromiseWrapper, wrapPromise } from './PromiseWrapper';
6
+ import { IsographEntrypoint } from './entrypoint';
5
7
 
6
8
  export type ComponentOrFieldName = string;
7
9
  export type StringifiedArgs = string;
@@ -27,6 +29,7 @@ type AnyRecordSubscription = {
27
29
 
28
30
  type Subscription = FragmentSubscription<Object> | AnyRecordSubscription;
29
31
  type Subscriptions = Set<Subscription>;
32
+ // Should this be a map?
30
33
  type CacheMap<T> = { [index: string]: ParentCache<T> };
31
34
 
32
35
  export type IsographEnvironment = {
@@ -38,6 +41,11 @@ export type IsographEnvironment = {
38
41
  // N.B. this must be <any, any>, but all *usages* of this should go through
39
42
  // a function that adds type parameters.
40
43
  readonly fragmentCache: CacheMap<FragmentReference<any, any>>;
44
+ // TODO make this a CacheMap and add GC
45
+ readonly entrypointArtifactCache: Map<
46
+ string,
47
+ PromiseWrapper<IsographEntrypoint<any, any>>
48
+ >;
41
49
  readonly retainedQueries: Set<RetainedQuery>;
42
50
  readonly gcBuffer: Array<RetainedQuery>;
43
51
  readonly gcBufferSize: number;
@@ -103,6 +111,7 @@ export function createIsographEnvironment(
103
111
  componentCache: {},
104
112
  subscriptions: new Set(),
105
113
  fragmentCache: {},
114
+ entrypointArtifactCache: new Map(),
106
115
  retainedQueries: new Set(),
107
116
  gcBuffer: [],
108
117
  gcBufferSize: DEFAULT_GC_BUFFER_SIZE,
@@ -158,3 +167,17 @@ export function getLink(maybeLink: DataTypeValue): Link | null {
158
167
  }
159
168
  return null;
160
169
  }
170
+
171
+ export function getOrLoadIsographArtifact(
172
+ environment: IsographEnvironment,
173
+ key: string,
174
+ loader: () => Promise<IsographEntrypoint<any, any>>,
175
+ ): PromiseWrapper<IsographEntrypoint<any, any>> {
176
+ const value = environment.entrypointArtifactCache.get(key);
177
+ if (value != null) {
178
+ return value;
179
+ }
180
+ const wrapped = wrapPromise(loader());
181
+ environment.entrypointArtifactCache.set(key, wrapped);
182
+ return wrapped;
183
+ }
@@ -29,6 +29,17 @@ export type IsographEntrypoint<
29
29
  >;
30
30
  };
31
31
 
32
+ export type IsographEntrypointLoader<
33
+ TReadFromStore extends Object,
34
+ TClientFieldValue,
35
+ > = {
36
+ readonly kind: 'EntrypointLoader';
37
+ readonly typeAndField: string;
38
+ readonly loader: () => Promise<
39
+ IsographEntrypoint<TReadFromStore, TClientFieldValue>
40
+ >;
41
+ };
42
+
32
43
  export type NormalizationAstNode =
33
44
  | NormalizationScalarField
34
45
  | NormalizationLinkedField
package/src/core/read.ts CHANGED
@@ -1,17 +1,24 @@
1
+ import { CleanupFn } from '@isograph/isograph-disposable-types/dist';
1
2
  import { getParentRecordKey, onNextChange } from './cache';
2
3
  import { getOrCreateCachedComponent } from './componentCache';
3
- import { RefetchQueryNormalizationArtifactWrapper } from './entrypoint';
4
+ import {
5
+ IsographEntrypoint,
6
+ RefetchQueryNormalizationArtifactWrapper,
7
+ } from './entrypoint';
4
8
  import { FragmentReference, Variables } from './FragmentReference';
5
9
  import {
6
10
  assertLink,
7
11
  DataId,
8
12
  defaultMissingFieldHandler,
13
+ getOrLoadIsographArtifact,
9
14
  IsographEnvironment,
10
15
  } from './IsographEnvironment';
11
16
  import { makeNetworkRequest } from './makeNetworkRequest';
12
17
  import {
18
+ getPromiseState,
13
19
  PromiseWrapper,
14
20
  readPromise,
21
+ wrapPromise,
15
22
  wrapResolvedValue,
16
23
  } from './PromiseWrapper';
17
24
  import { ReaderAst } from './reader';
@@ -291,44 +298,53 @@ function readData<TReadFromStore>(
291
298
  (index) => nestedRefetchQueries[index],
292
299
  );
293
300
 
294
- const kind = field.readerArtifact.kind;
295
- if (kind === 'EagerReaderArtifact') {
296
- const data = readData(
297
- environment,
298
- field.readerArtifact.readerAst,
299
- root,
300
- variables,
301
- resolverRefetchQueries,
302
- networkRequest,
303
- networkRequestOptions,
304
- mutableEncounteredRecords,
305
- );
306
- if (data.kind === 'MissingData') {
307
- return {
308
- kind: 'MissingData',
309
- reason: 'Missing data for ' + field.alias + ' on root ' + root,
310
- nestedReason: data,
311
- };
312
- } else {
313
- target[field.alias] = field.readerArtifact.resolver(data.data);
314
- }
315
- } else if (kind === 'ComponentReaderArtifact') {
316
- target[field.alias] = getOrCreateCachedComponent(
317
- environment,
318
- field.readerArtifact.componentName,
319
- {
320
- kind: 'FragmentReference',
321
- readerWithRefetchQueries: wrapResolvedValue({
322
- kind: 'ReaderWithRefetchQueries',
323
- readerArtifact: field.readerArtifact,
324
- nestedRefetchQueries: resolverRefetchQueries,
325
- }),
301
+ switch (field.readerArtifact.kind) {
302
+ case 'EagerReaderArtifact': {
303
+ const data = readData(
304
+ environment,
305
+ field.readerArtifact.readerAst,
326
306
  root,
327
- variables: generateChildVariableMap(variables, field.arguments),
307
+ variables,
308
+ resolverRefetchQueries,
328
309
  networkRequest,
329
- } as const,
330
- networkRequestOptions,
331
- );
310
+ networkRequestOptions,
311
+ mutableEncounteredRecords,
312
+ );
313
+ if (data.kind === 'MissingData') {
314
+ return {
315
+ kind: 'MissingData',
316
+ reason: 'Missing data for ' + field.alias + ' on root ' + root,
317
+ nestedReason: data,
318
+ };
319
+ } else {
320
+ target[field.alias] = field.readerArtifact.resolver(data.data);
321
+ }
322
+ break;
323
+ }
324
+ case 'ComponentReaderArtifact': {
325
+ target[field.alias] = getOrCreateCachedComponent(
326
+ environment,
327
+ field.readerArtifact.componentName,
328
+ {
329
+ kind: 'FragmentReference',
330
+ readerWithRefetchQueries: wrapResolvedValue({
331
+ kind: 'ReaderWithRefetchQueries',
332
+ readerArtifact: field.readerArtifact,
333
+ nestedRefetchQueries: resolverRefetchQueries,
334
+ }),
335
+ root,
336
+ variables: generateChildVariableMap(variables, field.arguments),
337
+ networkRequest,
338
+ } as const,
339
+ networkRequestOptions,
340
+ );
341
+ break;
342
+ }
343
+ default: {
344
+ let _: never = field.readerArtifact;
345
+ _;
346
+ throw new Error('Unexpected kind');
347
+ }
332
348
  }
333
349
  break;
334
350
  }
@@ -376,30 +392,111 @@ function readData<TReadFromStore>(
376
392
  stableStringifyArgs(localVariables),
377
393
  // Fetcher
378
394
  () => {
379
- const [networkRequest, disposeNetworkRequest] =
380
- makeNetworkRequest(
381
- environment,
395
+ const fragmentReferenceAndDisposeFromEntrypoint = (
396
+ entrypoint: IsographEntrypoint<any, any>,
397
+ ): [FragmentReference<any, any>, CleanupFn] => {
398
+ const [networkRequest, disposeNetworkRequest] =
399
+ makeNetworkRequest(environment, entrypoint, localVariables);
400
+
401
+ const fragmentReference: FragmentReference<any, any> = {
402
+ kind: 'FragmentReference',
403
+ readerWithRefetchQueries: wrapResolvedValue({
404
+ kind: 'ReaderWithRefetchQueries',
405
+ readerArtifact:
406
+ entrypoint.readerWithRefetchQueries.readerArtifact,
407
+ nestedRefetchQueries:
408
+ entrypoint.readerWithRefetchQueries
409
+ .nestedRefetchQueries,
410
+ } as const),
411
+
412
+ // TODO localVariables is not guaranteed to have an id field
413
+ root: localVariables.id,
414
+ variables: localVariables,
415
+ networkRequest,
416
+ };
417
+ return [fragmentReference, disposeNetworkRequest];
418
+ };
419
+
420
+ if (field.entrypoint.kind === 'Entrypoint') {
421
+ return fragmentReferenceAndDisposeFromEntrypoint(
382
422
  field.entrypoint,
383
- localVariables,
384
423
  );
424
+ } else {
425
+ const isographArtifactPromiseWrapper =
426
+ getOrLoadIsographArtifact(
427
+ environment,
428
+ field.entrypoint.typeAndField,
429
+ field.entrypoint.loader,
430
+ );
431
+ const state = getPromiseState(isographArtifactPromiseWrapper);
432
+ if (state.kind === 'Ok') {
433
+ return fragmentReferenceAndDisposeFromEntrypoint(
434
+ state.value,
435
+ );
436
+ } else {
437
+ // Promise is pending or thrown
385
438
 
386
- const fragmentReference: FragmentReference<any, any> = {
387
- kind: 'FragmentReference',
388
- readerWithRefetchQueries: wrapResolvedValue({
389
- kind: 'ReaderWithRefetchQueries',
390
- readerArtifact:
391
- field.entrypoint.readerWithRefetchQueries.readerArtifact,
392
- nestedRefetchQueries:
393
- field.entrypoint.readerWithRefetchQueries
394
- .nestedRefetchQueries,
395
- } as const),
439
+ let entrypointLoaderState:
440
+ | {
441
+ kind: 'EntrypointNotLoaded';
442
+ }
443
+ | {
444
+ kind: 'NetworkRequestStarted';
445
+ disposeNetworkRequest: CleanupFn;
446
+ }
447
+ | { kind: 'Disposed' } = { kind: 'EntrypointNotLoaded' };
396
448
 
397
- // TODO localVariables is not guaranteed to have an id field
398
- root: localVariables.id,
399
- variables: localVariables,
400
- networkRequest,
401
- };
402
- return [fragmentReference, disposeNetworkRequest];
449
+ const networkRequest = wrapPromise(
450
+ isographArtifactPromiseWrapper.promise.then(
451
+ (entrypoint) => {
452
+ if (
453
+ entrypointLoaderState.kind === 'EntrypointNotLoaded'
454
+ ) {
455
+ const [networkRequest, disposeNetworkRequest] =
456
+ makeNetworkRequest(
457
+ environment,
458
+ entrypoint,
459
+ localVariables,
460
+ );
461
+ entrypointLoaderState = {
462
+ kind: 'NetworkRequestStarted',
463
+ disposeNetworkRequest,
464
+ };
465
+ return networkRequest.promise;
466
+ }
467
+ },
468
+ ),
469
+ );
470
+ const readerWithRefetchPromise =
471
+ isographArtifactPromiseWrapper.promise.then(
472
+ (entrypoint) => entrypoint.readerWithRefetchQueries,
473
+ );
474
+
475
+ const fragmentReference: FragmentReference<any, any> = {
476
+ kind: 'FragmentReference',
477
+ readerWithRefetchQueries: wrapPromise(
478
+ readerWithRefetchPromise,
479
+ ),
480
+
481
+ // TODO localVariables is not guaranteed to have an id field
482
+ root: localVariables.id,
483
+ variables: localVariables,
484
+ networkRequest,
485
+ };
486
+
487
+ return [
488
+ fragmentReference,
489
+ () => {
490
+ if (
491
+ entrypointLoaderState.kind === 'NetworkRequestStarted'
492
+ ) {
493
+ entrypointLoaderState.disposeNetworkRequest();
494
+ }
495
+ entrypointLoaderState = { kind: 'Disposed' };
496
+ },
497
+ ];
498
+ }
499
+ }
403
500
  },
404
501
  ];
405
502
  };
@@ -7,6 +7,7 @@ import {
7
7
  } from './IsographEnvironment';
8
8
  import {
9
9
  IsographEntrypoint,
10
+ IsographEntrypointLoader,
10
11
  RefetchQueryNormalizationArtifact,
11
12
  RefetchQueryNormalizationArtifactWrapper,
12
13
  } from './entrypoint';
@@ -111,7 +112,10 @@ export type ReaderLoadableField = {
111
112
  readonly queryArguments: Arguments | null;
112
113
  readonly refetchReaderAst: ReaderAst<any>;
113
114
 
114
- readonly entrypoint: IsographEntrypoint<any, any>;
115
+ // TODO we should not type these as any
116
+ readonly entrypoint:
117
+ | IsographEntrypoint<any, any>
118
+ | IsographEntrypointLoader<any, any>;
115
119
  };
116
120
 
117
121
  type StableId = string;
@@ -41,7 +41,7 @@ const artifact: IsographEntrypoint<
41
41
  kind: "ReaderWithRefetchQueries",
42
42
  nestedRefetchQueries,
43
43
  readerArtifact: readerResolver,
44
- }
44
+ },
45
45
  };
46
46
 
47
47
  export default artifact;
@@ -77,7 +77,7 @@ const artifact: IsographEntrypoint<
77
77
  kind: "ReaderWithRefetchQueries",
78
78
  nestedRefetchQueries,
79
79
  readerArtifact: readerResolver,
80
- }
80
+ },
81
81
  };
82
82
 
83
83
  export default artifact;
@@ -40,7 +40,7 @@ const artifact: IsographEntrypoint<
40
40
  kind: "ReaderWithRefetchQueries",
41
41
  nestedRefetchQueries,
42
42
  readerArtifact: readerResolver,
43
- }
43
+ },
44
44
  };
45
45
 
46
46
  export default artifact;