@isograph/react 0.3.0 → 0.4.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.
Files changed (164) hide show
  1. package/.turbo/turbo-compile-libs.log +5 -0
  2. package/dist/core/FragmentReference.d.ts +17 -8
  3. package/dist/core/FragmentReference.d.ts.map +1 -1
  4. package/dist/core/FragmentReference.js +3 -12
  5. package/dist/core/IsographEnvironment.d.ts +30 -35
  6. package/dist/core/IsographEnvironment.d.ts.map +1 -1
  7. package/dist/core/IsographEnvironment.js +4 -0
  8. package/dist/core/PromiseWrapper.d.ts +6 -7
  9. package/dist/core/PromiseWrapper.d.ts.map +1 -1
  10. package/dist/core/PromiseWrapper.js +6 -12
  11. package/dist/core/areEqualWithDeepComparison.d.ts +1 -3
  12. package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -1
  13. package/dist/core/areEqualWithDeepComparison.js +16 -2
  14. package/dist/core/brand.d.ts +2 -0
  15. package/dist/core/brand.d.ts.map +1 -0
  16. package/dist/core/brand.js +2 -0
  17. package/dist/core/cache.d.ts +16 -24
  18. package/dist/core/cache.d.ts.map +1 -1
  19. package/dist/core/cache.js +105 -72
  20. package/dist/core/check.d.ts +11 -7
  21. package/dist/core/check.d.ts.map +1 -1
  22. package/dist/core/check.js +2 -2
  23. package/dist/core/componentCache.d.ts +1 -1
  24. package/dist/core/componentCache.d.ts.map +1 -1
  25. package/dist/core/componentCache.js +27 -31
  26. package/dist/core/entrypoint.d.ts +43 -28
  27. package/dist/core/entrypoint.d.ts.map +1 -1
  28. package/dist/core/garbageCollection.d.ts +5 -6
  29. package/dist/core/garbageCollection.d.ts.map +1 -1
  30. package/dist/core/garbageCollection.js +1 -1
  31. package/dist/core/logging.d.ts +23 -15
  32. package/dist/core/logging.d.ts.map +1 -1
  33. package/dist/core/logging.js +8 -5
  34. package/dist/core/makeNetworkRequest.d.ts +5 -5
  35. package/dist/core/makeNetworkRequest.d.ts.map +1 -1
  36. package/dist/core/makeNetworkRequest.js +113 -28
  37. package/dist/core/read.d.ts +16 -11
  38. package/dist/core/read.d.ts.map +1 -1
  39. package/dist/core/read.js +468 -305
  40. package/dist/core/reader.d.ts +33 -37
  41. package/dist/core/reader.d.ts.map +1 -1
  42. package/dist/core/startUpdate.d.ts +8 -0
  43. package/dist/core/startUpdate.d.ts.map +1 -0
  44. package/dist/core/startUpdate.js +163 -0
  45. package/dist/core/util.d.ts +3 -0
  46. package/dist/core/util.d.ts.map +1 -1
  47. package/dist/index.d.ts +18 -15
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +9 -1
  50. package/dist/loadable-hooks/useClientSideDefer.d.ts +4 -10
  51. package/dist/loadable-hooks/useClientSideDefer.d.ts.map +1 -1
  52. package/dist/loadable-hooks/useClientSideDefer.js +2 -2
  53. package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +8 -15
  54. package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -1
  55. package/dist/loadable-hooks/useConnectionSpecPagination.js +6 -4
  56. package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +1 -2
  57. package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts.map +1 -1
  58. package/dist/loadable-hooks/useImperativeLoadableField.d.ts +4 -6
  59. package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -1
  60. package/dist/loadable-hooks/useImperativeLoadableField.js +1 -1
  61. package/dist/loadable-hooks/useSkipLimitPagination.d.ts +6 -13
  62. package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -1
  63. package/dist/loadable-hooks/useSkipLimitPagination.js +11 -9
  64. package/dist/react/FragmentReader.d.ts +7 -14
  65. package/dist/react/FragmentReader.d.ts.map +1 -1
  66. package/dist/react/FragmentReader.js +3 -30
  67. package/dist/react/FragmentRenderer.d.ts +15 -0
  68. package/dist/react/FragmentRenderer.d.ts.map +1 -0
  69. package/dist/react/FragmentRenderer.js +35 -0
  70. package/dist/react/IsographEnvironmentProvider.d.ts.map +1 -1
  71. package/dist/react/LoadableFieldReader.d.ts +12 -0
  72. package/dist/react/LoadableFieldReader.d.ts.map +1 -0
  73. package/dist/react/LoadableFieldReader.js +10 -0
  74. package/dist/react/LoadableFieldRenderer.d.ts +13 -0
  75. package/dist/react/LoadableFieldRenderer.d.ts.map +1 -0
  76. package/dist/react/LoadableFieldRenderer.js +37 -0
  77. package/dist/react/useImperativeReference.d.ts +7 -10
  78. package/dist/react/useImperativeReference.d.ts.map +1 -1
  79. package/dist/react/useImperativeReference.js +8 -9
  80. package/dist/react/useLazyReference.d.ts +4 -7
  81. package/dist/react/useLazyReference.d.ts.map +1 -1
  82. package/dist/react/useLazyReference.js +26 -5
  83. package/dist/react/useReadAndSubscribe.d.ts +3 -9
  84. package/dist/react/useReadAndSubscribe.d.ts.map +1 -1
  85. package/dist/react/useReadAndSubscribe.js +7 -3
  86. package/dist/react/useRerenderOnChange.d.ts +1 -1
  87. package/dist/react/useRerenderOnChange.d.ts.map +1 -1
  88. package/dist/react/useResult.d.ts +3 -6
  89. package/dist/react/useResult.d.ts.map +1 -1
  90. package/dist/react/useResult.js +10 -8
  91. package/isograph.config.json +1 -0
  92. package/package.json +6 -6
  93. package/src/core/FragmentReference.ts +40 -16
  94. package/src/core/IsographEnvironment.ts +57 -39
  95. package/src/core/PromiseWrapper.ts +15 -18
  96. package/src/core/areEqualWithDeepComparison.ts +22 -2
  97. package/src/core/brand.ts +18 -0
  98. package/src/core/cache.ts +153 -113
  99. package/src/core/check.ts +17 -12
  100. package/src/core/componentCache.ts +47 -50
  101. package/src/core/entrypoint.ts +66 -21
  102. package/src/core/garbageCollection.ts +9 -9
  103. package/src/core/logging.ts +39 -25
  104. package/src/core/makeNetworkRequest.ts +212 -34
  105. package/src/core/read.ts +728 -440
  106. package/src/core/reader.ts +46 -29
  107. package/src/core/startUpdate.ts +334 -0
  108. package/src/core/util.ts +4 -0
  109. package/src/index.ts +89 -8
  110. package/src/loadable-hooks/useClientSideDefer.ts +11 -10
  111. package/src/loadable-hooks/useConnectionSpecPagination.ts +27 -13
  112. package/src/loadable-hooks/useImperativeExposedMutationField.ts +1 -1
  113. package/src/loadable-hooks/useImperativeLoadableField.ts +10 -12
  114. package/src/loadable-hooks/useSkipLimitPagination.ts +38 -19
  115. package/src/react/FragmentReader.tsx +23 -39
  116. package/src/react/FragmentRenderer.tsx +46 -0
  117. package/src/react/IsographEnvironmentProvider.tsx +1 -1
  118. package/src/react/LoadableFieldReader.tsx +40 -0
  119. package/src/react/LoadableFieldRenderer.tsx +41 -0
  120. package/src/react/useImperativeReference.ts +49 -27
  121. package/src/react/useLazyReference.ts +62 -14
  122. package/src/react/useReadAndSubscribe.ts +17 -9
  123. package/src/react/useRerenderOnChange.ts +2 -2
  124. package/src/react/useResult.ts +22 -8
  125. package/src/tests/__isograph/Economist/link/output_type.ts +2 -0
  126. package/src/tests/__isograph/Node/asEconomist/resolver_reader.ts +28 -0
  127. package/src/tests/__isograph/Node/link/output_type.ts +3 -0
  128. package/src/tests/__isograph/Query/linkedUpdate/entrypoint.ts +31 -0
  129. package/src/tests/__isograph/Query/linkedUpdate/normalization_ast.ts +95 -0
  130. package/src/tests/__isograph/Query/linkedUpdate/output_type.ts +3 -0
  131. package/src/tests/__isograph/Query/linkedUpdate/param_type.ts +51 -0
  132. package/src/tests/__isograph/Query/linkedUpdate/query_text.ts +20 -0
  133. package/src/tests/__isograph/Query/linkedUpdate/resolver_reader.ts +93 -0
  134. package/src/tests/__isograph/Query/meName/entrypoint.ts +8 -29
  135. package/src/tests/__isograph/Query/meName/normalization_ast.ts +25 -0
  136. package/src/tests/__isograph/Query/meName/query_text.ts +6 -0
  137. package/src/tests/__isograph/Query/meName/resolver_reader.ts +5 -0
  138. package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +8 -67
  139. package/src/tests/__isograph/Query/meNameSuccessor/normalization_ast.ts +56 -0
  140. package/src/tests/__isograph/Query/meNameSuccessor/query_text.ts +13 -0
  141. package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +10 -0
  142. package/src/tests/__isograph/Query/nodeField/entrypoint.ts +8 -34
  143. package/src/tests/__isograph/Query/nodeField/normalization_ast.ts +30 -0
  144. package/src/tests/__isograph/Query/nodeField/query_text.ts +6 -0
  145. package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +5 -0
  146. package/src/tests/__isograph/Query/startUpdate/entrypoint.ts +31 -0
  147. package/src/tests/__isograph/Query/startUpdate/normalization_ast.ts +51 -0
  148. package/src/tests/__isograph/Query/startUpdate/output_type.ts +3 -0
  149. package/src/tests/__isograph/Query/startUpdate/param_type.ts +26 -0
  150. package/src/tests/__isograph/Query/startUpdate/parameters_type.ts +3 -0
  151. package/src/tests/__isograph/Query/startUpdate/query_text.ts +11 -0
  152. package/src/tests/__isograph/Query/startUpdate/resolver_reader.ts +55 -0
  153. package/src/tests/__isograph/Query/subquery/entrypoint.ts +8 -44
  154. package/src/tests/__isograph/Query/subquery/normalization_ast.ts +38 -0
  155. package/src/tests/__isograph/Query/subquery/query_text.ts +8 -0
  156. package/src/tests/__isograph/Query/subquery/resolver_reader.ts +7 -0
  157. package/src/tests/__isograph/iso.ts +24 -3
  158. package/src/tests/__isograph/tsconfig.json +8 -0
  159. package/src/tests/garbageCollection.test.ts +10 -8
  160. package/src/tests/meNameSuccessor.ts +1 -1
  161. package/src/tests/nodeQuery.ts +2 -1
  162. package/src/tests/normalizeData.test.ts +1 -2
  163. package/src/tests/startUpdate.test.ts +205 -0
  164. package/tsconfig.pkg.json +1 -2
@@ -1,25 +1,25 @@
1
1
  import { Factory } from '@isograph/disposable-types';
2
+ import { FetchOptions } from './check';
3
+ import {
4
+ IsographEntrypoint,
5
+ IsographEntrypointLoader,
6
+ RefetchQueryNormalizationArtifact,
7
+ RefetchQueryNormalizationArtifactWrapper,
8
+ } from './entrypoint';
2
9
  import {
3
- FragmentReference,
4
10
  ExtractParameters,
5
- ExtractData,
11
+ FragmentReference,
12
+ type UnknownTReadFromStore,
6
13
  } from './FragmentReference';
7
14
  import {
8
15
  ComponentOrFieldName,
9
16
  IsographEnvironment,
10
- type Link,
17
+ type StoreLink,
11
18
  } from './IsographEnvironment';
12
- import {
13
- IsographEntrypoint,
14
- IsographEntrypointLoader,
15
- RefetchQueryNormalizationArtifact,
16
- RefetchQueryNormalizationArtifactWrapper,
17
- } from './entrypoint';
18
19
  import { Arguments } from './util';
19
- import { FetchOptions } from './check';
20
20
 
21
21
  export type TopLevelReaderArtifact<
22
- TReadFromStore extends { parameters: object; data: object },
22
+ TReadFromStore extends UnknownTReadFromStore,
23
23
  TClientFieldValue,
24
24
  TComponentProps extends Record<PropertyKey, never>,
25
25
  > =
@@ -27,35 +27,39 @@ export type TopLevelReaderArtifact<
27
27
  | ComponentReaderArtifact<TReadFromStore, TComponentProps>;
28
28
 
29
29
  export type EagerReaderArtifact<
30
- TReadFromStore extends { parameters: object; data: object },
30
+ TReadFromStore extends UnknownTReadFromStore,
31
31
  TClientFieldValue,
32
32
  > = {
33
33
  readonly kind: 'EagerReaderArtifact';
34
+ readonly fieldName: string;
34
35
  readonly readerAst: ReaderAst<TReadFromStore>;
35
36
  readonly resolver: (
36
37
  data: ResolverFirstParameter<TReadFromStore>,
37
38
  ) => TClientFieldValue;
39
+ readonly hasUpdatable: boolean;
38
40
  };
39
41
 
40
42
  export type ComponentReaderArtifact<
41
- TReadFromStore extends { parameters: object; data: object },
43
+ TReadFromStore extends UnknownTReadFromStore,
42
44
  TComponentProps extends Record<string, unknown> = Record<PropertyKey, never>,
43
45
  > = {
44
46
  readonly kind: 'ComponentReaderArtifact';
45
- readonly componentName: ComponentOrFieldName;
47
+ readonly fieldName: ComponentOrFieldName;
46
48
  readonly readerAst: ReaderAst<TReadFromStore>;
47
49
  readonly resolver: (
48
50
  data: ResolverFirstParameter<TReadFromStore>,
49
51
  runtimeProps: TComponentProps,
50
52
  ) => React.ReactNode;
53
+ readonly hasUpdatable: boolean;
51
54
  };
52
55
 
53
56
  export type ResolverFirstParameter<
54
- TReadFromStore extends { data: object; parameters: object },
55
- > = {
56
- data: ExtractData<TReadFromStore>;
57
- parameters: ExtractParameters<TReadFromStore>;
58
- };
57
+ TReadFromStore extends UnknownTReadFromStore,
58
+ > = Pick<TReadFromStore, 'data' | 'parameters' | 'startUpdate'>;
59
+
60
+ export type StartUpdate<UpdatableData> = (
61
+ updater: (updatableData: UpdatableData) => void,
62
+ ) => void;
59
63
 
60
64
  export type RefetchReaderArtifact = {
61
65
  readonly kind: 'RefetchReaderArtifact';
@@ -67,7 +71,7 @@ export type RefetchReaderArtifact = {
67
71
  variables: any,
68
72
  // TODO type this better
69
73
  filteredVariables: any,
70
- rootLink: Link,
74
+ rootLink: StoreLink,
71
75
  readerArtifact: TopLevelReaderArtifact<any, any, any> | null,
72
76
  // TODO type this better
73
77
  nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
@@ -79,7 +83,8 @@ export type ReaderAstNode =
79
83
  | ReaderLinkedField
80
84
  | ReaderNonLoadableResolverField
81
85
  | ReaderImperativelyLoadedField
82
- | ReaderLoadableField;
86
+ | LoadablySelectedField
87
+ | ReaderLinkField;
83
88
 
84
89
  // @ts-ignore
85
90
  export type ReaderAst<TReadFromStore> = ReadonlyArray<ReaderAstNode>;
@@ -89,7 +94,14 @@ export type ReaderScalarField = {
89
94
  readonly fieldName: string;
90
95
  readonly alias: string | null;
91
96
  readonly arguments: Arguments | null;
97
+ readonly isUpdatable: boolean;
98
+ };
99
+
100
+ export type ReaderLinkField = {
101
+ readonly kind: 'Link';
102
+ readonly alias: string;
92
103
  };
104
+
93
105
  export type ReaderLinkedField = {
94
106
  readonly kind: 'Linked';
95
107
  readonly fieldName: string;
@@ -97,9 +109,14 @@ export type ReaderLinkedField = {
97
109
  readonly selections: ReaderAst<unknown>;
98
110
  readonly arguments: Arguments | null;
99
111
  readonly condition: EagerReaderArtifact<
100
- { data: object; parameters: object },
101
- boolean | Link | null
112
+ { data: any; parameters: any; startUpdate?: StartUpdate<any> },
113
+ StoreLink | null
102
114
  > | null;
115
+ readonly isUpdatable: boolean;
116
+ /**
117
+ * If refetchQueryIndex != null, then the linked field is a client pointer.
118
+ */
119
+ readonly refetchQueryIndex: number | null;
103
120
  };
104
121
 
105
122
  export type ReaderNonLoadableResolverField = {
@@ -115,11 +132,11 @@ export type ReaderImperativelyLoadedField = {
115
132
  readonly kind: 'ImperativelyLoadedField';
116
133
  readonly alias: string;
117
134
  readonly refetchReaderArtifact: RefetchReaderArtifact;
118
- readonly refetchQuery: number;
135
+ readonly refetchQueryIndex: number;
119
136
  readonly name: string;
120
137
  };
121
138
 
122
- export type ReaderLoadableField = {
139
+ export type LoadablySelectedField = {
123
140
  readonly kind: 'LoadablySelectedField';
124
141
  readonly alias: string;
125
142
 
@@ -132,11 +149,11 @@ export type ReaderLoadableField = {
132
149
 
133
150
  // TODO we should not type these as any
134
151
  readonly entrypoint:
135
- | IsographEntrypoint<any, any>
152
+ | IsographEntrypoint<any, any, any>
136
153
  | IsographEntrypointLoader<any, any>;
137
154
  };
138
155
 
139
- type StableId = string;
156
+ export type StableId = string;
140
157
  /// Why is LoadableField the way it is? Let's work backwards.
141
158
  ///
142
159
  /// We ultimately need a stable id (for deduplication) and a way to produce a
@@ -147,7 +164,7 @@ type StableId = string;
147
164
  /// except to stringify the args or whatnot. Calling the factory can be
148
165
  /// expensive. For example, doing so will probably trigger a network request.
149
166
  export type LoadableField<
150
- TReadFromStore extends { data: object; parameters: object },
167
+ TReadFromStore extends UnknownTReadFromStore,
151
168
  TResult,
152
169
  TArgs = ExtractParameters<TReadFromStore>,
153
170
  > = (
@@ -156,5 +173,5 @@ export type LoadableField<
156
173
  // user-facing API. Users should only interact with LoadableFields via APIs
157
174
  // like useClientSideDefer. These APIs should have a nullable fetchOptions
158
175
  // parameter, and provide a default value ({}) to the LoadableField.
159
- fetchOptions: FetchOptions,
176
+ fetchOptions: FetchOptions<TResult>,
160
177
  ) => [StableId, Factory<FragmentReference<TReadFromStore, TResult>>];
@@ -0,0 +1,334 @@
1
+ import {
2
+ callSubscriptions,
3
+ getParentRecordKey,
4
+ insertEmptySetIfMissing,
5
+ type EncounteredIds,
6
+ } from './cache';
7
+ import type { RefetchQueryNormalizationArtifactWrapper } from './entrypoint';
8
+ import {
9
+ stableIdForFragmentReference,
10
+ type ExtractParameters,
11
+ type ExtractStartUpdate,
12
+ type ExtractUpdatableData,
13
+ type FragmentReference,
14
+ type UnknownTReadFromStore,
15
+ } from './FragmentReference';
16
+ import {
17
+ assertLink,
18
+ type IsographEnvironment,
19
+ type StoreLink,
20
+ } from './IsographEnvironment';
21
+ import { logMessage } from './logging';
22
+ import { readPromise, type PromiseWrapper } from './PromiseWrapper';
23
+ import {
24
+ readImperativelyLoadedField,
25
+ readLinkedFieldData,
26
+ readLoadablySelectedFieldData,
27
+ readResolverFieldData,
28
+ readScalarFieldData,
29
+ type NetworkRequestReaderOptions,
30
+ type ReadDataResultSuccess,
31
+ } from './read';
32
+ import type { ReaderAst } from './reader';
33
+
34
+ export function getOrCreateCachedStartUpdate<
35
+ TReadFromStore extends UnknownTReadFromStore,
36
+ >(
37
+ environment: IsographEnvironment,
38
+ fragmentReference: FragmentReference<TReadFromStore, unknown>,
39
+ eagerResolverName: string,
40
+ networkRequestOptions: NetworkRequestReaderOptions,
41
+ ): ExtractStartUpdate<TReadFromStore> {
42
+ return (environment.eagerReaderCache[
43
+ stableIdForFragmentReference(fragmentReference, eagerResolverName)
44
+ ] ??= createStartUpdate(
45
+ environment,
46
+ fragmentReference,
47
+ networkRequestOptions,
48
+ ));
49
+ }
50
+
51
+ export function createStartUpdate<TReadFromStore extends UnknownTReadFromStore>(
52
+ environment: IsographEnvironment,
53
+ fragmentReference: FragmentReference<TReadFromStore, unknown>,
54
+ networkRequestOptions: NetworkRequestReaderOptions,
55
+ ): ExtractStartUpdate<TReadFromStore> {
56
+ return (updater) => {
57
+ let mutableUpdatedIds: EncounteredIds = new Map();
58
+
59
+ let data = createUpdatableProxy(
60
+ environment,
61
+ fragmentReference,
62
+ networkRequestOptions,
63
+ mutableUpdatedIds,
64
+ );
65
+
66
+ try {
67
+ updater(data);
68
+ } catch (e) {
69
+ logMessage(environment, () => ({
70
+ kind: 'StartUpdateError',
71
+ error: e,
72
+ }));
73
+ throw e;
74
+ } finally {
75
+ logMessage(environment, () => ({
76
+ kind: 'StartUpdateComplete',
77
+ updatedIds: mutableUpdatedIds,
78
+ }));
79
+ callSubscriptions(environment, mutableUpdatedIds);
80
+ }
81
+ };
82
+ }
83
+
84
+ export function createUpdatableProxy<
85
+ TReadFromStore extends UnknownTReadFromStore,
86
+ >(
87
+ environment: IsographEnvironment,
88
+ fragmentReference: FragmentReference<TReadFromStore, unknown>,
89
+ networkRequestOptions: NetworkRequestReaderOptions,
90
+ mutableUpdatedIds: EncounteredIds,
91
+ ): ExtractUpdatableData<TReadFromStore> {
92
+ const readerWithRefetchQueries = readPromise(
93
+ fragmentReference.readerWithRefetchQueries,
94
+ );
95
+
96
+ return readUpdatableData(
97
+ environment,
98
+ readerWithRefetchQueries.readerArtifact.readerAst,
99
+ fragmentReference.root,
100
+ fragmentReference.variables ?? {},
101
+ readerWithRefetchQueries.nestedRefetchQueries,
102
+ fragmentReference.networkRequest,
103
+ networkRequestOptions,
104
+ {
105
+ lastInvalidated: 0,
106
+ },
107
+ mutableUpdatedIds,
108
+ ).data;
109
+ }
110
+
111
+ type MutableInvalidationState = {
112
+ lastInvalidated: number;
113
+ };
114
+
115
+ function defineCachedProperty<T>(
116
+ target: T,
117
+ property: PropertyKey,
118
+ mutableState: MutableInvalidationState,
119
+ get: () => any,
120
+ set?: (v: any) => void,
121
+ ) {
122
+ let value:
123
+ | { kind: 'Set'; value: T; validatedAt: number }
124
+ | {
125
+ kind: 'NotSet';
126
+ } = {
127
+ kind: 'NotSet',
128
+ };
129
+
130
+ Object.defineProperty(target, property, {
131
+ configurable: false,
132
+ enumerable: true,
133
+ get: () => {
134
+ if (
135
+ value.kind === 'NotSet' ||
136
+ value.validatedAt < mutableState.lastInvalidated
137
+ ) {
138
+ value = {
139
+ kind: 'Set',
140
+ value: get(),
141
+ validatedAt: mutableState.lastInvalidated,
142
+ };
143
+ }
144
+ return value.value;
145
+ },
146
+ ...(set && {
147
+ set: (newValue) => {
148
+ set(newValue);
149
+ mutableState.lastInvalidated++;
150
+ },
151
+ }),
152
+ });
153
+ }
154
+
155
+ function readUpdatableData<TReadFromStore extends UnknownTReadFromStore>(
156
+ environment: IsographEnvironment,
157
+ ast: ReaderAst<TReadFromStore>,
158
+ root: StoreLink,
159
+ variables: ExtractParameters<TReadFromStore>,
160
+ nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
161
+ networkRequest: PromiseWrapper<void, any>,
162
+ networkRequestOptions: NetworkRequestReaderOptions,
163
+ mutableState: MutableInvalidationState,
164
+ mutableUpdatedIds: EncounteredIds,
165
+ ): ReadDataResultSuccess<ExtractUpdatableData<TReadFromStore>> {
166
+ let storeRecord = environment.store[root.__typename]?.[root.__link];
167
+ if (storeRecord == null) {
168
+ return {
169
+ kind: 'Success',
170
+ data: null as any,
171
+ };
172
+ }
173
+
174
+ let target: { [index: string]: any } = {};
175
+
176
+ for (const field of ast) {
177
+ switch (field.kind) {
178
+ case 'Scalar': {
179
+ const storeRecordName = getParentRecordKey(field, variables);
180
+
181
+ defineCachedProperty(
182
+ target,
183
+ field.alias ?? field.fieldName,
184
+ mutableState,
185
+ () => {
186
+ const data = readScalarFieldData(
187
+ field,
188
+ storeRecord,
189
+ root,
190
+ variables,
191
+ );
192
+ if (data.kind === 'MissingData') {
193
+ throw new Error(data.reason);
194
+ }
195
+ return data.data;
196
+ },
197
+ field.isUpdatable
198
+ ? (newValue) => {
199
+ storeRecord[storeRecordName] = newValue;
200
+ const updatedIds = insertEmptySetIfMissing(
201
+ mutableUpdatedIds,
202
+ root.__typename,
203
+ );
204
+ updatedIds.add(root.__link);
205
+ }
206
+ : undefined,
207
+ );
208
+ break;
209
+ }
210
+ case 'Linked': {
211
+ const storeRecordName = getParentRecordKey(field, variables);
212
+ defineCachedProperty(
213
+ target,
214
+ field.alias ?? field.fieldName,
215
+ mutableState,
216
+ () => {
217
+ const data = readLinkedFieldData(
218
+ environment,
219
+ field,
220
+ storeRecord,
221
+ root,
222
+ variables,
223
+ nestedRefetchQueries,
224
+ networkRequest,
225
+ networkRequestOptions,
226
+ (ast, root) =>
227
+ readUpdatableData(
228
+ environment,
229
+ ast,
230
+ root,
231
+ variables,
232
+ nestedRefetchQueries,
233
+ networkRequest,
234
+ networkRequestOptions,
235
+ mutableState,
236
+ mutableUpdatedIds,
237
+ ),
238
+ );
239
+ if (data.kind === 'MissingData') {
240
+ throw new Error(data.reason);
241
+ }
242
+ return data.data;
243
+ },
244
+ 'isUpdatable' in field && field.isUpdatable
245
+ ? (newValue) => {
246
+ if (Array.isArray(newValue)) {
247
+ storeRecord[storeRecordName] = newValue.map((node) =>
248
+ assertLink(node?.link),
249
+ );
250
+ } else {
251
+ storeRecord[storeRecordName] = assertLink(newValue?.link);
252
+ }
253
+ const updatedIds = insertEmptySetIfMissing(
254
+ mutableUpdatedIds,
255
+ root.__typename,
256
+ );
257
+ updatedIds.add(root.__link);
258
+ }
259
+ : undefined,
260
+ );
261
+ break;
262
+ }
263
+ case 'ImperativelyLoadedField': {
264
+ defineCachedProperty(target, field.alias, mutableState, () => {
265
+ const data = readImperativelyLoadedField(
266
+ environment,
267
+ field,
268
+ root,
269
+ variables,
270
+ nestedRefetchQueries,
271
+ networkRequest,
272
+ networkRequestOptions,
273
+ new Map(),
274
+ );
275
+ if (data.kind === 'MissingData') {
276
+ throw new Error(data.reason);
277
+ }
278
+ return data.data;
279
+ });
280
+ break;
281
+ }
282
+ case 'Resolver': {
283
+ defineCachedProperty(target, field.alias, mutableState, () => {
284
+ const data = readResolverFieldData(
285
+ environment,
286
+ field,
287
+ root,
288
+ variables,
289
+ nestedRefetchQueries,
290
+ networkRequest,
291
+ networkRequestOptions,
292
+ new Map(),
293
+ );
294
+ if (data.kind === 'MissingData') {
295
+ throw new Error(data.reason);
296
+ }
297
+ return data.data;
298
+ });
299
+ break;
300
+ }
301
+ case 'LoadablySelectedField': {
302
+ defineCachedProperty(target, field.alias, mutableState, () => {
303
+ const data = readLoadablySelectedFieldData(
304
+ environment,
305
+ field,
306
+ root,
307
+ variables,
308
+ networkRequest,
309
+ networkRequestOptions,
310
+ new Map(),
311
+ );
312
+ if (data.kind === 'MissingData') {
313
+ throw new Error(data.reason);
314
+ }
315
+ return data.data;
316
+ });
317
+ break;
318
+ }
319
+ case 'Link': {
320
+ target[field.alias] = root;
321
+ break;
322
+ }
323
+ default: {
324
+ field satisfies never;
325
+ throw new Error('Unexpected case.');
326
+ }
327
+ }
328
+ }
329
+
330
+ return {
331
+ kind: 'Success',
332
+ data: target as any,
333
+ };
334
+ }
package/src/core/util.ts CHANGED
@@ -24,4 +24,8 @@ export type ArgumentValue =
24
24
  | {
25
25
  readonly kind: 'Enum';
26
26
  readonly value: string;
27
+ }
28
+ | {
29
+ readonly kind: 'Object';
30
+ readonly value: Arguments;
27
31
  };
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export {
3
3
  unretainQuery,
4
4
  type RetainedQuery,
5
5
  garbageCollectEnvironment,
6
+ type DidUnretainSomeQuery,
6
7
  } from './core/garbageCollection';
7
8
  export {
8
9
  type PromiseWrapper,
@@ -10,8 +11,21 @@ export {
10
11
  getPromiseState,
11
12
  wrapResolvedValue,
12
13
  wrapPromise,
14
+ type PromiseState,
15
+ type Result,
16
+ type AnyError,
17
+ type NotSet,
18
+ NOT_SET,
13
19
  } from './core/PromiseWrapper';
14
- export { subscribe, normalizeData } from './core/cache';
20
+ export {
21
+ callSubscriptions,
22
+ subscribe,
23
+ normalizeData,
24
+ type NetworkResponseObject,
25
+ type NetworkResponseValue,
26
+ type NetworkResponseScalarValue,
27
+ type EncounteredIds,
28
+ } from './core/cache';
15
29
  export { makeNetworkRequest } from './core/makeNetworkRequest';
16
30
  export {
17
31
  ROOT_ID,
@@ -20,10 +34,22 @@ export {
20
34
  type IsographEnvironment,
21
35
  type IsographNetworkFunction,
22
36
  type IsographStore,
37
+ type MissingFieldHandler,
38
+ type StoreLink,
23
39
  type Link,
24
40
  type StoreRecord,
41
+ type CacheMap,
25
42
  createIsographEnvironment,
26
43
  createIsographStore,
44
+ type FieldCache,
45
+ type Subscriptions,
46
+ type Subscription,
47
+ type TypeName,
48
+ type FragmentSubscription,
49
+ type AnyChangesToRecordSubscription,
50
+ type AnyRecordSubscription,
51
+ type ComponentOrFieldName,
52
+ type StringifiedArgs,
27
53
  } from './core/IsographEnvironment';
28
54
  export {
29
55
  type EagerReaderArtifact,
@@ -36,14 +62,24 @@ export {
36
62
  type ReaderScalarField,
37
63
  type TopLevelReaderArtifact,
38
64
  type LoadableField,
65
+ type StableId,
39
66
  type ResolverFirstParameter,
67
+ type ReaderImperativelyLoadedField,
68
+ type LoadablySelectedField as ReaderLoadableField,
69
+ type ReaderLinkField,
70
+ type StartUpdate,
40
71
  } from './core/reader';
41
72
  export {
42
73
  type NormalizationAst,
43
74
  type NormalizationAstNode,
75
+ type NormalizationAstNodes,
76
+ type NormalizationAstLoader,
44
77
  type NormalizationLinkedField,
45
78
  type NormalizationScalarField,
46
79
  type IsographEntrypoint,
80
+ type IsographOperation,
81
+ type IsographPersistedOperation,
82
+ type IsographPersistedOperationExtraInfo,
47
83
  assertIsEntrypoint,
48
84
  type RefetchQueryNormalizationArtifact,
49
85
  type RefetchQueryNormalizationArtifactWrapper,
@@ -51,8 +87,16 @@ export {
51
87
  type ExtractReadFromStore,
52
88
  type ExtractResolverResult,
53
89
  type NetworkRequestInfo,
90
+ type NormalizationInlineFragment,
91
+ type ReaderWithRefetchQueries,
92
+ type IsographEntrypointLoader,
54
93
  } from './core/entrypoint';
55
- export { readButDoNotEvaluate } from './core/read';
94
+ export {
95
+ readButDoNotEvaluate,
96
+ type WithEncounteredRecords,
97
+ type NetworkRequestReaderOptions,
98
+ type ReadDataResult,
99
+ } from './core/read';
56
100
  export {
57
101
  type ExtractSecondParam,
58
102
  type CombineWithIntrinsicAttributes,
@@ -66,23 +110,44 @@ export {
66
110
  type Variables,
67
111
  type ExtractParameters,
68
112
  type ExtractData,
113
+ type UnknownTReadFromStore,
69
114
  stableIdForFragmentReference,
115
+ type ExtractStartUpdate,
116
+ type VariableValue,
117
+ type StableIdForFragmentReference,
70
118
  } from './core/FragmentReference';
71
119
  export {
72
120
  type LogMessage,
73
121
  type LogFunction,
122
+ type WrappedLogFunction,
74
123
  logMessage,
75
124
  registerLogger,
76
125
  } from './core/logging';
77
- export { check, CheckResult, FetchOptions, ShouldFetch } from './core/check';
126
+ export {
127
+ check,
128
+ type CheckResult,
129
+ type FetchOptions,
130
+ type RequiredFetchOptions,
131
+ type ShouldFetch,
132
+ type RequiredShouldFetch,
133
+ } from './core/check';
78
134
 
79
135
  export {
80
136
  IsographEnvironmentProvider,
81
137
  useIsographEnvironment,
82
138
  type IsographEnvironmentProviderProps,
83
139
  } from './react/IsographEnvironmentProvider';
84
- export { useImperativeReference } from './react/useImperativeReference';
140
+ export {
141
+ useImperativeReference,
142
+ type UseImperativeReferenceResult,
143
+ } from './react/useImperativeReference';
144
+ export {
145
+ FragmentRenderer,
146
+ type IsExactlyIntrinsicAttributes,
147
+ } from './react/FragmentRenderer';
85
148
  export { FragmentReader } from './react/FragmentReader';
149
+ export { LoadableFieldReader } from './react/LoadableFieldReader';
150
+ export { LoadableFieldRenderer } from './react/LoadableFieldRenderer';
86
151
  export { useResult } from './react/useResult';
87
152
  export {
88
153
  useReadAndSubscribe,
@@ -93,7 +158,23 @@ export { useRerenderOnChange } from './react/useRerenderOnChange';
93
158
  export { RenderAfterCommit__DO_NOT_USE } from './react/RenderAfterCommit__DO_NOT_USE';
94
159
 
95
160
  export { useClientSideDefer } from './loadable-hooks/useClientSideDefer';
96
- export { useImperativeExposedMutationField } from './loadable-hooks/useImperativeExposedMutationField';
97
- export { useSkipLimitPagination } from './loadable-hooks/useSkipLimitPagination';
98
- export { useConnectionSpecPagination } from './loadable-hooks/useConnectionSpecPagination';
99
- export { useImperativeLoadableField } from './loadable-hooks/useImperativeLoadableField';
161
+ export {
162
+ useImperativeExposedMutationField,
163
+ type UseImperativeLoadableFieldReturn as UseImperativeExposedMutationFieldReturn,
164
+ } from './loadable-hooks/useImperativeExposedMutationField';
165
+ export {
166
+ useSkipLimitPagination,
167
+ type UseSkipLimitPaginationArgs,
168
+ type UseSkipLimitReturnValue,
169
+ } from './loadable-hooks/useSkipLimitPagination';
170
+ export {
171
+ useConnectionSpecPagination,
172
+ type Connection,
173
+ type PageInfo,
174
+ type UseConnectionSpecPaginationArgs,
175
+ type UsePaginationReturnValue,
176
+ } from './loadable-hooks/useConnectionSpecPagination';
177
+ export {
178
+ useImperativeLoadableField,
179
+ type UseImperativeLoadableFieldReturn,
180
+ } from './loadable-hooks/useImperativeLoadableField';