@isograph/react 0.0.0-main-366b2007 → 0.0.0-main-5046aeef

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.
@@ -5,7 +5,7 @@ export type VariableValue = string | number | boolean | null | object;
5
5
  export type Variables = {
6
6
  readonly [index: string]: VariableValue;
7
7
  };
8
- export type FragmentReference<TReadFromStore extends Object, TClientFieldValue> = {
8
+ export type FragmentReference<TReadFromStore extends object, TClientFieldValue> = {
9
9
  readonly kind: 'FragmentReference';
10
10
  readonly readerWithRefetchQueries: PromiseWrapper<ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>>;
11
11
  readonly root: DataId;
@@ -15,7 +15,7 @@ type ComponentCache = {
15
15
  };
16
16
  };
17
17
  };
18
- export type FragmentSubscription<TReadFromStore extends Object> = {
18
+ export type FragmentSubscription<TReadFromStore extends object> = {
19
19
  readonly kind: 'FragmentSubscription';
20
20
  readonly callback: (newEncounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>) => void;
21
21
  /** The value read out from the previous call to readButDoNotEvaluate */
@@ -4,14 +4,14 @@ import { IsographEntrypoint, NormalizationAst, NormalizationLinkedField, Normali
4
4
  import { ReaderLinkedField, ReaderScalarField, type ReaderAst } from './reader';
5
5
  import { WithEncounteredRecords } from './read';
6
6
  import { FragmentReference, Variables } from './FragmentReference';
7
- export declare function getOrCreateItemInSuspenseCache<TReadFromStore extends Object, TClientFieldValue>(environment: IsographEnvironment, index: string, factory: Factory<FragmentReference<TReadFromStore, TClientFieldValue>>): ParentCache<FragmentReference<TReadFromStore, TClientFieldValue>>;
7
+ export declare function getOrCreateItemInSuspenseCache<TReadFromStore extends object, TClientFieldValue>(environment: IsographEnvironment, index: string, factory: Factory<FragmentReference<TReadFromStore, TClientFieldValue>>): ParentCache<FragmentReference<TReadFromStore, TClientFieldValue>>;
8
8
  /**
9
9
  * Creates a copy of the provided value, ensuring any nested objects have their
10
10
  * keys sorted such that equivalent values would have identical JSON.stringify
11
11
  * results.
12
12
  */
13
13
  export declare function stableCopy<T>(value: T): T;
14
- export declare function getOrCreateCacheForArtifact<TReadFromStore extends Object, TClientFieldValue>(environment: IsographEnvironment, entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: Variables): ParentCache<FragmentReference<TReadFromStore, TClientFieldValue>>;
14
+ export declare function getOrCreateCacheForArtifact<TReadFromStore extends object, TClientFieldValue>(environment: IsographEnvironment, entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: Variables): ParentCache<FragmentReference<TReadFromStore, TClientFieldValue>>;
15
15
  type NetworkResponseScalarValue = string | number | boolean;
16
16
  type NetworkResponseValue = NetworkResponseScalarValue | null | NetworkResponseObject | NetworkResponseObject[] | NetworkResponseScalarValue[];
17
17
  type NetworkResponseObject = {
@@ -20,7 +20,7 @@ type NetworkResponseObject = {
20
20
  };
21
21
  export declare function normalizeData(environment: IsographEnvironment, normalizationAst: NormalizationAst, networkResponse: NetworkResponseObject, variables: Variables, nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[]): Set<DataId>;
22
22
  export declare function subscribeToAnyChange(environment: IsographEnvironment, callback: () => void): () => void;
23
- export declare function subscribe<TReadFromStore extends Object>(environment: IsographEnvironment, encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<TReadFromStore, any>, callback: (newEncounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>) => void, readerAst: ReaderAst<TReadFromStore>): () => void;
23
+ export declare function subscribe<TReadFromStore extends object>(environment: IsographEnvironment, encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<TReadFromStore, any>, callback: (newEncounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>) => void, readerAst: ReaderAst<TReadFromStore>): () => void;
24
24
  export declare function onNextChange(environment: IsographEnvironment): Promise<void>;
25
25
  export declare function getParentRecordKey(astNode: NormalizationLinkedField | NormalizationScalarField | ReaderLinkedField | ReaderScalarField, variables: Variables): string;
26
26
  export declare const FIRST_SPLIT_KEY = "____";
@@ -1,18 +1,18 @@
1
1
  /// <reference types="react" />
2
2
  import { TopLevelReaderArtifact } from './reader';
3
3
  import { Arguments } from './util';
4
- export type ReaderWithRefetchQueries<TReadFromStore extends Object, TClientFieldValue> = {
4
+ export type ReaderWithRefetchQueries<TReadFromStore extends object, TClientFieldValue> = {
5
5
  readonly kind: 'ReaderWithRefetchQueries';
6
6
  readonly readerArtifact: TopLevelReaderArtifact<TReadFromStore, TClientFieldValue, any>;
7
7
  readonly nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[];
8
8
  };
9
- export type IsographEntrypoint<TReadFromStore extends Object, TClientFieldValue> = {
9
+ export type IsographEntrypoint<TReadFromStore extends object, TClientFieldValue> = {
10
10
  readonly kind: 'Entrypoint';
11
11
  readonly queryText: string;
12
12
  readonly normalizationAst: NormalizationAst;
13
13
  readonly readerWithRefetchQueries: ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>;
14
14
  };
15
- export type IsographEntrypointLoader<TReadFromStore extends Object, TClientFieldValue> = {
15
+ export type IsographEntrypointLoader<TReadFromStore extends object, TClientFieldValue> = {
16
16
  readonly kind: 'EntrypointLoader';
17
17
  readonly typeAndField: string;
18
18
  readonly loader: () => Promise<IsographEntrypoint<TReadFromStore, TClientFieldValue>>;
@@ -44,7 +44,7 @@ export type RefetchQueryNormalizationArtifactWrapper = {
44
44
  readonly artifact: RefetchQueryNormalizationArtifact;
45
45
  readonly allowedVariables: string[];
46
46
  };
47
- export declare function assertIsEntrypoint<TReadFromStore extends Object, TClientFieldValue>(value: IsographEntrypoint<TReadFromStore, TClientFieldValue> | ((_: any) => any) | any): asserts value is IsographEntrypoint<TReadFromStore, TClientFieldValue>;
47
+ export declare function assertIsEntrypoint<TReadFromStore extends object, TClientFieldValue>(value: IsographEntrypoint<TReadFromStore, TClientFieldValue> | ((_: any) => any) | any): asserts value is IsographEntrypoint<TReadFromStore, TClientFieldValue>;
48
48
  export type ExtractReadFromStore<Type> = Type extends IsographEntrypoint<infer X, any> ? X : never;
49
49
  export type ExtractResolverResult<Type> = Type extends IsographEntrypoint<any, infer X> ? X : never;
50
50
  export type ExtractProps<Type> = Type extends React.FC<infer X> ? X : never;
@@ -4,7 +4,7 @@ export type WithEncounteredRecords<T> = {
4
4
  readonly encounteredRecords: Set<DataId>;
5
5
  readonly item: T;
6
6
  };
7
- export declare function readButDoNotEvaluate<TReadFromStore extends Object>(environment: IsographEnvironment, fragmentReference: FragmentReference<TReadFromStore, unknown>, networkRequestOptions: NetworkRequestReaderOptions): WithEncounteredRecords<TReadFromStore>;
7
+ export declare function readButDoNotEvaluate<TReadFromStore extends object>(environment: IsographEnvironment, fragmentReference: FragmentReference<TReadFromStore, unknown>, networkRequestOptions: NetworkRequestReaderOptions): WithEncounteredRecords<TReadFromStore>;
8
8
  export type NetworkRequestReaderOptions = {
9
9
  suspendIfInFlight: boolean;
10
10
  throwOnNetworkError: boolean;
@@ -4,19 +4,19 @@ import { FragmentReference, Variables } from './FragmentReference';
4
4
  import { ComponentOrFieldName, DataId, IsographEnvironment } from './IsographEnvironment';
5
5
  import { IsographEntrypoint, IsographEntrypointLoader, RefetchQueryNormalizationArtifact, RefetchQueryNormalizationArtifactWrapper } from './entrypoint';
6
6
  import { Arguments } from './util';
7
- export type TopLevelReaderArtifact<TReadFromStore extends Object, TClientFieldValue, TComponentProps extends Record<string, never>, TVariables = Variables> = EagerReaderArtifact<TReadFromStore, TClientFieldValue, TVariables> | ComponentReaderArtifact<TReadFromStore, TComponentProps, TVariables>;
8
- export type EagerReaderArtifact<TReadFromStore extends Object, TClientFieldValue, TVariables = Variables> = {
7
+ export type TopLevelReaderArtifact<TReadFromStore extends object, TClientFieldValue, TComponentProps extends Record<string, never>, TVariables = Variables> = EagerReaderArtifact<TReadFromStore, TClientFieldValue, TVariables> | ComponentReaderArtifact<TReadFromStore, TComponentProps, TVariables>;
8
+ export type EagerReaderArtifact<TReadFromStore extends object, TClientFieldValue, TVariables = Variables> = {
9
9
  readonly kind: 'EagerReaderArtifact';
10
10
  readonly readerAst: ReaderAst<TReadFromStore>;
11
11
  readonly resolver: (data: ResolverFirstParameter<TReadFromStore, TVariables>) => TClientFieldValue;
12
12
  };
13
- export type ComponentReaderArtifact<TReadFromStore extends Object, TComponentProps extends Record<string, unknown> = Record<string, never>, TVariables = Variables> = {
13
+ export type ComponentReaderArtifact<TReadFromStore extends object, TComponentProps extends Record<string, unknown> = Record<string, never>, TVariables = Variables> = {
14
14
  readonly kind: 'ComponentReaderArtifact';
15
15
  readonly componentName: ComponentOrFieldName;
16
16
  readonly readerAst: ReaderAst<TReadFromStore>;
17
17
  readonly resolver: (data: ResolverFirstParameter<TReadFromStore, TVariables>, runtimeProps: TComponentProps) => React.ReactNode;
18
18
  };
19
- export type ResolverFirstParameter<TReadFromStore extends Object, TVariables = Variables> = {
19
+ export type ResolverFirstParameter<TReadFromStore extends object, TVariables = Variables> = {
20
20
  readonly data: TReadFromStore;
21
21
  readonly parameters: TVariables;
22
22
  };
@@ -3,6 +3,6 @@ import { LoadableField } from '../core/reader';
3
3
  export declare function useClientSideDefer<TResult>(loadableField: LoadableField<void, TResult>): {
4
4
  fragmentReference: FragmentReference<Record<string, never>, TResult>;
5
5
  };
6
- export declare function useClientSideDefer<TArgs extends Object, TResult>(loadableField: LoadableField<TArgs, TResult>, args: TArgs): {
6
+ export declare function useClientSideDefer<TArgs extends object, TResult>(loadableField: LoadableField<TArgs, TResult>, args: TArgs): {
7
7
  fragmentReference: FragmentReference<TArgs, TResult>;
8
8
  };
@@ -11,13 +11,8 @@ type UseSkipLimitReturnValue<TArgs, TItem> = {
11
11
  readonly results: ReadonlyArray<TItem>;
12
12
  readonly pendingFragment: FragmentReference<any, ReadonlyArray<TItem>>;
13
13
  };
14
- /**
15
- * NOTE: this hook does not subscribe to changes. This is a known
16
- * issue. If you are running into this issue, reach out on GitHub/
17
- * Twitter, and we'll fix the issue.
18
- */
19
14
  export declare function useSkipLimitPagination<TArgs extends {
20
15
  skip: number | void | null;
21
16
  limit: number | void | null;
22
- }, TItem, TReadFromStore extends Object>(loadableField: LoadableField<TArgs, ReadonlyArray<TItem>>): UseSkipLimitReturnValue<TArgs, TItem>;
17
+ }, TItem, TReadFromStore extends object>(loadableField: LoadableField<TArgs, ReadonlyArray<TItem>>): UseSkipLimitReturnValue<TArgs, TItem>;
23
18
  export {};
@@ -9,6 +9,7 @@ const react_1 = require("react");
9
9
  const react_disposable_state_1 = require("@isograph/react-disposable-state");
10
10
  const reference_counted_pointer_1 = require("@isograph/reference-counted-pointer");
11
11
  const PromiseWrapper_1 = require("../core/PromiseWrapper");
12
+ const useReadAndSubscribe_1 = require("../react/useReadAndSubscribe");
12
13
  function flatten(arr) {
13
14
  let outArray = [];
14
15
  for (const subarr of arr) {
@@ -18,11 +19,6 @@ function flatten(arr) {
18
19
  }
19
20
  return outArray;
20
21
  }
21
- /**
22
- * NOTE: this hook does not subscribe to changes. This is a known
23
- * issue. If you are running into this issue, reach out on GitHub/
24
- * Twitter, and we'll fix the issue.
25
- */
26
22
  function useSkipLimitPagination(loadableField) {
27
23
  const networkRequestOptions = {
28
24
  suspendIfInFlight: true,
@@ -33,19 +29,10 @@ function useSkipLimitPagination(loadableField) {
33
29
  // TODO move this out of useSkipLimitPagination, and pass environment and networkRequestOptions
34
30
  // as parameters (or recreate networkRequestOptions)
35
31
  function readCompletedFragmentReferences(completedReferences) {
36
- // In general, this will not suspend. But it could, if there is missing data.
37
- // A better version of this hook would not do any reading here.
38
- const results = completedReferences.map(([pointer]) => {
39
- const fragmentReference = pointer.getItemIfNotDisposed();
40
- if (fragmentReference == null) {
41
- throw new Error('FragmentReference is unexpectedly disposed. \
42
- This is indicative of a bug in Isograph.');
43
- }
44
- (0, useResult_1.maybeUnwrapNetworkRequest)(fragmentReference.networkRequest, networkRequestOptions);
45
- const data = (0, read_1.readButDoNotEvaluate)(environment, fragmentReference, networkRequestOptions);
32
+ const results = completedReferences.map((fragmentReference, i) => {
46
33
  const readerWithRefetchQueries = (0, PromiseWrapper_1.readPromise)(fragmentReference.readerWithRefetchQueries);
47
34
  const firstParameter = {
48
- data: data.item,
35
+ data: readOutDataAndRecords[i].item,
49
36
  parameters: fragmentReference.variables,
50
37
  };
51
38
  if (readerWithRefetchQueries.readerArtifact.kind !== 'EagerReaderArtifact') {
@@ -56,6 +43,20 @@ function useSkipLimitPagination(loadableField) {
56
43
  const items = flatten(results);
57
44
  return items;
58
45
  }
46
+ function subscribeCompletedFragmentReferences(completedReferences) {
47
+ return completedReferences.map((fragmentReference, i) => {
48
+ (0, useResult_1.maybeUnwrapNetworkRequest)(fragmentReference.networkRequest, networkRequestOptions);
49
+ const readerWithRefetchQueries = (0, PromiseWrapper_1.readPromise)(fragmentReference.readerWithRefetchQueries);
50
+ return {
51
+ fragmentReference,
52
+ readerAst: readerWithRefetchQueries.readerArtifact.readerAst,
53
+ records: readOutDataAndRecords[i],
54
+ callback(_data) {
55
+ rerender({});
56
+ },
57
+ };
58
+ });
59
+ }
59
60
  const getFetchMore = (loadedSoFar) => (args, count) => {
60
61
  // @ts-expect-error
61
62
  const loadedField = loadableField(Object.assign(Object.assign({}, args), { skip: loadedSoFar, limit: count }))[1]();
@@ -81,23 +82,36 @@ function useSkipLimitPagination(loadableField) {
81
82
  };
82
83
  const [, rerender] = (0, react_1.useState)({});
83
84
  const loadedReferences = state === react_disposable_state_1.UNASSIGNED_STATE ? [] : state;
84
- if (loadedReferences.length === 0) {
85
+ const mostRecentItem = loadedReferences[loadedReferences.length - 1];
86
+ const mostRecentFragmentReference = mostRecentItem === null || mostRecentItem === void 0 ? void 0 : mostRecentItem[0].getItemIfNotDisposed();
87
+ if (mostRecentItem && mostRecentFragmentReference === null) {
88
+ throw new Error('FragmentReference is unexpectedly disposed. \
89
+ This is indicative of a bug in Isograph.');
90
+ }
91
+ const networkRequestStatus = mostRecentFragmentReference &&
92
+ (0, PromiseWrapper_1.getPromiseState)(mostRecentFragmentReference.networkRequest);
93
+ const slicedFragmentReferences = (networkRequestStatus === null || networkRequestStatus === void 0 ? void 0 : networkRequestStatus.kind) === 'Ok'
94
+ ? loadedReferences
95
+ : loadedReferences.slice(0, loadedReferences.length - 1);
96
+ const completedFragmentReferences = slicedFragmentReferences.map(([pointer]) => {
97
+ const fragmentReference = pointer.getItemIfNotDisposed();
98
+ if (fragmentReference == null) {
99
+ throw new Error('FragmentReference is unexpectedly disposed. \
100
+ This is indicative of a bug in Isograph.');
101
+ }
102
+ return fragmentReference;
103
+ });
104
+ const readOutDataAndRecords = completedFragmentReferences.map((fragmentReference) => (0, read_1.readButDoNotEvaluate)(environment, fragmentReference, networkRequestOptions));
105
+ (0, useReadAndSubscribe_1.useSubscribeToMultiple)(subscribeCompletedFragmentReferences(completedFragmentReferences));
106
+ if (!networkRequestStatus) {
85
107
  return {
86
108
  kind: 'Complete',
87
109
  fetchMore: getFetchMore(0),
88
110
  results: [],
89
111
  };
90
112
  }
91
- const mostRecentItem = loadedReferences[loadedReferences.length - 1];
92
- const mostRecentFragmentReference = mostRecentItem[0].getItemIfNotDisposed();
93
- if (mostRecentFragmentReference === null) {
94
- throw new Error('FragmentReference is unexpectedly disposed. \
95
- This is indicative of a bug in Isograph.');
96
- }
97
- const networkRequestStatus = (0, PromiseWrapper_1.getPromiseState)(mostRecentFragmentReference.networkRequest);
98
113
  switch (networkRequestStatus.kind) {
99
114
  case 'Pending': {
100
- const completedFragmentReferences = loadedReferences.slice(0, loadedReferences.length - 1);
101
115
  const unsubscribe = (0, cache_1.subscribeToAnyChange)(environment, () => {
102
116
  unsubscribe();
103
117
  rerender({});
@@ -112,7 +126,7 @@ function useSkipLimitPagination(loadableField) {
112
126
  throw networkRequestStatus.error;
113
127
  }
114
128
  case 'Ok': {
115
- const results = readCompletedFragmentReferences(loadedReferences);
129
+ const results = readCompletedFragmentReferences(completedFragmentReferences);
116
130
  return {
117
131
  kind: 'Complete',
118
132
  results,
@@ -1,7 +1,7 @@
1
1
  import { UnassignedState } from '@isograph/react-disposable-state';
2
2
  import { IsographEntrypoint } from '../core/entrypoint';
3
3
  import { FragmentReference, Variables } from '../core/FragmentReference';
4
- export declare function useImperativeReference<TReadFromStore extends Object, TClientFieldValue>(entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>): {
4
+ export declare function useImperativeReference<TReadFromStore extends object, TClientFieldValue>(entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>): {
5
5
  fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue> | UnassignedState;
6
6
  loadFragmentReference: (variables: Variables) => void;
7
7
  };
@@ -1,5 +1,5 @@
1
1
  import { FragmentReference, Variables } from '../core/FragmentReference';
2
2
  import { IsographEntrypoint } from '../core/entrypoint';
3
- export declare function useLazyReference<TReadFromStore extends Object, TClientFieldValue>(entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: Variables): {
3
+ export declare function useLazyReference<TReadFromStore extends object, TClientFieldValue>(entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: Variables): {
4
4
  fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>;
5
5
  };
@@ -4,8 +4,8 @@ import type { ReaderAst } from '../core/reader';
4
4
  /**
5
5
  * Read the data from a fragment reference and subscribe to updates.
6
6
  */
7
- export declare function useReadAndSubscribe<TReadFromStore extends Object>(fragmentReference: FragmentReference<TReadFromStore, any>, networkRequestOptions: NetworkRequestReaderOptions, readerAst: ReaderAst<TReadFromStore>): TReadFromStore;
8
- export declare function useSubscribeToMultiple<TReadFromStore extends Object>(items: ReadonlyArray<{
7
+ export declare function useReadAndSubscribe<TReadFromStore extends object>(fragmentReference: FragmentReference<TReadFromStore, any>, networkRequestOptions: NetworkRequestReaderOptions, readerAst: ReaderAst<TReadFromStore>): TReadFromStore;
8
+ export declare function useSubscribeToMultiple<TReadFromStore extends object>(items: ReadonlyArray<{
9
9
  records: WithEncounteredRecords<TReadFromStore>;
10
10
  callback: (updatedRecords: WithEncounteredRecords<TReadFromStore>) => void;
11
11
  fragmentReference: FragmentReference<TReadFromStore, any>;
@@ -1,4 +1,4 @@
1
1
  import { WithEncounteredRecords } from '../core/read';
2
2
  import { FragmentReference } from '../core/FragmentReference';
3
3
  import type { ReaderAst } from '../core/reader';
4
- export declare function useRerenderOnChange<TReadFromStore extends Object>(encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<any, any>, setEncounteredDataAndRecords: (data: WithEncounteredRecords<TReadFromStore>) => void, readerAst: ReaderAst<TReadFromStore>): void;
4
+ export declare function useRerenderOnChange<TReadFromStore extends object>(encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<any, any>, setEncounteredDataAndRecords: (data: WithEncounteredRecords<TReadFromStore>) => void, readerAst: ReaderAst<TReadFromStore>): void;
@@ -1,5 +1,5 @@
1
1
  import { FragmentReference } from '../core/FragmentReference';
2
2
  import { NetworkRequestReaderOptions } from '../core/read';
3
3
  import { PromiseWrapper } from '../core/PromiseWrapper';
4
- export declare function useResult<TReadFromStore extends Object, TClientFieldValue>(fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>, partialNetworkRequestOptions?: Partial<NetworkRequestReaderOptions> | void): TClientFieldValue;
4
+ export declare function useResult<TReadFromStore extends object, TClientFieldValue>(fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>, partialNetworkRequestOptions?: Partial<NetworkRequestReaderOptions> | void): TClientFieldValue;
5
5
  export declare function maybeUnwrapNetworkRequest(networkRequest: PromiseWrapper<void, any>, networkRequestOptions: NetworkRequestReaderOptions): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isograph/react",
3
- "version": "0.0.0-main-366b2007",
3
+ "version": "0.0.0-main-5046aeef",
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-366b2007",
21
- "@isograph/react-disposable-state": "0.0.0-main-366b2007",
22
- "@isograph/reference-counted-pointer": "0.0.0-main-366b2007"
20
+ "@isograph/disposable-types": "0.0.0-main-5046aeef",
21
+ "@isograph/react-disposable-state": "0.0.0-main-5046aeef",
22
+ "@isograph/reference-counted-pointer": "0.0.0-main-5046aeef"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "react": "18.2.0"
@@ -8,7 +8,7 @@ export type VariableValue = string | number | boolean | null | object;
8
8
  export type Variables = { readonly [index: string]: VariableValue };
9
9
 
10
10
  export type FragmentReference<
11
- TReadFromStore extends Object,
11
+ TReadFromStore extends object,
12
12
  TClientFieldValue,
13
13
  > = {
14
14
  readonly kind: 'FragmentReference';
@@ -14,7 +14,7 @@ type ComponentCache = {
14
14
  };
15
15
  };
16
16
 
17
- export type FragmentSubscription<TReadFromStore extends Object> = {
17
+ export type FragmentSubscription<TReadFromStore extends object> = {
18
18
  readonly kind: 'FragmentSubscription';
19
19
  readonly callback: (
20
20
  newEncounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>,
package/src/core/cache.ts CHANGED
@@ -32,7 +32,7 @@ import { wrapResolvedValue } from './PromiseWrapper';
32
32
  const TYPENAME_FIELD_NAME = '__typename';
33
33
 
34
34
  export function getOrCreateItemInSuspenseCache<
35
- TReadFromStore extends Object,
35
+ TReadFromStore extends object,
36
36
  TClientFieldValue,
37
37
  >(
38
38
  environment: IsographEnvironment,
@@ -77,7 +77,7 @@ export function stableCopy<T>(value: T): T {
77
77
  }
78
78
 
79
79
  export function getOrCreateCacheForArtifact<
80
- TReadFromStore extends Object,
80
+ TReadFromStore extends object,
81
81
  TClientFieldValue,
82
82
  >(
83
83
  environment: IsographEnvironment,
@@ -180,7 +180,7 @@ export function subscribeToAnyChange(
180
180
  }
181
181
 
182
182
  // TODO we should re-read and call callback if the value has changed
183
- export function subscribe<TReadFromStore extends Object>(
183
+ export function subscribe<TReadFromStore extends object>(
184
184
  environment: IsographEnvironment,
185
185
  encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>,
186
186
  fragmentReference: FragmentReference<TReadFromStore, any>,
@@ -2,7 +2,7 @@ import { TopLevelReaderArtifact } from './reader';
2
2
  import { Arguments } from './util';
3
3
 
4
4
  export type ReaderWithRefetchQueries<
5
- TReadFromStore extends Object,
5
+ TReadFromStore extends object,
6
6
  TClientFieldValue,
7
7
  > = {
8
8
  readonly kind: 'ReaderWithRefetchQueries';
@@ -17,7 +17,7 @@ export type ReaderWithRefetchQueries<
17
17
 
18
18
  // This type should be treated as an opaque type.
19
19
  export type IsographEntrypoint<
20
- TReadFromStore extends Object,
20
+ TReadFromStore extends object,
21
21
  TClientFieldValue,
22
22
  > = {
23
23
  readonly kind: 'Entrypoint';
@@ -30,7 +30,7 @@ export type IsographEntrypoint<
30
30
  };
31
31
 
32
32
  export type IsographEntrypointLoader<
33
- TReadFromStore extends Object,
33
+ TReadFromStore extends object,
34
34
  TClientFieldValue,
35
35
  > = {
36
36
  readonly kind: 'EntrypointLoader';
@@ -79,7 +79,7 @@ export type RefetchQueryNormalizationArtifactWrapper = {
79
79
  };
80
80
 
81
81
  export function assertIsEntrypoint<
82
- TReadFromStore extends Object,
82
+ TReadFromStore extends object,
83
83
  TClientFieldValue,
84
84
  >(
85
85
  value:
package/src/core/read.ts CHANGED
@@ -29,7 +29,7 @@ export type WithEncounteredRecords<T> = {
29
29
  readonly item: T;
30
30
  };
31
31
 
32
- export function readButDoNotEvaluate<TReadFromStore extends Object>(
32
+ export function readButDoNotEvaluate<TReadFromStore extends object>(
33
33
  environment: IsographEnvironment,
34
34
  fragmentReference: FragmentReference<TReadFromStore, unknown>,
35
35
  networkRequestOptions: NetworkRequestReaderOptions,
@@ -14,7 +14,7 @@ import {
14
14
  import { Arguments } from './util';
15
15
 
16
16
  export type TopLevelReaderArtifact<
17
- TReadFromStore extends Object,
17
+ TReadFromStore extends object,
18
18
  TClientFieldValue,
19
19
  TComponentProps extends Record<string, never>,
20
20
  TVariables = Variables,
@@ -23,7 +23,7 @@ export type TopLevelReaderArtifact<
23
23
  | ComponentReaderArtifact<TReadFromStore, TComponentProps, TVariables>;
24
24
 
25
25
  export type EagerReaderArtifact<
26
- TReadFromStore extends Object,
26
+ TReadFromStore extends object,
27
27
  TClientFieldValue,
28
28
  TVariables = Variables,
29
29
  > = {
@@ -35,7 +35,7 @@ export type EagerReaderArtifact<
35
35
  };
36
36
 
37
37
  export type ComponentReaderArtifact<
38
- TReadFromStore extends Object,
38
+ TReadFromStore extends object,
39
39
  TComponentProps extends Record<string, unknown> = Record<string, never>,
40
40
  TVariables = Variables,
41
41
  > = {
@@ -49,7 +49,7 @@ export type ComponentReaderArtifact<
49
49
  };
50
50
 
51
51
  export type ResolverFirstParameter<
52
- TReadFromStore extends Object,
52
+ TReadFromStore extends object,
53
53
  TVariables = Variables,
54
54
  > = {
55
55
  readonly data: TReadFromStore;
@@ -8,12 +8,12 @@ export function useClientSideDefer<TResult>(
8
8
  loadableField: LoadableField<void, TResult>,
9
9
  ): { fragmentReference: FragmentReference<Record<string, never>, TResult> };
10
10
 
11
- export function useClientSideDefer<TArgs extends Object, TResult>(
11
+ export function useClientSideDefer<TArgs extends object, TResult>(
12
12
  loadableField: LoadableField<TArgs, TResult>,
13
13
  args: TArgs,
14
14
  ): { fragmentReference: FragmentReference<TArgs, TResult> };
15
15
 
16
- export function useClientSideDefer<TArgs extends Object, TResult>(
16
+ export function useClientSideDefer<TArgs extends object, TResult>(
17
17
  loadableField: LoadableField<TArgs, TResult>,
18
18
  args?: TArgs,
19
19
  ): { fragmentReference: FragmentReference<TArgs, TResult> } {
@@ -1,4 +1,4 @@
1
- import { LoadableField } from '../core/reader';
1
+ import { LoadableField, type ReaderAst } from '../core/reader';
2
2
  import { useIsographEnvironment } from '../react/IsographEnvironmentProvider';
3
3
  import { ItemCleanupPair } from '@isograph/disposable-types';
4
4
  import { FragmentReference } from '../core/FragmentReference';
@@ -15,6 +15,8 @@ import {
15
15
  ReferenceCountedPointer,
16
16
  } from '@isograph/reference-counted-pointer';
17
17
  import { getPromiseState, readPromise } from '../core/PromiseWrapper';
18
+ import { type WithEncounteredRecords } from '../core/read';
19
+ import { useSubscribeToMultiple } from '../react/useReadAndSubscribe';
18
20
 
19
21
  type SkipOrLimit = 'skip' | 'limit';
20
22
  type OmitSkipLimit<TArgs> = keyof Omit<TArgs, SkipOrLimit> extends never
@@ -34,17 +36,20 @@ type UseSkipLimitReturnValue<TArgs, TItem> =
34
36
  };
35
37
 
36
38
  type ArrayFragmentReference<
37
- TReadFromStore extends Object,
39
+ TReadFromStore extends object,
38
40
  TItem,
39
41
  > = FragmentReference<TReadFromStore, ReadonlyArray<TItem>>;
40
42
 
41
43
  type LoadedFragmentReferences<
42
- TReadFromStore extends Object,
44
+ TReadFromStore extends object,
43
45
  TItem,
44
- > = ReadonlyArray<
45
- ItemCleanupPair<
46
- ReferenceCountedPointer<ArrayFragmentReference<TReadFromStore, TItem>>
47
- >
46
+ > = ReadonlyArray<LoadedFragmentReference<TReadFromStore, TItem>>;
47
+
48
+ type LoadedFragmentReference<
49
+ TReadFromStore extends object,
50
+ TItem,
51
+ > = ItemCleanupPair<
52
+ ReferenceCountedPointer<ArrayFragmentReference<TReadFromStore, TItem>>
48
53
  >;
49
54
 
50
55
  function flatten<T>(arr: ReadonlyArray<ReadonlyArray<T>>): ReadonlyArray<T> {
@@ -57,18 +62,13 @@ function flatten<T>(arr: ReadonlyArray<ReadonlyArray<T>>): ReadonlyArray<T> {
57
62
  return outArray;
58
63
  }
59
64
 
60
- /**
61
- * NOTE: this hook does not subscribe to changes. This is a known
62
- * issue. If you are running into this issue, reach out on GitHub/
63
- * Twitter, and we'll fix the issue.
64
- */
65
65
  export function useSkipLimitPagination<
66
66
  TArgs extends {
67
67
  skip: number | void | null;
68
68
  limit: number | void | null;
69
69
  },
70
70
  TItem,
71
- TReadFromStore extends Object,
71
+ TReadFromStore extends object,
72
72
  >(
73
73
  loadableField: LoadableField<TArgs, ReadonlyArray<TItem>>,
74
74
  ): UseSkipLimitReturnValue<TArgs, TItem> {
@@ -86,39 +86,15 @@ export function useSkipLimitPagination<
86
86
  // TODO move this out of useSkipLimitPagination, and pass environment and networkRequestOptions
87
87
  // as parameters (or recreate networkRequestOptions)
88
88
  function readCompletedFragmentReferences(
89
- completedReferences: ReadonlyArray<
90
- ItemCleanupPair<
91
- ReferenceCountedPointer<ArrayFragmentReference<TReadFromStore, TItem>>
92
- >
93
- >,
89
+ completedReferences: ArrayFragmentReference<TReadFromStore, TItem>[],
94
90
  ) {
95
- // In general, this will not suspend. But it could, if there is missing data.
96
- // A better version of this hook would not do any reading here.
97
- const results = completedReferences.map(([pointer]) => {
98
- const fragmentReference = pointer.getItemIfNotDisposed();
99
- if (fragmentReference == null) {
100
- throw new Error(
101
- 'FragmentReference is unexpectedly disposed. \
102
- This is indicative of a bug in Isograph.',
103
- );
104
- }
105
-
106
- maybeUnwrapNetworkRequest(
107
- fragmentReference.networkRequest,
108
- networkRequestOptions,
109
- );
110
- const data = readButDoNotEvaluate(
111
- environment,
112
- fragmentReference,
113
- networkRequestOptions,
114
- );
115
-
91
+ const results = completedReferences.map((fragmentReference, i) => {
116
92
  const readerWithRefetchQueries = readPromise(
117
93
  fragmentReference.readerWithRefetchQueries,
118
94
  );
119
95
 
120
96
  const firstParameter = {
121
- data: data.item,
97
+ data: readOutDataAndRecords[i].item,
122
98
  parameters: fragmentReference.variables,
123
99
  };
124
100
 
@@ -137,6 +113,42 @@ export function useSkipLimitPagination<
137
113
  return items;
138
114
  }
139
115
 
116
+ function subscribeCompletedFragmentReferences(
117
+ completedReferences: ArrayFragmentReference<TReadFromStore, TItem>[],
118
+ ) {
119
+ return completedReferences.map(
120
+ (
121
+ fragmentReference,
122
+ i,
123
+ ): {
124
+ records: WithEncounteredRecords<TReadFromStore>;
125
+ callback: (
126
+ updatedRecords: WithEncounteredRecords<TReadFromStore>,
127
+ ) => void;
128
+ fragmentReference: ArrayFragmentReference<TReadFromStore, TItem>;
129
+ readerAst: ReaderAst<TItem>;
130
+ } => {
131
+ maybeUnwrapNetworkRequest(
132
+ fragmentReference.networkRequest,
133
+ networkRequestOptions,
134
+ );
135
+
136
+ const readerWithRefetchQueries = readPromise(
137
+ fragmentReference.readerWithRefetchQueries,
138
+ );
139
+
140
+ return {
141
+ fragmentReference,
142
+ readerAst: readerWithRefetchQueries.readerArtifact.readerAst,
143
+ records: readOutDataAndRecords[i],
144
+ callback(_data) {
145
+ rerender({});
146
+ },
147
+ };
148
+ },
149
+ );
150
+ }
151
+
140
152
  const getFetchMore =
141
153
  (loadedSoFar: number) =>
142
154
  (args: OmitSkipLimit<TArgs>, count: number): void => {
@@ -182,33 +194,64 @@ export function useSkipLimitPagination<
182
194
  const [, rerender] = useState({});
183
195
 
184
196
  const loadedReferences = state === UNASSIGNED_STATE ? [] : state;
185
- if (loadedReferences.length === 0) {
186
- return {
187
- kind: 'Complete',
188
- fetchMore: getFetchMore(0),
189
- results: [],
190
- };
191
- }
192
197
 
193
- const mostRecentItem = loadedReferences[loadedReferences.length - 1];
194
- const mostRecentFragmentReference = mostRecentItem[0].getItemIfNotDisposed();
195
- if (mostRecentFragmentReference === null) {
198
+ const mostRecentItem: LoadedFragmentReference<TReadFromStore, TItem> | null =
199
+ loadedReferences[loadedReferences.length - 1];
200
+ const mostRecentFragmentReference =
201
+ mostRecentItem?.[0].getItemIfNotDisposed();
202
+
203
+ if (mostRecentItem && mostRecentFragmentReference === null) {
196
204
  throw new Error(
197
205
  'FragmentReference is unexpectedly disposed. \
198
206
  This is indicative of a bug in Isograph.',
199
207
  );
200
208
  }
201
209
 
202
- const networkRequestStatus = getPromiseState(
203
- mostRecentFragmentReference.networkRequest,
210
+ const networkRequestStatus =
211
+ mostRecentFragmentReference &&
212
+ getPromiseState(mostRecentFragmentReference.networkRequest);
213
+
214
+ const slicedFragmentReferences =
215
+ networkRequestStatus?.kind === 'Ok'
216
+ ? loadedReferences
217
+ : loadedReferences.slice(0, loadedReferences.length - 1);
218
+
219
+ const completedFragmentReferences = slicedFragmentReferences.map(
220
+ ([pointer]) => {
221
+ const fragmentReference = pointer.getItemIfNotDisposed();
222
+ if (fragmentReference == null) {
223
+ throw new Error(
224
+ 'FragmentReference is unexpectedly disposed. \
225
+ This is indicative of a bug in Isograph.',
226
+ );
227
+ }
228
+ return fragmentReference;
229
+ },
204
230
  );
231
+
232
+ const readOutDataAndRecords = completedFragmentReferences.map(
233
+ (fragmentReference) =>
234
+ readButDoNotEvaluate(
235
+ environment,
236
+ fragmentReference,
237
+ networkRequestOptions,
238
+ ),
239
+ );
240
+
241
+ useSubscribeToMultiple<TReadFromStore>(
242
+ subscribeCompletedFragmentReferences(completedFragmentReferences),
243
+ );
244
+
245
+ if (!networkRequestStatus) {
246
+ return {
247
+ kind: 'Complete',
248
+ fetchMore: getFetchMore(0),
249
+ results: [],
250
+ };
251
+ }
252
+
205
253
  switch (networkRequestStatus.kind) {
206
254
  case 'Pending': {
207
- const completedFragmentReferences = loadedReferences.slice(
208
- 0,
209
- loadedReferences.length - 1,
210
- );
211
-
212
255
  const unsubscribe = subscribeToAnyChange(environment, () => {
213
256
  unsubscribe();
214
257
  rerender({});
@@ -224,7 +267,9 @@ export function useSkipLimitPagination<
224
267
  throw networkRequestStatus.error;
225
268
  }
226
269
  case 'Ok': {
227
- const results = readCompletedFragmentReferences(loadedReferences);
270
+ const results = readCompletedFragmentReferences(
271
+ completedFragmentReferences,
272
+ );
228
273
  return {
229
274
  kind: 'Complete',
230
275
  results,
@@ -12,7 +12,7 @@ import { wrapResolvedValue } from '../core/PromiseWrapper';
12
12
  // TODO rename this to useImperativelyLoadedEntrypoint
13
13
 
14
14
  export function useImperativeReference<
15
- TReadFromStore extends Object,
15
+ TReadFromStore extends object,
16
16
  TClientFieldValue,
17
17
  >(
18
18
  entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>,
@@ -5,7 +5,7 @@ import { getOrCreateCacheForArtifact } from '../core/cache';
5
5
  import { useLazyDisposableState } from '@isograph/react-disposable-state';
6
6
 
7
7
  export function useLazyReference<
8
- TReadFromStore extends Object,
8
+ TReadFromStore extends object,
9
9
  TClientFieldValue,
10
10
  >(
11
11
  entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>,
@@ -16,7 +16,7 @@ import type { ReaderAst } from '../core/reader';
16
16
  /**
17
17
  * Read the data from a fragment reference and subscribe to updates.
18
18
  */
19
- export function useReadAndSubscribe<TReadFromStore extends Object>(
19
+ export function useReadAndSubscribe<TReadFromStore extends object>(
20
20
  fragmentReference: FragmentReference<TReadFromStore, any>,
21
21
  networkRequestOptions: NetworkRequestReaderOptions,
22
22
  readerAst: ReaderAst<TReadFromStore>,
@@ -34,7 +34,7 @@ export function useReadAndSubscribe<TReadFromStore extends Object>(
34
34
  return readOutDataAndRecords.item;
35
35
  }
36
36
 
37
- export function useSubscribeToMultiple<TReadFromStore extends Object>(
37
+ export function useSubscribeToMultiple<TReadFromStore extends object>(
38
38
  items: ReadonlyArray<{
39
39
  records: WithEncounteredRecords<TReadFromStore>;
40
40
  callback: (updatedRecords: WithEncounteredRecords<TReadFromStore>) => void;
@@ -7,7 +7,7 @@ import type { ReaderAst } from '../core/reader';
7
7
 
8
8
  // TODO add unit tests for this. Add integration tests that test
9
9
  // behavior when the encounteredRecords underneath a fragment change.
10
- export function useRerenderOnChange<TReadFromStore extends Object>(
10
+ export function useRerenderOnChange<TReadFromStore extends object>(
11
11
  encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>,
12
12
  fragmentReference: FragmentReference<any, any>,
13
13
  setEncounteredDataAndRecords: (
@@ -12,7 +12,7 @@ import {
12
12
  readPromise,
13
13
  } from '../core/PromiseWrapper';
14
14
 
15
- export function useResult<TReadFromStore extends Object, TClientFieldValue>(
15
+ export function useResult<TReadFromStore extends object, TClientFieldValue>(
16
16
  fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>,
17
17
  partialNetworkRequestOptions?: Partial<NetworkRequestReaderOptions> | void,
18
18
  ): TClientFieldValue {
@@ -10,7 +10,7 @@ import entrypoint_Query__nodeField from '../__isograph/Query/nodeField/entrypoin
10
10
  // This means that the type of the exported iso literal is exactly
11
11
  // the type of the passed-in function, which takes one parameter
12
12
  // of type TParam.
13
- type IdentityWithParam<TParam extends Object> = <TClientFieldReturn, TVariables = Variables>(
13
+ type IdentityWithParam<TParam extends object> = <TClientFieldReturn, TVariables = Variables>(
14
14
  clientField: (param: TParam) => TClientFieldReturn
15
15
  ) => (param: ResolverFirstParameter<TParam, TVariables>) => TClientFieldReturn;
16
16
 
@@ -21,7 +21,7 @@ type IdentityWithParam<TParam extends Object> = <TClientFieldReturn, TVariables
21
21
  //
22
22
  // TComponentProps becomes the types of the props you must pass
23
23
  // whenever the @component field is rendered.
24
- type IdentityWithParamComponent<TParam extends Object> = <
24
+ type IdentityWithParamComponent<TParam extends object> = <
25
25
  TClientFieldReturn,
26
26
  TComponentProps = Record<string, never>,
27
27
  TVariables = Variables