@isograph/react 0.0.0-main-ae8aa2fe → 0.0.0-main-d3ef6e33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/FragmentReference.d.ts +2 -0
- package/dist/core/PromiseWrapper.d.ts +17 -4
- package/dist/core/PromiseWrapper.js +35 -10
- package/dist/core/cache.d.ts +2 -2
- package/dist/core/cache.js +31 -4
- package/dist/core/componentCache.d.ts +2 -1
- package/dist/core/componentCache.js +2 -2
- package/dist/core/entrypoint.d.ts +2 -0
- package/dist/core/makeNetworkRequest.d.ts +2 -2
- package/dist/core/makeNetworkRequest.js +6 -2
- package/dist/core/read.d.ts +5 -1
- package/dist/core/read.js +75 -33
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -3
- package/dist/loadable-hooks/useClientSideDefer.js +0 -1
- package/dist/react/{FragmentReferenceReader.d.ts → FragmentReader.d.ts} +4 -1
- package/dist/react/{FragmentReferenceReader.js → FragmentReader.js} +5 -4
- package/dist/react/useImperativeReference.d.ts +1 -1
- package/dist/react/useImperativeReference.js +3 -2
- package/dist/react/useLazyReference.js +2 -3
- package/dist/react/useReadAndSubscribe.d.ts +2 -2
- package/dist/react/useReadAndSubscribe.js +5 -3
- package/dist/react/useRerenderOnChange.d.ts +1 -2
- package/dist/react/useRerenderOnChange.js +3 -1
- package/dist/react/useResult.d.ts +4 -1
- package/dist/react/useResult.js +17 -4
- package/package.json +3 -3
- package/src/core/FragmentReference.ts +2 -0
- package/src/core/PromiseWrapper.ts +58 -12
- package/src/core/cache.ts +80 -57
- package/src/core/componentCache.ts +6 -1
- package/src/core/entrypoint.ts +1 -0
- package/src/core/makeNetworkRequest.ts +11 -6
- package/src/core/read.ts +108 -41
- package/src/index.ts +35 -25
- package/src/loadable-hooks/useClientSideDefer.ts +1 -1
- package/src/react/{FragmentReferenceReader.tsx → FragmentReader.tsx} +8 -2
- package/src/react/useImperativeReference.ts +4 -3
- package/src/react/useLazyReference.ts +2 -3
- package/src/react/useReadAndSubscribe.ts +8 -5
- package/src/react/useRerenderOnChange.ts +2 -2
- package/src/react/useResult.ts +28 -1
@@ -1,6 +1,7 @@
|
|
1
1
|
import { DataId } from './IsographEnvironment';
|
2
2
|
import { RefetchQueryNormalizationArtifactWrapper } from '../core/entrypoint';
|
3
3
|
import { TopLevelReaderArtifact } from './reader';
|
4
|
+
import { PromiseWrapper } from './PromiseWrapper';
|
4
5
|
export type VariableValue = string | number | boolean | null | object;
|
5
6
|
export type Variables = {
|
6
7
|
readonly [index: string]: VariableValue;
|
@@ -11,4 +12,5 @@ export type FragmentReference<TReadFromStore extends Object, TClientFieldValue>
|
|
11
12
|
readonly root: DataId;
|
12
13
|
readonly variables: Variables | null;
|
13
14
|
readonly nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[];
|
15
|
+
readonly networkRequest: PromiseWrapper<void, any>;
|
14
16
|
};
|
@@ -1,13 +1,26 @@
|
|
1
|
+
export type AnyError = any;
|
1
2
|
declare const NOT_SET: Symbol;
|
2
3
|
type NotSet = typeof NOT_SET;
|
4
|
+
type Result<T, E> = {
|
5
|
+
kind: 'Ok';
|
6
|
+
value: T;
|
7
|
+
} | {
|
8
|
+
kind: 'Err';
|
9
|
+
error: E;
|
10
|
+
};
|
3
11
|
/**
|
4
12
|
* Invariant:
|
5
13
|
* Before the promise is resolved, value becomes non-null.
|
6
14
|
*/
|
7
|
-
export type PromiseWrapper<T> = {
|
15
|
+
export type PromiseWrapper<T, E> = {
|
8
16
|
readonly promise: Promise<T>;
|
9
|
-
|
17
|
+
result: Result<Exclude<T, NotSet>, E> | NotSet;
|
10
18
|
};
|
11
|
-
export declare function wrapPromise<T>(promise: Promise<T>): PromiseWrapper<T>;
|
12
|
-
export declare function
|
19
|
+
export declare function wrapPromise<T>(promise: Promise<T>): PromiseWrapper<T, any>;
|
20
|
+
export declare function readPromise<T, E>(p: PromiseWrapper<T, E>): T;
|
21
|
+
export type PromiseState<T, E> = {
|
22
|
+
kind: 'Pending';
|
23
|
+
promise: Promise<T>;
|
24
|
+
} | Result<T, E>;
|
25
|
+
export declare function getPromiseState<T, E>(p: PromiseWrapper<T, E>): PromiseState<T, E>;
|
13
26
|
export {};
|
@@ -1,22 +1,47 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.
|
3
|
+
exports.getPromiseState = exports.readPromise = exports.wrapPromise = void 0;
|
4
4
|
const NOT_SET = Symbol('NOT_SET');
|
5
5
|
function wrapPromise(promise) {
|
6
6
|
// TODO confirm suspense works if the promise is already resolved.
|
7
|
-
const wrapper = { promise,
|
8
|
-
promise
|
9
|
-
|
10
|
-
|
7
|
+
const wrapper = { promise, result: NOT_SET };
|
8
|
+
promise
|
9
|
+
.then((v) => {
|
10
|
+
// v is assignable to Exclude<T, Symbol> | Symbol
|
11
|
+
wrapper.result = { kind: 'Ok', value: v };
|
12
|
+
})
|
13
|
+
.catch((e) => {
|
14
|
+
// e is assignable to Exclude<T, Symbol> | Symbol
|
15
|
+
wrapper.result = { kind: 'Err', error: e };
|
11
16
|
});
|
12
17
|
return wrapper;
|
13
18
|
}
|
14
19
|
exports.wrapPromise = wrapPromise;
|
15
|
-
function
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
function readPromise(p) {
|
21
|
+
const { result } = p;
|
22
|
+
if (result !== NOT_SET) {
|
23
|
+
// Safety: p.result is either NOT_SET or an actual value.
|
24
|
+
const resultKind = result;
|
25
|
+
if (resultKind.kind === 'Ok') {
|
26
|
+
return resultKind.value;
|
27
|
+
}
|
28
|
+
else {
|
29
|
+
throw resultKind.error;
|
30
|
+
}
|
19
31
|
}
|
20
32
|
throw p.promise;
|
21
33
|
}
|
22
|
-
exports.
|
34
|
+
exports.readPromise = readPromise;
|
35
|
+
function getPromiseState(p) {
|
36
|
+
const { result } = p;
|
37
|
+
if (result !== NOT_SET) {
|
38
|
+
// Safety: p.result is either NOT_SET or an actual value.
|
39
|
+
const resultKind = result;
|
40
|
+
return resultKind;
|
41
|
+
}
|
42
|
+
return {
|
43
|
+
kind: 'Pending',
|
44
|
+
promise: p.promise,
|
45
|
+
};
|
46
|
+
}
|
47
|
+
exports.getPromiseState = getPromiseState;
|
package/dist/core/cache.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Factory, ParentCache } from '@isograph/react-disposable-state';
|
2
|
-
import { PromiseWrapper } from './PromiseWrapper';
|
2
|
+
import { AnyError, PromiseWrapper } from './PromiseWrapper';
|
3
3
|
import { DataId, type IsographEnvironment } from './IsographEnvironment';
|
4
4
|
import { IsographEntrypoint, NormalizationAst, NormalizationLinkedField, NormalizationScalarField, RefetchQueryNormalizationArtifactWrapper } from '../core/entrypoint';
|
5
5
|
import { ReaderLinkedField, ReaderScalarField } from './reader';
|
@@ -17,7 +17,7 @@ export declare function getOrCreateCache<T>(environment: IsographEnvironment, in
|
|
17
17
|
* results.
|
18
18
|
*/
|
19
19
|
export declare function stableCopy<T>(value: T): T;
|
20
|
-
export declare function getOrCreateCacheForArtifact<TReadFromStore extends Object, TClientFieldValue>(environment: IsographEnvironment, artifact: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: Variables): ParentCache<PromiseWrapper<
|
20
|
+
export declare function getOrCreateCacheForArtifact<TReadFromStore extends Object, TClientFieldValue>(environment: IsographEnvironment, artifact: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: Variables): ParentCache<PromiseWrapper<void, AnyError>>;
|
21
21
|
type NetworkResponseScalarValue = string | number | boolean;
|
22
22
|
type NetworkResponseValue = NetworkResponseScalarValue | null | NetworkResponseObject | NetworkResponseObject[] | NetworkResponseScalarValue[];
|
23
23
|
type NetworkResponseObject = {
|
package/dist/core/cache.js
CHANGED
@@ -96,15 +96,41 @@ function onNextChange(environment) {
|
|
96
96
|
});
|
97
97
|
}
|
98
98
|
exports.onNextChange = onNextChange;
|
99
|
+
// Calls to readButDoNotEvaluate can suspend (i.e. throw a promise).
|
100
|
+
// Maybe in the future, they will be able to throw errors.
|
101
|
+
//
|
102
|
+
// That's probably okay to ignore. We don't, however, want to prevent
|
103
|
+
// updating other subscriptions if one subscription had missing data.
|
104
|
+
function withErrorHandling(f) {
|
105
|
+
return (t) => {
|
106
|
+
try {
|
107
|
+
return f(t);
|
108
|
+
}
|
109
|
+
catch (_a) { }
|
110
|
+
};
|
111
|
+
}
|
99
112
|
function callSubscriptions(environment, recordsEncounteredWhenNormalizing) {
|
100
|
-
environment.subscriptions.forEach((subscription) => {
|
113
|
+
environment.subscriptions.forEach(withErrorHandling((subscription) => {
|
101
114
|
switch (subscription.kind) {
|
102
115
|
case 'FragmentSubscription': {
|
103
116
|
// TODO if there are multiple components subscribed to the same
|
104
117
|
// fragment, we will call readButNotEvaluate multiple times. We
|
105
118
|
// should fix that.
|
106
119
|
if (hasOverlappingIds(recordsEncounteredWhenNormalizing, subscription.encounteredDataAndRecords.encounteredRecords)) {
|
107
|
-
const newEncounteredDataAndRecords = (0, read_1.readButDoNotEvaluate)(environment, subscription.fragmentReference
|
120
|
+
const newEncounteredDataAndRecords = (0, read_1.readButDoNotEvaluate)(environment, subscription.fragmentReference,
|
121
|
+
// Is this wrong?
|
122
|
+
// Reasons to think no:
|
123
|
+
// - we are only updating the read-out value, and the network
|
124
|
+
// options only affect whether we throw.
|
125
|
+
// - the component will re-render, and re-throw on its own, anyway.
|
126
|
+
//
|
127
|
+
// Reasons to think not:
|
128
|
+
// - it seems more efficient to suspend here and not update state,
|
129
|
+
// if we expect that the component will just throw anyway
|
130
|
+
// - consistency
|
131
|
+
// - it's also weird, this is called from makeNetworkRequest, where
|
132
|
+
// we don't currently pass network request options
|
133
|
+
{});
|
108
134
|
if (!(0, areEqualWithDeepComparison_1.areEqualObjectsWithDeepComparison)(subscription.encounteredDataAndRecords.item, newEncounteredDataAndRecords.item)) {
|
109
135
|
if (typeof window !== 'undefined' && window.__LOG) {
|
110
136
|
console.log('Deep equality - No', {
|
@@ -137,7 +163,7 @@ function callSubscriptions(environment, recordsEncounteredWhenNormalizing) {
|
|
137
163
|
throw new Error('Unexpected case');
|
138
164
|
}
|
139
165
|
}
|
140
|
-
});
|
166
|
+
}));
|
141
167
|
}
|
142
168
|
function hasOverlappingIds(set1, set2) {
|
143
169
|
for (const id of set1) {
|
@@ -309,12 +335,13 @@ function getParentRecordKey(astNode, variables) {
|
|
309
335
|
}
|
310
336
|
exports.getParentRecordKey = getParentRecordKey;
|
311
337
|
function getStoreKeyChunkForArgumentValue(argumentValue, variables) {
|
338
|
+
var _a;
|
312
339
|
switch (argumentValue.kind) {
|
313
340
|
case 'Literal': {
|
314
341
|
return argumentValue.value;
|
315
342
|
}
|
316
343
|
case 'Variable': {
|
317
|
-
return variables[argumentValue.name];
|
344
|
+
return (_a = variables[argumentValue.name]) !== null && _a !== void 0 ? _a : 'null';
|
318
345
|
}
|
319
346
|
case 'String': {
|
320
347
|
return argumentValue.value;
|
@@ -1,4 +1,5 @@
|
|
1
1
|
/// <reference types="react" />
|
2
2
|
import { IsographEnvironment } from './IsographEnvironment';
|
3
3
|
import { FragmentReference } from './FragmentReference';
|
4
|
-
|
4
|
+
import { NetworkRequestReaderOptions } from './read';
|
5
|
+
export declare function getOrCreateCachedComponent(environment: IsographEnvironment, componentName: string, fragmentReference: FragmentReference<any, any>, networkRequestOptions: NetworkRequestReaderOptions): React.FC<any>;
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getOrCreateCachedComponent = void 0;
|
4
4
|
const cache_1 = require("./cache");
|
5
5
|
const useReadAndSubscribe_1 = require("../react/useReadAndSubscribe");
|
6
|
-
function getOrCreateCachedComponent(environment, componentName, fragmentReference) {
|
6
|
+
function getOrCreateCachedComponent(environment, componentName, fragmentReference, networkRequestOptions) {
|
7
7
|
var _a, _b, _c;
|
8
8
|
// cachedComponentsById is a three layer cache: id, then component name, then
|
9
9
|
// stringified args. These three, together, uniquely identify a read at a given
|
@@ -18,7 +18,7 @@ function getOrCreateCachedComponent(environment, componentName, fragmentReferenc
|
|
18
18
|
byArgs[stringifiedArgs] =
|
19
19
|
(_c = byArgs[stringifiedArgs]) !== null && _c !== void 0 ? _c : (() => {
|
20
20
|
function Component(additionalRuntimeProps) {
|
21
|
-
const data = (0, useReadAndSubscribe_1.useReadAndSubscribe)(
|
21
|
+
const data = (0, useReadAndSubscribe_1.useReadAndSubscribe)(fragmentReference, networkRequestOptions);
|
22
22
|
if (typeof window !== 'undefined' && window.__LOG) {
|
23
23
|
console.log('Component re-rendered: ' +
|
24
24
|
componentName +
|
@@ -1,3 +1,4 @@
|
|
1
|
+
/// <reference types="react" />
|
1
2
|
import { TopLevelReaderArtifact } from './reader';
|
2
3
|
import { Arguments } from './util';
|
3
4
|
export type IsographEntrypoint<TReadFromStore extends Object, TClientFieldValue> = {
|
@@ -37,3 +38,4 @@ export type RefetchQueryNormalizationArtifactWrapper = {
|
|
37
38
|
export declare function assertIsEntrypoint<TReadFromStore extends Object, TClientFieldValue>(value: IsographEntrypoint<TReadFromStore, TClientFieldValue> | ((_: any) => any) | any): asserts value is IsographEntrypoint<TReadFromStore, TClientFieldValue>;
|
38
39
|
export type ExtractReadFromStore<Type> = Type extends IsographEntrypoint<infer X, any> ? X : never;
|
39
40
|
export type ExtractResolverResult<Type> = Type extends IsographEntrypoint<any, infer X> ? X : never;
|
41
|
+
export type ExtractProps<Type> = Type extends React.FC<infer X> ? X : never;
|
@@ -2,5 +2,5 @@ import { ItemCleanupPair } from '@isograph/disposable-types';
|
|
2
2
|
import { IsographEntrypoint, RefetchQueryNormalizationArtifact } from './entrypoint';
|
3
3
|
import { Variables } from './FragmentReference';
|
4
4
|
import { IsographEnvironment } from './IsographEnvironment';
|
5
|
-
import { PromiseWrapper } from './PromiseWrapper';
|
6
|
-
export declare function makeNetworkRequest
|
5
|
+
import { AnyError, PromiseWrapper } from './PromiseWrapper';
|
6
|
+
export declare function makeNetworkRequest(environment: IsographEnvironment, artifact: RefetchQueryNormalizationArtifact | IsographEntrypoint<any, any>, variables: Variables): ItemCleanupPair<PromiseWrapper<void, AnyError>>;
|
@@ -19,6 +19,12 @@ function makeNetworkRequest(environment, artifact, variables) {
|
|
19
19
|
if (typeof window !== 'undefined' && window.__LOG) {
|
20
20
|
console.log('network response', artifact, networkResponse);
|
21
21
|
}
|
22
|
+
if (networkResponse.errors != null) {
|
23
|
+
// @ts-expect-error Why are we getting the wrong constructor here?
|
24
|
+
throw new Error('GraphQL network response had errors', {
|
25
|
+
cause: networkResponse,
|
26
|
+
});
|
27
|
+
}
|
22
28
|
if (status.kind === 'UndisposedIncomplete') {
|
23
29
|
(0, cache_1.normalizeData)(environment, artifact.normalizationAst, (_a = networkResponse.data) !== null && _a !== void 0 ? _a : {}, variables, artifact.kind === 'Entrypoint' ? artifact.nestedRefetchQueries : []);
|
24
30
|
const retainedQuery = {
|
@@ -31,8 +37,6 @@ function makeNetworkRequest(environment, artifact, variables) {
|
|
31
37
|
};
|
32
38
|
(0, garbageCollection_1.retainQuery)(environment, retainedQuery);
|
33
39
|
}
|
34
|
-
// TODO return null
|
35
|
-
return networkResponse;
|
36
40
|
});
|
37
41
|
const wrapper = (0, PromiseWrapper_1.wrapPromise)(promise);
|
38
42
|
const response = [
|
package/dist/core/read.d.ts
CHANGED
@@ -4,4 +4,8 @@ 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,
|
7
|
+
export declare function readButDoNotEvaluate<TReadFromStore extends Object>(environment: IsographEnvironment, fragmentReference: FragmentReference<TReadFromStore, unknown>, networkRequestOptions: NetworkRequestReaderOptions): WithEncounteredRecords<TReadFromStore>;
|
8
|
+
export type NetworkRequestReaderOptions = {
|
9
|
+
suspendIfInFlight?: boolean;
|
10
|
+
throwOnNetworkError?: boolean;
|
11
|
+
};
|
package/dist/core/read.js
CHANGED
@@ -5,14 +5,31 @@ const cache_1 = require("./cache");
|
|
5
5
|
const componentCache_1 = require("./componentCache");
|
6
6
|
const IsographEnvironment_1 = require("./IsographEnvironment");
|
7
7
|
const makeNetworkRequest_1 = require("./makeNetworkRequest");
|
8
|
-
function readButDoNotEvaluate(environment,
|
8
|
+
function readButDoNotEvaluate(environment, fragmentReference, networkRequestOptions) {
|
9
9
|
var _a;
|
10
10
|
const mutableEncounteredRecords = new Set();
|
11
|
-
const response = readData(environment,
|
11
|
+
const response = readData(environment, fragmentReference.readerArtifact.readerAst, fragmentReference.root, (_a = fragmentReference.variables) !== null && _a !== void 0 ? _a : {}, fragmentReference.nestedRefetchQueries, fragmentReference.networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
12
12
|
if (typeof window !== 'undefined' && window.__LOG) {
|
13
13
|
console.log('done reading', { response });
|
14
14
|
}
|
15
15
|
if (response.kind === 'MissingData') {
|
16
|
+
// There are two cases here that we care about:
|
17
|
+
// 1. the network request is in flight, we haven't suspend on it, and we want
|
18
|
+
// to throw if it errors out. So, networkRequestOptions.suspendIfInFlight === false
|
19
|
+
// and networkRequestOptions.throwOnNetworkError === true.
|
20
|
+
// 2. everything else
|
21
|
+
//
|
22
|
+
// In the first case, we cannot simply throw onNextChange, because if the network
|
23
|
+
// response errors out, we will not update the store, so the onNextChange promise
|
24
|
+
// will not resolve.
|
25
|
+
if (!networkRequestOptions.suspendIfInFlight &&
|
26
|
+
networkRequestOptions.throwOnNetworkError) {
|
27
|
+
// TODO assert that the network request state is not Err
|
28
|
+
throw new Promise((resolve, reject) => {
|
29
|
+
(0, cache_1.onNextChange)(environment).then(resolve);
|
30
|
+
fragmentReference.networkRequest.promise.catch(reject);
|
31
|
+
});
|
32
|
+
}
|
16
33
|
throw (0, cache_1.onNextChange)(environment);
|
17
34
|
}
|
18
35
|
else {
|
@@ -23,7 +40,7 @@ function readButDoNotEvaluate(environment, reference) {
|
|
23
40
|
}
|
24
41
|
}
|
25
42
|
exports.readButDoNotEvaluate = readButDoNotEvaluate;
|
26
|
-
function readData(environment, ast, root, variables, nestedRefetchQueries, mutableEncounteredRecords) {
|
43
|
+
function readData(environment, ast, root, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords) {
|
27
44
|
var _a, _b, _c, _d, _e;
|
28
45
|
mutableEncounteredRecords.add(root);
|
29
46
|
let storeRecord = environment.store[root];
|
@@ -79,7 +96,7 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, mutab
|
|
79
96
|
results.push(null);
|
80
97
|
continue;
|
81
98
|
}
|
82
|
-
const result = readData(environment, field.selections, link.__link, variables, nestedRefetchQueries, mutableEncounteredRecords);
|
99
|
+
const result = readData(environment, field.selections, link.__link, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
83
100
|
if (result.kind === 'MissingData') {
|
84
101
|
return {
|
85
102
|
kind: 'MissingData',
|
@@ -122,7 +139,7 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, mutab
|
|
122
139
|
break;
|
123
140
|
}
|
124
141
|
const targetId = link.__link;
|
125
|
-
const data = readData(environment, field.selections, targetId, variables, nestedRefetchQueries, mutableEncounteredRecords);
|
142
|
+
const data = readData(environment, field.selections, targetId, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
126
143
|
if (data.kind === 'MissingData') {
|
127
144
|
return {
|
128
145
|
kind: 'MissingData',
|
@@ -138,7 +155,10 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, mutab
|
|
138
155
|
// id field).
|
139
156
|
const data = readData(environment, field.refetchReaderArtifact.readerAst, root, variables,
|
140
157
|
// Refetch fields just read the id, and don't need refetch query artifacts
|
141
|
-
[],
|
158
|
+
[],
|
159
|
+
// This is probably indicative of the fact that we are doing redundant checks
|
160
|
+
// on the status of this network request...
|
161
|
+
networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
142
162
|
if (data.kind === 'MissingData') {
|
143
163
|
return {
|
144
164
|
kind: 'MissingData',
|
@@ -172,7 +192,7 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, mutab
|
|
172
192
|
const resolverRefetchQueries = usedRefetchQueries.map((index) => nestedRefetchQueries[index]);
|
173
193
|
const kind = field.readerArtifact.kind;
|
174
194
|
if (kind === 'EagerReaderArtifact') {
|
175
|
-
const data = readData(environment, field.readerArtifact.readerAst, root, variables, resolverRefetchQueries, mutableEncounteredRecords);
|
195
|
+
const data = readData(environment, field.readerArtifact.readerAst, root, variables, resolverRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
176
196
|
if (data.kind === 'MissingData') {
|
177
197
|
return {
|
178
198
|
kind: 'MissingData',
|
@@ -190,15 +210,16 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, mutab
|
|
190
210
|
readerArtifact: field.readerArtifact,
|
191
211
|
root,
|
192
212
|
variables: generateChildVariableMap(variables, field.arguments),
|
213
|
+
networkRequest,
|
193
214
|
nestedRefetchQueries: resolverRefetchQueries,
|
194
|
-
});
|
215
|
+
}, networkRequestOptions);
|
195
216
|
}
|
196
217
|
break;
|
197
218
|
}
|
198
219
|
case 'LoadablySelectedField': {
|
199
220
|
const refetchReaderParams = readData(environment, field.refetchReaderAst, root, variables,
|
200
221
|
// Refetch fields just read the id, and don't need refetch query artifacts
|
201
|
-
[], mutableEncounteredRecords);
|
222
|
+
[], networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
202
223
|
if (refetchReaderParams.kind === 'MissingData') {
|
203
224
|
return {
|
204
225
|
kind: 'MissingData',
|
@@ -207,30 +228,37 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, mutab
|
|
207
228
|
};
|
208
229
|
}
|
209
230
|
else {
|
210
|
-
target[field.alias] = (args) =>
|
211
|
-
//
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
231
|
+
target[field.alias] = (args) => {
|
232
|
+
// TODO we should use the reader AST for this
|
233
|
+
const includeReadOutData = (variables, readOutData) => {
|
234
|
+
variables.id = readOutData.id;
|
235
|
+
return variables;
|
236
|
+
};
|
237
|
+
const localVariables = includeReadOutData(args !== null && args !== void 0 ? args : {}, refetchReaderParams.data);
|
238
|
+
writeQueryArgsToVariables(localVariables, field.queryArguments, variables);
|
239
|
+
return [
|
240
|
+
// Stable id
|
241
|
+
root +
|
242
|
+
'/' +
|
243
|
+
field.name +
|
244
|
+
'/' +
|
245
|
+
stableStringifyArgs(localVariables),
|
246
|
+
// Fetcher
|
247
|
+
() => {
|
248
|
+
const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.makeNetworkRequest)(environment, field.entrypoint, localVariables);
|
249
|
+
const fragmentReference = {
|
250
|
+
kind: 'FragmentReference',
|
251
|
+
readerArtifact: field.entrypoint.readerArtifact,
|
252
|
+
// TODO localVariables is not guaranteed to have an id field
|
253
|
+
root: localVariables.id,
|
254
|
+
variables: localVariables,
|
255
|
+
nestedRefetchQueries: field.entrypoint.nestedRefetchQueries,
|
256
|
+
networkRequest,
|
257
|
+
};
|
258
|
+
return [fragmentReference, disposeNetworkRequest];
|
259
|
+
},
|
260
|
+
];
|
261
|
+
};
|
234
262
|
}
|
235
263
|
break;
|
236
264
|
}
|
@@ -301,3 +329,17 @@ function writeQueryArgsToVariables(targetVariables, queryArgs, variables) {
|
|
301
329
|
}
|
302
330
|
}
|
303
331
|
}
|
332
|
+
// TODO use a description of the params for this?
|
333
|
+
// TODO call stableStringifyArgs on the variable values, as well.
|
334
|
+
// This doesn't matter for now, since we are just using primitive values
|
335
|
+
// in the demo.
|
336
|
+
function stableStringifyArgs(args) {
|
337
|
+
const keys = Object.keys(args);
|
338
|
+
keys.sort();
|
339
|
+
let s = '';
|
340
|
+
for (const key of keys) {
|
341
|
+
// @ts-expect-error
|
342
|
+
s += `${key}=${JSON.stringify(args[key])};`;
|
343
|
+
}
|
344
|
+
return s;
|
345
|
+
}
|
package/dist/index.d.ts
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
export { retainQuery, unretainQuery, type RetainedQuery, garbageCollectEnvironment, } from './core/garbageCollection';
|
2
|
-
export { type PromiseWrapper } from './core/PromiseWrapper';
|
2
|
+
export { type PromiseWrapper, readPromise, getPromiseState, } from './core/PromiseWrapper';
|
3
3
|
export { subscribe, normalizeData } from './core/cache';
|
4
4
|
export { makeNetworkRequest } from './core/makeNetworkRequest';
|
5
5
|
export { ROOT_ID, type DataId, type DataTypeValue, type IsographEnvironment, type IsographNetworkFunction, type IsographStore, type Link, type StoreRecord, createIsographEnvironment, createIsographStore, defaultMissingFieldHandler, } from './core/IsographEnvironment';
|
6
|
-
export { EagerReaderArtifact, ComponentReaderArtifact, RefetchReaderArtifact, ReaderAst, ReaderAstNode, ReaderLinkedField, ReaderNonLoadableResolverField, ReaderScalarField, TopLevelReaderArtifact, LoadableField, } from './core/reader';
|
7
|
-
export { NormalizationAst, NormalizationAstNode, NormalizationLinkedField, NormalizationScalarField, IsographEntrypoint, assertIsEntrypoint, RefetchQueryNormalizationArtifact, RefetchQueryNormalizationArtifactWrapper, } from './core/entrypoint';
|
6
|
+
export { type EagerReaderArtifact, type ComponentReaderArtifact, type RefetchReaderArtifact, type ReaderAst, type ReaderAstNode, type ReaderLinkedField, type ReaderNonLoadableResolverField, type ReaderScalarField, type TopLevelReaderArtifact, type LoadableField, } from './core/reader';
|
7
|
+
export { type NormalizationAst, type NormalizationAstNode, type NormalizationLinkedField, type NormalizationScalarField, type IsographEntrypoint, assertIsEntrypoint, type RefetchQueryNormalizationArtifact, type RefetchQueryNormalizationArtifactWrapper, type ExtractProps, type ExtractReadFromStore, type ExtractResolverResult, } from './core/entrypoint';
|
8
8
|
export { readButDoNotEvaluate } from './core/read';
|
9
|
-
export { ExtractSecondParam, Argument, ArgumentName, ArgumentValue, Arguments, } from './core/util';
|
10
|
-
export { type FragmentReference } from './core/FragmentReference';
|
9
|
+
export { type ExtractSecondParam, type Argument, type ArgumentName, type ArgumentValue, type Arguments, } from './core/util';
|
10
|
+
export { type FragmentReference, type Variables, } from './core/FragmentReference';
|
11
11
|
export { IsographEnvironmentProvider, useIsographEnvironment, type IsographEnvironmentProviderProps, } from './react/IsographEnvironmentProvider';
|
12
12
|
export { useImperativeReference } from './react/useImperativeReference';
|
13
|
-
export {
|
13
|
+
export { FragmentReader } from './react/FragmentReader';
|
14
14
|
export { useResult } from './react/useResult';
|
15
15
|
export { useLazyReference } from './react/useLazyReference';
|
16
16
|
export { useRerenderOnChange } from './react/useRerenderOnChange';
|
package/dist/index.js
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.useClientSideDefer = exports.useRerenderOnChange = exports.useLazyReference = exports.useResult = exports.
|
3
|
+
exports.useClientSideDefer = exports.useRerenderOnChange = exports.useLazyReference = exports.useResult = exports.FragmentReader = exports.useImperativeReference = exports.useIsographEnvironment = exports.IsographEnvironmentProvider = exports.readButDoNotEvaluate = exports.assertIsEntrypoint = exports.defaultMissingFieldHandler = exports.createIsographStore = exports.createIsographEnvironment = exports.ROOT_ID = exports.makeNetworkRequest = exports.normalizeData = exports.subscribe = exports.getPromiseState = exports.readPromise = exports.garbageCollectEnvironment = exports.unretainQuery = exports.retainQuery = void 0;
|
4
4
|
var garbageCollection_1 = require("./core/garbageCollection");
|
5
5
|
Object.defineProperty(exports, "retainQuery", { enumerable: true, get: function () { return garbageCollection_1.retainQuery; } });
|
6
6
|
Object.defineProperty(exports, "unretainQuery", { enumerable: true, get: function () { return garbageCollection_1.unretainQuery; } });
|
7
7
|
Object.defineProperty(exports, "garbageCollectEnvironment", { enumerable: true, get: function () { return garbageCollection_1.garbageCollectEnvironment; } });
|
8
|
+
var PromiseWrapper_1 = require("./core/PromiseWrapper");
|
9
|
+
Object.defineProperty(exports, "readPromise", { enumerable: true, get: function () { return PromiseWrapper_1.readPromise; } });
|
10
|
+
Object.defineProperty(exports, "getPromiseState", { enumerable: true, get: function () { return PromiseWrapper_1.getPromiseState; } });
|
8
11
|
var cache_1 = require("./core/cache");
|
9
12
|
Object.defineProperty(exports, "subscribe", { enumerable: true, get: function () { return cache_1.subscribe; } });
|
10
13
|
Object.defineProperty(exports, "normalizeData", { enumerable: true, get: function () { return cache_1.normalizeData; } });
|
@@ -24,8 +27,8 @@ Object.defineProperty(exports, "IsographEnvironmentProvider", { enumerable: true
|
|
24
27
|
Object.defineProperty(exports, "useIsographEnvironment", { enumerable: true, get: function () { return IsographEnvironmentProvider_1.useIsographEnvironment; } });
|
25
28
|
var useImperativeReference_1 = require("./react/useImperativeReference");
|
26
29
|
Object.defineProperty(exports, "useImperativeReference", { enumerable: true, get: function () { return useImperativeReference_1.useImperativeReference; } });
|
27
|
-
var
|
28
|
-
Object.defineProperty(exports, "
|
30
|
+
var FragmentReader_1 = require("./react/FragmentReader");
|
31
|
+
Object.defineProperty(exports, "FragmentReader", { enumerable: true, get: function () { return FragmentReader_1.FragmentReader; } });
|
29
32
|
var useResult_1 = require("./react/useResult");
|
30
33
|
Object.defineProperty(exports, "useResult", { enumerable: true, get: function () { return useResult_1.useResult; } });
|
31
34
|
var useLazyReference_1 = require("./react/useLazyReference");
|
@@ -4,7 +4,6 @@ exports.useClientSideDefer = void 0;
|
|
4
4
|
const IsographEnvironmentProvider_1 = require("../react/IsographEnvironmentProvider");
|
5
5
|
const cache_1 = require("../core/cache");
|
6
6
|
const react_disposable_state_1 = require("@isograph/react-disposable-state");
|
7
|
-
// TODO allow the user to pass props somehow
|
8
7
|
function useClientSideDefer(loadableField, args) {
|
9
8
|
// @ts-expect-error args is missing iff it has the type void
|
10
9
|
const [id, loader] = loadableField(args);
|
@@ -1,10 +1,13 @@
|
|
1
1
|
import * as React from 'react';
|
2
2
|
import { ExtractReadFromStore, IsographEntrypoint } from '../core/entrypoint';
|
3
3
|
import { FragmentReference } from '../core/FragmentReference';
|
4
|
-
|
4
|
+
import { NetworkRequestReaderOptions } from '../core/read';
|
5
|
+
export declare function FragmentReader<TProps extends Record<any, any>, TEntrypoint extends IsographEntrypoint<any, React.FC<TProps>>>(props: TProps extends Record<string, never> ? {
|
5
6
|
fragmentReference: FragmentReference<ExtractReadFromStore<TEntrypoint>, React.FC<{}>>;
|
6
7
|
additionalProps?: TProps;
|
8
|
+
networkRequestOptions?: NetworkRequestReaderOptions;
|
7
9
|
} : {
|
8
10
|
fragmentReference: FragmentReference<ExtractReadFromStore<TEntrypoint>, React.FC<TProps>>;
|
9
11
|
additionalProps: TProps;
|
12
|
+
networkRequestOptions?: NetworkRequestReaderOptions;
|
10
13
|
}): React.ReactNode;
|
@@ -23,11 +23,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
23
23
|
return result;
|
24
24
|
};
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
-
exports.
|
26
|
+
exports.FragmentReader = void 0;
|
27
27
|
const React = __importStar(require("react"));
|
28
28
|
const useResult_1 = require("./useResult");
|
29
|
-
function
|
30
|
-
|
29
|
+
function FragmentReader(props) {
|
30
|
+
var _a;
|
31
|
+
const Component = (0, useResult_1.useResult)(props.fragmentReference, (_a = props.networkRequestOptions) !== null && _a !== void 0 ? _a : {});
|
31
32
|
return React.createElement(Component, Object.assign({}, props.additionalProps));
|
32
33
|
}
|
33
|
-
exports.
|
34
|
+
exports.FragmentReader = FragmentReader;
|
@@ -3,5 +3,5 @@ import { IsographEntrypoint } from '../core/entrypoint';
|
|
3
3
|
import { FragmentReference, Variables } from '../core/FragmentReference';
|
4
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
|
};
|
@@ -10,8 +10,8 @@ function useImperativeReference(entrypoint) {
|
|
10
10
|
const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
|
11
11
|
return {
|
12
12
|
fragmentReference: state,
|
13
|
-
|
14
|
-
const [
|
13
|
+
loadFragmentReference: (variables) => {
|
14
|
+
const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.makeNetworkRequest)(environment, entrypoint, variables);
|
15
15
|
setState([
|
16
16
|
{
|
17
17
|
kind: 'FragmentReference',
|
@@ -19,6 +19,7 @@ function useImperativeReference(entrypoint) {
|
|
19
19
|
root: IsographEnvironment_1.ROOT_ID,
|
20
20
|
variables,
|
21
21
|
nestedRefetchQueries: entrypoint.nestedRefetchQueries,
|
22
|
+
networkRequest,
|
22
23
|
},
|
23
24
|
() => {
|
24
25
|
disposeNetworkRequest();
|
@@ -8,9 +8,7 @@ const react_disposable_state_1 = require("@isograph/react-disposable-state");
|
|
8
8
|
function useLazyReference(entrypoint, variables) {
|
9
9
|
const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
|
10
10
|
const cache = (0, cache_1.getOrCreateCacheForArtifact)(environment, entrypoint, variables);
|
11
|
-
|
12
|
-
// @ts-ignore(6133)
|
13
|
-
const _data = (0, react_disposable_state_1.useLazyDisposableState)(cache).state;
|
11
|
+
const networkRequest = (0, react_disposable_state_1.useLazyDisposableState)(cache).state;
|
14
12
|
return {
|
15
13
|
fragmentReference: {
|
16
14
|
kind: 'FragmentReference',
|
@@ -18,6 +16,7 @@ function useLazyReference(entrypoint, variables) {
|
|
18
16
|
root: IsographEnvironment_1.ROOT_ID,
|
19
17
|
variables,
|
20
18
|
nestedRefetchQueries: entrypoint.nestedRefetchQueries,
|
19
|
+
networkRequest,
|
21
20
|
},
|
22
21
|
};
|
23
22
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { FragmentReference } from '../core/FragmentReference';
|
2
|
-
import {
|
2
|
+
import { NetworkRequestReaderOptions } from '../core/read';
|
3
3
|
/**
|
4
4
|
* Read the data from a fragment reference and subscribe to updates.
|
5
5
|
* Does not pass the data to the fragment reference's resolver function.
|
6
6
|
*/
|
7
|
-
export declare function useReadAndSubscribe<TReadFromStore extends Object>(
|
7
|
+
export declare function useReadAndSubscribe<TReadFromStore extends Object>(fragmentReference: FragmentReference<TReadFromStore, any>, networkRequestOptions: NetworkRequestReaderOptions): TReadFromStore;
|